IVGCVSW-4118 Fix long unit test execution
authorColm Donelan <Colm.Donelan@arm.com>
Fri, 29 Nov 2019 09:10:59 +0000 (09:10 +0000)
committerMatteo Martincigh <matteo.martincigh@arm.com>
Fri, 29 Nov 2019 11:37:17 +0000 (11:37 +0000)
 * Reduced sleep_for timings
 * Removed duplicate SendStreamMetaDataPacket.
 * Modified SendCounterPacket::WaitForPacketSent to use wait_for
 * Modified SendCounterPacket::Send WaitingForAck to use wait_for
 * Added destructor to StreamRedirector.
 * Added method SendCounterPacketTests::HasWrittenData
 * Restructured many tests in ProfilingTests.

Signed-off-by: Keith Davis <keith.davis@arm.com>
Change-Id: I55c59cac6674ac40a1056a5302a997d5da9e9d91
Signed-off-by: Colm Donelan <Colm.Donelan@arm.com>
src/profiling/ConnectionAcknowledgedCommandHandler.cpp
src/profiling/ProfilingService.hpp
src/profiling/SendCounterPacket.cpp
src/profiling/SendCounterPacket.hpp
src/profiling/test/ProfilingGuidTest.cpp
src/profiling/test/ProfilingTests.cpp
src/profiling/test/ProfilingTests.hpp
src/profiling/test/SendCounterPacketTests.cpp
src/profiling/test/SendCounterPacketTests.hpp

index 630b555..a2a045d 100644 (file)
@@ -37,9 +37,7 @@ void ConnectionAcknowledgedCommandHandler::operator()(const Packet& packet)
 
         // Once a Connection Acknowledged packet has been received, move to the Active state immediately
         m_StateMachine.TransitionToState(ProfilingState::Active);
-
-        // Send all the packet required for the handshake with the external profiling service
-        m_SendCounterPacket.SendStreamMetaDataPacket();
+        // Send the counter directory packet.
         m_SendCounterPacket.SendCounterDirectoryPacket(m_CounterDirectory);
         m_SendTimelinePacket.SendTimelineMessageDirectoryPackage();
 
index ee199d5..9fc642f 100644 (file)
@@ -197,9 +197,9 @@ protected:
     {
         instance.m_StateMachine.TransitionToState(newState);
     }
-    void WaitForPacketSent(ProfilingService& instance)
+    void WaitForPacketSent(ProfilingService& instance, uint32_t timeout = 1000)
     {
-        return instance.m_SendCounterPacket.WaitForPacketSent();
+        return instance.m_SendCounterPacket.WaitForPacketSent(timeout);
     }
 };
 
index 1ed926b..2d64583 100644 (file)
@@ -1012,10 +1012,10 @@ void SendCounterPacket::Send(IProfilingConnection& profilingConnection)
                  // Flush the buffer manually to send the packet
                 FlushBuffer(profilingConnection);
 
-                // Wait indefinitely until notified otherwise (it could that the profiling state has changed due to the
-                // connection being acknowledged, or that new data is ready to be sent, or that the send thread is
-                // being shut down, etc.)
-                m_WaitCondition.wait(lock);
+                // Wait for a connection ack from the remote server. We should expect a response within timeout value.
+                // If not, drop back to the start of the loop and detect somebody closing the thread. Then send the
+                // StreamMetadata again.
+                m_WaitCondition.wait_for(lock, std::chrono::milliseconds(m_Timeout));
 
                 // Do not flush the buffer again
                 continue;
index 102cbcc..42e8432 100644 (file)
@@ -64,12 +64,11 @@ public:
     void Stop(bool rethrowSendThreadExceptions = true);
     bool IsRunning() { return m_IsRunning.load(); }
 
-    void WaitForPacketSent()
+    void WaitForPacketSent(uint32_t timeout = 1000)
     {
         std::unique_lock<std::mutex> lock(m_PacketSentWaitMutex);
-
-        // Blocks until notified that at least a packet has been sent
-        m_PacketSentWaitCondition.wait(lock);
+        // Blocks until notified that at least a packet has been sent or until timeout expires.
+        m_PacketSentWaitCondition.wait_for(lock, std::chrono::milliseconds(timeout));
     }
 
 private:
index cf5941d..5782d21 100644 (file)
@@ -81,7 +81,7 @@ BOOST_AUTO_TEST_CASE(StaticGuidGeneratorCollisionTest)
 {
     ProfilingGuidGenerator generator;
     std::set<uint64_t> guids;
-    for (int i = 0; i < 1000000; ++i)
+    for ( int i = 0; i < 100000; ++i )
     {
         std::stringstream ss;
         ss << i;
index 4c4ec0a..73f1c20 100644 (file)
@@ -143,53 +143,90 @@ BOOST_AUTO_TEST_CASE(CheckCommandHandler)
     profilingStateMachine.TransitionToState(ProfilingState::NotConnected);
     profilingStateMachine.TransitionToState(ProfilingState::WaitingForAck);
 
+    // A 1mSec timeout should be enough to slow the command handler thread a little.
     CommandHandler commandHandler0(1, true, commandHandlerRegistry, packetVersionResolver);
 
+    // This should start the command handler thread return the connection ack and put the profiling
+    // service into active state.
     commandHandler0.Start(testProfilingConnectionBase);
-    commandHandler0.Start(testProfilingConnectionBase);
+    // Try to start the send thread many times, it must only start once
     commandHandler0.Start(testProfilingConnectionBase);
 
-    commandHandler0.Stop();
+    // This could take up to 20mSec but we'll check often.
+    for (int i = 0; i < 10; i++)
+    {
+        if (profilingStateMachine.GetCurrentState() == ProfilingState::Active)
+        {
+            break;
+        }
+        std::this_thread::sleep_for(std::chrono::milliseconds(2));
+    }
 
     BOOST_CHECK(profilingStateMachine.GetCurrentState() == ProfilingState::Active);
 
+    // Close the thread again.
+    commandHandler0.Stop();
+
     profilingStateMachine.TransitionToState(ProfilingState::NotConnected);
     profilingStateMachine.TransitionToState(ProfilingState::WaitingForAck);
-    // commandHandler1 should give up after one timeout
-    CommandHandler commandHandler1(10, true, commandHandlerRegistry, packetVersionResolver);
 
-    commandHandler1.Start(testProfilingConnectionTimeOutError);
+    // In this test we'll simulate a timeout without a connection ack packet being received.
+    // Stop after timeout is set so we expect the command handler to stop almost immediately.
+    CommandHandler commandHandler1(1, true, commandHandlerRegistry, packetVersionResolver);
 
-    std::this_thread::sleep_for(std::chrono::milliseconds(100));
+    commandHandler1.Start(testProfilingConnectionTimeOutError);
+    // Wait until we know a timeout exception has been sent at least once.
+    for (int i = 0; i < 10; i++)
+    {
+        if (testProfilingConnectionTimeOutError.ReadCalledCount())
+        {
+            break;
+        }
+        std::this_thread::sleep_for(std::chrono::milliseconds(2));
+    }
+    // and leave another short period for the timeout exception to be processed and the loop to break.
+    std::this_thread::sleep_for(std::chrono::milliseconds(3));
 
+    // The command handler loop should have stopped after the timeout.
     BOOST_CHECK(!commandHandler1.IsRunning());
-    commandHandler1.Stop();
 
+    commandHandler1.Stop();
+    // The state machine should never have received the ack so will still be in WaitingForAck.
     BOOST_CHECK(profilingStateMachine.GetCurrentState() == ProfilingState::WaitingForAck);
-    // Now commandHandler1 should persist after a timeout
+
+    // Disable stop after timeout and now commandHandler1 should persist after a timeout
     commandHandler1.SetStopAfterTimeout(false);
+    // Restart the thread.
     commandHandler1.Start(testProfilingConnectionTimeOutError);
 
-    for (int i = 0; i < 100; i++)
+    // Wait for at the three timeouts and the ack to be sent.
+    for (int i = 0; i < 10; i++)
     {
-        if (profilingStateMachine.GetCurrentState() == ProfilingState::Active)
+        if (testProfilingConnectionTimeOutError.ReadCalledCount() > 3)
         {
             break;
         }
-
-        std::this_thread::sleep_for(std::chrono::milliseconds(100));
+        std::this_thread::sleep_for(std::chrono::milliseconds(2));
     }
-
     commandHandler1.Stop();
 
+    // Even after the 3 exceptions the ack packet should have transitioned the command handler to active.
     BOOST_CHECK(profilingStateMachine.GetCurrentState() == ProfilingState::Active);
 
-    CommandHandler commandHandler2(100, false, commandHandlerRegistry, packetVersionResolver);
+    // A command handler that gets exceptions other than timeouts should keep going.
+    CommandHandler commandHandler2(1, false, commandHandlerRegistry, packetVersionResolver);
 
     commandHandler2.Start(testProfilingConnectionArmnnError);
 
-    // commandHandler2 should not stop once it encounters a non timing error
-    std::this_thread::sleep_for(std::chrono::milliseconds(500));
+    // Wait for two exceptions to be thrown.
+    for (int i = 0; i < 10; i++)
+    {
+        if (testProfilingConnectionTimeOutError.ReadCalledCount() >= 2)
+        {
+            break;
+        }
+        std::this_thread::sleep_for(std::chrono::milliseconds(2));
+    }
 
     BOOST_CHECK(commandHandler2.IsRunning());
     commandHandler2.Stop();
@@ -591,50 +628,6 @@ BOOST_AUTO_TEST_CASE(CheckProfilingServiceDisabled)
     BOOST_CHECK(profilingService.GetCurrentState() == ProfilingState::Uninitialised);
 }
 
-BOOST_AUTO_TEST_CASE(CheckProfilingServiceEnabled)
-{
-    // Locally reduce log level to "Warning", as this test needs to parse a warning message from the standard output
-    LogLevelSwapper logLevelSwapper(armnn::LogSeverity::Warning);
-
-    armnn::Runtime::CreationOptions::ExternalProfilingOptions options;
-    options.m_EnableProfiling          = true;
-    ProfilingService& profilingService = ProfilingService::Instance();
-    profilingService.ResetExternalProfilingOptions(options, true);
-    BOOST_CHECK(profilingService.GetCurrentState() == ProfilingState::Uninitialised);
-    profilingService.Update();
-    BOOST_CHECK(profilingService.GetCurrentState() == ProfilingState::NotConnected);
-
-    // Redirect the output to a local stream so that we can parse the warning message
-    std::stringstream ss;
-    StreamRedirector streamRedirector(std::cout, ss.rdbuf());
-    profilingService.Update();
-    BOOST_CHECK(boost::contains(ss.str(), "Cannot connect to stream socket: Connection refused"));
-}
-
-BOOST_AUTO_TEST_CASE(CheckProfilingServiceEnabledRuntime)
-{
-    // Locally reduce log level to "Warning", as this test needs to parse a warning message from the standard output
-    LogLevelSwapper logLevelSwapper(armnn::LogSeverity::Warning);
-
-    armnn::Runtime::CreationOptions::ExternalProfilingOptions options;
-    ProfilingService& profilingService = ProfilingService::Instance();
-    profilingService.ResetExternalProfilingOptions(options, true);
-    BOOST_CHECK(profilingService.GetCurrentState() == ProfilingState::Uninitialised);
-    profilingService.Update();
-    BOOST_CHECK(profilingService.GetCurrentState() == ProfilingState::Uninitialised);
-    options.m_EnableProfiling = true;
-    profilingService.ResetExternalProfilingOptions(options);
-    BOOST_CHECK(profilingService.GetCurrentState() == ProfilingState::Uninitialised);
-    profilingService.Update();
-    BOOST_CHECK(profilingService.GetCurrentState() == ProfilingState::NotConnected);
-
-    // Redirect the output to a local stream so that we can parse the warning message
-    std::stringstream ss;
-    StreamRedirector streamRedirector(std::cout, ss.rdbuf());
-    profilingService.Update();
-    BOOST_CHECK(boost::contains(ss.str(), "Cannot connect to stream socket: Connection refused"));
-}
-
 BOOST_AUTO_TEST_CASE(CheckProfilingServiceCounterDirectory)
 {
     armnn::Runtime::CreationOptions::ExternalProfilingOptions options;
@@ -653,6 +646,9 @@ BOOST_AUTO_TEST_CASE(CheckProfilingServiceCounterDirectory)
     BOOST_CHECK(counterDirectory1.GetCounterCount() == 0);
     profilingService.Update();
     BOOST_CHECK(counterDirectory1.GetCounterCount() != 0);
+    // Reset the profiling service to stop any running thread
+    options.m_EnableProfiling = false;
+    profilingService.ResetExternalProfilingOptions(options, true);
 }
 
 BOOST_AUTO_TEST_CASE(CheckProfilingServiceCounterValues)
@@ -682,7 +678,6 @@ BOOST_AUTO_TEST_CASE(CheckProfilingServiceCounterValues)
         writers.push_back(std::thread(&ProfilingService::AddCounterValue, profilingServicePtr, counterUid, 10));
         writers.push_back(std::thread(&ProfilingService::SubtractCounterValue, profilingServicePtr, counterUid, 5));
     }
