[t:/]$ 지식_

gcc atomic, cpu 제한

2014/07/02

http://www.alexonlinux.com/multithreaded-simple-data-type-access-and-atomic-variables

아토믹 증가 예제코드. 8개 쓰레드에서 정확히 아토믹처리 해준다.

빌드할 때는 GCC 특화 기능이므로 gcc -o atom2 atom2.c -lpthread -D_GNU_SOURCE 와 같이 한다.

내용을 보면 CPU_SET이 있는데… CPU를 타겟팅한다. 보통 커널이 알아서 나눠주는 것 같다.

참조 : http://bookworm.pe.kr/wordpress/2010/04/20/1670/comment-page-1

만약 CPU_SET을 1로 지정하면 어떻게 될까? 더 빠르다.

CPU를 8개 다 쓰기 vs CPU 1개 다 쓰기를 time으로 재면, 13초 vs 4.5초가 나온다.

그러니까 CPU 1개만 쓸 때가 더 빠르다. 여기서 스핀락은 없다.

아래는 예전에 쓴 내용인데 틀렸다. NUMA는 소켓단위 CPU 분할일때만 동작한다고. 아무튼 CPU 단위 L2의 캐시 어긋남 때문인 것 같긴 하다.

이유가 뭘까? 아마도 NUMA 탓일것이다. NUMA에서는 CPU마다 각각 부여된 주소를 갖고 있는 상황이다. 그런데 변수는 한 개고 주인 CPU도 한 개이다. 주인이 아닌 CPU가 해당 메모리에 접근하려면 몇 턴 더 거쳐야한다. 아마도 L2 캐시가 매번 깨질지도 모른다. (정확히는 모르겠다. 잘 모르겠다..)

sched_setaffinity 는 CPU를 타겟팅한다.

__sync_fetch_and_add 는 gcc atomic 기능으로서 크리티컬 섹션 구현하지 않아도 된다. 해당 부분 주석처리하고 그냥 inc로 바꾸면 예상 값이 틀어진다. 동기화가 어긋나기 때문이다.

– fork로 2개 프로세스에서 tmp / mmap 태우고 하니까 3.5초 걸린다.

#define _GNU_SOURCE 1

#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
#include <stdlib.h>
#include <sched.h>
#include <linux/unistd.h>
#include <sys/syscall.h>
#include <errno.h>

#define INC_TO 100000000 // one million...

int global_int = 0;

pid_t gettid( void )
{
    return syscall( __NR_gettid );
}

void *thread_routine( void *arg )
{
    int i;
    int proc_num = (int)(long)arg;
    cpu_set_t set;

    CPU_ZERO( &set );
    CPU_SET( proc_num, &set );
//  CPU_SET( 1, &set );

    if (sched_setaffinity( gettid(), sizeof( cpu_set_t ), &set ))
    {
        perror( "sched_setaffinity" );
        return NULL;
    }

    for (i = 0; i < INC_TO; i++)
    {
//      global_int++;
        __sync_fetch_and_add( &global_int, 1 );
    }

    return NULL;
}

int main()
{
    int procs = 0;
    int i;
    pthread_t *thrs;

    // Getting number of CPUs
    procs = (int)sysconf( _SC_NPROCESSORS_ONLN );
    if (procs < 0)
    {
        perror( "sysconf" );
        return -1;
    }

    thrs = malloc( sizeof( pthread_t ) * procs );
    if (thrs == NULL)
    {
        perror( "malloc" );
        return -1;
    }

    printf( "Starting %d threads...\n", procs );

    for (i = 0; i < procs; i++)
    {
        if (pthread_create( &thrs[i], NULL, thread_routine,
            (void *)(long)i ))
        {
            perror( "pthread_create" );
            procs = i;
            break;
        }
    }

    for (i = 0; i < procs; i++)
        pthread_join( thrs[i], NULL );

    free( thrs );

    printf( "After doing all the math, global_int value is: %d\n",
        global_int );
    printf( "Expected value is: %d\n", INC_TO * procs );

    return 0;
}

https://github.com/dawnsea/codes/blob/master/atom2.c









[t:/] is not "technology - root". dawnsea, rss