Removes ThreadDrillerEvents, replaces handlers with TreadEventBus

Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com>
monroegm-disable-blank-issue-2
Esteban Papp 4 years ago
parent 8bde44d5fb
commit 19ddeeded9

@ -37,7 +37,7 @@ namespace AZ
using namespace AZ; using namespace AZ;
// Handle asserts // Handle asserts
class TraceDrillerHook class TestEnvironmentHook
: public AZ::Test::ITestEnvironment : public AZ::Test::ITestEnvironment
, public UnitTest::TraceBusRedirector , public UnitTest::TraceBusRedirector
{ {
@ -57,5 +57,5 @@ public:
} }
}; };
AZ_UNIT_TEST_HOOK(new TraceDrillerHook()); AZ_UNIT_TEST_HOOK(new TestEnvironmentHook());

@ -29,12 +29,12 @@ namespace AZ::Debug
EventTraceDriller::EventTraceDriller() EventTraceDriller::EventTraceDriller()
{ {
EventTraceDrillerSetupBus::Handler::BusConnect(); EventTraceDrillerSetupBus::Handler::BusConnect();
AZStd::ThreadDrillerEventBus::Handler::BusConnect(); AZStd::ThreadEventBus::Handler::BusConnect();
} }
EventTraceDriller::~EventTraceDriller() EventTraceDriller::~EventTraceDriller()
{ {
AZStd::ThreadDrillerEventBus::Handler::BusDisconnect(); AZStd::ThreadEventBus::Handler::BusDisconnect();
EventTraceDrillerSetupBus::Handler::BusDisconnect(); EventTraceDrillerSetupBus::Handler::BusDisconnect();
} }

@ -22,7 +22,7 @@ namespace AZ
: public Driller : public Driller
, public EventTraceDrillerBus::Handler , public EventTraceDrillerBus::Handler
, public EventTraceDrillerSetupBus::Handler , public EventTraceDrillerSetupBus::Handler
, public AZStd::ThreadDrillerEventBus::Handler , public AZStd::ThreadEventBus::Handler
, public AZ::TickBus::Handler , public AZ::TickBus::Handler
{ {
public: public:

@ -8,7 +8,7 @@
#pragma once #pragma once
#ifndef AZ_PROFILE_MEMORY_ALLOC #ifndef AZ_PROFILE_MEMORY_ALLOC
// No other profiler has defined the performance markers AZ_PROFILE_MEMORY_ALLOC (and friends), fall back to a Driller implementation (currently empty) // No other profiler has defined the performance markers AZ_PROFILE_MEMORY_ALLOC (and friends), fall back to current implementation (empty)
# define AZ_PROFILE_MEMORY_ALLOC(category, address, size, context) # define AZ_PROFILE_MEMORY_ALLOC(category, address, size, context)
# define AZ_PROFILE_MEMORY_ALLOC_EX(category, filename, lineNumber, address, size, context) # define AZ_PROFILE_MEMORY_ALLOC_EX(category, filename, lineNumber, address, size, context)
# define AZ_PROFILE_MEMORY_FREE(category, address) # define AZ_PROFILE_MEMORY_FREE(category, address)

@ -32,24 +32,7 @@ namespace AZStd
virtual void OnThreadExit(const AZStd::thread::id& id) = 0; virtual void OnThreadExit(const AZStd::thread::id& id) = 0;
}; };
//! Thread events driller bus - only "drillers" (profilers) should connect to this.
//! A global mutex that includes a lock on the memory manager and other driller busses
//! is held during dispatch, and listeners are expected to do no allocation
//! or thread workloads or blocking or mutex operations of their own - only dump the data to
//! network or file ASAP.
//! DO NOT USE this bus unless you are a profiler capture system, use the ThreadEvents / ThreadBus instead
class ThreadDrillerEvents
: public AZ::Debug::DrillerEBusTraits
{
public:
/// Called when we enter a thread, optional thread_desc is provided when the use provides one.
virtual void OnThreadEnter(const AZStd::thread::id& id, const AZStd::thread_desc* desc) = 0;
/// Called when we exit a thread.
virtual void OnThreadExit(const AZStd::thread::id& id) = 0;
};
typedef AZ::EBus<ThreadEvents> ThreadEventBus; typedef AZ::EBus<ThreadEvents> ThreadEventBus;
typedef AZ::EBus<ThreadDrillerEvents> ThreadDrillerEventBus;
} }
#endif // AZSTD_THREAD_BUS_H #endif // AZSTD_THREAD_BUS_H

@ -35,7 +35,6 @@ namespace AZStd
destroy_thread_info(ti); destroy_thread_info(ti);
ThreadEventBus::Broadcast(&ThreadEventBus::Events::OnThreadExit, this_thread::get_id()); ThreadEventBus::Broadcast(&ThreadEventBus::Events::OnThreadExit, this_thread::get_id());
ThreadDrillerEventBus::Broadcast(&ThreadDrillerEventBus::Events::OnThreadExit, this_thread::get_id());
pthread_exit(nullptr); pthread_exit(nullptr);
return nullptr; return nullptr;
} }
@ -88,7 +87,6 @@ namespace AZStd
Platform::PostCreateThread(tId, name, cpuId); Platform::PostCreateThread(tId, name, cpuId);
ThreadEventBus::Broadcast(&ThreadEventBus::Events::OnThreadEnter, thread::id(tId), desc); ThreadEventBus::Broadcast(&ThreadEventBus::Events::OnThreadEnter, thread::id(tId), desc);
ThreadDrillerEventBus::Broadcast(&ThreadDrillerEventBus::Events::OnThreadEnter, thread::id(tId), desc);
return tId; return tId;
} }
} }