-
     std::for_each(writers.begin(), writers.end(), mem_fn(&std::thread::join));
 
     uint32_t counterValue = 0;
@@ -692,6 +687,9 @@ BOOST_AUTO_TEST_CASE(CheckProfilingServiceCounterValues)
     BOOST_CHECK_NO_THROW(profilingService.SetCounterValue(counterUid, 0));
     BOOST_CHECK_NO_THROW(counterValue = profilingService.GetCounterValue(counterUid));
     BOOST_CHECK(counterValue == 0);
+    // Reset the profiling service to stop any running thread
+    options.m_EnableProfiling = false;
+    profilingService.ResetExternalProfilingOptions(options, true);
 }
 
 BOOST_AUTO_TEST_CASE(CheckProfilingObjectUids)
@@ -2187,18 +2185,11 @@ BOOST_AUTO_TEST_CASE(RequestCounterDirectoryCommandHandlerTest2)
     BOOST_TEST(header2Word1 == 419);                      // data length
 }
 
-BOOST_AUTO_TEST_CASE(CheckProfilingServiceBadConnectionAcknowledgedPacket)
+BOOST_AUTO_TEST_CASE(CheckProfilingServiceGoodConnectionAcknowledgedPacket)
 {
-    // Locally reduce log level to "Warning", as this test needs to parse a warning message from the standard output
-    LogLevelSwapper logLevelSwapper(armnn::LogSeverity::Warning);
-
     // Swap the profiling connection factory in the profiling service instance with our mock one
     SwapProfilingConnectionFactoryHelper helper;
 
-    // Redirect the standard output to a local stream so that we can parse the warning message
-    std::stringstream ss;
-    StreamRedirector streamRedirector(std::cout, ss.rdbuf());
-
     // Calculate the size of a Stream Metadata packet
     std::string processName      = GetProcessName().substr(0, 60);
     unsigned int processNameSize = processName.empty() ? 0 : boost::numeric_cast<unsigned int>(processName.size()) + 1;
@@ -2224,15 +2215,27 @@ BOOST_AUTO_TEST_CASE(CheckProfilingServiceBadConnectionAcknowledgedPacket)
     mockProfilingConnection->Clear();
 
     BOOST_CHECK(profilingService.GetCurrentState() == ProfilingState::WaitingForAck);
-    profilingService.Update();
+    profilingService.Update();    // Start the command handler and the send thread
 
     // Wait for the Stream Metadata packet to be sent
-    helper.WaitForProfilingPacketsSent();
+    helper.WaitForProfilingPacketsSent(mockProfilingConnection);
 
     // Check that the mock profiling connection contains one Stream Metadata packet
     const std::vector<uint32_t> writtenData = mockProfilingConnection->GetWrittenData();
-    BOOST_TEST(writtenData.size() == 1);
-    BOOST_TEST(writtenData[0] == streamMetadataPacketsize);
+    if (writtenData.size() > 1)
+    {
+        // If this thread has been blocked for some time a second or more Stream Metadata packet could have been sent.
+        // In these cases make sure all packet are of length streamMetadataPacketsize
+        for(uint32_t packetLength : writtenData)
+        {
+            BOOST_TEST(packetLength == streamMetadataPacketsize);
+        }
+    }
+    else
+    {
+        BOOST_TEST(writtenData.size() == 1);
+        BOOST_TEST(writtenData[0] == streamMetadataPacketsize);
+    }
 
     // Write a valid "Connection Acknowledged" packet into the mock profiling connection, to simulate a valid
     // reply from an external profiling service
@@ -2243,7 +2246,7 @@ BOOST_AUTO_TEST_CASE(CheckProfilingServiceBadConnectionAcknowledgedPacket)
     // 8:15  [8]  reserved: Reserved, value 0b00000000
     // 0:7   [8]  reserved: Reserved, value 0b00000000
     uint32_t packetFamily = 0;
-    uint32_t packetId     = 37;    // Wrong packet id!!!
+    uint32_t packetId     = 1;
     uint32_t header       = ((packetFamily & 0x0000003F) << 26) | ((packetId & 0x000003FF) << 16);
 
     // Create the Connection Acknowledged Packet
@@ -2252,83 +2255,79 @@ BOOST_AUTO_TEST_CASE(CheckProfilingServiceBadConnectionAcknowledgedPacket)
     // Write the packet to the mock profiling connection
     mockProfilingConnection->WritePacket(std::move(connectionAcknowledgedPacket));
 
-    // Wait for a bit (must at least be the delay value of the mock profiling connection) to make sure that
-    // the Connection Acknowledged packet gets processed by the profiling service
-    std::this_thread::sleep_for(std::chrono::seconds(2));
-
-    // Check that the expected error has occurred and logged to the standard output
-    BOOST_CHECK(boost::contains(ss.str(), "Functor with requested PacketId=37 and Version=4194304 does not exist"));
+    // Wait for the counter directory packet to ensure the ConnectionAcknowledgedCommandHandler has run.
+    helper.WaitForProfilingPacketsSent(mockProfilingConnection, 5000);
 
-    // The Connection Acknowledged Command Handler should not have updated the profiling state
-    BOOST_CHECK(profilingService.GetCurrentState() == ProfilingState::WaitingForAck);
+    // The Connection Acknowledged Command Handler should have updated the profiling state accordingly
+    BOOST_CHECK(profilingService.GetCurrentState() == ProfilingState::Active);
 
     // Reset the profiling service to stop any running thread
     options.m_EnableProfiling = false;
     profilingService.ResetExternalProfilingOptions(options, true);
 }
 
-BOOST_AUTO_TEST_CASE(CheckProfilingServiceGoodConnectionAcknowledgedPacket)
+BOOST_AUTO_TEST_CASE(CheckProfilingServiceGoodRequestCounterDirectoryPacket)
 {
     // Swap the profiling connection factory in the profiling service instance with our mock one
     SwapProfilingConnectionFactoryHelper helper;
 
-    // Calculate the size of a Stream Metadata packet
-    std::string processName      = GetProcessName().substr(0, 60);
-    unsigned int processNameSize = processName.empty() ? 0 : boost::numeric_cast<unsigned int>(processName.size()) + 1;
-    unsigned int streamMetadataPacketsize = 118 + processNameSize;
-
     // Reset the profiling service to the uninitialized state
     armnn::Runtime::CreationOptions::ExternalProfilingOptions options;
     options.m_EnableProfiling          = true;
     ProfilingService& profilingService = ProfilingService::Instance();
     profilingService.ResetExternalProfilingOptions(options, true);
 
-    // Bring the profiling service to the "WaitingForAck" state
+    // Bring the profiling service to the "Active" state
     BOOST_CHECK(profilingService.GetCurrentState() == ProfilingState::Uninitialised);
     profilingService.Update();    // Initialize the counter directory
     BOOST_CHECK(profilingService.GetCurrentState() == ProfilingState::NotConnected);
     profilingService.Update();    // Create the profiling connection
+    BOOST_CHECK(profilingService.GetCurrentState() == ProfilingState::WaitingForAck);
+    profilingService.Update();    // Start the command handler and the send thread
 
     // Get the mock profiling connection
     MockProfilingConnection* mockProfilingConnection = helper.GetMockProfilingConnection();
     BOOST_CHECK(mockProfilingConnection);
 
-    // Remove the packets received so far
-    mockProfilingConnection->Clear();
-
-    BOOST_CHECK(profilingService.GetCurrentState() == ProfilingState::WaitingForAck);
-    profilingService.Update();    // Start the command handler and the send thread
+    // Wait for the Stream Metadata packet the be sent
+    // (we are not testing the connection acknowledgement here so it will be ignored by this test)
+    helper.WaitForProfilingPacketsSent(mockProfilingConnection);
 
-    // Wait for the Stream Metadata packet to be sent
-    helper.WaitForProfilingPacketsSent();
+    // Force the profiling service to the "Active" state
+    helper.ForceTransitionToState(ProfilingState::Active);
+    BOOST_CHECK(profilingService.GetCurrentState() == ProfilingState::Active);
 
-    // Check that the mock profiling connection contains one Stream Metadata packet
-    const std::vector<uint32_t> writtenData = mockProfilingConnection->GetWrittenData();
-    BOOST_TEST(writtenData.size() == 1);
-    BOOST_TEST(writtenData[0] == streamMetadataPacketsize);
+    // Remove the packets received so far
+    mockProfilingConnection->Clear();
 
-    // Write a valid "Connection Acknowledged" packet into the mock profiling connection, to simulate a valid
+    // Write a valid "Request Counter Directory" packet into the mock profiling connection, to simulate a valid
     // reply from an external profiling service
 
-    // Connection Acknowledged Packet header (word 0, word 1 is always zero):
+    // Request Counter Directory packet header (word 0, word 1 is always zero):
     // 26:31 [6]  packet_family: Control Packet Family, value 0b000000
-    // 16:25 [10] packet_id: Packet identifier, value 0b0000000001
+    // 16:25 [10] packet_id: Packet identifier, value 0b0000000011
     // 8:15  [8]  reserved: Reserved, value 0b00000000
     // 0:7   [8]  reserved: Reserved, value 0b00000000
     uint32_t packetFamily = 0;
-    uint32_t packetId     = 1;
+    uint32_t packetId     = 3;
     uint32_t header       = ((packetFamily & 0x0000003F) << 26) | ((packetId & 0x000003FF) << 16);
 
-    // Create the Connection Acknowledged Packet
-    Packet connectionAcknowledgedPacket(header);
+    // Create the Request Counter Directory packet
+    Packet requestCounterDirectoryPacket(header);
 
     // Write the packet to the mock profiling connection
-    mockProfilingConnection->WritePacket(std::move(connectionAcknowledgedPacket));
+    mockProfilingConnection->WritePacket(std::move(requestCounterDirectoryPacket));
 
     // Wait for the Counter Directory packet to be sent
-    helper.WaitForProfilingPacketsSent();
+    helper.WaitForProfilingPacketsSent(mockProfilingConnection, 5000);
 
-    // The Connection Acknowledged Command Handler should have updated the profiling state accordingly
+    // Check that the mock profiling connection contains one Counter Directory packet
+    const std::vector<uint32_t> writtenData = mockProfilingConnection->GetWrittenData();
+    BOOST_TEST(writtenData.size() == 2);
+    BOOST_TEST(writtenData[0] == 427); // The size of the expected Timeline Directory packet
+    BOOST_TEST(writtenData[1] == 416); // The size of the expected Counter Directory packet
+
+    // The Request Counter Directory Command Handler should not have updated the profiling state
     BOOST_CHECK(profilingService.GetCurrentState() == ProfilingState::Active);
 
     // Reset the profiling service to stop any running thread
@@ -2336,18 +2335,11 @@ BOOST_AUTO_TEST_CASE(CheckProfilingServiceGoodConnectionAcknowledgedPacket)
     profilingService.ResetExternalProfilingOptions(options, true);
 }
 
