Как использовать sched_getaffinity и sched_setaffinity в Linux из C?

Я пытаюсь:

  • Запуск 16 копий одновременно с закреплением процессора (2 копии на ядро)

  • Запустите 8 копий одновременно с закреплением процессора (2 копии на ядро) и переключением ядра процессора на самое дальнее ядро после выполнения определенной функции, скажем, функции 1.

Проблема, с которой я сталкиваюсь, заключается в том, как выбрать самый дальний процессор.

Некоторые друзья предложили использовать sched_getaffinity и sched_setaffinity, но я считаю, что не нашел хороших примеров.

Ответ 1

Чтобы использовать sched_setaffinity для выполнения текущего процесса на ядре 7, вы делаете это:

cpu_set_t my_set;        /* Define your cpu_set bit mask. */
CPU_ZERO(&my_set);       /* Initialize it all to 0, i.e. no CPUs selected. */
CPU_SET(7, &my_set);     /* set the bit that represents core 7. */
sched_setaffinity(0, sizeof(cpu_set_t), &my_set); /* Set affinity of tihs process to */
                                                  /* the defined mask, i.e. only 7. */

Смотрите http://linux.die.net/man/2/sched_setaffinity и http://www.gnu.org/software/libc/manual/html_node/CPU-Affinity.html для Дополнительная информация.

Ответ 2

Не используйте CPU_SETSIZE в качестве параметра cpusetsize для слияния sched_ [set | get]. Имена вводят в заблуждение, но это неправильно. Макро CPU_SETSIZE - это (цитирование man 3 cpu_set) "значение, большее, чем максимальный номер ЦП, который может быть сохранен в cpu_set_t." Вы должны использовать

sched_setaffinity(0, sizeof(cpu_set_t), &my_set);

вместо.

Ответ 3

Минимальный работоспособный пример

В этом примере мы получаем сходство, модифицируем его и проверяем, вступило ли оно в силу с 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 разветвляется: как предотвратить наследование taskset процессора дочерним разветвленным процессом?

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