리눅스에서 태스크가 특정 코어에서 동작하게 하기 (affinity 설정)

Posted at 2008/11/27 16:07 // in Programming // by Daniel

커널 2.6부터 지원됩니다.


프로세스는 sched_setaffinity()가 있습니다.

쓰레드는 pthread_setaffinity_np()가 있습니다

커널의 소스에 보면 migration하는 경우에도 cpu affinity를 보고 설정된 CPU가 아니면 하지 않습니다.

그러므로 …_setaffinity()를 호출하면 해당 CPU에 고정되는 것이 맞습니다.

Hotplug시 affinity 설정된 모든 CPU가 꺼진 경우만 예외적으로 affinity를 변경합니다.

[code]
static void sched_migrate_task(task_t *p, int dest_cpu)
{
    migration_req_t req;
    runqueue_t *rq;
    unsigned long flags;

    rq = task_rq_lock(p, &flags);
    if (!cpu_isset(dest_cpu, p->cpus_allowed)
        || unlikely(cpu_is_offline(dest_cpu)))
        goto out;
....
static
int can_migrate_task(task_t *p, runqueue_t *rq, int this_cpu,
             struct sched_domain *sd, enum idle_type idle,
             int *all_pinned)
{
    /*
     * We do not migrate tasks that are:
     * 1) running (obviously), or
     * 2) cannot be migrated to this CPU due to cpus_allowed, or
     * 3) are cache-hot on their current CPU.
     */
    if (!cpu_isset(this_cpu, p->cpus_allowed))
        return 0;
[/code]

아래 코드를 2.6.24, x86, 4코어에서 테스트했습니다.

( http://www.thinkingparallel.com/2006/08 ··· inity%2F 에 나온 코드를 컴파일 되도록 수정 )

[code]
/* Short test program to test the pthread_setaffinity_np
* (which sets the affinity of threads to processors).
* Compile: gcc pthread_setaffinity_np_test.c
*            -o pthread_setaffinity_np_test -lm -lpthread
* Usage: ./pthread_setaffinity_test
*
* Open a "top"-window at the same time and see all the work
* being done on CPU 0 first and after a short wait on CPU 1.
* Repeat with different numbers to make sure, it is not a
* coincidence.
*/
#include <stdio.h>
#include <math.h>
#include <unistd.h>
#define __USE_GNU
#include <pthread.h>
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), (cpu_set_t *)&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 */
    sleep(2);
    if (pthread_setaffinity_np(pthread_self(), sizeof(mask), (cpu_set_t *)&mask) <0) {
        perror("pthread_setaffinity_np");
    }
    /* waste some more time to see the processor switch */
    printf("result: %f\n", waste_time(2000));
    return 0;
}
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);
    pthread_join(my_thread, NULL);
    return 0;
}

[/code]

---------------------------------

프로세스의 경우 소스는 다음과 같습니다.

[code]
/* Short test program to test sched_setaffinity
* (which sets the affinity of processes to processors).
* Compile: gcc sched_setaffinity_test.c
*            -o sched_setaffinity_test -lm
* Usage: ./sched_setaffinity_test
*
* Open a "top"-window at the same time and see all the work
* being done on CPU 0 first and after a short wait on CPU 1.
* Repeat with different numbers to make sure, it is not a
* coincidence.
*/
#include <stdio.h>
#include <math.h>
#include <unistd.h>
#define __USE_GNU
#include <sched.h>
double waste_time(long n)
{
    double res = 0;
    long i = 0;
    while(i <n * 200000) {
        i++;
        res += sqrt (i);
    }
    return res;
}
int main(int argc, char **argv)
{
    unsigned long mask = 1; /* processor 0 */
    /* bind process to processor 0 */
    if (sched_setaffinity(0, sizeof(mask), (cpu_set_t*)&mask) <0) {
        perror("sched_setaffinity");
    }
    /* 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 (sched_setaffinity(0, sizeof(mask), (cpu_set_t*)&mask) <0) {
        perror("sched_setaffinity");
    }
    /* waste some more time to see the processor switch */
    printf ("result: %f\n", waste_time (2000));
    return 0;
}

[/code]

크리에이티브 커먼즈 라이센스
Creative Commons License