-BOOST_AUTO_TEST_CASE(CheckProfilingServiceBadRequestCounterDirectoryPacket)
+BOOST_AUTO_TEST_CASE(CheckProfilingServiceBadPeriodicCounterSelectionPacketInvalidCounterUid)
 {
-    // Locally reduce log level to "Warning", as this test needs to parse a warning message from the standard output
-    LogLevelSwapper logLevelSwapper(armnn::LogSeverity::Warning);
-
     // Swap the profiling connection factory in the profiling service instance with our mock one
     SwapProfilingConnectionFactoryHelper helper;
 
-    // Redirect the standard output to a local stream so that we can parse the warning message
-    std::stringstream ss;
-    StreamRedirector streamRedirector(std::cout, ss.rdbuf());
-
     // Reset the profiling service to the uninitialized state
     armnn::Runtime::CreationOptions::ExternalProfilingOptions options;
     options.m_EnableProfiling          = true;
@@ -2356,53 +2348,87 @@ BOOST_AUTO_TEST_CASE(CheckProfilingServiceBadRequestCounterDirectoryPacket)
 
     // Bring the profiling service to the "Active" state
     BOOST_CHECK(profilingService.GetCurrentState() == ProfilingState::Uninitialised);
-    helper.ForceTransitionToState(ProfilingState::NotConnected);
+    profilingService.Update();    // Initialize the counter directory
     BOOST_CHECK(profilingService.GetCurrentState() == ProfilingState::NotConnected);
     profilingService.Update();    // Create the profiling connection
     BOOST_CHECK(profilingService.GetCurrentState() == ProfilingState::WaitingForAck);
     profilingService.Update();    // Start the command handler and the send thread
 
+    // Get the mock profiling connection
+    MockProfilingConnection* mockProfilingConnection = helper.GetMockProfilingConnection();
+    BOOST_CHECK(mockProfilingConnection);
+
     // Wait for the Stream Metadata packet the be sent
     // (we are not testing the connection acknowledgement here so it will be ignored by this test)
-    helper.WaitForProfilingPacketsSent();
+    helper.WaitForProfilingPacketsSent(mockProfilingConnection);
 
     // Force the profiling service to the "Active" state
     helper.ForceTransitionToState(ProfilingState::Active);
     BOOST_CHECK(profilingService.GetCurrentState() == ProfilingState::Active);
 
-    // Get the mock profiling connection
-    MockProfilingConnection* mockProfilingConnection = helper.GetMockProfilingConnection();
-    BOOST_CHECK(mockProfilingConnection);
-
     // Remove the packets received so far
     mockProfilingConnection->Clear();
 
-    // Write a valid "Request Counter Directory" packet into the mock profiling connection, to simulate a valid
-    // reply from an external profiling service
+    // Write a "Periodic Counter Selection" packet into the mock profiling connection, to simulate an input from an
+    // external profiling service
 
-    // Request Counter Directory packet header (word 0, word 1 is always zero):
+    // Periodic Counter Selection packet header:
     // 26:31 [6]  packet_family: Control Packet Family, value 0b000000
-    // 16:25 [10] packet_id: Packet identifier, value 0b0000000011
+    // 16:25 [10] packet_id: Packet identifier, value 0b0000000100
     // 8:15  [8]  reserved: Reserved, value 0b00000000
     // 0:7   [8]  reserved: Reserved, value 0b00000000
     uint32_t packetFamily = 0;
-    uint32_t packetId     = 123;    // Wrong packet id!!!
+    uint32_t packetId     = 4;
     uint32_t header       = ((packetFamily & 0x0000003F) << 26) | ((packetId & 0x000003FF) << 16);
 
-    // Create the Request Counter Directory packet
-    Packet requestCounterDirectoryPacket(header);
+    uint32_t capturePeriod = 123456;    // Some capture period (microseconds)
+
+    // Get the first valid counter UID
+    const ICounterDirectory& counterDirectory = profilingService.GetCounterDirectory();
+    const Counters& counters                  = counterDirectory.GetCounters();
+    BOOST_CHECK(counters.size() > 1);
+    uint16_t counterUidA = counters.begin()->first;    // First valid counter UID
+    uint16_t counterUidB = 9999;                       // Second invalid counter UID
+
+    uint32_t length = 8;
+
+    auto data = std::make_unique<unsigned char[]>(length);
+    WriteUint32(data.get(), 0, capturePeriod);
+    WriteUint16(data.get(), 4, counterUidA);
+    WriteUint16(data.get(), 6, counterUidB);
+
+    // Create the Periodic Counter Selection packet
+    Packet periodicCounterSelectionPacket(header, length, data);    // Length > 0, this will start the Period Counter
+                                                                    // Capture thread
 
     // Write the packet to the mock profiling connection
-    mockProfilingConnection->WritePacket(std::move(requestCounterDirectoryPacket));
+    mockProfilingConnection->WritePacket(std::move(periodicCounterSelectionPacket));
 
-    // Wait for a bit (must at least be the delay value of the mock profiling connection) to make sure that
-    // the Create the Request Counter packet gets processed by the profiling service
-    std::this_thread::sleep_for(std::chrono::seconds(2));
+    // Expecting one Periodic Counter Selection packet and at least one Periodic Counter Capture packet
+    int expectedPackets = 2;
+    std::vector<uint32_t> receivedPackets;
 
-    // Check that the expected error has occurred and logged to the standard output
-    BOOST_CHECK(boost::contains(ss.str(), "Functor with requested PacketId=123 and Version=4194304 does not exist"));
+    // Keep waiting until all the expected packets have been received
+    do
+    {
+        helper.WaitForProfilingPacketsSent(mockProfilingConnection);
+        const std::vector<uint32_t> writtenData = mockProfilingConnection->GetWrittenData();
+        if (writtenData.empty())
+        {
+            BOOST_ERROR("Packets should be available for reading at this point");
+            return;
+        }
+        receivedPackets.insert(receivedPackets.end(), writtenData.begin(), writtenData.end());
+        expectedPackets -= boost::numeric_cast<int>(writtenData.size());
+    } while (expectedPackets > 0);
+    BOOST_TEST(!receivedPackets.empty());
 
-    // The Request Counter Directory Command Handler should not have updated the profiling state
+    // The size of the expected Periodic Counter Selection packet
+    BOOST_TEST((std::find(receivedPackets.begin(), receivedPackets.end(), 14) != receivedPackets.end()));
+    // The size of the expected Periodic Counter Capture packet
+    BOOST_TEST((std::find(receivedPackets.begin(), receivedPackets.end(), 22) != receivedPackets.end()));
+
+    // The Periodic Counter Selection Handler should not have updated the profiling state
     BOOST_CHECK(profilingService.GetCurrentState() == ProfilingState::Active);
 
     // Reset the profiling service to stop any running thread
@@ -2410,7 +2436,7 @@ BOOST_AUTO_TEST_CASE(CheckProfilingServiceBadRequestCounterDirectoryPacket)
     profilingService.ResetExternalProfilingOptions(options, true);
 }
 
-BOOST_AUTO_TEST_CASE(CheckProfilingServiceGoodRequestCounterDirectoryPacket)
+BOOST_AUTO_TEST_CASE(CheckProfilingServiceGoodPeriodicCounterSelectionPacketNoCounters)
 {
     // Swap the profiling connection factory in the profiling service instance with our mock one
     SwapProfilingConnectionFactoryHelper helper;
@@ -2429,68 +2455,60 @@ BOOST_AUTO_TEST_CASE(CheckProfilingServiceGoodRequestCounterDirectoryPacket)
     BOOST_CHECK(profilingService.GetCurrentState() == ProfilingState::WaitingForAck);
     profilingService.Update();    // Start the command handler and the send thread
 
+    // Get the mock profiling connection
+    MockProfilingConnection* mockProfilingConnection = helper.GetMockProfilingConnection();
+    BOOST_CHECK(mockProfilingConnection);
+
     // Wait for the Stream Metadata packet the be sent
     // (we are not testing the connection acknowledgement here so it will be ignored by this test)
-    helper.WaitForProfilingPacketsSent();
+    helper.WaitForProfilingPacketsSent(mockProfilingConnection);
 
     // Force the profiling service to the "Active" state
     helper.ForceTransitionToState(ProfilingState::Active);
     BOOST_CHECK(profilingService.GetCurrentState() == ProfilingState::Active);
 
-    // Get the mock profiling connection
-    MockProfilingConnection* mockProfilingConnection = helper.GetMockProfilingConnection();
-    BOOST_CHECK(mockProfilingConnection);
-
     // Remove the packets received so far
     mockProfilingConnection->Clear();
 
-    // Write a valid "Request Counter Directory" packet into the mock profiling connection, to simulate a valid
-    // reply from an external profiling service
+    // Write a "Periodic Counter Selection" packet into the mock profiling connection, to simulate an input from an
+    // external profiling service
 
-    // Request Counter Directory packet header (word 0, word 1 is always zero):
+    // Periodic Counter Selection packet header:
     // 26:31 [6]  packet_family: Control Packet Family, value 0b000000
-    // 16:25 [10] packet_id: Packet identifier, value 0b0000000011
+    // 16:25 [10] packet_id: Packet identifier, value 0b0000000100
     // 8:15  [8]  reserved: Reserved, value 0b00000000
     // 0:7   [8]  reserved: Reserved, value 0b00000000
     uint32_t packetFamily = 0;
-    uint32_t packetId     = 3;
+    uint32_t packetId     = 4;
     uint32_t header       = ((packetFamily & 0x0000003F) << 26) | ((packetId & 0x000003FF) << 16);
 
-    // Create the Request Counter Directory packet
-    Packet requestCounterDirectoryPacket(header);
+    // Create the Periodic Counter Selection packet
+    Packet periodicCounterSelectionPacket(header);    // Length == 0, this will disable the collection of counters
 
     // Write the packet to the mock profiling connection
-    mockProfilingConnection->WritePacket(std::move(requestCounterDirectoryPacket));
+    mockProfilingConnection->WritePacket(std::move(periodicCounterSelectionPacket));
 
-    // Wait for the Counter Directory packet to be sent
-    helper.WaitForProfilingPacketsSent();
-
-    // Check that the mock profiling connection contains one Counter Directory packet
-    const std::vector<uint32_t> writtenData = mockProfilingConnection->GetWrittenData();
-    BOOST_TEST(writtenData.size() == 2);
-    BOOST_TEST(writtenData[0] == 427); // The size of the expected Timeline Directory packet
-    BOOST_TEST(writtenData[1] == 416); // The size of the expected Counter Directory packet
+    // Wait for the Periodic Counter Selection packet to be sent
+    helper.WaitForProfilingPacketsSent(mockProfilingConnection, 5000);
 
-    // The Request Counter Directory Command Handler should not have updated the profiling state
+    // The Periodic Counter Selection Handler should not have updated the profiling state
     BOOST_CHECK(profilingService.GetCurrentState() == ProfilingState::Active);
 
+    // Check that the mock profiling connection contains one Periodic Counter Selection
+    const std::vector<uint32_t> writtenData = mockProfilingConnection->GetWrittenData();
+    BOOST_TEST(writtenData.size() == 1);    // Only one packet is expected (no Periodic Counter packets)
+    BOOST_TEST(writtenData[0] == 12);       // The size of the expected Periodic Counter Selection (echos the sent one)
+
     // Reset the profiling service to stop any running thread
     options.m_EnableProfiling = false;
     profilingService.ResetExternalProfilingOptions(options, true);
 }
 
