16 #if defined( _WIN32 ) && BT_THREADSAFE 27 struct btProcessorInfo
29 int numLogicalProcessors;
35 int numPhysicalPackages;
36 static const int maxNumTeamMasks = 32;
38 UINT64 processorTeamMasks[ maxNumTeamMasks ];
41 UINT64 getProcessorTeamMask(
const btProcessorInfo& procInfo,
int procId )
43 UINT64 procMask = UINT64( 1 ) << procId;
44 for (
int i = 0; i < procInfo.numTeamMasks; ++i )
46 if ( procMask & procInfo.processorTeamMasks[ i ] )
48 return procInfo.processorTeamMasks[ i ];
54 int getProcessorTeamIndex(
const btProcessorInfo& procInfo,
int procId )
56 UINT64 procMask = UINT64( 1 ) << procId;
57 for (
int i = 0; i < procInfo.numTeamMasks; ++i )
59 if ( procMask & procInfo.processorTeamMasks[ i ] )
67 int countSetBits( ULONG64 bits )
82 typedef BOOL( WINAPI *Pfn_GetLogicalProcessorInformation )( PSYSTEM_LOGICAL_PROCESSOR_INFORMATION, PDWORD );
85 void getProcessorInformation( btProcessorInfo* procInfo )
87 memset( procInfo, 0,
sizeof( *procInfo ) );
88 Pfn_GetLogicalProcessorInformation getLogicalProcInfo =
89 (Pfn_GetLogicalProcessorInformation) GetProcAddress( GetModuleHandle( TEXT(
"kernel32" ) ),
"GetLogicalProcessorInformation" );
90 if ( getLogicalProcInfo == NULL )
95 PSYSTEM_LOGICAL_PROCESSOR_INFORMATION buf = NULL;
99 if ( getLogicalProcInfo( buf, &bufSize ) )
105 if ( GetLastError() == ERROR_INSUFFICIENT_BUFFER )
111 buf = (PSYSTEM_LOGICAL_PROCESSOR_INFORMATION) malloc( bufSize );
116 int len = bufSize /
sizeof( *buf );
117 for (
int i = 0; i < len; ++i )
119 PSYSTEM_LOGICAL_PROCESSOR_INFORMATION info = buf + i;
120 switch ( info->Relationship )
122 case RelationNumaNode:
123 procInfo->numNumaNodes++;
126 case RelationProcessorCore:
127 procInfo->numCores++;
128 procInfo->numLogicalProcessors += countSetBits( info->ProcessorMask );
132 if ( info->Cache.Level == 1 )
134 procInfo->numL1Cache++;
136 else if ( info->Cache.Level == 2 )
138 procInfo->numL2Cache++;
140 else if ( info->Cache.Level == 3 )
142 procInfo->numL3Cache++;
152 if ( procInfo->numTeamMasks < btProcessorInfo::maxNumTeamMasks )
154 procInfo->processorTeamMasks[ procInfo->numTeamMasks ] = info->ProcessorMask;
155 procInfo->numTeamMasks++;
160 case RelationProcessorPackage:
161 procInfo->numPhysicalPackages++;
174 struct btThreadStatus
180 ThreadFunc m_userThreadFunc;
183 void* m_threadHandle;
185 void* m_eventStartHandle;
186 char m_eventStartHandleName[ 32 ];
188 void* m_eventCompleteHandle;
189 char m_eventCompleteHandleName[ 32 ];
196 DWORD_PTR m_startedThreadMask;
197 btProcessorInfo m_processorInfo;
199 void startThreads(
const ConstructionInfo& threadInfo );
201 int waitForResponse();
205 btThreadSupportWin32(
const ConstructionInfo& threadConstructionInfo );
206 virtual ~btThreadSupportWin32();
208 virtual int getNumWorkerThreads() const
BT_OVERRIDE {
return m_numThreads; }
209 virtual int getCacheFriendlyNumThreads() const
BT_OVERRIDE {
return countSetBits(m_processorInfo.processorTeamMasks[0]); }
210 virtual int getLogicalToPhysicalCoreRatio() const
BT_OVERRIDE {
return m_processorInfo.numLogicalProcessors / m_processorInfo.numCores; }
212 virtual void runTask(
int threadIndex,
void* userData )
BT_OVERRIDE;
213 virtual void waitForAllTasks() BT_OVERRIDE;
216 virtual
void deleteCriticalSection(
btCriticalSection* criticalSection ) BT_OVERRIDE;
220 btThreadSupportWin32::btThreadSupportWin32( const ConstructionInfo & threadConstructionInfo )
222 startThreads( threadConstructionInfo );
226 btThreadSupportWin32::~btThreadSupportWin32()
232 DWORD WINAPI win32threadStartFunc( LPVOID lpParam )
234 btThreadSupportWin32::btThreadStatus* status = ( btThreadSupportWin32::btThreadStatus* )lpParam;
238 WaitForSingleObject( status->m_eventStartHandle, INFINITE );
239 void* userPtr = status->m_userPtr;
244 status->m_userThreadFunc( userPtr );
245 status->m_status = 2;
246 SetEvent( status->m_eventCompleteHandle );
251 status->m_status = 3;
252 printf(
"Thread with taskId %i with handle %p exiting\n", status->m_taskId, status->m_threadHandle );
253 SetEvent( status->m_eventCompleteHandle );
257 printf(
"Thread TERMINATED\n" );
262 void btThreadSupportWin32::runTask(
int threadIndex,
void* userData )
264 btThreadStatus& threadStatus = m_activeThreadStatus[ threadIndex ];
266 btAssert(
int( threadIndex ) < m_activeThreadStatus.
size() );
268 threadStatus.m_commandId = 1;
269 threadStatus.m_status = 1;
270 threadStatus.m_userPtr = userData;
271 m_startedThreadMask |= DWORD_PTR( 1 ) << threadIndex;
274 SetEvent( threadStatus.m_eventStartHandle );
278 int btThreadSupportWin32::waitForResponse()
283 DWORD res = WaitForMultipleObjects( m_completeHandles.
size(), &m_completeHandles[ 0 ], FALSE, INFINITE );
285 last = res - WAIT_OBJECT_0;
287 btThreadStatus& threadStatus = m_activeThreadStatus[ last ];
288 btAssert( threadStatus.m_threadHandle );
289 btAssert( threadStatus.m_eventCompleteHandle );
292 btAssert( threadStatus.m_status > 1 );
293 threadStatus.m_status = 0;
297 m_startedThreadMask &= ~( DWORD_PTR( 1 ) << last );
303 void btThreadSupportWin32::waitForAllTasks()
305 while ( m_startedThreadMask )
312 void btThreadSupportWin32::startThreads(
const ConstructionInfo& threadConstructionInfo )
316 btProcessorInfo& procInfo = m_processorInfo;
317 getProcessorInformation( &procInfo );
318 DWORD_PTR dwProcessAffinityMask = 0;
319 DWORD_PTR dwSystemAffinityMask = 0;
320 if ( !GetProcessAffinityMask( GetCurrentProcess(), &dwProcessAffinityMask, &dwSystemAffinityMask ) )
322 dwProcessAffinityMask = 0;
327 m_activeThreadStatus.
resize( m_numThreads );
328 m_completeHandles.
resize( m_numThreads );
329 m_startedThreadMask = 0;
332 if ( DWORD_PTR mask = dwProcessAffinityMask & getProcessorTeamMask( procInfo, 0 ))
334 SetThreadAffinityMask( GetCurrentThread(), mask );
335 SetThreadIdealProcessor( GetCurrentThread(), 0 );
338 for (
int i = 0; i < m_numThreads; i++ )
340 printf(
"starting thread %d\n", i );
342 btThreadStatus& threadStatus = m_activeThreadStatus[ i ];
344 LPSECURITY_ATTRIBUTES lpThreadAttributes = NULL;
345 SIZE_T dwStackSize = threadConstructionInfo.m_threadStackSize;
346 LPTHREAD_START_ROUTINE lpStartAddress = &win32threadStartFunc;
347 LPVOID lpParameter = &threadStatus;
348 DWORD dwCreationFlags = 0;
349 LPDWORD lpThreadId = 0;
351 threadStatus.m_userPtr = 0;
353 sprintf( threadStatus.m_eventStartHandleName,
"es%.8s%d%d", threadConstructionInfo.m_uniqueName, uniqueId, i );
354 threadStatus.m_eventStartHandle = CreateEventA( 0,
false,
false, threadStatus.m_eventStartHandleName );
356 sprintf( threadStatus.m_eventCompleteHandleName,
"ec%.8s%d%d", threadConstructionInfo.m_uniqueName, uniqueId, i );
357 threadStatus.m_eventCompleteHandle = CreateEventA( 0,
false,
false, threadStatus.m_eventCompleteHandleName );
359 m_completeHandles[ i ] = threadStatus.m_eventCompleteHandle;
361 HANDLE handle = CreateThread( lpThreadAttributes, dwStackSize, lpStartAddress, lpParameter, dwCreationFlags, lpThreadId );
369 int processorId = i + 1;
370 DWORD_PTR teamMask = getProcessorTeamMask( procInfo, processorId );
377 DWORD_PTR mask = teamMask & dwProcessAffinityMask;
380 SetThreadAffinityMask( handle, mask );
383 SetThreadIdealProcessor( handle, processorId );
386 threadStatus.m_taskId = i;
387 threadStatus.m_commandId = 0;
388 threadStatus.m_status = 0;
389 threadStatus.m_threadHandle = handle;
390 threadStatus.m_userThreadFunc = threadConstructionInfo.m_userThreadFunc;
392 printf(
"started %s thread %d with threadHandle %p\n", threadConstructionInfo.m_uniqueName, i, handle );
397 void btThreadSupportWin32::stopThreads()
399 for (
int i = 0; i < m_activeThreadStatus.
size(); i++ )
401 btThreadStatus& threadStatus = m_activeThreadStatus[ i ];
402 if ( threadStatus.m_status > 0 )
404 WaitForSingleObject( threadStatus.m_eventCompleteHandle, INFINITE );
407 threadStatus.m_userPtr = NULL;
408 SetEvent( threadStatus.m_eventStartHandle );
409 WaitForSingleObject( threadStatus.m_eventCompleteHandle, INFINITE );
411 CloseHandle( threadStatus.m_eventCompleteHandle );
412 CloseHandle( threadStatus.m_eventStartHandle );
413 CloseHandle( threadStatus.m_threadHandle );
417 m_activeThreadStatus.
clear();
418 m_completeHandles.
clear();
425 CRITICAL_SECTION mCriticalSection;
428 btWin32CriticalSection()
430 InitializeCriticalSection( &mCriticalSection );
433 ~btWin32CriticalSection()
435 DeleteCriticalSection( &mCriticalSection );
440 EnterCriticalSection( &mCriticalSection );
445 LeaveCriticalSection( &mCriticalSection );
452 unsigned char* mem = (
unsigned char*)
btAlignedAlloc(
sizeof( btWin32CriticalSection ), 16 );
453 btWin32CriticalSection* cs =
new( mem ) btWin32CriticalSection();
457 void btThreadSupportWin32::deleteCriticalSection(
btCriticalSection* criticalSection )
466 return new btThreadSupportWin32( info );
471 #endif //defined(_WIN32) && BT_THREADSAFE The btAlignedObjectArray template class uses a subset of the stl::vector interface for its methods It...
static btThreadSupportInterface * create(const ConstructionInfo &info)
const unsigned int BT_MAX_THREAD_COUNT
void clear()
clear the array, deallocated memory. Generally it is better to use array.resize(0), to reduce performance overhead of run-time memory (de)allocations.
int size() const
return the number of elements in the array
#define btAlignedFree(ptr)
virtual ~btCriticalSection()
void resize(int newsize, const T &fillData=T())
#define btAlignedAlloc(size, alignment)
const T & btMin(const T &a, const T &b)