1 #include <MTScheduler.h>
2 #include "Profiler.h"
3 
4 
5 #if defined(MT_INSTRUMENTED_BUILD) && defined(MT_ENABLE_BROFILER_SUPPORT)
6 
7 #pragma comment( lib, "BrofilerCore.lib" )
8 #pragma comment( lib, "Advapi32.lib" )
9 
10 
11 const uint32 MAX_INSTRUMENTED_WORKERS = 8;
12 const char *g_WorkerNames[MAX_INSTRUMENTED_WORKERS] = {"worker0","worker1","worker2","worker3","worker4","worker5","worker6","worker7"};
13 
14 class ProfilerEventListener : public MT::IProfilerEventListener
15 {
16 	Brofiler::EventStorage* fiberEventStorages[MT::MT_MAX_STANDART_FIBERS_COUNT + MT::MT_MAX_EXTENDED_FIBERS_COUNT];
17 	uint32 totalFibersCount;
18 
19 	static mt_thread_local Brofiler::EventStorage* originalThreadStorage;
20 	static mt_thread_local Brofiler::EventStorage* activeThreadStorage;
21 
22 public:
23 
ProfilerEventListener()24 	ProfilerEventListener()
25 		: totalFibersCount(0)
26 	{
27 	}
28 
OnFibersCreated(uint32 fibersCount)29 	virtual void OnFibersCreated(uint32 fibersCount) override
30 	{
31 		totalFibersCount = fibersCount;
32 		MT_ASSERT(fibersCount <= MT_ARRAY_SIZE(fiberEventStorages), "Too many fibers!");
33 		for(uint32 fiberIndex = 0; fiberIndex < fibersCount; fiberIndex++)
34 		{
35 			Brofiler::RegisterFiber(fiberIndex, &fiberEventStorages[fiberIndex]);
36 		}
37 	}
38 
OnThreadsCreated(uint32 threadsCount)39 	virtual void OnThreadsCreated(uint32 threadsCount) override
40 	{
41 		MT_UNUSED(threadsCount);
42 	}
43 
OnTemporaryWorkerThreadLeave()44 	virtual void OnTemporaryWorkerThreadLeave() override
45 	{
46 		Brofiler::EventStorage** currentThreadStorageSlot = Brofiler::GetEventStorageSlotForCurrentThread();
47 		MT_ASSERT(currentThreadStorageSlot, "Sanity check failed");
48 		Brofiler::EventStorage* storage = *currentThreadStorageSlot;
49 
50 		// if profile session is not active
51 		if (storage == nullptr)
52 		{
53 			return;
54 		}
55 
56 		MT_ASSERT(IsFiberStorage(storage) == false, "Sanity check failed");
57 	}
58 
OnTemporaryWorkerThreadJoin()59 	virtual void OnTemporaryWorkerThreadJoin() override
60 	{
61 		Brofiler::EventStorage** currentThreadStorageSlot = Brofiler::GetEventStorageSlotForCurrentThread();
62 		MT_ASSERT(currentThreadStorageSlot, "Sanity check failed");
63 		Brofiler::EventStorage* storage = *currentThreadStorageSlot;
64 
65 		// if profile session is not active
66 		if (storage == nullptr)
67 		{
68 			return;
69 		}
70 
71 		MT_ASSERT(IsFiberStorage(storage) == false, "Sanity check failed");
72 	}
73 
74 
OnThreadCreated(uint32 workerIndex)75 	virtual void OnThreadCreated(uint32 workerIndex) override
76 	{
77 		BROFILER_START_THREAD("Scheduler(Worker)");
78 		MT_UNUSED(workerIndex);
79 	}
80 
OnThreadStarted(uint32 workerIndex)81 	virtual void OnThreadStarted(uint32 workerIndex) override
82 	{
83 		MT_UNUSED(workerIndex);
84 	}
85 
OnThreadStoped(uint32 workerIndex)86 	virtual void OnThreadStoped(uint32 workerIndex) override
87 	{
88 		MT_UNUSED(workerIndex);
89 		BROFILER_STOP_THREAD();
90 	}
91 
OnThreadIdleStarted(uint32 workerIndex)92 	virtual void OnThreadIdleStarted(uint32 workerIndex) override
93 	{
94 		MT_UNUSED(workerIndex);
95 	}
96 
OnThreadIdleFinished(uint32 workerIndex)97 	virtual void OnThreadIdleFinished(uint32 workerIndex) override
98 	{
99 		MT_UNUSED(workerIndex);
100 	}
101 
OnThreadWaitStarted()102 	virtual void OnThreadWaitStarted() override
103 	{
104 	}
105 
OnThreadWaitFinished()106 	virtual void OnThreadWaitFinished() override
107 	{
108 	}
109 
OnTaskExecuteStateChanged(MT::Color::Type debugColor,const mt_char * debugID,MT::TaskExecuteState::Type type,int32 fiberIndex)110 	virtual void OnTaskExecuteStateChanged(MT::Color::Type debugColor, const mt_char* debugID, MT::TaskExecuteState::Type type, int32 fiberIndex) override
111 	{
112 		MT_UNUSED(debugColor);
113 		MT_UNUSED(debugID);
114 		//MT_UNUSED(type);
115 
116 		MT_ASSERT(fiberIndex < (int32)totalFibersCount, "Sanity check failed");
117 
118 		Brofiler::EventStorage** currentThreadStorageSlot = Brofiler::GetEventStorageSlotForCurrentThread();
119 		MT_ASSERT(currentThreadStorageSlot, "Sanity check failed");
120 
121 		// if profile session is not active
122 		if (*currentThreadStorageSlot == nullptr)
123 		{
124 			return;
125 		}
126 
127 		// if actual fiber is scheduler internal fiber (don't have event storage for internal scheduler fibers)
128 		if (fiberIndex < 0)
129 		{
130 			return;
131 		}
132 
133 		switch(type)
134 		{
135 		case MT::TaskExecuteState::START:
136 		case MT::TaskExecuteState::RESUME:
137 			{
138 				MT_ASSERT(originalThreadStorage == nullptr, "Sanity check failed");
139 
140 				originalThreadStorage = *currentThreadStorageSlot;
141 
142 				MT_ASSERT(IsFiberStorage(originalThreadStorage) == false, "Sanity check failed");
143 
144 				Brofiler::EventStorage* currentFiberStorage = nullptr;
145 				if (fiberIndex >= (int32)0)
146 				{
147 					currentFiberStorage = fiberEventStorages[fiberIndex];
148 				}
149 
150 				*currentThreadStorageSlot = currentFiberStorage;
151 				activeThreadStorage = currentFiberStorage;
152 				Brofiler::FiberSyncData::AttachToThread(currentFiberStorage, MT::ThreadId::Self().AsUInt64());
153 			}
154 			break;
155 
156 		case MT::TaskExecuteState::STOP:
157 		case MT::TaskExecuteState::SUSPEND:
158 			{
159 				Brofiler::EventStorage* currentFiberStorage = *currentThreadStorageSlot;
160 
161 				//////////////////////////////////////////////////////////////////////////
162 				Brofiler::EventStorage* checkFiberStorage = nullptr;
163 				if (fiberIndex >= (int32)0)
164 				{
165 					checkFiberStorage = fiberEventStorages[fiberIndex];
166 				}
167 				MT_ASSERT(checkFiberStorage == currentFiberStorage, "Sanity check failed");
168 
169 				MT_ASSERT(activeThreadStorage == currentFiberStorage, "Sanity check failed");
170 
171 				//////////////////////////////////////////////////////////////////////////
172 
173 				MT_ASSERT(IsFiberStorage(currentFiberStorage) == true, "Sanity check failed");
174 
175 				Brofiler::FiberSyncData::DetachFromThread(currentFiberStorage);
176 
177 				*currentThreadStorageSlot = originalThreadStorage;
178 				originalThreadStorage = nullptr;
179 			}
180 			break;
181 		}
182 	}
183 };
184 
185 
186 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
187 mt_thread_local Brofiler::EventStorage* ProfilerEventListener::originalThreadStorage = nullptr;
188 mt_thread_local Brofiler::EventStorage* ProfilerEventListener::activeThreadStorage = 0;
189 
190 #endif
191 
192 
GetProfiler()193 MT::IProfilerEventListener* GetProfiler()
194 {
195 #if defined(MT_INSTRUMENTED_BUILD) && defined(MT_ENABLE_BROFILER_SUPPORT)
196 	static ProfilerEventListener profilerListener;
197 	return &profilerListener;
198 #else
199 	return nullptr;
200 #endif
201 }
202 
203