-BOOST_AUTO_TEST_CASE(CheckProfilingServiceBadPeriodicCounterSelectionPacket)
+BOOST_AUTO_TEST_CASE(CheckProfilingServiceGoodPeriodicCounterSelectionPacketSingleCounter)
 {
-    // Locally reduce log level to "Warning", as this test needs to parse a warning message from the standard output
-    LogLevelSwapper logLevelSwapper(armnn::LogSeverity::Warning);
-
     // Swap the profiling connection factory in the profiling service instance with our mock one
     SwapProfilingConnectionFactoryHelper helper;
 
-    // Redirect the standard output to a local stream so that we can parse the warning message
-    std::stringstream ss;
-    StreamRedirector streamRedirector(std::cout, ss.rdbuf());
-
     // Reset the profiling service to the uninitialized state
     armnn::Runtime::CreationOptions::ExternalProfilingOptions options;
     options.m_EnableProfiling          = true;
@@ -2505,18 +2523,18 @@ BOOST_AUTO_TEST_CASE(CheckProfilingServiceBadPeriodicCounterSelectionPacket)
     BOOST_CHECK(profilingService.GetCurrentState() == ProfilingState::WaitingForAck);
     profilingService.Update();    // Start the command handler and the send thread
 
+    // Get the mock profiling connection
+    MockProfilingConnection* mockProfilingConnection = helper.GetMockProfilingConnection();
+    BOOST_CHECK(mockProfilingConnection);
+
     // Wait for the Stream Metadata packet the be sent
     // (we are not testing the connection acknowledgement here so it will be ignored by this test)
-    helper.WaitForProfilingPacketsSent();
+    helper.WaitForProfilingPacketsSent(mockProfilingConnection);
 
     // Force the profiling service to the "Active" state
     helper.ForceTransitionToState(ProfilingState::Active);
     BOOST_CHECK(profilingService.GetCurrentState() == ProfilingState::Active);
 
-    // Get the mock profiling connection
-    MockProfilingConnection* mockProfilingConnection = helper.GetMockProfilingConnection();
-    BOOST_CHECK(mockProfilingConnection);
-
     // Remove the packets received so far
     mockProfilingConnection->Clear();
 
@@ -2529,21 +2547,53 @@ BOOST_AUTO_TEST_CASE(CheckProfilingServiceBadPeriodicCounterSelectionPacket)
     // 8:15  [8]  reserved: Reserved, value 0b00000000
     // 0:7   [8]  reserved: Reserved, value 0b00000000
     uint32_t packetFamily = 0;
-    uint32_t packetId     = 999;    // Wrong packet id!!!
+    uint32_t packetId     = 4;
     uint32_t header       = ((packetFamily & 0x0000003F) << 26) | ((packetId & 0x000003FF) << 16);
 
+    uint32_t capturePeriod = 123456;    // Some capture period (microseconds)
+
+    // Get the first valid counter UID
+    const ICounterDirectory& counterDirectory = profilingService.GetCounterDirectory();
+    const Counters& counters                  = counterDirectory.GetCounters();
+    BOOST_CHECK(!counters.empty());
+    uint16_t counterUid = counters.begin()->first;    // Valid counter UID
+
+    uint32_t length = 6;
+
+    auto data = std::make_unique<unsigned char[]>(length);
+    WriteUint32(data.get(), 0, capturePeriod);
+    WriteUint16(data.get(), 4, counterUid);
+
     // Create the Periodic Counter Selection packet
-    Packet periodicCounterSelectionPacket(header);    // Length == 0, this will disable the collection of counters
+    Packet periodicCounterSelectionPacket(header, length, data);    // Length > 0, this will start the Period Counter
+                                                                    // Capture thread
 
     // Write the packet to the mock profiling connection
     mockProfilingConnection->WritePacket(std::move(periodicCounterSelectionPacket));
 
-    // Wait for a bit (must at least be the delay value of the mock profiling connection) to make sure that
-    // the Periodic Counter Selection packet gets processed by the profiling service
-    std::this_thread::sleep_for(std::chrono::seconds(2));
+    // Expecting one Periodic Counter Selection packet and at least one Periodic Counter Capture packet
+    int expectedPackets = 2;
+    std::vector<uint32_t> receivedPackets;
 
-    // Check that the expected error has occurred and logged to the standard output
-    BOOST_CHECK(boost::contains(ss.str(), "Functor with requested PacketId=999 and Version=4194304 does not exist"));
+    // Keep waiting until all the expected packets have been received
+    do
+    {
+        helper.WaitForProfilingPacketsSent(mockProfilingConnection);
+        const std::vector<uint32_t> writtenData = mockProfilingConnection->GetWrittenData();
+        if (writtenData.empty())
+        {
+            BOOST_ERROR("Packets should be available for reading at this point");
+            return;
+        }
+        receivedPackets.insert(receivedPackets.end(), writtenData.begin(), writtenData.end());
+        expectedPackets -= boost::numeric_cast<int>(writtenData.size());
+    } while (expectedPackets > 0);
+    BOOST_TEST(!receivedPackets.empty());
+
+    // The size of the expected Periodic Counter Selection packet (echos the sent one)
+    BOOST_TEST((std::find(receivedPackets.begin(), receivedPackets.end(), 14) != receivedPackets.end()));
+    // The size of the expected Periodic Counter Capture packet
+    BOOST_TEST((std::find(receivedPackets.begin(), receivedPackets.end(), 22) != receivedPackets.end()));
 
     // The Periodic Counter Selection Handler should not have updated the profiling state
     BOOST_CHECK(profilingService.GetCurrentState() == ProfilingState::Active);
@@ -2553,14 +2603,10 @@ BOOST_AUTO_TEST_CASE(CheckProfilingServiceBadPeriodicCounterSelectionPacket)
     profilingService.ResetExternalProfilingOptions(options, true);
 }
 
