Как установить привязку к процессору для процесса из C или C ++ в Linux? - PullRequest
34 голосов
/ 11 ноября 2008

Существует ли программный метод для установки соответствия ЦП для процесса в c / c ++ для операционной системы Linux.

Ответы [ 5 ]

47 голосов
/ 11 ноября 2008

Вам нужно использовать sched_setaffinity(2).

Например, для запуска только на процессорах 0 и 2:

#define _GNU_SOURCE
#include <sched.h>

cpu_set_t  mask;
CPU_ZERO(&mask);
CPU_SET(0, &mask);
CPU_SET(2, &mask);
result = sched_setaffinity(0, sizeof(mask), &mask);

(0 для первого параметра означает текущий процесс, укажите PID, если это другой процесс, которым вы хотите управлять).

См. Также sched_getcpu(3).

8 голосов
/ 11 ноября 2008

Используйте sched_setaffinity на уровне процесса или pthread_attr_setaffinity_np для отдельных потоков.

2 голосов
/ 11 ноября 2008

Короче

unsigned long mask = 7; /* processors 0, 1, and 2 */
unsigned int len = sizeof(mask);
if (sched_setaffinity(0, len, &mask) < 0) {
    perror("sched_setaffinity");
}

Подробнее CPU Affinity

1 голос

sched_setaffinity + sched_getaffinity пример минимального запуска C

Этот пример был извлечен из моего ответа по адресу: Как использовать sched_getaffinity и sched_setaffinity в Linux из C? Я считаю, что вопросы не являются дубликатами, поскольку этот вопрос является подмножеством этого, поскольку он спрашивает sched_getaffinity только и не упоминает C ++.

В этом примере мы получаем сходство, изменяем его и проверяем, вступило ли оно в силу с помощью sched_getcpu().

#define _GNU_SOURCE
#include <assert.h>
#include <sched.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

void print_affinity() {
    cpu_set_t mask;
    long nproc, i;

    if (sched_getaffinity(0, sizeof(cpu_set_t), &mask) == -1) {
        perror("sched_getaffinity");
        assert(false);
    } else {
        nproc = sysconf(_SC_NPROCESSORS_ONLN);
        printf("sched_getaffinity = ");
        for (i = 0; i < nproc; i++) {
            printf("%d ", CPU_ISSET(i, &mask));
        }
        printf("\n");
    }
}

int main(void) {
    cpu_set_t mask;

    print_affinity();
    printf("sched_getcpu = %d\n", sched_getcpu());
    CPU_ZERO(&mask);
    CPU_SET(0, &mask);
    if (sched_setaffinity(0, sizeof(cpu_set_t), &mask) == -1) {
        perror("sched_setaffinity");
        assert(false);
    }
    print_affinity();
    /* TODO is it guaranteed to have taken effect already? Always worked on my tests. */
    printf("sched_getcpu = %d\n", sched_getcpu());
    return EXIT_SUCCESS;
}

Скомпилируйте и запустите с:

gcc -std=c99 main.c
./a.out

Пример вывода:

sched_getaffinity = 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 
sched_getcpu = 9
sched_getaffinity = 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
sched_getcpu = 0

Что означает, что:

  • Первоначально все мои 16 ядер были включены, и процесс был запущен случайным образом на ядре 9 (10-е)
  • после того, как мы установили привязку только к первому ядру, процесс обязательно был перемещен в ядро ​​0 (первое)

Также интересно запускать эту программу через taskset:

taskset -c 1,3 ./a.out

, который дает вывод формы:

sched_getaffinity = 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 
sched_getcpu = 2
sched_getaffinity = 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
sched_getcpu = 0

и мы видим, что это ограничивало сродство с самого начала.

Это работает, потому что сходство наследуется дочерними процессами, которые taskset разветвляется: Как предотвратить наследование привязки процессора дочерним разветвленным процессом?

Протестировано в Ubuntu 16.04, GitHub upstream .

1 голос
/ 23 декабря 2016

Я приложил много усилий, чтобы понять, что происходит, поэтому я добавляю этот ответ, чтобы помочь таким людям, как я (я использую gcc компилятор в Linux Mint)

#include <sched.h> 
cpu_set_t  mask;

inline void assignToThisCore(int core_id)
{
    CPU_ZERO(&mask);
    CPU_SET(core_id, &mask);
    sched_setaffinity(0, sizeof(mask), &mask);
}
int main(){
    //cal this:
    assignToThisCore(2);//assign to core 0,1,2,...

    return 0;
}

Но не забудьте добавить следующие опции в команду компилятора: -D _GNU_SOURCE Поскольку операционная система может назначить процесс конкретному ядру, вы можете добавить это GRUB_CMDLINE_LINUX_DEFAULT="quiet splash isolcpus=2,3" в файл grub, расположенный в /etc/default, и запустить sudo update-grub в терминале, чтобы зарезервировать нужные вам ядра

...