int geopm_sched_woomp(int num_cpu, cpu_set_t *woomp) { /*! @brief Function that returns a cpuset that has bits set for all CPUs enabled for the process which are not used by OpenMP. Rather than returning an empty mask, if all CPUs allocated for the process are used by OpenMP, then the woomp mask will have all bits set. */ int err = pthread_once(&g_proc_cpuset_once, geopm_proc_cpuset_once); int sched_num_cpu = geopm_sched_num_cpu(); size_t req_alloc_size = CPU_ALLOC_SIZE(num_cpu); if (!err && !g_proc_cpuset) { err = ENOMEM; } if (!err && req_alloc_size < g_proc_cpuset_size) { err = EINVAL; } if (!err) { /* Copy the process CPU mask into the output. */ memcpy(woomp, g_proc_cpuset, g_proc_cpuset_size); /* Start an OpenMP parallel region and have each thread clear its bit from the mask. */ #ifdef _OPENMP #pragma omp parallel default(shared) { #pragma omp critical { int cpu_index = sched_getcpu(); if (cpu_index != -1 && cpu_index < num_cpu) { /* Clear the bit for this OpenMP thread's CPU. */ CPU_CLR_S(cpu_index, g_proc_cpuset_size, woomp); } else { err = errno ? errno : GEOPM_ERROR_LOGIC; } } /* end pragma omp critical */ } /* end pragma omp parallel */ #endif /* _OPENMP */ } if (!err) { for (int i = sched_num_cpu; i < num_cpu; ++i) { CPU_CLR_S(i, req_alloc_size, woomp); } } if (err || CPU_COUNT_S(g_proc_cpuset_size, woomp) == 0) { /* If all CPUs are used by the OpenMP gang, then leave the mask open and allow the Linux scheduler to choose. */ for (int i = 0; i < num_cpu; ++i) { CPU_SET_S(i, g_proc_cpuset_size, woomp); } } return err; }
int geopm_sched_proc_cpuset(int num_cpu, cpu_set_t *proc_cpuset) { int err = pthread_once(&g_proc_cpuset_once, geopm_proc_cpuset_once); int sched_num_cpu = geopm_sched_num_cpu(); size_t cpuset_size = CPU_ALLOC_SIZE(num_cpu); if (!err && cpuset_size < g_proc_cpuset_size) { err = GEOPM_ERROR_INVALID; } if (!err) { memcpy(proc_cpuset, g_proc_cpuset, g_proc_cpuset_size); for (int i = sched_num_cpu; i < num_cpu; ++i) { CPU_CLR_S(i, cpuset_size, proc_cpuset); } } return err; }
bool gomp_affinity_remove_cpu (void *p, unsigned long num) { cpu_set_t *cpusetp = (cpu_set_t *) p; if (num >= 8 * gomp_cpuset_size) { gomp_error ("Logical CPU number %lu out of range", num); return false; } if (!CPU_ISSET_S (num, gomp_cpuset_size, cpusetp)) { gomp_error ("Logical CPU %lu to be removed is not in the set", num); return false; } CPU_CLR_S (num, gomp_cpuset_size, cpusetp); return true; }
bool gomp_affinity_init_level (int level, unsigned long count, bool quiet) { unsigned long i, max = 8 * gomp_cpuset_size; if (gomp_cpusetp) { unsigned long maxcount = gomp_cpuset_popcount (gomp_cpuset_size, gomp_cpusetp); if (count > maxcount) count = maxcount; } gomp_places_list = gomp_affinity_alloc (count, quiet); gomp_places_list_len = 0; if (gomp_places_list == NULL) return false; /* SMT (threads). */ if (level == 1) { for (i = 0; i < max && gomp_places_list_len < count; i++) if (CPU_ISSET_S (i, gomp_cpuset_size, gomp_cpusetp)) { gomp_affinity_init_place (gomp_places_list[gomp_places_list_len]); gomp_affinity_add_cpus (gomp_places_list[gomp_places_list_len], i, 1, 0, true); ++gomp_places_list_len; } return true; } else { char name[sizeof ("/sys/devices/system/cpu/cpu/topology/" "thread_siblings_list") + 3 * sizeof (unsigned long)]; size_t prefix_len = sizeof ("/sys/devices/system/cpu/cpu") - 1; cpu_set_t *copy = gomp_alloca (gomp_cpuset_size); FILE *f; char *line = NULL; size_t linelen = 0; memcpy (name, "/sys/devices/system/cpu/cpu", prefix_len); memcpy (copy, gomp_cpusetp, gomp_cpuset_size); for (i = 0; i < max && gomp_places_list_len < count; i++) if (CPU_ISSET_S (i, gomp_cpuset_size, copy)) { sprintf (name + prefix_len, "%lu/topology/%s_siblings_list", i, level == 2 ? "thread" : "core"); f = fopen (name, "r"); if (f != NULL) { if (getline (&line, &linelen, f) > 0) { char *p = line; bool seen_i = false; void *pl = gomp_places_list[gomp_places_list_len]; gomp_affinity_init_place (pl); while (*p && *p != '\n') { unsigned long first, last; errno = 0; first = strtoul (p, &p, 10); if (errno) break; last = first; if (*p == '-') { errno = 0; last = strtoul (p + 1, &p, 10); if (errno || last < first) break; } for (; first <= last; first++) if (CPU_ISSET_S (first, gomp_cpuset_size, copy) && gomp_affinity_add_cpus (pl, first, 1, 0, true)) { CPU_CLR_S (first, gomp_cpuset_size, copy); if (first == i) seen_i = true; } if (*p == ',') ++p; } if (seen_i) gomp_places_list_len++; } fclose (f); } } if (gomp_places_list_len == 0) { if (!quiet) gomp_error ("Error reading %s topology", level == 2 ? "core" : "socket"); free (gomp_places_list); gomp_places_list = NULL; return false; } return true; } return false; }