-BOOST_AUTO_TEST_CASE(CheckProfilingServiceBadPeriodicCounterSelectionPacketInvalidCounterUid)
+BOOST_AUTO_TEST_CASE(CheckProfilingServiceGoodPeriodicCounterSelectionPacketMultipleCounters)
 {
-    // Locally reduce log level to "Warning", as this test needs to parse a warning message from the standard output
-    LogLevelSwapper logLevelSwapper(armnn::LogSeverity::Warning);
-
     // Swap the profiling connection factory in the profiling service instance with our mock one
     SwapProfilingConnectionFactoryHelper helper;
-
     // Reset the profiling service to the uninitialized state
     armnn::Runtime::CreationOptions::ExternalProfilingOptions options;
     options.m_EnableProfiling          = true;
@@ -2575,18 +2621,18 @@ BOOST_AUTO_TEST_CASE(CheckProfilingServiceBadPeriodicCounterSelectionPacketInval
     BOOST_CHECK(profilingService.GetCurrentState() == ProfilingState::WaitingForAck);
     profilingService.Update();    // Start the command handler and the send thread
 
+    // Get the mock profiling connection
+    MockProfilingConnection* mockProfilingConnection = helper.GetMockProfilingConnection();
+    BOOST_CHECK(mockProfilingConnection);
+
     // Wait for the Stream Metadata packet the be sent
     // (we are not testing the connection acknowledgement here so it will be ignored by this test)
-    helper.WaitForProfilingPacketsSent();
+    helper.WaitForProfilingPacketsSent(mockProfilingConnection);
 
     // Force the profiling service to the "Active" state
     helper.ForceTransitionToState(ProfilingState::Active);
     BOOST_CHECK(profilingService.GetCurrentState() == ProfilingState::Active);
 
-    // Get the mock profiling connection
-    MockProfilingConnection* mockProfilingConnection = helper.GetMockProfilingConnection();
-    BOOST_CHECK(mockProfilingConnection);
-
     // Remove the packets received so far
     mockProfilingConnection->Clear();
 
@@ -2608,8 +2654,8 @@ BOOST_AUTO_TEST_CASE(CheckProfilingServiceBadPeriodicCounterSelectionPacketInval
     const ICounterDirectory& counterDirectory = profilingService.GetCounterDirectory();
     const Counters& counters                  = counterDirectory.GetCounters();
     BOOST_CHECK(counters.size() > 1);
-    uint16_t counterUidA = counters.begin()->first;    // First valid counter UID
-    uint16_t counterUidB = 9999;                       // Second invalid counter UID
+    uint16_t counterUidA = counters.begin()->first;        // First valid counter UID
+    uint16_t counterUidB = (counters.begin()++)->first;    // Second valid counter UID
 
     uint32_t length = 8;
 
@@ -2632,7 +2678,7 @@ BOOST_AUTO_TEST_CASE(CheckProfilingServiceBadPeriodicCounterSelectionPacketInval
     // Keep waiting until all the expected packets have been received
     do
     {
-        helper.WaitForProfilingPacketsSent();
+        helper.WaitForProfilingPacketsSent(mockProfilingConnection);
         const std::vector<uint32_t> writtenData = mockProfilingConnection->GetWrittenData();
         if (writtenData.empty())
         {
@@ -2644,10 +2690,10 @@ BOOST_AUTO_TEST_CASE(CheckProfilingServiceBadPeriodicCounterSelectionPacketInval
     } while (expectedPackets > 0);
     BOOST_TEST(!receivedPackets.empty());
 
-    // The size of the expected Periodic Counter Selection packet
-    BOOST_TEST((std::find(receivedPackets.begin(), receivedPackets.end(), 14) != receivedPackets.end()));
+    // The size of the expected Periodic Counter Selection packet (echos the sent one)
+    BOOST_TEST((std::find(receivedPackets.begin(), receivedPackets.end(), 16) != receivedPackets.end()));
     // The size of the expected Periodic Counter Capture packet
-    BOOST_TEST((std::find(receivedPackets.begin(), receivedPackets.end(), 22) != receivedPackets.end()));
+    BOOST_TEST((std::find(receivedPackets.begin(), receivedPackets.end(), 28) != receivedPackets.end()));
 
     // The Periodic Counter Selection Handler should not have updated the profiling state
     BOOST_CHECK(profilingService.GetCurrentState() == ProfilingState::Active);
@@ -2657,79 +2703,67 @@ BOOST_AUTO_TEST_CASE(CheckProfilingServiceBadPeriodicCounterSelectionPacketInval
     profilingService.ResetExternalProfilingOptions(options, true);
 }
 
-BOOST_AUTO_TEST_CASE(CheckProfilingServiceGoodPeriodicCounterSelectionPacketNoCounters)
+BOOST_AUTO_TEST_CASE(CheckProfilingServiceDisconnect)
 {
     // Swap the profiling connection factory in the profiling service instance with our mock one
     SwapProfilingConnectionFactoryHelper helper;
-
     // Reset the profiling service to the uninitialized state
     armnn::Runtime::CreationOptions::ExternalProfilingOptions options;
     options.m_EnableProfiling          = true;
     ProfilingService& profilingService = ProfilingService::Instance();
     profilingService.ResetExternalProfilingOptions(options, true);
 
-    // Bring the profiling service to the "Active" state
+    // Try to disconnect the profiling service while in the "Uninitialised" state
     BOOST_CHECK(profilingService.GetCurrentState() == ProfilingState::Uninitialised);
+    profilingService.Disconnect();
+    BOOST_CHECK(profilingService.GetCurrentState() == ProfilingState::Uninitialised);    // The state should not change
+
+    // Try to disconnect the profiling service while in the "NotConnected" state
     profilingService.Update();    // Initialize the counter directory
     BOOST_CHECK(profilingService.GetCurrentState() == ProfilingState::NotConnected);
+    profilingService.Disconnect();
+    BOOST_CHECK(profilingService.GetCurrentState() == ProfilingState::NotConnected);    // The state should not change
+
+    // Try to disconnect the profiling service while in the "WaitingForAck" state
     profilingService.Update();    // Create the profiling connection
     BOOST_CHECK(profilingService.GetCurrentState() == ProfilingState::WaitingForAck);
+    profilingService.Disconnect();
+    BOOST_CHECK(profilingService.GetCurrentState() == ProfilingState::WaitingForAck);    // The state should not change
+
+    // Try to disconnect the profiling service while in the "Active" state
     profilingService.Update();    // Start the command handler and the send thread
 
+    // Get the mock profiling connection
+    MockProfilingConnection* mockProfilingConnection = helper.GetMockProfilingConnection();
+    BOOST_CHECK(mockProfilingConnection);
+
     // Wait for the Stream Metadata packet the be sent
     // (we are not testing the connection acknowledgement here so it will be ignored by this test)
-    helper.WaitForProfilingPacketsSent();
+    helper.WaitForProfilingPacketsSent(mockProfilingConnection);
 
     // Force the profiling service to the "Active" state
     helper.ForceTransitionToState(ProfilingState::Active);
     BOOST_CHECK(profilingService.GetCurrentState() == ProfilingState::Active);
 
-    // Get the mock profiling connection
-    MockProfilingConnection* mockProfilingConnection = helper.GetMockProfilingConnection();
-    BOOST_CHECK(mockProfilingConnection);
-
-    // Remove the packets received so far
-    mockProfilingConnection->Clear();
-
-    // Write a "Periodic Counter Selection" packet into the mock profiling connection, to simulate an input from an
-    // external profiling service
-
-    // Periodic Counter Selection packet header:
-    // 26:31 [6]  packet_family: Control Packet Family, value 0b000000
-    // 16:25 [10] packet_id: Packet identifier, value 0b0000000100
-    // 8:15  [8]  reserved: Reserved, value 0b00000000
-    // 0:7   [8]  reserved: Reserved, value 0b00000000
-    uint32_t packetFamily = 0;
-    uint32_t packetId     = 4;
-    uint32_t header       = ((packetFamily & 0x0000003F) << 26) | ((packetId & 0x000003FF) << 16);
-
-    // Create the Periodic Counter Selection packet
-    Packet periodicCounterSelectionPacket(header);    // Length == 0, this will disable the collection of counters
-
-    // Write the packet to the mock profiling connection
-    mockProfilingConnection->WritePacket(std::move(periodicCounterSelectionPacket));
-
-    // Wait for the Periodic Counter Selection packet to be sent
-    helper.WaitForProfilingPacketsSent();
+    // Check that the profiling connection is open
+    BOOST_CHECK(mockProfilingConnection->IsOpen());
 
-    // The Periodic Counter Selection Handler should not have updated the profiling state
-    BOOST_CHECK(profilingService.GetCurrentState() == ProfilingState::Active);
+    profilingService.Disconnect();
+    BOOST_CHECK(profilingService.GetCurrentState() == ProfilingState::NotConnected);   // The state should have changed
 
-    // Check that the mock profiling connection contains one Periodic Counter Selection
-    const std::vector<uint32_t> writtenData = mockProfilingConnection->GetWrittenData();
-    BOOST_TEST(writtenData.size() == 1);    // Only one packet is expected (no Periodic Counter packets)
-    BOOST_TEST(writtenData[0] == 12);       // The size of the expected Periodic Counter Selection (echos the sent one)
+    // Check that the profiling connection has been reset
+    mockProfilingConnection = helper.GetMockProfilingConnection();
+    BOOST_CHECK(mockProfilingConnection == nullptr);
 
     // Reset the profiling service to stop any running thread
     options.m_EnableProfiling = false;
     profilingService.ResetExternalProfilingOptions(options, true);
 }
 
-BOOST_AUTO_TEST_CASE(CheckProfilingServiceGoodPeriodicCounterSelectionPacketSingleCounter)
+BOOST_AUTO_TEST_CASE(CheckProfilingServiceGoodPerJobCounterSelectionPacket)
 {
     // Swap the profiling connection factory in the profiling service instance with our mock one
     SwapProfilingConnectionFactoryHelper helper;
-
     // Reset the profiling service to the uninitialized state
     armnn::Runtime::CreationOptions::ExternalProfilingOptions options;
     options.m_EnableProfiling          = true;
@@ -2744,79 +2778,49 @@ BOOST_AUTO_TEST_CASE(CheckProfilingServiceGoodPeriodicCounterSelectionPacketSing
     BOOST_CHECK(profilingService.GetCurrentState() == ProfilingState::WaitingForAck);
     profilingService.Update();    // Start the command handler and the send thread
 
+    // Get the mock profiling connection
+    MockProfilingConnection* mockProfilingConnection = helper.GetMockProfilingConnection();
+    BOOST_CHECK(mockProfilingConnection);
+
     // Wait for the Stream Metadata packet the be sent
     // (we are not testing the connection acknowledgement here so it will be ignored by this test)
-    helper.WaitForProfilingPacketsSent();
+    helper.WaitForProfilingPacketsSent(mockProfilingConnection);
 
     // Force the profiling service to the "Active" state
     helper.ForceTransitionToState(ProfilingState::Active);
     BOOST_CHECK(profilingService.GetCurrentState() == ProfilingState::Active);
 
-    // Get the mock profiling connection
-    MockProfilingConnection* mockProfilingConnection = helper.GetMockProfilingConnection();
-    BOOST_CHECK(mockProfilingConnection);
-
     // Remove the packets received so far
     mockProfilingConnection->Clear();
 
-    // Write a "Periodic Counter Selection" packet into the mock profiling connection, to simulate an input from an
+    // Write a "Per-Job Counter Selection" packet into the mock profiling connection, to simulate an input from an
     // external profiling service
 
-    // Periodic Counter Selection packet header:
+    // Per-Job Counter Selection packet header:
     // 26:31 [6]  packet_family: Control Packet Family, value 0b000000
     // 16:25 [10] packet_id: Packet identifier, value 0b0000000100
     // 8:15  [8]  reserved: Reserved, value 0b00000000
     // 0:7   [8]  reserved: Reserved, value 0b00000000
     uint32_t packetFamily = 0;
-    uint32_t packetId     = 4;
+    uint32_t packetId     = 5;
     uint32_t header       = ((packetFamily & 0x0000003F) << 26) | ((packetId & 0x000003FF) << 16);
 
-    uint32_t capturePeriod = 123456;    // Some capture period (microseconds)
-
-    // Get the first valid counter UID
-    const ICounterDirectory& counterDirectory = profilingService.GetCounterDirectory();
-    const Counters& counters                  = counterDirectory.GetCounters();
-    BOOST_CHECK(!counters.empty());
-    uint16_t counterUid = counters.begin()->first;    // Valid counter UID
-
-    uint32_t length = 6;
-
-    auto data = std::make_unique<unsigned char[]>(length);
-    WriteUint32(data.get(), 0, capturePeriod);
-    WriteUint16(data.get(), 4, counterUid);
-
-    // Create the Periodic Counter Selection packet
-    Packet periodicCounterSelectionPacket(header, length, data);    // Length > 0, this will start the Period Counter
-                                                                    // Capture thread
+    // Create the Per-Job Counter Selection packet
+    Packet periodicCounterSelectionPacket(header);    // Length == 0, this will disable the collection of counters
 
     // Write the packet to the mock profiling connection
     mockProfilingConnection->WritePacket(std::move(periodicCounterSelectionPacket));
 
-    // Expecting one Periodic Counter Selection packet and at least one Periodic Counter Capture packet
-    int expectedPackets = 2;
-    std::vector<uint32_t> receivedPackets;
-
-    // Keep waiting until all the expected packets have been received
-    do
-    {
-        helper.WaitForProfilingPacketsSent();
-        const std::vector<uint32_t> writtenData = mockProfilingConnection->GetWrittenData();
-        if (writtenData.empty())
-        {
-            BOOST_ERROR("Packets should be available for reading at this point");
-            return;
-        }
-        receivedPackets.insert(receivedPackets.end(), writtenData.begin(), writtenData.end());
-        expectedPackets -= boost::numeric_cast<int>(writtenData.size());
-    } while (expectedPackets > 0);
-    BOOST_TEST(!receivedPackets.empty());
+    // Wait for a bit (must at least be the delay value of the mock profiling connection) to make sure that
+    // the Per-Job Counter Selection packet gets processed by the profiling service
+    std::this_thread::sleep_for(std::chrono::milliseconds(5));
 
-    // The size of the expected Periodic Counter Selection packet (echos the sent one)
-    BOOST_TEST((std::find(receivedPackets.begin(), receivedPackets.end(), 14) != receivedPackets.end()));
-    // The size of the expected Periodic Counter Capture packet
-    BOOST_TEST((std::find(receivedPackets.begin(), receivedPackets.end(), 22) != receivedPackets.end()));
+    // The Per-Job Counter Selection packets are dropped silently, so there should be no reply coming
+    // from the profiling service
+    const std::vector<uint32_t> writtenData = mockProfilingConnection->GetWrittenData();
+    BOOST_TEST(writtenData.empty());
 
-    // The Periodic Counter Selection Handler should not have updated the profiling state
+    // The Per-Job Counter Selection Command Handler should not have updated the profiling state
     BOOST_CHECK(profilingService.GetCurrentState() == ProfilingState::Active);
 
     // Reset the profiling service to stop any running thread
@@ -2824,32 +2828,123 @@ BOOST_AUTO_TEST_CASE(CheckProfilingServiceGoodPeriodicCounterSelectionPacketSing
     profilingService.ResetExternalProfilingOptions(options, true);
 }
 
-BOOST_AUTO_TEST_CASE(CheckProfilingServiceGoodPeriodicCounterSelectionPacketMultipleCounters)
+BOOST_AUTO_TEST_CASE(CheckConfigureProfilingServiceOn)
 {
-    // Swap the profiling connection factory in the profiling service instance with our mock one
-    SwapProfilingConnectionFactoryHelper helper;
-
-    // Reset the profiling service to the uninitialized state
     armnn::Runtime::CreationOptions::ExternalProfilingOptions options;
     options.m_EnableProfiling          = true;
     ProfilingService& profilingService = ProfilingService::Instance();
-    profilingService.ResetExternalProfilingOptions(options, true);
-
-    // Bring the profiling service to the "Active" state
     BOOST_CHECK(profilingService.GetCurrentState() == ProfilingState::Uninitialised);
-    profilingService.Update();    // Initialize the counter directory
+    profilingService.ConfigureProfilingService(options);
+    // should get as far as NOT_CONNECTED
     BOOST_CHECK(profilingService.GetCurrentState() == ProfilingState::NotConnected);
-    profilingService.Update();    // Create the profiling connection
-    BOOST_CHECK(profilingService.GetCurrentState() == ProfilingState::WaitingForAck);
-    profilingService.Update();    // Start the command handler and the send thread
+    // Reset the profiling service to stop any running thread
+    options.m_EnableProfiling = false;
+    profilingService.ResetExternalProfilingOptions(options, true);
+}
 
-    // Wait for the Stream Metadata packet the be sent
-    // (we are not testing the connection acknowledgement here so it will be ignored by this test)
-    helper.WaitForProfilingPacketsSent();
+BOOST_AUTO_TEST_CASE(CheckConfigureProfilingServiceOff)
+{
+    armnn::Runtime::CreationOptions::ExternalProfilingOptions options;
+    ProfilingService& profilingService = ProfilingService::Instance();
+    BOOST_CHECK(profilingService.GetCurrentState() == ProfilingState::Uninitialised);
+    profilingService.ConfigureProfilingService(options);
+    // should not move from Uninitialised
+    BOOST_CHECK(profilingService.GetCurrentState() == ProfilingState::Uninitialised);
+    // Reset the profiling service to stop any running thread
+    options.m_EnableProfiling = false;
+    profilingService.ResetExternalProfilingOptions(options, true);
+}
 
-    // Force the profiling service to the "Active" state
-    helper.ForceTransitionToState(ProfilingState::Active);
-    BOOST_CHECK(profilingService.GetCurrentState() == ProfilingState::Active);
+BOOST_AUTO_TEST_CASE(CheckProfilingServiceEnabled)
+{
+    // Locally reduce log level to "Warning", as this test needs to parse a warning message from the standard output
+    LogLevelSwapper logLevelSwapper(armnn::LogSeverity::Warning);
+    armnn::Runtime::CreationOptions::ExternalProfilingOptions options;
+    options.m_EnableProfiling          = true;
+    ProfilingService& profilingService = ProfilingService::Instance();
+    profilingService.ResetExternalProfilingOptions(options, true);
+    BOOST_CHECK(profilingService.GetCurrentState() == ProfilingState::Uninitialised);
+    profilingService.Update();
+    BOOST_CHECK(profilingService.GetCurrentState() == ProfilingState::NotConnected);
+
+    // Redirect the output to a local stream so that we can parse the warning message
+    std::stringstream ss;
+    StreamRedirector streamRedirector(std::cout, ss.rdbuf());
+    profilingService.Update();
+    streamRedirector.CancelRedirect();
+
+    // Check that the expected error has occurred and logged to the standard output
+    if (!boost::contains(ss.str(), "Cannot connect to stream socket: Connection refused"))
+    {
+        std::cout << ss.str();
+        BOOST_FAIL("Expected string not found.");
+    }
+    // Reset the profiling service to stop any running thread
+    options.m_EnableProfiling = false;
+    profilingService.ResetExternalProfilingOptions(options, true);
+}
+
+BOOST_AUTO_TEST_CASE(CheckProfilingServiceEnabledRuntime)
+{
+    // Locally reduce log level to "Warning", as this test needs to parse a warning message from the standard output
+    LogLevelSwapper logLevelSwapper(armnn::LogSeverity::Warning);
+    armnn::Runtime::CreationOptions::ExternalProfilingOptions options;
+    ProfilingService& profilingService = ProfilingService::Instance();
+    profilingService.ResetExternalProfilingOptions(options, true);
+    BOOST_CHECK(profilingService.GetCurrentState() == ProfilingState::Uninitialised);
+    profilingService.Update();
+    BOOST_CHECK(profilingService.GetCurrentState() == ProfilingState::Uninitialised);
+    options.m_EnableProfiling = true;
+    profilingService.ResetExternalProfilingOptions(options);
+    BOOST_CHECK(profilingService.GetCurrentState() == ProfilingState::Uninitialised);
+    profilingService.Update();
+    BOOST_CHECK(profilingService.GetCurrentState() == ProfilingState::NotConnected);
+
+    // Redirect the output to a local stream so that we can parse the warning message
+    std::stringstream ss;
+    StreamRedirector streamRedirector(std::cout, ss.rdbuf());
+    profilingService.Update();
+
+    streamRedirector.CancelRedirect();
+
+    // Check that the expected error has occurred and logged to the standard output
+    if (!boost::contains(ss.str(), "Cannot connect to stream socket: Connection refused"))
+    {
+        std::cout << ss.str();
+        BOOST_FAIL("Expected string not found.");
+    }
+    // Reset the profiling service to stop any running thread
+    options.m_EnableProfiling = false;
+    profilingService.ResetExternalProfilingOptions(options, true);
+}
+
+BOOST_AUTO_TEST_CASE(CheckProfilingServiceBadConnectionAcknowledgedPacket)
+{
+    // Locally reduce log level to "Warning", as this test needs to parse a warning message from the standard output
+    LogLevelSwapper logLevelSwapper(armnn::LogSeverity::Warning);
+    // Swap the profiling connection factory in the profiling service instance with our mock one
+    SwapProfilingConnectionFactoryHelper helper;
+
+    // Redirect the standard output to a local stream so that we can parse the warning message
+    std::stringstream ss;
+    StreamRedirector streamRedirector(std::cout, ss.rdbuf());
+
+    // Calculate the size of a Stream Metadata packet
+    std::string processName      = GetProcessName().substr(0, 60);
+    unsigned int processNameSize = processName.empty() ? 0 : boost::numeric_cast<unsigned int>(processName.size()) + 1;
+    unsigned int streamMetadataPacketsize = 118 + processNameSize;
+
+    // Reset the profiling service to the uninitialized state
+    armnn::Runtime::CreationOptions::ExternalProfilingOptions options;
+    options.m_EnableProfiling          = true;
+    ProfilingService& profilingService = ProfilingService::Instance();
+    profilingService.ResetExternalProfilingOptions(options, true);
+
+    // Bring the profiling service to the "WaitingForAck" state
+    BOOST_CHECK(profilingService.GetCurrentState() == ProfilingState::Uninitialised);
+    profilingService.Update();    // Initialize the counter directory
+    BOOST_CHECK(profilingService.GetCurrentState() == ProfilingState::NotConnected);
+    profilingService.Update();    // Create the profiling connection
 
     // Get the mock profiling connection
     MockProfilingConnection* mockProfilingConnection = helper.GetMockProfilingConnection();
@@ -2858,136 +2953,158 @@ BOOST_AUTO_TEST_CASE(CheckProfilingServiceGoodPeriodicCounterSelectionPacketMult
     // Remove the packets received so far
     mockProfilingConnection->Clear();
 
-    // Write a "Periodic Counter Selection" packet into the mock profiling connection, to simulate an input from an
-    // external profiling service
+    BOOST_CHECK(profilingService.GetCurrentState() == ProfilingState::WaitingForAck);
+    profilingService.Update();
 
-    // Periodic Counter Selection packet header:
+    // Wait for the Stream Metadata packet to be sent
+    helper.WaitForProfilingPacketsSent(mockProfilingConnection);
+
+    // Check that the mock profiling connection contains one Stream Metadata packet
+    const std::vector<uint32_t> writtenData = mockProfilingConnection->GetWrittenData();
+    if (writtenData.size() > 1)
+    {
+        // If this thread has been blocked for some time a second or more Stream Metadata packet could have been sent.
+        // In these cases make sure all packet are of length streamMetadataPacketsize
+        for(uint32_t packetLength : writtenData)
+        {
+            BOOST_TEST(packetLength == streamMetadataPacketsize);
+        }
+    }
+    else
+    {
+        BOOST_TEST(writtenData.size() == 1);
+        BOOST_TEST(writtenData[0] == streamMetadataPacketsize);
+    }
+
+    // Write a valid "Connection Acknowledged" packet into the mock profiling connection, to simulate a valid
+    // reply from an external profiling service
+
+    // Connection Acknowledged Packet header (word 0, word 1 is always zero):
     // 26:31 [6]  packet_family: Control Packet Family, value 0b000000
-    // 16:25 [10] packet_id: Packet identifier, value 0b0000000100
+    // 16:25 [10] packet_id: Packet identifier, value 0b0000000001
     // 8:15  [8]  reserved: Reserved, value 0b00000000
     // 0:7   [8]  reserved: Reserved, value 0b00000000
     uint32_t packetFamily = 0;
-    uint32_t packetId     = 4;
+    uint32_t packetId     = 37;    // Wrong packet id!!!
     uint32_t header       = ((packetFamily & 0x0000003F) << 26) | ((packetId & 0x000003FF) << 16);
 
-    uint32_t capturePeriod = 123456;    // Some capture period (microseconds)
-
-    // Get the first valid counter UID
-    const ICounterDirectory& counterDirectory = profilingService.GetCounterDirectory();
-    const Counters& counters                  = counterDirectory.GetCounters();
-    BOOST_CHECK(counters.size() > 1);
-    uint16_t counterUidA = counters.begin()->first;        // First valid counter UID
-    uint16_t counterUidB = (counters.begin()++)->first;    // Second valid counter UID
-
-    uint32_t length = 8;
-
-    auto data = std::make_unique<unsigned char[]>(length);
-    WriteUint32(data.get(), 0, capturePeriod);
-    WriteUint16(data.get(), 4, counterUidA);
-    WriteUint16(data.get(), 6, counterUidB);
-
-    // Create the Periodic Counter Selection packet
-    Packet periodicCounterSelectionPacket(header, length, data);    // Length > 0, this will start the Period Counter
-                                                                    // Capture thread
+    // Create the Connection Acknowledged Packet
+    Packet connectionAcknowledgedPacket(header);
 
     // Write the packet to the mock profiling connection
-    mockProfilingConnection->WritePacket(std::move(periodicCounterSelectionPacket));
+    mockProfilingConnection->WritePacket(std::move(connectionAcknowledgedPacket));
 
-    // Expecting one Periodic Counter Selection packet and at least one Periodic Counter Capture packet
-    int expectedPackets = 2;
-    std::vector<uint32_t> receivedPackets;
+    // Wait for a bit (must at least be the delay value of the mock profiling connection) to make sure that
+    // the Connection Acknowledged packet gets processed by the profiling service
+    std::this_thread::sleep_for(std::chrono::milliseconds(7));
 
-    // Keep waiting until all the expected packets have been received
-    do
-    {
-        helper.WaitForProfilingPacketsSent();
-        const std::vector<uint32_t> writtenData = mockProfilingConnection->GetWrittenData();
-        if (writtenData.empty())
-        {
-            BOOST_ERROR("Packets should be available for reading at this point");
-            return;
-        }
-        receivedPackets.insert(receivedPackets.end(), writtenData.begin(), writtenData.end());
-        expectedPackets -= boost::numeric_cast<int>(writtenData.size());
-    } while (expectedPackets > 0);
-    BOOST_TEST(!receivedPackets.empty());
+    streamRedirector.CancelRedirect();
 
-    // The size of the expected Periodic Counter Selection packet (echos the sent one)
-    BOOST_TEST((std::find(receivedPackets.begin(), receivedPackets.end(), 16) != receivedPackets.end()));
-    // The size of the expected Periodic Counter Capture packet
-    BOOST_TEST((std::find(receivedPackets.begin(), receivedPackets.end(), 28) != receivedPackets.end()));
+    // Check that the expected error has occurred and logged to the standard output
+    if (!boost::contains(ss.str(), "Functor with requested PacketId=37 and Version=4194304 does not exist"))
+    {
+        std::cout << ss.str();
+        BOOST_FAIL("Expected string not found.");
+    }
 
-    // The Periodic Counter Selection Handler should not have updated the profiling state
-    BOOST_CHECK(profilingService.GetCurrentState() == ProfilingState::Active);
+    // The Connection Acknowledged Command Handler should not have updated the profiling state
+    BOOST_CHECK(profilingService.GetCurrentState() == ProfilingState::WaitingForAck);
 
     // Reset the profiling service to stop any running thread
     options.m_EnableProfiling = false;
     profilingService.ResetExternalProfilingOptions(options, true);
 }
 
-BOOST_AUTO_TEST_CASE(CheckProfilingServiceDisconnect)
+BOOST_AUTO_TEST_CASE(CheckProfilingServiceBadRequestCounterDirectoryPacket)
 {
+    // Locally reduce log level to "Warning", as this test needs to parse a warning message from the standard output
+    LogLevelSwapper logLevelSwapper(armnn::LogSeverity::Warning);
     // Swap the profiling connection factory in the profiling service instance with our mock one
     SwapProfilingConnectionFactoryHelper helper;
 
+    // Redirect the standard output to a local stream so that we can parse the warning message
+    std::stringstream ss;
+    StreamRedirector streamRedirector(std::cout, ss.rdbuf());
+
     // Reset the profiling service to the uninitialized state
     armnn::Runtime::CreationOptions::ExternalProfilingOptions options;
     options.m_EnableProfiling          = true;
     ProfilingService& profilingService = ProfilingService::Instance();
     profilingService.ResetExternalProfilingOptions(options, true);
 
-    // Try to disconnect the profiling service while in the "Uninitialised" state
+    // Bring the profiling service to the "Active" state
     BOOST_CHECK(profilingService.GetCurrentState() == ProfilingState::Uninitialised);
-    profilingService.Disconnect();
-    BOOST_CHECK(profilingService.GetCurrentState() == ProfilingState::Uninitialised);    // The state should not change
-
-    // Try to disconnect the profiling service while in the "NotConnected" state
-    profilingService.Update();    // Initialize the counter directory
+    helper.ForceTransitionToState(ProfilingState::NotConnected);
     BOOST_CHECK(profilingService.GetCurrentState() == ProfilingState::NotConnected);
-    profilingService.Disconnect();
-    BOOST_CHECK(profilingService.GetCurrentState() == ProfilingState::NotConnected);    // The state should not change
-
-    // Try to disconnect the profiling service while in the "WaitingForAck" state
     profilingService.Update();    // Create the profiling connection
     BOOST_CHECK(profilingService.GetCurrentState() == ProfilingState::WaitingForAck);
-    profilingService.Disconnect();
-    BOOST_CHECK(profilingService.GetCurrentState() == ProfilingState::WaitingForAck);    // The state should not change
-
-    // Try to disconnect the profiling service while in the "Active" state
     profilingService.Update();    // Start the command handler and the send thread
 
+    // Get the mock profiling connection
+    MockProfilingConnection* mockProfilingConnection = helper.GetMockProfilingConnection();
+    BOOST_CHECK(mockProfilingConnection);
+
     // Wait for the Stream Metadata packet the be sent
     // (we are not testing the connection acknowledgement here so it will be ignored by this test)
-    helper.WaitForProfilingPacketsSent();
+    helper.WaitForProfilingPacketsSent(mockProfilingConnection);
 
     // Force the profiling service to the "Active" state
     helper.ForceTransitionToState(ProfilingState::Active);
     BOOST_CHECK(profilingService.GetCurrentState() == ProfilingState::Active);
 
-    // Get the mock profiling connection
-    MockProfilingConnection* mockProfilingConnection = helper.GetMockProfilingConnection();
-    BOOST_CHECK(mockProfilingConnection);
+    // Remove the packets received so far
+    mockProfilingConnection->Clear();
 
-    // Check that the profiling connection is open
-    BOOST_CHECK(mockProfilingConnection->IsOpen());
+    // Write a valid "Request Counter Directory" packet into the mock profiling connection, to simulate a valid
+    // reply from an external profiling service
 
-    profilingService.Disconnect();
-    BOOST_CHECK(profilingService.GetCurrentState() == ProfilingState::NotConnected);    // The state should have changed
+    // Request Counter Directory packet header (word 0, word 1 is always zero):
+    // 26:31 [6]  packet_family: Control Packet Family, value 0b000000
+    // 16:25 [10] packet_id: Packet identifier, value 0b0000000011
+    // 8:15  [8]  reserved: Reserved, value 0b00000000
+    // 0:7   [8]  reserved: Reserved, value 0b00000000
+    uint32_t packetFamily = 0;
+    uint32_t packetId     = 123;    // Wrong packet id!!!
+    uint32_t header       = ((packetFamily & 0x0000003F) << 26) | ((packetId & 0x000003FF) << 16);
 
-    // Check that the profiling connection has been reset
-    mockProfilingConnection = helper.GetMockProfilingConnection();
-    BOOST_CHECK(mockProfilingConnection == nullptr);
+    // Create the Request Counter Directory packet
+    Packet requestCounterDirectoryPacket(header);
+
+    // Write the packet to the mock profiling connection
+    mockProfilingConnection->WritePacket(std::move(requestCounterDirectoryPacket));
+
+    // Wait for a bit (must at least be the delay value of the mock profiling connection) to make sure that
+    // the Create the Request Counter packet gets processed by the profiling service
+    std::this_thread::sleep_for(std::chrono::milliseconds(7));
+
+    streamRedirector.CancelRedirect();
+
+    // Check that the expected error has occurred and logged to the standard output
+    if (!boost::contains(ss.str(), "Functor with requested PacketId=123 and Version=4194304 does not exist"))
+    {
+        std::cout << ss.str();
+        BOOST_FAIL("Expected string not found.");
+    }
+
+    // The Request Counter Directory Command Handler should not have updated the profiling state
+    BOOST_CHECK(profilingService.GetCurrentState() == ProfilingState::Active);
 
     // Reset the profiling service to stop any running thread
     options.m_EnableProfiling = false;
     profilingService.ResetExternalProfilingOptions(options, true);
 }
 
-BOOST_AUTO_TEST_CASE(CheckProfilingServiceGoodPerJobCounterSelectionPacket)
+BOOST_AUTO_TEST_CASE(CheckProfilingServiceBadPeriodicCounterSelectionPacket)
 {
+    // Locally reduce log level to "Warning", as this test needs to parse a warning message from the standard output
+    LogLevelSwapper logLevelSwapper(armnn::LogSeverity::Warning);
     // Swap the profiling connection factory in the profiling service instance with our mock one
     SwapProfilingConnectionFactoryHelper helper;
 
+    // Redirect the standard output to a local stream so that we can parse the warning message
+    std::stringstream ss;
+    StreamRedirector streamRedirector(std::cout, ss.rdbuf());
+
     // Reset the profiling service to the uninitialized state
     armnn::Runtime::CreationOptions::ExternalProfilingOptions options;
     options.m_EnableProfiling          = true;
@@ -3002,78 +3119,56 @@ BOOST_AUTO_TEST_CASE(CheckProfilingServiceGoodPerJobCounterSelectionPacket)
     BOOST_CHECK(profilingService.GetCurrentState() == ProfilingState::WaitingForAck);
     profilingService.Update();    // Start the command handler and the send thread
 
+    // Get the mock profiling connection
+    MockProfilingConnection* mockProfilingConnection = helper.GetMockProfilingConnection();
+    BOOST_CHECK(mockProfilingConnection);
+
     // Wait for the Stream Metadata packet the be sent
     // (we are not testing the connection acknowledgement here so it will be ignored by this test)
-    helper.WaitForProfilingPacketsSent();
+    helper.WaitForProfilingPacketsSent(mockProfilingConnection);
 
     // Force the profiling service to the "Active" state
     helper.ForceTransitionToState(ProfilingState::Active);
     BOOST_CHECK(profilingService.GetCurrentState() == ProfilingState::Active);
 
-    // Get the mock profiling connection
-    MockProfilingConnection* mockProfilingConnection = helper.GetMockProfilingConnection();
-    BOOST_CHECK(mockProfilingConnection);
-
     // Remove the packets received so far
     mockProfilingConnection->Clear();
 
-    // Write a "Per-Job Counter Selection" packet into the mock profiling connection, to simulate an input from an
+    // Write a "Periodic Counter Selection" packet into the mock profiling connection, to simulate an input from an
     // external profiling service
 
-    // Per-Job Counter Selection packet header:
+    // Periodic Counter Selection packet header:
     // 26:31 [6]  packet_family: Control Packet Family, value 0b000000
     // 16:25 [10] packet_id: Packet identifier, value 0b0000000100
     // 8:15  [8]  reserved: Reserved, value 0b00000000
     // 0:7   [8]  reserved: Reserved, value 0b00000000
     uint32_t packetFamily = 0;
-    uint32_t packetId     = 5;
+    uint32_t packetId     = 999;    // Wrong packet id!!!
     uint32_t header       = ((packetFamily & 0x0000003F) << 26) | ((packetId & 0x000003FF) << 16);
 
-    // Create the Per-Job Counter Selection packet
+    // Create the Periodic Counter Selection packet
     Packet periodicCounterSelectionPacket(header);    // Length == 0, this will disable the collection of counters
 
     // Write the packet to the mock profiling connection
     mockProfilingConnection->WritePacket(std::move(periodicCounterSelectionPacket));
 
     // Wait for a bit (must at least be the delay value of the mock profiling connection) to make sure that
-    // the Per-Job Counter Selection packet gets processed by the profiling service
-    std::this_thread::sleep_for(std::chrono::seconds(2));
-
-    // The Per-Job Counter Selection packets are dropped silently, so there should be no reply coming
-    // from the profiling service
-    const std::vector<uint32_t> writtenData = mockProfilingConnection->GetWrittenData();
-    BOOST_TEST(writtenData.empty());
+    // the Periodic Counter Selection packet gets processed by the profiling service
+    std::this_thread::sleep_for(std::chrono::milliseconds(7));
 
-    // The Per-Job Counter Selection Command Handler should not have updated the profiling state
-    BOOST_CHECK(profilingService.GetCurrentState() == ProfilingState::Active);
+    // Check that the expected error has occurred and logged to the standard output
+    streamRedirector.CancelRedirect();
 
-    // Reset the profiling service to stop any running thread
-    options.m_EnableProfiling = false;
-    profilingService.ResetExternalProfilingOptions(options, true);
-}
+    // Check that the expected error has occurred and logged to the standard output
+    if (!boost::contains(ss.str(), "Functor with requested PacketId=999 and Version=4194304 does not exist"))
+    {
+        std::cout << ss.str();
+        BOOST_FAIL("Expected string not found.");
+    }
 
-BOOST_AUTO_TEST_CASE(CheckConfigureProfilingServiceOn)
-{
-    armnn::Runtime::CreationOptions::ExternalProfilingOptions options;
-    options.m_EnableProfiling          = true;
-    ProfilingService& profilingService = ProfilingService::Instance();
-    BOOST_CHECK(profilingService.GetCurrentState() == ProfilingState::Uninitialised);
-    profilingService.ConfigureProfilingService(options);
-    // should get as far as NOT_CONNECTED
-    BOOST_CHECK(profilingService.GetCurrentState() == ProfilingState::NotConnected);
-    // Reset the profiling service to stop any running thread
-    options.m_EnableProfiling = false;
-    profilingService.ResetExternalProfilingOptions(options, true);
-}
+    // The Periodic Counter Selection Handler should not have updated the profiling state
+    BOOST_CHECK(profilingService.GetCurrentState() == ProfilingState::Active);
 
-BOOST_AUTO_TEST_CASE(CheckConfigureProfilingServiceOff)
-{
-    armnn::Runtime::CreationOptions::ExternalProfilingOptions options;
-    ProfilingService& profilingService = ProfilingService::Instance();
-    BOOST_CHECK(profilingService.GetCurrentState() == ProfilingState::Uninitialised);
-    profilingService.ConfigureProfilingService(options);
-    // should not move from Uninitialised
-    BOOST_CHECK(profilingService.GetCurrentState() == ProfilingState::Uninitialised);
     // Reset the profiling service to stop any running thread
     options.m_EnableProfiling = false;
     profilingService.ResetExternalProfilingOptions(options, true);
index 86b5c31..65c182b 100644 (file)
@@ -46,7 +46,18 @@ public:
         : m_Stream(stream)
         , m_BackupBuffer(m_Stream.rdbuf(newStreamBuffer))
     {}
-    ~StreamRedirector() { m_Stream.rdbuf(m_BackupBuffer); }
+
+    ~StreamRedirector() { CancelRedirect(); }
+
+    void CancelRedirect()
+    {
+        // Only cancel the redirect once.
+        if (m_BackupBuffer != nullptr )
+        {
+            m_Stream.rdbuf(m_BackupBuffer);
+            m_BackupBuffer = nullptr;
+        }
+    }
 
 private:
     std::ostream& m_Stream;
@@ -67,11 +78,21 @@ public:
 
     Packet ReadPacket(uint32_t timeout) override
     {
-        std::this_thread::sleep_for(std::chrono::milliseconds(timeout));
-
-        // Return connection acknowledged packet
-        return Packet(65536);
+        // First time we're called return a connection ack packet. After that always timeout.
+        if (m_FirstCall)
+        {
+            m_FirstCall = false;
+            // Return connection acknowledged packet
+            return Packet(65536);
+        }
+        else
+        {
+            std::this_thread::sleep_for(std::chrono::milliseconds(timeout));
+            throw armnn::TimeoutException("Simulate a timeout error\n");
+        }
     }
+
+    bool m_FirstCall = true;
 };
 
 class TestProfilingConnectionTimeoutError : public TestProfilingConnectionBase
@@ -83,31 +104,46 @@ public:
 
     Packet ReadPacket(uint32_t timeout) override
     {
-        std::this_thread::sleep_for(std::chrono::milliseconds(timeout));
-
-        if (m_ReadRequests < 3)
+        // Return connection acknowledged packet after three timeouts
+        if (m_ReadRequests % 3 == 0)
         {
-            m_ReadRequests++;
+            std::this_thread::sleep_for(std::chrono::milliseconds(timeout));
+            ++m_ReadRequests;
             throw armnn::TimeoutException("Simulate a timeout error\n");
         }
 
-        // Return connection acknowledged packet after three timeouts
         return Packet(65536);
     }
 
+    int ReadCalledCount()
+    {
+        return m_ReadRequests.load();
+    }
+
 private:
-    int m_ReadRequests;
+    std::atomic<int> m_ReadRequests;
 };
 
 class TestProfilingConnectionArmnnError : public TestProfilingConnectionBase
 {
 public:
+    TestProfilingConnectionArmnnError()
+        : m_ReadRequests(0)
+    {}
+
     Packet ReadPacket(uint32_t timeout) override
     {
-        std::this_thread::sleep_for(std::chrono::milliseconds(timeout));
-
+        ++m_ReadRequests;
         throw armnn::Exception("Simulate a non-timeout error");
     }
+
+    int ReadCalledCount()
+    {
+        return m_ReadRequests.load();
+    }
+
+private:
+    std::atomic<int> m_ReadRequests;
 };
 
 class TestFunctorA : public CommandHandlerFunctor
@@ -172,9 +208,17 @@ public:
         TransitionToState(ProfilingService::Instance(), newState);
     }
 
-    void WaitForProfilingPacketsSent()
+    void WaitForProfilingPacketsSent(MockProfilingConnection* mockProfilingConnection, uint32_t timeout = 1000)
     {
-        return WaitForPacketSent(ProfilingService::Instance());
+        if (!mockProfilingConnection->HasWrittenData())
+        {
+            WaitForPacketSent(ProfilingService::Instance(), timeout);
+            // It's possible the wait has timed out. Check there is some data.
+            if (!mockProfilingConnection->HasWrittenData())
+            {
+                throw RuntimeException("ProfilingTests::WaitForProfilingPacketsSent timeout waiting for packet.");
+            }
+        }
     }
 
 private:
index b33b62f..740ea33 100644 (file)
@@ -24,6 +24,9 @@ using namespace armnn::profiling;
 namespace
 {
 
+// A short delay to wait for the thread to process a packet.
+uint16_t constexpr WAIT_UNTIL_READABLE_MS = 100;
+
 void SetNotConnectedProfilingState(ProfilingStateMachine& profilingStateMachine)
 {
     ProfilingState currentState = profilingStateMachine.GetCurrentState();
@@ -1790,7 +1793,7 @@ BOOST_AUTO_TEST_CASE(SendThreadTest0)
     sendCounterPacket.Start(mockProfilingConnection);
     BOOST_CHECK(sendCounterPacket.IsRunning());
 
-    std::this_thread::sleep_for(std::chrono::seconds(1));
+    std::this_thread::sleep_for(std::chrono::milliseconds(WAIT_UNTIL_READABLE_MS));
 
     sendCounterPacket.Stop();
     BOOST_CHECK(!sendCounterPacket.IsRunning());
@@ -1811,7 +1814,7 @@ BOOST_AUTO_TEST_CASE(SendThreadTest1)
     // Interleaving writes and reads to/from the buffer with pauses to test that the send thread actually waits for
     // something to become available for reading
 
-    std::this_thread::sleep_for(std::chrono::seconds(1));
+    std::this_thread::sleep_for(std::chrono::milliseconds(WAIT_UNTIL_READABLE_MS));
 
     CounterDirectory counterDirectory;
     sendCounterPacket.SendStreamMetaDataPacket();
@@ -1824,7 +1827,7 @@ BOOST_AUTO_TEST_CASE(SendThreadTest1)
 
     sendCounterPacket.SetReadyToRead();
 
-    std::this_thread::sleep_for(std::chrono::milliseconds(100));
+    std::this_thread::sleep_for(std::chrono::milliseconds(WAIT_UNTIL_READABLE_MS));
 
     sendCounterPacket.SendCounterDirectoryPacket(counterDirectory);
 
@@ -1834,7 +1837,7 @@ BOOST_AUTO_TEST_CASE(SendThreadTest1)
 
     sendCounterPacket.SetReadyToRead();
 
-    std::this_thread::sleep_for(std::chrono::milliseconds(100));
+    std::this_thread::sleep_for(std::chrono::milliseconds(WAIT_UNTIL_READABLE_MS));
 
     sendCounterPacket.SendPeriodicCounterCapturePacket(123u,
                                                        {
@@ -1848,7 +1851,7 @@ BOOST_AUTO_TEST_CASE(SendThreadTest1)
 
     sendCounterPacket.SetReadyToRead();
 
-    std::this_thread::sleep_for(std::chrono::milliseconds(100));
+    std::this_thread::sleep_for(std::chrono::milliseconds(WAIT_UNTIL_READABLE_MS));
 
     sendCounterPacket.SendPeriodicCounterCapturePacket(44u,
                                                        {
@@ -1886,7 +1889,7 @@ BOOST_AUTO_TEST_CASE(SendThreadTest1)
 
     sendCounterPacket.SetReadyToRead();
 
-    std::this_thread::sleep_for(std::chrono::milliseconds(100));
+    std::this_thread::sleep_for(std::chrono::milliseconds(WAIT_UNTIL_READABLE_MS));
 
     sendCounterPacket.SendPeriodicCounterSelectionPacket(1000u, { 1345u, 254u, 4536u, 408u, 54u, 6323u, 428u, 1u, 6u });
 
@@ -1898,7 +1901,7 @@ BOOST_AUTO_TEST_CASE(SendThreadTest1)
 
     // To test an exact value of the "read size" in the mock buffer, wait two seconds to allow the send thread to
     // read all what's remaining in the buffer
-    std::this_thread::sleep_for(std::chrono::seconds(2));
+    std::this_thread::sleep_for(std::chrono::milliseconds(WAIT_UNTIL_READABLE_MS));
 
     sendCounterPacket.Stop();
 
@@ -1922,7 +1925,7 @@ BOOST_AUTO_TEST_CASE(SendThreadTest2)
     // Adding many spurious "ready to read" signals throughout the test to check that the send thread is
     // capable of handling unnecessary read requests
 
-    std::this_thread::sleep_for(std::chrono::seconds(1));
+    std::this_thread::sleep_for(std::chrono::milliseconds(WAIT_UNTIL_READABLE_MS));
 
     sendCounterPacket.SetReadyToRead();
 
@@ -1937,7 +1940,7 @@ BOOST_AUTO_TEST_CASE(SendThreadTest2)
 
     sendCounterPacket.SetReadyToRead();
 
-    std::this_thread::sleep_for(std::chrono::milliseconds(100));
+    std::this_thread::sleep_for(std::chrono::milliseconds(WAIT_UNTIL_READABLE_MS));
 
     sendCounterPacket.SendCounterDirectoryPacket(counterDirectory);
 
@@ -1948,7 +1951,7 @@ BOOST_AUTO_TEST_CASE(SendThreadTest2)
     sendCounterPacket.SetReadyToRead();
     sendCounterPacket.SetReadyToRead();
 
-    std::this_thread::sleep_for(std::chrono::milliseconds(100));
+    std::this_thread::sleep_for(std::chrono::milliseconds(WAIT_UNTIL_READABLE_MS));
 
     sendCounterPacket.SendPeriodicCounterCapturePacket(123u,
                                                        {
@@ -1962,13 +1965,13 @@ BOOST_AUTO_TEST_CASE(SendThreadTest2)
 
     sendCounterPacket.SetReadyToRead();
 
-    std::this_thread::sleep_for(std::chrono::milliseconds(100));
+    std::this_thread::sleep_for(std::chrono::milliseconds(WAIT_UNTIL_READABLE_MS));
 
     sendCounterPacket.SetReadyToRead();
     sendCounterPacket.SetReadyToRead();
     sendCounterPacket.SetReadyToRead();
 
-    std::this_thread::sleep_for(std::chrono::milliseconds(100));
+    std::this_thread::sleep_for(std::chrono::milliseconds(WAIT_UNTIL_READABLE_MS));
 
     sendCounterPacket.SetReadyToRead();
     sendCounterPacket.SendPeriodicCounterCapturePacket(44u,
@@ -2009,7 +2012,7 @@ BOOST_AUTO_TEST_CASE(SendThreadTest2)
     sendCounterPacket.SetReadyToRead();
     sendCounterPacket.SetReadyToRead();
 
-    std::this_thread::sleep_for(std::chrono::milliseconds(100));
+    std::this_thread::sleep_for(std::chrono::milliseconds(WAIT_UNTIL_READABLE_MS));
 
     sendCounterPacket.SendPeriodicCounterSelectionPacket(1000u, { 1345u, 254u, 4536u, 408u, 54u, 6323u, 428u, 1u, 6u });
 
@@ -2021,7 +2024,7 @@ BOOST_AUTO_TEST_CASE(SendThreadTest2)
 
     // To test an exact value of the "read size" in the mock buffer, wait two seconds to allow the send thread to
     // read all what's remaining in the buffer
-    std::this_thread::sleep_for(std::chrono::seconds(2));
+    std::this_thread::sleep_for(std::chrono::milliseconds(WAIT_UNTIL_READABLE_MS));
 
     sendCounterPacket.Stop();
 
@@ -2148,7 +2151,7 @@ BOOST_AUTO_TEST_CASE(SendThreadBufferTest)
 
     // Interleaving writes and reads to/from the buffer with pauses to test that the send thread actually waits for
     // something to become available for reading
-    std::this_thread::sleep_for(std::chrono::seconds(1));
+    std::this_thread::sleep_for(std::chrono::milliseconds(WAIT_UNTIL_READABLE_MS));
 
     // SendStreamMetaDataPacket
     sendCounterPacket.SendStreamMetaDataPacket();
@@ -2173,7 +2176,7 @@ BOOST_AUTO_TEST_CASE(SendThreadBufferTest)
 
     sendCounterPacket.SetReadyToRead();
 
-    std::this_thread::sleep_for(std::chrono::seconds(1));
+    std::this_thread::sleep_for(std::chrono::milliseconds(WAIT_UNTIL_READABLE_MS));
 
     // The buffer is read by the send thread so it should not be in the readable buffer.
     auto readBuffer = bufferManager.GetReadableBuffer();
@@ -2211,7 +2214,7 @@ BOOST_AUTO_TEST_CASE(SendThreadBufferTest)
 
     sendCounterPacket.SetReadyToRead();
 
-    std::this_thread::sleep_for(std::chrono::seconds(1));
+    std::this_thread::sleep_for(std::chrono::milliseconds(WAIT_UNTIL_READABLE_MS));
 
     // The buffer is read by the send thread so it should not be in the readable buffer.
     readBuffer = bufferManager.GetReadableBuffer();
@@ -2252,7 +2255,7 @@ BOOST_AUTO_TEST_CASE(SendThreadBufferTest)
 
     sendCounterPacket.SetReadyToRead();
 
-    std::this_thread::sleep_for(std::chrono::seconds(1));
+    std::this_thread::sleep_for(std::chrono::milliseconds(WAIT_UNTIL_READABLE_MS));
 
     // The buffer is read by the send thread so it should not be in the readable buffer.
     readBuffer = bufferManager.GetReadableBuffer();
@@ -2345,7 +2348,7 @@ BOOST_AUTO_TEST_CASE(SendThreadSendStreamMetadataPacket1)
     // The profiling state is set to "Uninitialized", so the send thread should throw an exception
 
     // Wait a bit to make sure that the send thread is properly started
-    std::this_thread::sleep_for(std::chrono::milliseconds(100));
+    std::this_thread::sleep_for(std::chrono::milliseconds(WAIT_UNTIL_READABLE_MS));
 
     BOOST_CHECK_THROW(sendCounterPacket.Stop(), armnn::RuntimeException);
 }
@@ -2363,7 +2366,7 @@ BOOST_AUTO_TEST_CASE(SendThreadSendStreamMetadataPacket2)
     // The profiling state is set to "NotConnected", so the send thread should throw an exception
 
     // Wait a bit to make sure that the send thread is properly started
-    std::this_thread::sleep_for(std::chrono::milliseconds(100));
+    std::this_thread::sleep_for(std::chrono::milliseconds(WAIT_UNTIL_READABLE_MS));
 
     BOOST_CHECK_THROW(sendCounterPacket.Stop(), armnn::RuntimeException);
 }
@@ -2386,7 +2389,7 @@ BOOST_AUTO_TEST_CASE(SendThreadSendStreamMetadataPacket3)
     // The profiling state is set to "WaitingForAck", so the send thread should send a Stream Metadata packet
 
     // Wait for a bit to make sure that we get the packet
-    std::this_thread::sleep_for(std::chrono::milliseconds(100));
+    std::this_thread::sleep_for(std::chrono::milliseconds(WAIT_UNTIL_READABLE_MS));
 
     BOOST_CHECK_NO_THROW(sendCounterPacket.Stop());
 
@@ -2414,7 +2417,7 @@ BOOST_AUTO_TEST_CASE(SendThreadSendStreamMetadataPacket4)
     // The profiling state is set to "WaitingForAck", so the send thread should send a Stream Metadata packet
 
     // Wait for a bit to make sure that we get the packet
-    std::this_thread::sleep_for(std::chrono::milliseconds(100));
+    std::this_thread::sleep_for(std::chrono::milliseconds(WAIT_UNTIL_READABLE_MS));
 
     // Check that the profiling state is still "WaitingForAck"
     BOOST_TEST((profilingStateMachine.GetCurrentState() == ProfilingState::WaitingForAck));
@@ -2430,7 +2433,7 @@ BOOST_AUTO_TEST_CASE(SendThreadSendStreamMetadataPacket4)
     sendCounterPacket.SetReadyToRead();
 
     // Wait for a bit to make sure that we get the packet
-    std::this_thread::sleep_for(std::chrono::milliseconds(100));
+    std::this_thread::sleep_for(std::chrono::milliseconds(WAIT_UNTIL_READABLE_MS));
 
     // Check that the profiling state is still "WaitingForAck"
     BOOST_TEST((profilingStateMachine.GetCurrentState() == ProfilingState::WaitingForAck));
index cd41418..4395d81 100644 (file)
@@ -67,11 +67,9 @@ public:
 
     Packet ReadPacket(uint32_t timeout) override
     {
-        // Simulate a delay in the reading process
-        std::this_thread::sleep_for(std::chrono::milliseconds(timeout));
-
+        // Simulate a delay in the reading process. The default timeout is way too long.
+        std::this_thread::sleep_for(std::chrono::milliseconds(5));
         std::lock_guard<std::mutex> lock(m_Mutex);
-
         return std::move(m_Packet);
     }
 
@@ -84,6 +82,12 @@ public:
         return writtenData;
     }
 
+    const bool HasWrittenData()
+    {
+        std::lock_guard<std::mutex> lock(m_Mutex);
+        return !m_WrittenData.empty();
+    }
+
     void Clear()
     {
         std::lock_guard<std::mutex> lock(m_Mutex);