1f25ce65dSSergey Makeev // The MIT License (MIT)
2f25ce65dSSergey Makeev //
3f25ce65dSSergey Makeev // 	Copyright (c) 2015 Sergey Makeev, Vadim Slyusarev
4f25ce65dSSergey Makeev //
5f25ce65dSSergey Makeev // 	Permission is hereby granted, free of charge, to any person obtaining a copy
6f25ce65dSSergey Makeev // 	of this software and associated documentation files (the "Software"), to deal
7f25ce65dSSergey Makeev // 	in the Software without restriction, including without limitation the rights
8f25ce65dSSergey Makeev // 	to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9f25ce65dSSergey Makeev // 	copies of the Software, and to permit persons to whom the Software is
10f25ce65dSSergey Makeev // 	furnished to do so, subject to the following conditions:
11f25ce65dSSergey Makeev //
12f25ce65dSSergey Makeev //  The above copyright notice and this permission notice shall be included in
13f25ce65dSSergey Makeev // 	all copies or substantial portions of the Software.
14f25ce65dSSergey Makeev //
15f25ce65dSSergey Makeev // 	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16f25ce65dSSergey Makeev // 	IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17f25ce65dSSergey Makeev // 	FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18f25ce65dSSergey Makeev // 	AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19f25ce65dSSergey Makeev // 	LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20f25ce65dSSergey Makeev // 	OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21f25ce65dSSergey Makeev // 	THE SOFTWARE.
22f25ce65dSSergey Makeev 
2358964d0bSSergey Makeev #include <MTScheduler.h>
2458964d0bSSergey Makeev 
252b4df162SSergey Makeev 
2658964d0bSSergey Makeev namespace MT
2758964d0bSSergey Makeev {
2858964d0bSSergey Makeev 	namespace internal
2958964d0bSSergey Makeev 	{
3058964d0bSSergey Makeev 		static const size_t TASK_BUFFER_CAPACITY = 4096;
3158964d0bSSergey Makeev 
322b4df162SSergey Makeev 		// Prime numbers for linear congruential generator seed
332b4df162SSergey Makeev 		static const uint32 primeNumbers[] = {
342b4df162SSergey Makeev 			128473, 135349, 159499, 173839, 209213, 241603, 292709, 314723,
352b4df162SSergey Makeev 			343943, 389299, 419473, 465169, 518327, 649921, 748271, 851087,
362b4df162SSergey Makeev 			862171, 974551, 1002973, 1034639, 1096289, 1153123, 1251037, 1299269,
372b4df162SSergey Makeev 			1272941, 1252151, 1231091, 1206761, 1185469, 1169933, 1141351, 1011583 };
382b4df162SSergey Makeev 
392b4df162SSergey Makeev 		uint32 GetPrimeNumber(uint32 index)
402b4df162SSergey Makeev 		{
4134a394c3SSergey Makeev 			return primeNumbers[index % MT_ARRAY_SIZE(primeNumbers)];
422b4df162SSergey Makeev 		}
432b4df162SSergey Makeev 
442b4df162SSergey Makeev 
452b4df162SSergey Makeev 
4658964d0bSSergey Makeev 		ThreadContext::ThreadContext()
4758964d0bSSergey Makeev 			: lastActiveFiberContext(nullptr)
4858964d0bSSergey Makeev 			, taskScheduler(nullptr)
4958964d0bSSergey Makeev 			, hasNewTasksEvent(EventReset::AUTOMATIC, true)
5058964d0bSSergey Makeev 			, state(ThreadState::ALIVE)
5158964d0bSSergey Makeev 			, descBuffer(TASK_BUFFER_CAPACITY)
522b4df162SSergey Makeev 			, workerIndex(0)
5358964d0bSSergey Makeev 		{
5458964d0bSSergey Makeev 		}
5558964d0bSSergey Makeev 
5658964d0bSSergey Makeev 		ThreadContext::~ThreadContext()
5758964d0bSSergey Makeev 		{
5858964d0bSSergey Makeev 		}
5958964d0bSSergey Makeev 
602b4df162SSergey Makeev 		void ThreadContext::SetThreadIndex(uint32 threadIndex)
612b4df162SSergey Makeev 		{
622b4df162SSergey Makeev 			workerIndex = threadIndex;
632b4df162SSergey Makeev 			random.SetSeed( GetPrimeNumber(threadIndex) );
642b4df162SSergey Makeev 		}
652b4df162SSergey Makeev 
6658964d0bSSergey Makeev 		void ThreadContext::RestoreAwaitingTasks(TaskGroup::Type taskGroup)
6758964d0bSSergey Makeev 		{
6834a394c3SSergey Makeev 			MT_ASSERT(taskScheduler, "Invalid Task Scheduler");
6934a394c3SSergey Makeev 			MT_ASSERT(taskScheduler->IsWorkerThread(), "Can't use RunAsync outside Task. Use TaskScheduler.RunAsync() instead.");
7058964d0bSSergey Makeev 
7158964d0bSSergey Makeev 			ConcurrentQueueLIFO<FiberContext*> & groupQueue = taskScheduler->waitTaskQueues[taskGroup];
7258964d0bSSergey Makeev 
7358964d0bSSergey Makeev 			if (groupQueue.IsEmpty())
7458964d0bSSergey Makeev 			{
7558964d0bSSergey Makeev 				return;
7658964d0bSSergey Makeev 			}
7758964d0bSSergey Makeev 
7858964d0bSSergey Makeev 			//copy awaiting tasks list to stack
79a101e543SSergey Makeev 			StackArray<FiberContext*, MT_MAX_FIBERS_COUNT> groupQueueCopy(MT_MAX_FIBERS_COUNT, nullptr);
80a101e543SSergey Makeev 			size_t taskCount = groupQueue.PopAll(groupQueueCopy.Begin(), groupQueueCopy.Size());
8158964d0bSSergey Makeev 
82*56aa031bSSergey Makeev 			ArrayView<internal::GroupedTask> buffer(&descBuffer.front(), taskCount);
8358964d0bSSergey Makeev 
8458964d0bSSergey Makeev 			TaskScheduler & scheduler = *(taskScheduler);
851e8563ffSSergey Makeev 			size_t bucketCount = MT::Min((size_t)scheduler.GetWorkerCount(), taskCount);
86*56aa031bSSergey Makeev 			ArrayView<internal::TaskBucket>	buckets(MT_ALLOCATE_ON_STACK(sizeof(internal::TaskBucket) * bucketCount), bucketCount);
8758964d0bSSergey Makeev 
88a101e543SSergey Makeev 			internal::DistibuteDescriptions(TaskGroup::GROUP_UNDEFINED, groupQueueCopy.Begin(), buffer, buckets);
8958964d0bSSergey Makeev 			scheduler.RunTasksImpl(buckets, nullptr, true);
9058964d0bSSergey Makeev 		}
9158964d0bSSergey Makeev 
928112dedfSSergey Makeev #ifdef MT_INSTRUMENTED_BUILD
938112dedfSSergey Makeev 
948112dedfSSergey Makeev 		void ThreadContext::NotifyTaskFinished(const internal::TaskDesc & desc)
958112dedfSSergey Makeev 		{
968112dedfSSergey Makeev 			ProfileEventDesc eventDesc;
97a1626843SSergey Makeev 			eventDesc.id = desc.debugID;
98a1626843SSergey Makeev 			eventDesc.colorIndex = desc.colorIndex;
998112dedfSSergey Makeev 			eventDesc.type = ProfileEventType::TASK_DONE;
100aac5f829SSergey Makeev 			eventDesc.timeStampMicroSeconds = MT::GetTimeMicroSeconds() - taskScheduler->GetStartTime();
101aac5f829SSergey Makeev 
1028112dedfSSergey Makeev 			profileEvents.Push(std::move(eventDesc));
1038112dedfSSergey Makeev 		}
1048112dedfSSergey Makeev 
1058112dedfSSergey Makeev 		void ThreadContext::NotifyTaskResumed(const internal::TaskDesc & desc)
1068112dedfSSergey Makeev 		{
1078112dedfSSergey Makeev 			ProfileEventDesc eventDesc;
108a1626843SSergey Makeev 			eventDesc.id = desc.debugID;
109a1626843SSergey Makeev 			eventDesc.colorIndex = desc.colorIndex;
1108112dedfSSergey Makeev 			eventDesc.type = ProfileEventType::TASK_RESUME;
111aac5f829SSergey Makeev 			eventDesc.timeStampMicroSeconds = MT::GetTimeMicroSeconds() - taskScheduler->GetStartTime();
1128112dedfSSergey Makeev 			profileEvents.Push(std::move(eventDesc));
1138112dedfSSergey Makeev 		}
1148112dedfSSergey Makeev 
1158112dedfSSergey Makeev 		void ThreadContext::NotifyTaskYielded(const internal::TaskDesc & desc)
1168112dedfSSergey Makeev 		{
1178112dedfSSergey Makeev 			ProfileEventDesc eventDesc;
118a1626843SSergey Makeev 			eventDesc.id = desc.debugID;
119a1626843SSergey Makeev 			eventDesc.colorIndex = desc.colorIndex;
1208112dedfSSergey Makeev 			eventDesc.type = ProfileEventType::TASK_YIELD;
121aac5f829SSergey Makeev 			eventDesc.timeStampMicroSeconds = MT::GetTimeMicroSeconds() - taskScheduler->GetStartTime();
1228112dedfSSergey Makeev 			profileEvents.Push(std::move(eventDesc));
1238112dedfSSergey Makeev 		}
1248112dedfSSergey Makeev 
125a1626843SSergey Makeev 		void ThreadContext::NotifyWorkerAwait(int64 waitFrom, int64 waitTo)
126a1626843SSergey Makeev 		{
127a1626843SSergey Makeev 			waitFrom;
128a1626843SSergey Makeev 			waitTo;
129a1626843SSergey Makeev /*
130a1626843SSergey Makeev 			if ((waitTo - waitFrom) > 100)
131a1626843SSergey Makeev 			{
132a1626843SSergey Makeev 				ProfileEventDesc eventDesc;
133a1626843SSergey Makeev 				eventDesc.id = "#";
13434a394c3SSergey Makeev 				eventDesc.colorIndex = MT_COLOR_YELLOW;
135a1626843SSergey Makeev 				eventDesc.type = ProfileEventType::TASK_RESUME;
136a1626843SSergey Makeev 				eventDesc.timeStampMicroSeconds = waitFrom - MT::TaskScheduler::GetStartTime();
137a1626843SSergey Makeev 				profileEvents.Push(std::move(eventDesc));
138a1626843SSergey Makeev 
139a1626843SSergey Makeev 				eventDesc.id = "#";
14034a394c3SSergey Makeev 				eventDesc.colorIndex = MT_COLOR_YELLOW;
141a1626843SSergey Makeev 				eventDesc.type = ProfileEventType::TASK_DONE;
142a1626843SSergey Makeev 				eventDesc.timeStampMicroSeconds = waitTo - MT::TaskScheduler::GetStartTime();
143a1626843SSergey Makeev 				profileEvents.Push(std::move(eventDesc));
144a1626843SSergey Makeev 			}
145a1626843SSergey Makeev */
146a1626843SSergey Makeev 
147a1626843SSergey Makeev 		}
148a1626843SSergey Makeev 
149a1626843SSergey Makeev 
1508112dedfSSergey Makeev 
1518112dedfSSergey Makeev #endif
1528112dedfSSergey Makeev 
15358964d0bSSergey Makeev 	}
15458964d0bSSergey Makeev 
15558964d0bSSergey Makeev }
156