@ -38,7 +38,6 @@ namespace AZStd
destroy_thread_info(ti); destroy_thread_info(ti);
ThreadEventBus::Broadcast(&ThreadEventBus::Events::OnThreadExit, this_thread::get_id()); // goes to client listeners ThreadEventBus::Broadcast(&ThreadEventBus::Events::OnThreadExit, this_thread::get_id()); // goes to client listeners
ThreadDrillerEventBus::Broadcast(&ThreadDrillerEventBus::Events::OnThreadExit, this_thread::get_id()); // goes to the profiler.
return Platform::PostThreadRun(); return Platform::PostThreadRun();
} }
@ -73,7 +72,6 @@ namespace AZStd
} }
ThreadEventBus::Broadcast(&ThreadEventBus::Events::OnThreadEnter, thread::id(*id), desc); ThreadEventBus::Broadcast(&ThreadEventBus::Events::OnThreadEnter, thread::id(*id), desc);
ThreadDrillerEventBus::Broadcast(&ThreadDrillerEventBus::Events::OnThreadEnter, thread::id(*id), desc);
::ResumeThread(hThread); ::ResumeThread(hThread);

@ -1438,44 +1438,33 @@ namespace UnitTest
TEST_F(ThreadEventsBus, Broadcasts_BothBusses) TEST_F(ThreadEventsBus, Broadcasts_BothBusses)
{ {
ThreadEventCounter<AZStd::ThreadEventBus::Handler> eventBusCounter; ThreadEventCounter<AZStd::ThreadEventBus::Handler> eventBusCounter;
ThreadEventCounter<AZStd::ThreadDrillerEventBus::Handler> drillerBusCounter;
auto thread_function = [&]() auto thread_function = [&]()
{ {
; // intentionally left blank ; // intentionally left blank
}; };
eventBusCounter.Connect(); eventBusCounter.Connect();
drillerBusCounter.Connect();
AZStd::thread starter = AZStd::thread(thread_function); AZStd::thread starter = AZStd::thread(thread_function);
starter.join(); starter.join();
EXPECT_EQ(drillerBusCounter.m_enterCount, 1);
EXPECT_EQ(drillerBusCounter.m_exitCount, 1);
EXPECT_EQ(eventBusCounter.m_enterCount, 1); EXPECT_EQ(eventBusCounter.m_enterCount, 1);
EXPECT_EQ(eventBusCounter.m_exitCount, 1); EXPECT_EQ(eventBusCounter.m_exitCount, 1);
eventBusCounter.Disconnect(); eventBusCounter.Disconnect();
drillerBusCounter.Disconnect();
} }
// this class tests for deadlocks caused by interactions between the thread // This class tests for deadlocks caused by multiple threads interacting with the ThreadEventBus.
// driller bus and the other driller busses. // Client code can connect to the ThreadEventBus and be told when threads are started and stopped.
// Client code (ie, not part of the driller system) can connec to the // A deadlock condition could be caused if they lock a mutex that another thread needs in order to proceed.
// ThreadEventBus and be told when threads are started and stopped // This test makes sure that using the ThreadEventBus does NOT cause a deadlock.
// However, if they instead listen to the ThreadDrillerEventBus, a deadlock condition
// could be caused if they lock a mutex that another thread needs in order to proceed.
// This test makes sure that using the ThreadEventBus (ie, the one meant for client code)
// instead of the ThreadDrillerEventBus (the one meant only for profilers) does NOT cause
// a deadlock.
// We will simulate this series of events by doing the following // We will simulate this series of events by doing the following
// 1. Main thread listens on the ThreadEventBus // 1. Main thread listens on the ThreadEventBus
// 2. OnThreadExit will lock a mutex, perform an allocation, unlock a mutex // 2. OnThreadExit will lock a mutex, perform an allocation, unlock a mutex
// 3. The thread itself will lock the mutex, perform an allocation, unlock the mutex. // 3. The thread itself will lock the mutex, perform an allocation, unlock the mutex.
// As long as there is no cross talk between the client and the driller busses, the // As long as there is no cross talk between threads, the above operation should not deadlock.
// above operation should not deadlock. // If there is, then a deadlock can occur where one thread will be unable to perform
// but if there is, then a deadlock can occur where one thread will be unable to perform // its allocation because the other is in OnThreadExit() and the other will not be able to perform
// its allocation because the other is in OnThreadExit() // OnThreadExit() because it cannot lock the mutex.
// and the other will not be able to perform OnThreadExit() because it cannot lock the mutex.
class ThreadEventsDeathTest : class ThreadEventsDeathTest :
public AllocatorsFixture public AllocatorsFixture

Loading…
Cancel
Save