리눅스 커널 메모리 할당

Posted at 2008/12/03 15:55 // in Programming // by Daniel
커널 메모리 할당

· kmalloc의 실제 동작


· Lookaside Caches


· vmalloc과 관련함수


· Boot-Time Allocation



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

리눅스에서 태스크가 특정 코어에서 동작하게 하기 (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

Direct Disk-to-Disk Copy on Linux

Posted at 2008/09/18 14:57 // in Tips // by Daniel

(해본 것은 아님. 앞으로 하기 위해 남겨두는 자료)

디스크 내용을 그대로 복사할 때.

http://www.linuxplanet.com/linuxplanet/tutorials/986/4/

1. 아래 명령을 쓰면 된다.

# dd if=/dev/hda of=/dev/hdb bs=1024k

if -> 이전 디스크

of -> 새 디스크

그대로 카피한다.

bs -> 블럭 사이즈. (안해봤으니 주의!)

the blocksize, which depends on the disk's cache, but typical figures would be 64k on a small modern IDE to 2048k on a ultrawide SCSI with much larger cache

--> disk 캐시에 관련된다고 한다.

/dev/hda, /dev/sda 등인지는 자기 시스템 맞춰서 볼 것. 다음 명령으로 알 수 있음.

sudo fdisk -l

SATA가 붙은 내 시스템의 경우는 /dev/sda

$ sudo fdisk -l

Disk /dev/sda: 250.0 GB, 250059350016 bytes
255 heads, 63 sectors/track, 30401 cylinders
Units = cylinders of 16065 * 512 = 8225280 bytes
Disk identifier: 0x15e915e8

   Device Boot      Start         End      Blocks   Id  System
/dev/sda1   *           1          24      192748+  83  Linux
/dev/sda2              25       11695    93747307+  83  Linux
/dev/sda3           14840       30401   125001765   83  Linux
/dev/sda4           11696       14839    25254180    5  Extended
/dev/sda5           11696       12181     3903763+  82  Linux swap / Solaris
/dev/sda6           12182       14839    21350353+  83  Linux

Partition table entries are not in disk order

 

2. 일단 리부트해서 깨끗하게 까먹어주고

(아직 디스크 옮겨 달지 말고)

디스크 체크

fsck -y /dev/hdb1

마운트 한 다음

mount /dev/hdb1 /target

/target/etc/hostname, /target/etc/init.d/network 등을 수정해서 세 설정에 맞춰준다.

lilo -v -r /target

lilo로 부팅 설정 제대로 해주고 (grub에서 어떻게 되는 지 모르겠다. 나는 부팅이 안된다면 ubuntu live CD로 부팅시켜 부트로더를 인스톨할 생각)

(부트 섹터는 디스크 앞에 있으니, ( dd if=/dev/hda of=backup.boot bs=512 count=1 같은 명령으로 복사함)

아마 아까 처음에 카피한 것으로 부트로더도 들어가있을 것..)

마지막으로 sync로 써준 내용들이 잘 들어가도록 한다.

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

gcc 컴파일 옵션으로 커스텀 프로파일 해서 실행 트레이스 뽑기

Posted at 2008/09/04 10:36 // in Programming // by Daniel

실행 트레이스 뽑기

  • 이 링크 (원문 IBM) 에 보면 소스에 작은 글루 코드를 컴파일 시 붙여 콜 그래프를 뽑을 수 있다고 나옵니다.(gcc에서 지원하는 트레이스 뽑는 방법). –g 옵션과 -finstrument-functions 로 됨.

사용방법 :
1. Instrument.c
Instrument.c를 만들고 내용에
void main_constructor( void )
void main_deconstructor( void )
void __cyg_profile_func_enter( void *this, void *callsite )
void __cyg_profile_func_exit( void *this, void *callsite )

를 만들어 넣음. (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

trace.txt를 얻어,

image

콜 그래프 생성했습니다.

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

ubuntu 리눅스 커스텀 커널 컴파일 하기

Posted at 2008/08/29 16:30 // in Tips // by Daniel

사용하는 머신의 램이 8기가인데 우분트 웍스테이션의 기본 커널이 4기가까지 지원이라 커널을 새로 빌드해야 할 일이 있었습니다.

여기는 참고한 영문 페이지.

우분투에서 채용된 원래 커널 소스에 그 설정을 가지고 램 설정만 바꿔서 컴파일했습니다.


다음은 하는 방법입니다.

1. 커널 소스 구하기

우분투는 데비안 계열이니 바로 소스 설치 가능합니다.

그리고 커널은 특별히 소스 패키지 이름이 따로 있습니다.

$ sudo apt-get install linux-source

그러면 /usr/src 아래에 깔립니다.

image


2. 커널 개발용 패키지 설치

개발용 패키지를 미리 다 받아둔다기 보단 필요한 패키지가 있다고 에러 메시지가 나므로, 그 때 설치했습니다.

예를 들어,

$ sudo apt-get install kernel-package libncurses5-dev fakeroot wget bzip2 kernel-wedge xmlto


3. configuration 복사해오기

이제 지금 돌고 있는 커널의 소스를 받았으니 configuration을 복사해 와야겠지요

이제부턴 편의를 위해 루트로 작업하겠습니다.

$ sudo su

# cp /boot/config-2.6.24-19-generic linux-2.4.24/config_old

(이건 현재 커널의 config을 카피해오는 겁니다. 요새 배포판들은 이 파일을 /boot 아래에 남겨두더군요 기특하게)

4. make menuconfig (-> configuration)

# make menuconfig

그리고 Load an Alternate Configuration File를 선택해서 config_old를 불러옵니다.

image

그리고 저 같은 경우 여기서 하나만 바꾸면 됩니다.

Processor type and features -> High Memory Support (4GB)

이렇게 돼 있는 걸 64GB로 바꿉니다.

image

그리고 추가로 General setup 에서 Local version - append to kernel release 항목을 고쳐주면 커널의 정보에서 이름이 추가됩니다.

예를 들어 -custom-bigmem 로 써주면 되지요. (실제 제가 할 때는 -를 앞에 빼먹고 custom-bigmem으로 썼습니다. -가 자동으로 붙는 줄 알았어요...)

image

그리고 exit. 저장하고 나옵니다.


5. 컴파일 && deb 패키지 생성

이제 빌드해봅니다.

# make-kpkg clean

# fakeroot make-kpkg  --initrd kernel_image kernel_headers

이렇게 하면 주욱 빌드할 것이고 커널 헤더와 커널 이미지 패키지가 만들어집니다.


6. 새로운 커널 설치

만들어진 패키지를 설치해줍니다.

# dpkg -i linux-image-2.6.24.3custom-bigmem_2.6.24.3-custom-bigmem-10.00.Custom_i386.deb 
# dpkg -i linux-headers-2.6.24.3custom-bigmem_2.6.24.3-custom-bigmem-10.00.Custom_i386.deb


7. 재부팅

일단 /boot/grub/menu.lst 에 부팅 설정이 제대로 써졌는지 보고, (저의 경우 새 커널로 부팅하도록 우선순위가 자동으로 매겨져서 추가돼 있더군요.)

재부팅

# reboot


부팅하고나서 현재 커널이 어떤 건지 확인하려면 uname -a나 /proc/version을 보시면 됩니다.

# uname -a
Linux danwon 2.6.24.3custom-bigmem #1 SMP Tue Aug 26 16:08:04 KST 2008 i686 GNU/Linux

image

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

nload 콘솔에서 네트웍 부하 보기

Posted at 2008/08/26 16:14 // in Tips // by Daniel

nload 라는 프로그램이 있습니다.

image

네트웍 부하를 콘솔에서 볼 수 있습니다.

원격으로 관리할 때 편리하겠네요.

 

관리하는 서버에서 누군가 네트웍을 심하게 쓰는군요. 음. 살펴봐야겠습니다.

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

코드에서 glibc 버전 알아내기

Posted at 2008/08/21 21:19 // in Programming // by Daniel

http://www.technovelty.org/linux/tips/glibc-version.html

실행중에 libc 버전을 봐야 할 경우, contstr을 쓰면 된다고 합니다

#include <stdio.h>

#include <unistd.h>

#include <alloca.h>

#include <string.h>


int main (void)

{

    size_t n = confstr (_CS_GNU_LIBC_VERSION, NULL, 0);

    if (n > 0)

    {

        char *buf = alloca (n);

        confstr (_CS_GNU_LIBC_VERSION, buf, n);

        printf("%s\n", buf);

    }

    return 0;

}

 

실행해 보면
 $ ./a.out
glibc 2.7

이렇게 나옵니다.
또는 돌리는 코드상에서가 아니고 콘솔에서 보고 싶다면 /lib/libc.so.6 파일을 실행해봐도 됩니다.
$ /lib/libc.so.6
GNU C Library stable release version 2.7, by Roland McGrath et al.
Copyright (C) 2007 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.
There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE.
Compiled by GNU CC version 4.2.3 (Ubuntu 4.2.3-2ubuntu7).
Compiled on a Linux >>2.6.24-14-server<< system on 2008-04-04.
Available extensions:
    crypt add-on version 2.1 by Michael Glad and others
    GNU Libidn by Simon Josefsson
    Native POSIX Threads Library by Ulrich Drepper et al
    BIND-8.2.3-T5B
For bug reporting instructions, please see:
<http://www.gnu.org/software/libc/bugs.html>.

그리고 LD_DEBUG를 이용하면 많은 정보를 볼 수 있습니다.

$ LD_DEBUG=help ls
Valid options for the LD_DEBUG environment variable are:

  libs        display library search paths
  reloc       display relocation processing
  files       display progress for input file
  symbols     display symbol table processing
  bindings    display information about symbol binding
  versions    display version dependencies
  all         all previous options combined
  statistics  display relocation statistics
  unused      determined unused DSOs
  help        display this help message and exit

To direct the debugging output into a file instead of standard output
a filename can be specified using the LD_DEBUG_OUTPUT environment variable.


예를 들어 아까의 a.out을 실행하면

$ LD_DEBUG=versions ./a.out
      1565:     checking for version `GLIBC_2.4' in file /lib/tls/i686/cmov/libc.so.6 [0] required by file ./a.out [0]
      1565:     checking for version `GLIBC_2.0' in file /lib/tls/i686/cmov/libc.so.6 [0] required by file ./a.out [0]
      1565:     checking for version `GLIBC_PRIVATE' in file /lib/ld-linux.so.2 [0] required by file /lib/tls/i686/cmov/libc.so.6 [0]
      1565:     checking for version `GLIBC_2.3' in file /lib/ld-linux.so.2 [0] required by file /lib/tls/i686/cmov/libc.so.6 [0]
      1565:     checking for version `GLIBC_2.1' in file /lib/ld-linux.so.2 [0] required by file /lib/tls/i686/cmov/libc.so.6 [0]
      1565:
      1565:     calling init: /lib/tls/i686/cmov/libc.so.6
      1565:
      1565:
      1565:     initialize program: ./a.out
      1565:
      1565:
      1565:     transferring control: ./a.out
      1565:
glibc 2.7
      1565:
      1565:     calling fini: ./a.out [0]
      1565:
      1565:
      1565:     calling fini: /lib/tls/i686/cmov/libc.so.6 [0]
      1565:

이런 식으로 나옵니다.
크리에이티브 커먼즈 라이센스
Creative Commons License

예약한 시각에 명령어 실행하기 - at

Posted at 2008/08/15 01:51 // in Tips // by Daniel

학교가 토요일에 정전된다길래 정전 되기 직전에 리눅스 서버를 꺼줘야겠습니다.

제가 직접 가서 꺼야되는 상황은 만들고 싶지 않기에 예약해서 꺼야겠지요

이럴 때 쓰기 쉬운 명령어, at가 있습니다.


이대로 따라 하면 됩니다.

리눅스에서 컴퓨터 끄기 예약.

지정된 시간에 자동으로 끄려면 at를 사용하면 됩니다.

0. 먼저 시스템 시간을 확인합니다. 시간과 날짜가 맞아야지요.

$ date

2008. 08. 14. (목) 21:38:27 KST

1. 루트로 변경합니다. (끄려면 권한이 있어야 하므로)

daniel@server $su

root@server #

su가 안되는 시스템에서는 sudo su로 사용자를 바꾸실 수 있을 겁니다. 안되면 루트로 로그인하시든지요.

daniel@server $ sudo su

root@server #

2. at으로 시간 입력 & 할 일 입력

root@server # at 8:30am Aug 16

warning: commands will be executed using /bin/sh

at> poweroff (혹시 poweroff가 아니고 다른 명령 – 예를 들어 shutdown –h now – 인지는 알아서 확인)

at> (Ctrl+D입력으로 종료)

job 1 at Thu Aug 16 08:30:00 2008


  • atq로 예약된 명령을 볼 수 있습니다.

root@server # atq

1       Thu Aug 16 08:30:00 2008 a danielsong

  • atrm으로 예약 명령을 취소할 수 있습니다.

root@server # atrm 1


추가 정리하자면,

1. at 명령어로 원하는 시간에 명령을 실행할 수 있다. (명령은 한줄이 아니어도 됨.)

2. 그리고 입력받는  시간 형식은 다양해서 at 4pm + 3 days , at 1am tomorrow 등으로 입력도 가능.

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

ubuntu에서 firewall 설정

Posted at 2008/08/14 23:29 // in Tips // by Daniel

ubuntu linux에는 처음에 기본적으로 firewall을 작동시키지 않습니다.

iptables를 이용한 firewall 셋업은 원래 좀 피곤합니다. 이걸 GUI로 쉽게 해주는 툴이 있으면 좋겠는데요

찾아보면 많아서 뭘 써야할 지 모르는데, 인터넷 검색으로 추천하는 툴을 찾았습니다.

(http://linuxappfinder.com 라는 사이트에서 카테고리별로 브라우즈 할 수 있습니다. 랭크가 나와요)

 

기본 기능만 원한다면 firestarter를,

좀더 자세한 기능을 쓰려면 Guarddog을,

더 강력한 그리고 복잡한 기능을 쓰려면 fwbuilder를 쓰라는군요

 

예전에 iptables를 직접 스크립트를 작성해서 써봤지만 이번엔 간단하게 가고 싶어서 firestart를 썼습니다.

http://useopensource.blogspot.com/2007/03/how-to-setup-firewall-in-ubuntu.html 이쪽 링크에 잘 나옵니다.

설치방법은

$ sudo apt-get install firestarter

이렇게 하면 됩니다.

실행은

$ sudo firestarter

하시면 되구요

처음에 간단한 기능만 물어보는 마법사가 뜨고, Next Next로 설정하고 나면


 

image

이런 모양으로 나옵니다.

Policy 탭에서 열기 원하는 포트와 ip주소를 적어주고, Start Firewall 버튼을 눌러 활성화시키면 됩니다.

image

ps. 참고로 Lock Firewall 버튼은 누르지 마세요. 모든 통신을 끊어버립니다. 원격으로 실행하다가 이걸 누르면 서버 콘솔까지 달려가야 됩니다.

나머지 설명은 여기 링크에서 읽어보세요.

 

나머지 Guarddog, fwbuilder 도 위 링크에서 읽어보시기 바랍니다.

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

데비안 패키지 사용

Posted at 2008/08/14 00:30 // in Tips // by Daniel

필요할 때 까먹어서 찾아야되는 내용들


단순히 패키지 찾고 싶을 때

apt-cache search 관련이름

(예를 들어 apt-cache search "web browser")

이러면 리스트가 쫙 나온다.

패키지의 정보를 프린트할 때

apt-cache show 패키지이름

패키지 이름과 저자, 의존성, 설명 등등 다 나온다.

패키지를 소스로 받아서 컴파일까지 하고 싶을 때(설치는 안하고)

apt-get source -b 패키지 이름


dpkg

설치된 패키지의 정보를 프린트할 때

dpkg-query -s 패키지이름

패키지 이름과 저자, 의존성, 설명 등등 다 나온다.

특정 패턴이 포함된 파일이 어느어느 패키지들에 있는 지 볼 때

dpkg-query -S 패턴

여러 파일들이 쫙 검색되고 어느 패키지에 있는 파일인지 나온다.


패키지가 설치됐는지, 상태가 어떤지 볼 때

dpkg-query -l 패키지이름

정확한 이름 입력해야 함. 설치여부, 이름, 버전, 설명이 나온다.

패키지에 들어있는 파일들이 무엇인지 볼 때

dpkg-query -L 패키지 이름

패키지에 소속된 파일들이 쫙 리스트된다.


데모화면(플래시 동영상)

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