gcc에서만 일단 사용이 가능하지만 한가지 흥미있는 키워드를 발견했다. __builtin_expect 라는 키워드다 다음과 같이 사용할 수 있다.
void* p = malloc(100);
// if (p == NULL) // error();
if (__builtin_expect(p == NULL, 0)) error();
위와 같은 경우는 아주 많이 접할 것이다. 그런데 사실 포인터 p가 NULL인 경우는 잘 없다. 99.99%는 항상 p != NULL가 될 것이다. 이럴 경우 __builtin_expect는 매우 유용하게 사용할 수 있다. 이 키워드는 p == NULL의 값이 *대부분* false가 될 것이 라고 컴파일러에게 알려준다. 그래서 CPU가 좀 더 효율적으로 명령어를 fetch할 수 있도록 한다. 물론 그렇다고해서 프로그램의 정확성, 즉 p가 NULL이면 error가 실행되라는 것까지 해치지는 않는다. 단순히 프로그램의 성능 향상을 위한 키워드이다.
pthread 소스 보면서 찾았네요.
pthread_mutex_lock 소스가 상당히 기네요..
glibc-2.7/nptl/pthread_mutex_lock.c
int __pthread_mutex_lock (mutex) pthread_mutex_t *mutex; { assert (sizeof (mutex->__size) >= sizeof (mutex->__data)); int oldval; pid_t id = THREAD_GETMEM (THREAD_SELF, tid); int retval = 0; switch (__builtin_expect (PTHREAD_MUTEX_TYPE (mutex), PTHREAD_MUTEX_TIMED_NP)) { /* Recursive mutex. */ case PTHREAD_MUTEX_RECURSIVE_NP: /* Check whether we already hold the mutex. */ if (mutex->__data.__owner == id) { /* Just bump the counter. */ if (__builtin_expect (mutex->__data.__count + 1 == 0, 0)) /* Overflow of the counter. */ return EAGAIN; ++mutex->__data.__count; return 0; } /* We have to get the mutex. */ LLL_MUTEX_LOCK (mutex); assert (mutex->__data.__owner == 0); mutex->__data.__count = 1; break; /* Error checking mutex. */ case PTHREAD_MUTEX_ERRORCHECK_NP: /* Check whether we already hold the mutex. */ if (__builtin_expect (mutex->__data.__owner == id, 0)) return EDEADLK; /* FALLTHROUGH */
.......
이게 LinuxThreads와 NPTL의 소스가 다 있어서 한참을 검색했는데
이렇게 하면 나오네요. NPTL을 쓰는군요
$ /lib/libpthread.so.0 Native POSIX Threads Library by Ulrich Drepper et al Copyright (C) 2006 Free Software Foundation, Inc.
데비안에서 소스 받기는
$ dpkg-query -S /lib/libpthread.so.0 libc6: /lib/libpthread.so.0 이렇게 찾고
$ apt-get source libc6 이렇게 받습니다. 압축은 푸셔야 되구요. -b 로 빌드도 같이 되게 할 수 있지만 의존성 때매 실패할겁니다
먼저 커널의 다음 3 파일을 수정하여 새로운 system call을 추가하자. 1. arch/arm/kernel/calls.S 2. include/asm-arm/unistd.h 3. 해당 system call을 구현 할 부분(따로 분리해서 구현해도 상관없고 기존의 아무 소스 파일에나 구현해도 상관없다. 단지 makefile만 잘 수정해준다면)
시스템 콜을 추가하는 하고자 하는데 잘안되네요 시스템 콜 함수까지는 제대로 구현되는 거는 같은데 그것을 test하는 user application이 잘되지 않네요 _syscall2(int, pedagogictime, int, flag, struct timeval *, thetime);
이런식으로 해주고 user application을 작성해서 컴파일 해주면 '__NR_pedagogictime' undeclared라고 나오네요 분명히 include/asm/arch/unistd.h에서 추가해줬는데 말입니다.
그런데 여러 자료를 보니까 include/asm-arm/unistd.h를 변경해준다고 하고 그런데 거기에 include에 가보니까 asm~~이런 것들이 굉장히 많은데 이것들의 차이는 무언가요 제가 맞게 바꾼거는 맞나요??
혹시 arch디렉토리가 없지 않나요? 인텔칩을 사용한다면 include/asm-i386/unistd.h 파일을 수정해주세요. 저 파일에
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]
[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; }
2005년 기사입니다만, 소프트웨어 안정성이 얼마나 중요한지 다시 생각할 수 있는 내용입니다. 저는 원래 기계 신봉자라, (탱크 로켓 이런 걸 엄청 좋아했죠) 기계는 잘못할 수 가 없다는 믿음을 가졌었는데, 원자력 발전소 제어쪽 프로그램을 하다보니, 꼭 그런 건 아니구나 하는 깨달음이 있었습니다. 컴퓨터도 실수를 합니다. 그리고 그보다 수백배 더, 그걸 운용하는 사람과 그걸 만드는 프로그래머가 실수를 합니다. 요즘엔 프로그램이 정말 많이 사용됩니다. 몇년전부터 휴대폰의 소프트웨어 개발비가 하드웨어 개발비를 초과하기 시작한 걸로 알고 있고 전체 비용에서 비율이 기하급수적으로 늘고 있습니다. 그만큼 버그의 위험이, 그리고 그로 인한 재난의 발생 확률이 높아지는 거지요. 일부를 번역해봤습니다.
Last month automaker Toyota announced a recall of 160,000 of its Prius hybrid vehicles following reports of vehicle warning lights illuminating for no reason, and cars' gasoline engines stalling unexpectedly. But unlike the large-scale auto recalls of years past, the root of the Prius issue wasn't a hardware problem -- it was a programming error in the smart car's embedded code. The Prius had a software bug.
지난달(그러니까 2005년)에 16만대를 리콜한 도요타의 프리우스, 엔진이 갑자기 꺼지고 경고등이 이유없이 켜지는 등의 현상이었다. 이번 경우엔 소프트웨어 문제였다. 프리우스가 소프트웨어 버그가 있었던 것이다.
July 28, 1962 -- Mariner I space probe. A bug in the flight software for the Mariner 1 causes the rocket to divert from its intended path on launch. Mission control destroys the rocket over the Atlantic Ocean. The investigation into the accident discovers that a formula written on paper in pencil was improperly transcribed into computer code, causing the computer to miscalculate the rocket's trajectory.
화성탐사선 마리너 1호 얘깁니다. 4분만에 대서양으로 추락.
문제의 원인은 이렇다 저렇다 말이 많다고 하는데, 공통점은 소프트웨어 버그였으며 포트란 코드에서 한 글자를 잘못 써서, 궤도 계산이 지속적으로 발산하는 바람에 일어났고 엄청난 손실을 입었습니다.
1982 -- Soviet gas pipeline. Operatives working for the Central Intelligence Agency allegedly (.pdf) plant a bug in a Canadian computer system purchased to control the trans-Siberian gas pipeline. The Soviets had obtained the system as part of a wide-ranging effort to covertly purchase or steal sensitive U.S. technology. The CIA reportedly found out about the program and decided to make it backfire with equipment that would pass Soviet inspection and then fail once in operation. The resulting event is reportedly the largest non-nuclear explosion in the planet's history.
소련 가스 파이프라인 사고입니다. 이 파이프라인에 캐나다제 제어 시스템을 수입했는데 CIA에서 기술 유출로 단정하고 버그를 심었답니다. 핵폭발 이외의 가장 큰 폭발 사고.
1985-1987 -- Therac-25 medical accelerator. A radiation therapy device malfunctions and delivers lethal radiation doses at several medical facilities. Based upon a previous design, the Therac-25 was an "improved" therapy system that could deliver two different kinds of radiation: either a low-power electron beam (beta particles) or X-rays. The Therac-25's X-rays were generated by smashing high-power electrons into a metal target positioned between the electron gun and the patient. A second "improvement" was the replacement of the older Therac-20's electromechanical safety interlocks with software control, a decision made because software was perceived to be more reliable.
What engineers didn't know was that both the 20 and the 25 were built upon an operating system that had been kludged together by a programmer with no formal training. Because of a subtle bug called a "race condition," a quick-fingered typist could accidentally configure the Therac-25 so the electron beam would fire in high-power mode but with the metal X-ray target out of position. At least five patients die; others are seriously injured
Therac-25 엑스레이 이전의 20 버전에서 25로 업그레이드했는데 안전장치(safety interlock)를 소프트웨어로 교체함. 소프트웨어에 "race condition"(간단히 설명하면 어느쪽이 먼저 했냐에 따라 결과 값이 달라짐) 버그가 있는 걸 몰랐고 결과적으로 대량의 방사선을 누출하는 일이 생겨서 5명이 죽고 많은 사람이 다침.
1988 -- Buffer overflow in Berkeley Unix finger daemon. The first internet worm (the so-called Morris Worm) infects between 2,000 and 6,000 computers in less than a day by taking advantage of a buffer overflow. The specific code is a function in the standard input/output library routine called gets() designed to get a line of text over the network. Unfortunately, gets() has no provision to limit its input, and an overly large input allows the worm to take over any machine to which it can connect.
Programmers respond by attempting to stamp out the gets() function in working code, but they refuse to remove it from the C programming language's standard input/output library, where it remains to this day.
핑거 서비스 프로그램 버그. 그 유명한 버퍼 오버플로우 버그(문자열 버퍼등에 크기보다 더 많은 데이터를 보냄으로써 상대편 프로그램에 코드를 심을 수 있음)를 이용해 첫번째 인터넷 웜이 출현. 이 프로그램을 만든 모리스의 이름을 다서 모리스 웜이라고 불립니다. 당시 인터넷의 10%가 뚫려서 수천대의 서버가 다운되고 수십개 학교, 정부, 연구소가 공격당했습니다.
Posted at 2008/09/09 14:48 //
in Programming //
by Daniel
$* <- 확장자가 없는 현재의 목표 파일(Target)
$@ <- 현재의 목표 파일(Target)
$< <- 현재의 목표 파일(Target)보다 더 최근에 갱신된 파일 이름
$? <- 현재의 목표 파일(Target)보다 더 최근에 갱신된 파일들 이름
main.o : main.c io.h
gcc -c $*.c
$* 는 확장자가 없는 현재의 목표 파일이므로 $* 는 결국 main 에 해당한다.
test : $(OBJS)
gcc -o $@ $*.c
$@는 현재의 목표 파일이다. 즉 test에 해당된다.
.c.o :
gcc -c $< (또는 gcc -c $*.c)
$< 는 현재의 목표 파일보다 더 최근에 갱신된 파일 이름이라고 하였다. .o 파일보다 더 최근에 갱신된 .c 파일은 자동적으로 컴파일이 된다. 가령 main.o를 만들고 난 다음에 main.c를 갱신하게 되면 main.c는 $<의 작용에 의해 새롭게 컴파일이 된다.
를 만들어 넣음. (trace.txt를 열고 닫고, 포인터 프린트하는 걸로 충분. 예제 코드 있음.) #include <stdio.h> #include <stdlib.h> 필요. 2. 컴파일 gcc –g -finstrument-functions test.c instrument.c –o test 로 컴파일
3. 실행 이러면 trace.txt가 나옴. 여기엔 들어가고 나온 함수의 주소가 나옴.
4. 심볼 이름 뽑고 정리하기 여기까지만 하고 addr2line으로 함수이름 뽑을 수 있고, 나머지 복잡한 것은 링크 참조. pvtrace라는 프로그램을 컴파일해서 콜 그래프 생성 예제가 있습니다. Thread 정보 보고싶으면, self = pthread_self();으로 쓰레드 아이디 읽어와서 뿌리면 됨.
런타임에 함수 이름 뽑고 싶으면 몇가지 방법이 있을 듯 합니다. libtrace_resolve (func, buf_func, CTRACE_BUF_LEN, NULL, 0); 등을 써서..
심볼 이름 찾는 또다른 방법은 여기 더 설명 나옴. backtrace, backtrace_symbols libbfd 등. 이곳에서는 트레이스 함수를 좀더 많이 정보를 뿌리게 만들었음.
제가 실행해본 예입니다.
해당 방법으로 midori 브라우저(웹킷 기반의 가벼운 브라우저입니다) instrumentation
Makefile.in에서
midori_OBJECTS = $(am_midori_OBJECTS) instrument.$(OBJEXT)
이렇게 고치고
CFLAGS = @CFLAGS@ -finstrument-functions
이렇게 추가.
Makefile.am에서
midori_SOURCES = 에 instrument.c 추가 (이건 별 효과 없는 듯)
$ make clean
$ make
$ ./midori
$ ~/misc/pvtrace/pvtrace midori
$ dot -Tjpg graph.dot -o graph.jpg
그림 확인
$ eog graph.jpg
I was senseless and ignorant; I was a brute beast before you.
Yet I am always with you; you hold me by my right hand.
You guide me with your counsel, and afterward you will take me into glory.
Whom have I in heaven but you?
I only have you in my life
by Daniel
2010/01/29 00:41 [수정/삭제] [답글]
관리자만 볼 수 있는 댓글입니다.
2010/01/29 20:48 [수정/삭제]
헐
야녀