Fix T50034: Blender changes processor affinity unauthorized

This commit is contained in:
Sergey Sharybin 2016-11-22 16:03:16 +01:00
parent cb694d6595
commit 751573ce6f
5 changed files with 68 additions and 3 deletions

@ -89,6 +89,20 @@ int system_cpu_thread_count()
return count; return count;
} }
unsigned short system_cpu_process_groups(unsigned short max_groups,
unsigned short *grpups)
{
#ifdef _WIN32
unsigned short group_count = max_groups;
if(!GetProcessGroupAffinity(GetCurrentProcess(), &group_count, grpups)) {
return 0;
}
return group_count;
#else
return 0;
#endif
}
#if !defined(_WIN32) || defined(FREE_WINDOWS) #if !defined(_WIN32) || defined(FREE_WINDOWS)
static void __cpuid(int data[4], int selector) static void __cpuid(int data[4], int selector)
{ {

@ -30,6 +30,10 @@ int system_cpu_group_thread_count(int group);
/* Get total number of threads in all groups. */ /* Get total number of threads in all groups. */
int system_cpu_thread_count(); int system_cpu_thread_count();
/* Get current process groups. */
unsigned short system_cpu_process_groups(unsigned short max_groups,
unsigned short *grpups);
string system_cpu_brand_string(); string system_cpu_brand_string();
int system_cpu_bits(); int system_cpu_bits();
bool system_cpu_support_sse2(); bool system_cpu_support_sse2();

@ -195,7 +195,8 @@ void TaskScheduler::init(int num_threads)
if(users == 0) { if(users == 0) {
do_exit = false; do_exit = false;
if(num_threads == 0) { const bool use_auto_threads = (num_threads == 0);
if(use_auto_threads) {
/* automatic number of threads */ /* automatic number of threads */
num_threads = system_cpu_thread_count(); num_threads = system_cpu_thread_count();
} }
@ -204,7 +205,18 @@ void TaskScheduler::init(int num_threads)
/* launch threads that will be waiting for work */ /* launch threads that will be waiting for work */
threads.resize(num_threads); threads.resize(num_threads);
int num_groups = system_cpu_group_count(); const int num_groups = system_cpu_group_count();
unsigned short num_process_groups;
vector<unsigned short> process_groups;
int current_group_threads;
if(num_groups > 1) {
process_groups.resize(num_groups);
num_process_groups = system_cpu_process_groups(num_groups,
&process_groups[0]);
if(num_process_groups == 1) {
current_group_threads = system_cpu_group_thread_count(process_groups[0]);
}
}
int thread_index = 0; int thread_index = 0;
for(int group = 0; group < num_groups; ++group) { for(int group = 0; group < num_groups; ++group) {
/* NOTE: That's not really efficient from threading point of view, /* NOTE: That's not really efficient from threading point of view,
@ -218,9 +230,25 @@ void TaskScheduler::init(int num_threads)
group_thread < num_group_threads && thread_index < threads.size(); group_thread < num_group_threads && thread_index < threads.size();
++group_thread, ++thread_index) ++group_thread, ++thread_index)
{ {
/* NOTE: Thread group of -1 means we would not force thread affinity. */
int thread_group;
if(num_groups == 1) {
/* Use default affinity if there's only one CPU group in the system. */
thread_group = -1;
}
else if(use_auto_threads &&
num_process_groups == 1 &&
num_threads <= current_group_threads)
{
/* If we fit into curent CPU group we also don't force any affinity. */
thread_group = -1;
}
else {
thread_group = group;
}
threads[thread_index] = new thread(function_bind(&TaskScheduler::thread_run, threads[thread_index] = new thread(function_bind(&TaskScheduler::thread_run,
thread_index + 1), thread_index + 1),
group); thread_group);
} }
} }
} }

@ -28,6 +28,7 @@ CCL_NAMESPACE_BEGIN
tGetActiveProcessorGroupCount *GetActiveProcessorGroupCount; tGetActiveProcessorGroupCount *GetActiveProcessorGroupCount;
tGetActiveProcessorCount *GetActiveProcessorCount; tGetActiveProcessorCount *GetActiveProcessorCount;
tSetThreadGroupAffinity *SetThreadGroupAffinity; tSetThreadGroupAffinity *SetThreadGroupAffinity;
tGetProcessGroupAffinity *GetProcessGroupAffinity;
#endif #endif
static WORD GetActiveProcessorGroupCount_stub() static WORD GetActiveProcessorGroupCount_stub()
@ -50,6 +51,18 @@ static BOOL SetThreadGroupAffinity_stub(
return TRUE; return TRUE;
} }
static BOOL GetProcessGroupAffinity_stub(HANDLE hProcess,
PUSHORT GroupCount,
PUSHORT GroupArray)
{
if(*GroupCount < 1) {
return FALSE;
}
*GroupCount = 1;
GroupArray[0] = 0;
return TRUE;
}
static bool supports_numa() static bool supports_numa()
{ {
#ifndef _M_X64 #ifndef _M_X64
@ -72,6 +85,7 @@ void util_windows_init_numa_groups()
GetActiveProcessorGroupCount = GetActiveProcessorGroupCount_stub; GetActiveProcessorGroupCount = GetActiveProcessorGroupCount_stub;
GetActiveProcessorCount = GetActiveProcessorCount_stub; GetActiveProcessorCount = GetActiveProcessorCount_stub;
SetThreadGroupAffinity = SetThreadGroupAffinity_stub; SetThreadGroupAffinity = SetThreadGroupAffinity_stub;
GetProcessGroupAffinity = GetProcessGroupAffinity_stub;
return; return;
} }
HMODULE kernel = GetModuleHandleA("kernel32.dll"); HMODULE kernel = GetModuleHandleA("kernel32.dll");
@ -79,6 +93,7 @@ void util_windows_init_numa_groups()
READ_SYMBOL(GetActiveProcessorGroupCount); READ_SYMBOL(GetActiveProcessorGroupCount);
READ_SYMBOL(GetActiveProcessorCount); READ_SYMBOL(GetActiveProcessorCount);
READ_SYMBOL(SetThreadGroupAffinity); READ_SYMBOL(SetThreadGroupAffinity);
READ_SYMBOL(GetProcessGroupAffinity);
# undef READ_SUMBOL # undef READ_SUMBOL
#endif #endif
} }

@ -39,10 +39,14 @@ typedef DWORD tGetActiveProcessorCount(WORD GroupNumber);
typedef BOOL tSetThreadGroupAffinity(HANDLE hThread, typedef BOOL tSetThreadGroupAffinity(HANDLE hThread,
const GROUP_AFFINITY *GroupAffinity, const GROUP_AFFINITY *GroupAffinity,
PGROUP_AFFINITY PreviousGroupAffinity); PGROUP_AFFINITY PreviousGroupAffinity);
typedef BOOL tGetProcessGroupAffinity(HANDLE hProcess,
PUSHORT GroupCount,
PUSHORT GroupArray);
extern tGetActiveProcessorGroupCount *GetActiveProcessorGroupCount; extern tGetActiveProcessorGroupCount *GetActiveProcessorGroupCount;
extern tGetActiveProcessorCount *GetActiveProcessorCount; extern tGetActiveProcessorCount *GetActiveProcessorCount;
extern tSetThreadGroupAffinity *SetThreadGroupAffinity; extern tSetThreadGroupAffinity *SetThreadGroupAffinity;
extern tGetProcessGroupAffinity *GetProcessGroupAffinity;
#endif #endif
/* Make sure NUMA and processor groups API is initialized. */ /* Make sure NUMA and processor groups API is initialized. */