Как установить сродство процессора конкретного pthread?
Я хотел бы указать сродство к процессору конкретного pthread. Все ссылки, которые я нашел до сих пор, касаются установки привязки к процессору (pid_t), а не потоку (pthread_t). Я попробовал некоторые эксперименты, передавая pthread_t, и, как и ожидалось, они провалились. Я пытаюсь сделать что-то невозможное? Если нет, можете ли вы отправить указатель, пожалуйста? Бесконечно благодарен.
5 ответов
Это обертка, которую я сделал, чтобы сделать мою жизнь проще. Это приводит к тому, что вызывающий поток "застревает" в ядре с идентификатором core_id
:
// core_id = 0, 1, ... n-1, where n is the system's number of cores
int stick_this_thread_to_core(int core_id) {
int num_cores = sysconf(_SC_NPROCESSORS_ONLN);
if (core_id < 0 || core_id >= num_cores)
return EINVAL;
cpu_set_t cpuset;
CPU_ZERO(&cpuset);
CPU_SET(core_id, &cpuset);
pthread_t current_thread = pthread_self();
return pthread_setaffinity_np(current_thread, sizeof(cpu_set_t), &cpuset);
}
Предполагая Linux:
Интерфейс для настройки соответствия - как вы, вероятно, уже обнаружили:
int sched_setaffinity(pid_t pid,size_t cpusetsize,cpu_set_t *mask);
Передача 0 в качестве pid, и он будет применяться только к текущему потоку, или же другой поток сообщит свой pid ядра с помощью специального вызова linux pid_t gettid(void); и передать это как пид.
Цитирование справочной страницы
Маска сходства фактически является атрибутом для каждого потока, который можно настраивать независимо для каждого из потоков в группе потоков. Значение, возвращаемое из вызова gettid(2), может быть передано в аргументе pid. Указание pid в качестве 0 установит атрибут для вызывающего потока, а передача значения, возвращенного из вызова getpid(2), установит атрибут для основного потока группы потоков. (Если вы используете API потоков POSIX, тогда используйте pthread_setaffinity_np (3) вместо sched_setaffinity().)
//compilation: gcc -o affinity affinity.c -lpthread
#define _GNU_SOURCE
#include <sched.h> //cpu_set_t , CPU_SET
#include <pthread.h> //pthread_t
#include <stdio.h>
void *th_func(void * arg);
int main(void) {
pthread_t thread; //the thread
pthread_create(&thread,NULL,th_func,NULL);
pthread_join(thread,NULL);
return 0;
}
void *th_func(void * arg)
{
//we can set one or more bits here, each one representing a single CPU
cpu_set_t cpuset;
//the CPU we whant to use
int cpu = 2;
CPU_ZERO(&cpuset); //clears the cpuset
CPU_SET( cpu , &cpuset); //set CPU 2 on cpuset
/*
* cpu affinity for the calling thread
* first parameter is the pid, 0 = calling thread
* second parameter is the size of your cpuset
* third param is the cpuset in which your thread will be
* placed. Each bit represents a CPU
*/
sched_setaffinity(0, sizeof(cpuset), &cpuset);
while (1);
; //burns the CPU 2
return 0;
}
В среде POSIX вы можете использовать cpusets для управления тем, какие процессоры могут использоваться процессами или pthreads. Этот тип управления называется привязкой к процессору.
Функция 'sched_setaffinity' получает в качестве параметра идентификаторы pthread и процессор. Когда вы используете 0 в первом параметре, это повлияет на вызывающий поток
Пожалуйста, найдите приведенный ниже пример программы для cpu-affinity определенного pthread.
Пожалуйста, добавьте соответствующие библиотеки.
double waste_time(long n)
{
double res = 0;
long i = 0;
while (i <n * 200000) {
i++;
res += sqrt(i);
}
return res;
}
void *thread_func(void *param)
{
unsigned long mask = 1; /* processor 0 */
/* bind process to processor 0 */
if (pthread_setaffinity_np(pthread_self(), sizeof(mask),
&mask) <0) {
perror("pthread_setaffinity_np");
}
/* waste some time so the work is visible with "top" */
printf("result: %f\n", waste_time(2000));
mask = 2; /* process switches to processor 1 now */
if (pthread_setaffinity_np(pthread_self(), sizeof(mask),
&mask) <0) {
perror("pthread_setaffinity_np");
}
/* waste some more time to see the processor switch */
printf("result: %f\n", waste_time(2000));
}
int main(int argc, char *argv[])
{
pthread_t my_thread;
if (pthread_create(&my_thread, NULL, thread_func, NULL) != 0) {
perror("pthread_create");
}
pthread_exit(NULL);
}
Скомпилируйте вышеуказанную программу с флагом -D_GNU_SOURCE.
Планировщик изменит сродство процессора так, как считает нужным; чтобы установить его постоянно, смотрите cpuset в файловой системе / proc.
http://man7.org/linux/man-pages/man7/cpuset.7.html
Или вы можете написать короткую программу, которая устанавливает привязку процессора периодически (каждые несколько секунд) с помощью sched_setaffinity