Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergey Sharybin <sergey.vfx@gmail.com>2016-06-04 02:29:13 +0300
committerSergey Sharybin <sergey.vfx@gmail.com>2016-06-06 10:14:37 +0300
commitb62faa54de70fd8a4125c98cce2d12f3291139fc (patch)
tree64cae6f76c23212ff2dc93b26eef9647386aea1a
parent9d090ed1cde2ae75c36548ed31daae10f121317a (diff)
Cycles: Add support of processor groups
Currently for windows only, this is an initial commit towards native support of NUMA. Current commit makes it so Cycles will use all logical processors on Windows running on system with more than 64 threads. Reviewers: juicyfruit, dingto, lukasstockner97, maiself, brecht Subscribers: LazyDodo Differential Revision: https://developer.blender.org/D2049
-rw-r--r--intern/cycles/util/CMakeLists.txt2
-rw-r--r--intern/cycles/util/util_system.cpp53
-rw-r--r--intern/cycles/util/util_system.h8
-rw-r--r--intern/cycles/util/util_task.cpp23
-rw-r--r--intern/cycles/util/util_thread.cpp66
-rw-r--r--intern/cycles/util/util_thread.h36
-rw-r--r--intern/cycles/util/util_windows.cpp82
-rw-r--r--intern/cycles/util/util_windows.h19
8 files changed, 248 insertions, 41 deletions
diff --git a/intern/cycles/util/CMakeLists.txt b/intern/cycles/util/CMakeLists.txt
index cceec8d444c..e6140b3ed09 100644
--- a/intern/cycles/util/CMakeLists.txt
+++ b/intern/cycles/util/CMakeLists.txt
@@ -19,8 +19,10 @@ set(SRC
util_simd.cpp
util_system.cpp
util_task.cpp
+ util_thread.cpp
util_time.cpp
util_transform.cpp
+ util_windows.cpp
)
if(NOT CYCLES_STANDALONE_REPOSITORY)
diff --git a/intern/cycles/util/util_system.cpp b/intern/cycles/util/util_system.cpp
index 4ff0ee91d73..16f713e1ea6 100644
--- a/intern/cycles/util/util_system.cpp
+++ b/intern/cycles/util/util_system.cpp
@@ -15,7 +15,9 @@
*/
#include "util_system.h"
+
#include "util_debug.h"
+#include "util_logging.h"
#include "util_types.h"
#include "util_string.h"
@@ -33,28 +35,57 @@
CCL_NAMESPACE_BEGIN
-int system_cpu_thread_count()
+int system_cpu_group_count()
{
- static uint count = 0;
-
- if(count > 0)
- return count;
+#ifdef _WIN32
+ util_windows_init_numa_groups();
+ return GetActiveProcessorGroupCount();
+#else
+ /* TODO(sergey): Need to adopt for other platforms. */
+ return 1;
+#endif
+}
+int system_cpu_group_thread_count(int group)
+{
+ /* TODO(sergey): Need make other platforms aware of groups. */
#ifdef _WIN32
- SYSTEM_INFO info;
- GetSystemInfo(&info);
- count = (uint)info.dwNumberOfProcessors;
+ util_windows_init_numa_groups();
+ return GetActiveProcessorCount(group);
#elif defined(__APPLE__)
+ (void)group;
size_t len = sizeof(count);
int mib[2] = { CTL_HW, HW_NCPU };
-
+
+ int count;
sysctl(mib, 2, &count, &len, NULL, 0);
+ return count;
#else
- count = (uint)sysconf(_SC_NPROCESSORS_ONLN);
+ (void)group;
+ return sysconf(_SC_NPROCESSORS_ONLN);
#endif
+}
+
+int system_cpu_thread_count()
+{
+ static uint count = 0;
- if(count < 1)
+ if(count > 0) {
+ return count;
+ }
+
+ int max_group = system_cpu_group_count();
+ VLOG(1) << "Detected " << max_group << " CPU groups.";
+ for(int group = 0; group < max_group; ++group) {
+ int num_threads = system_cpu_group_thread_count(group);
+ VLOG(1) << "Group " << group
+ << " has " << num_threads << " threads.";
+ count += num_threads;
+ }
+
+ if(count < 1) {
count = 1;
+ }
return count;
}
diff --git a/intern/cycles/util/util_system.h b/intern/cycles/util/util_system.h
index 4e7e00f85fd..557aab6cbae 100644
--- a/intern/cycles/util/util_system.h
+++ b/intern/cycles/util/util_system.h
@@ -21,7 +21,15 @@
CCL_NAMESPACE_BEGIN
+/* Get number of available CPU groups. */
+int system_cpu_group_count();
+
+/* Get number of threads/processors in the specified group. */
+int system_cpu_group_thread_count(int group);
+
+/* Get total number of threads in all groups. */
int system_cpu_thread_count();
+
string system_cpu_brand_string();
int system_cpu_bits();
bool system_cpu_support_sse2();
diff --git a/intern/cycles/util/util_task.cpp b/intern/cycles/util/util_task.cpp
index d86aa8a4a46..352ba81c95a 100644
--- a/intern/cycles/util/util_task.cpp
+++ b/intern/cycles/util/util_task.cpp
@@ -16,6 +16,7 @@
#include "util_debug.h"
#include "util_foreach.h"
+#include "util_logging.h"
#include "util_system.h"
#include "util_task.h"
#include "util_time.h"
@@ -198,12 +199,30 @@ void TaskScheduler::init(int num_threads)
/* automatic number of threads */
num_threads = system_cpu_thread_count();
}
+ VLOG(1) << "Creating pool of " << num_threads << " threads.";
/* launch threads that will be waiting for work */
threads.resize(num_threads);
- for(size_t i = 0; i < threads.size(); i++)
- threads[i] = new thread(function_bind(&TaskScheduler::thread_run, i + 1));
+ int num_groups = system_cpu_group_count();
+ int thread_index = 0;
+ for(int group = 0; group < num_groups; ++group) {
+ /* NOTE: That's not really efficient from threading point of view,
+ * but it is simple to read and it doesn't make sense to use more
+ * user-specified threads than logical threads anyway.
+ */
+ int num_group_threads = (group == num_groups - 1)
+ ? (threads.size() - thread_index)
+ : system_cpu_group_thread_count(group);
+ for(int group_thread = 0;
+ group_thread < num_group_threads && thread_index < threads.size();
+ ++group_thread, ++thread_index)
+ {
+ threads[thread_index] = new thread(function_bind(&TaskScheduler::thread_run,
+ thread_index + 1),
+ group);
+ }
+ }
}
users++;
diff --git a/intern/cycles/util/util_thread.cpp b/intern/cycles/util/util_thread.cpp
new file mode 100644
index 00000000000..3db8b4bd197
--- /dev/null
+++ b/intern/cycles/util/util_thread.cpp
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2011-2016 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "util_thread.h"
+
+#include "util_system.h"
+#include "util_windows.h"
+
+CCL_NAMESPACE_BEGIN
+
+thread::thread(function<void(void)> run_cb, int group)
+ : run_cb_(run_cb),
+ joined_(false),
+ group_(group)
+{
+ pthread_create(&pthread_id_, NULL, run, (void*)this);
+}
+
+thread::~thread()
+{
+ if(!joined_) {
+ join();
+ }
+}
+
+void *thread::run(void *arg)
+{
+ thread *self = (thread*)(arg);
+ if(self->group_ != -1) {
+#ifdef _WIN32
+ HANDLE thread_handle = GetCurrentThread();
+ GROUP_AFFINITY group_affinity = { 0 };
+ int num_threads = system_cpu_group_thread_count(self->group_);
+ group_affinity.Group = self->group_;
+ group_affinity.Mask = (num_threads == 64)
+ ? -1
+ : (1ull << num_threads) - 1;
+ if(SetThreadGroupAffinity(thread_handle, &group_affinity, NULL) == 0) {
+ fprintf(stderr, "Error setting thread affinity.\n");
+ }
+#endif
+ }
+ self->run_cb_();
+ return NULL;
+}
+
+bool thread::join()
+{
+ joined_ = true;
+ return pthread_join(pthread_id_, NULL) == 0;
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/util/util_thread.h b/intern/cycles/util/util_thread.h
index 59575f31c13..427c633d2ce 100644
--- a/intern/cycles/util/util_thread.h
+++ b/intern/cycles/util/util_thread.h
@@ -52,37 +52,17 @@ typedef boost::condition_variable thread_condition_variable;
class thread {
public:
- thread(function<void(void)> run_cb_)
+ thread(function<void(void)> run_cb, int group = -1);
+ ~thread();
- {
- joined = false;
- run_cb = run_cb_;
-
- pthread_create(&pthread_id, NULL, run, (void*)this);
- }
-
- ~thread()
- {
- if(!joined)
- join();
- }
-
- static void *run(void *arg)
- {
- ((thread*)arg)->run_cb();
- return NULL;
- }
-
- bool join()
- {
- joined = true;
- return pthread_join(pthread_id, NULL) == 0;
- }
+ static void *run(void *arg);
+ bool join();
protected:
- function<void(void)> run_cb;
- pthread_t pthread_id;
- bool joined;
+ function<void(void)> run_cb_;
+ pthread_t pthread_id_;
+ bool joined_;
+ int group_;
};
/* Own wrapper around pthread's spin lock to make it's use easier. */
diff --git a/intern/cycles/util/util_windows.cpp b/intern/cycles/util/util_windows.cpp
new file mode 100644
index 00000000000..6fd259713d9
--- /dev/null
+++ b/intern/cycles/util/util_windows.cpp
@@ -0,0 +1,82 @@
+/*
+ * Copyright 2011-2016 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "util_windows.h"
+
+#ifdef _WIN32
+
+CCL_NAMESPACE_BEGIN
+
+#include <VersionHelpers.h>
+
+#if _WIN32_WINNT < 0x0601
+tGetActiveProcessorGroupCount *GetActiveProcessorGroupCount;
+tGetActiveProcessorCount *GetActiveProcessorCount;
+tSetThreadGroupAffinity *SetThreadGroupAffinity;
+#endif
+
+static WORD GetActiveProcessorGroupCount_stub()
+{
+ return 1;
+}
+
+static DWORD GetActiveProcessorCount_stub(WORD /*GroupNumber*/)
+{
+ SYSTEM_INFO info;
+ GetSystemInfo(&info);
+ return info.dwNumberOfProcessors;
+}
+
+static BOOL SetThreadGroupAffinity_stub(
+ HANDLE /*hThread*/,
+ const GROUP_AFFINITY * /*GroupAffinity*/,
+ PGROUP_AFFINITY /*PreviousGroupAffinity*/)
+{
+ return TRUE;
+}
+
+static bool supports_numa()
+{
+ return IsWindows7OrGreater();
+}
+
+void util_windows_init_numa_groups()
+{
+ static bool initialized = false;
+ if(initialized) {
+ return;
+ }
+ initialized = true;
+#if _WIN32_WINNT < 0x0601
+ if(!supports_numa()) {
+ /* Use stubs on platforms which doesn't have rean NUMA/Groups. */
+ GetActiveProcessorGroupCount = GetActiveProcessorGroupCount_stub;
+ GetActiveProcessorCount = GetActiveProcessorCount_stub;
+ SetThreadGroupAffinity = SetThreadGroupAffinity_stub;
+ return;
+ }
+ HMODULE kernel = GetModuleHandleA("kernel32.dll");
+# define READ_SYMBOL(sym) sym = (t##sym*)GetProcAddress(kernel, #sym)
+ READ_SYMBOL(GetActiveProcessorGroupCount);
+ READ_SYMBOL(GetActiveProcessorCount);
+ READ_SYMBOL(SetThreadGroupAffinity);
+# undef READ_SUMBOL
+#endif
+}
+
+CCL_NAMESPACE_END
+
+#endif /* _WIN32 */
diff --git a/intern/cycles/util/util_windows.h b/intern/cycles/util/util_windows.h
index f67e34d0f31..ac61d5348c3 100644
--- a/intern/cycles/util/util_windows.h
+++ b/intern/cycles/util/util_windows.h
@@ -31,6 +31,25 @@
#include <windows.h>
+CCL_NAMESPACE_BEGIN
+
+#if _WIN32_WINNT < 0x0601
+typedef WORD tGetActiveProcessorGroupCount();
+typedef DWORD tGetActiveProcessorCount(WORD GroupNumber);
+typedef BOOL tSetThreadGroupAffinity(HANDLE hThread,
+ const GROUP_AFFINITY *GroupAffinity,
+ PGROUP_AFFINITY PreviousGroupAffinity);
+
+extern tGetActiveProcessorGroupCount *GetActiveProcessorGroupCount;
+extern tGetActiveProcessorCount *GetActiveProcessorCount;
+extern tSetThreadGroupAffinity *SetThreadGroupAffinity;
+#endif
+
+/* Make sure NUMA and processor groups API is initialized. */
+void util_windows_init_numa_groups();
+
+CCL_NAMESPACE_END
+
#endif /* WIN32 */
#endif /* __UTIL_WINDOWS_H__ */