gallium/util: don't let child processes inherit our thread affinity
authorMarek Olšák <marek.olsak@amd.com>
Thu, 13 Sep 2018 00:29:19 +0000 (20:29 -0400)
committerMarek Olšák <marek.olsak@amd.com>
Sat, 15 Sep 2018 01:15:39 +0000 (21:15 -0400)
v2: corrected the comment

src/gallium/auxiliary/util/u_helpers.c

index 14367e5a1189d0602ad4257e7bcea0642fc8dc6d..b6cebf96329d16de6c914e00dccca04b29d27a49 100644 (file)
@@ -121,17 +121,40 @@ util_upload_index_buffer(struct pipe_context *pipe,
    return *out_buffer != NULL;
 }
 
+#ifdef HAVE_PTHREAD_SETAFFINITY
+
 static unsigned L3_cache_number;
-static once_flag init_cache_number_flag = ONCE_FLAG_INIT;
+static once_flag thread_pinning_once_flag = ONCE_FLAG_INIT;
+
+static void
+util_set_full_cpu_affinity(void)
+{
+   cpu_set_t cpuset;
+
+   CPU_ZERO(&cpuset);
+   for (unsigned i = 0; i < CPU_SETSIZE; i++)
+      CPU_SET(i, &cpuset);
+
+   pthread_setaffinity_np(pthread_self(), sizeof(cpuset), &cpuset);
+}
 
 static void
-util_init_cache_number(void)
+util_init_thread_pinning(void)
 {
    /* Get a semi-random number. */
    int64_t t = os_time_get_nano();
    L3_cache_number = (t ^ (t >> 8) ^ (t >> 16));
+
+   /* Reset thread affinity for all child processes to prevent them from
+    * inheriting the current thread's affinity.
+    *
+    * What happens if a driver is unloaded and the app creates a thread?
+    */
+   pthread_atfork(NULL, NULL, util_set_full_cpu_affinity);
 }
 
+#endif
+
 /**
  * Called by MakeCurrent. Used to notify the driver that the application
  * thread may have been changed.
@@ -146,18 +169,23 @@ util_init_cache_number(void)
 void
 util_context_thread_changed(struct pipe_context *ctx, thrd_t *upper_thread)
 {
-#ifdef HAVE_PTHREAD
+#ifdef HAVE_PTHREAD_SETAFFINITY
+   /* If pinning has no effect, don't do anything. */
+   if (util_cpu_caps.nr_cpus == util_cpu_caps.cores_per_L3)
+      return;
+
    thrd_t current = thrd_current();
    int cache = util_get_L3_for_pinned_thread(current,
                                              util_cpu_caps.cores_per_L3);
 
+   call_once(&thread_pinning_once_flag, util_init_thread_pinning);
+
    /* If the main thread is not pinned, choose the L3 cache. */
    if (cache == -1) {
       unsigned num_L3_caches = util_cpu_caps.nr_cpus /
                                util_cpu_caps.cores_per_L3;
 
       /* Choose a different L3 cache for each subsequent MakeCurrent. */
-      call_once(&init_cache_number_flag, util_init_cache_number);
       cache = p_atomic_inc_return(&L3_cache_number) % num_L3_caches;
       util_pin_thread_to_L3(current, cache, util_cpu_caps.cores_per_L3);
    }