FREEDOM. FRIENDS. FEATURES. FIRST.
페도라 한국 사용자 모임

Thread program에 대해 gprof의 사용법

게시판 Tech/Tip Thread program에 대해 gprof의 사용법

  • This topic has 2개 답변, 2명 참여, and was last updated 11 years 전에 by 인베인. This post has been viewed 27 times
  • 만든이
    게시글
  • #12081
    인베인
    참가자
    • 게시글141
    • 댓글379
    • 총합520
    • ★★
    @leemgs

    gcc의 -pg 옵션을 사용하여 컴파일하면 gprof를 통해 함수별 실행 시간을 자세히 살펴 볼수 있다. 방법은 다음과 같이 간단하다.

    $ gcc -pg -o hello hello.c
    $ hello
    $ gprof hello gmon.out

    주의할 점은 컴파일과 링크 옵션 모두에 -pg 가 들어가야만 한다.

    그런데, 리눅스에서 pthread로 사용하여 작성한 프로그램을 gprof 보면 시간 측정이 제대로 되지 않는다. 이럴때엔 아래의 wrapping 함수를 사용하면 제대로된 결과를 얻을수 있다. 사용법은 소스의 주석을 살펴보라.

    물론, 실행 프로그램을 -static 옵션을 사용하여 정적 링크를 했을 경우엔 효과가 없을 것이다.

                               
                   

       

       /* gprof-helper.c -- preload library to profile pthread-enabled programs
       *
       * Authors: Sam Hocevar
       *          Daniel J?nsson
       *
       *  This program is free software; you can redistribute it and/or
       *  modify it under the terms of the Do What The Fuck You Want To
       *  Public License as published by Banlu Kemiyatorn. See
       *  http://sam.zoy.org/projects/COPYING.WTFPL for more details.
       *
       * Compilation example:
       * gcc -shared -fPIC gprof-helper.c -o gprof-helper.so -lpthread -ldl
       *
       * Usage example:
       * LD_PRELOAD=./gprof-helper.so your_program
       */

       #define _GNU_SOURCE
       #include
       #include
       #include
       #include
       #include

       static void * wrapper_routine(void *);

       /* Original pthread function */
       static int (*pthread_create_orig)(pthread_t *__restrict,
                                        __const pthread_attr_t *__restrict,
                                        void *(*)(void *),
                                        void *__restrict) = NULL;

       /* Library initialization function */
       void wooinit(void) __attribute__((constructor));

       void wooinit(void)
       {
          pthread_create_orig = dlsym(RTLD_NEXT, "pthread_create");
          fprintf(stderr, "pthreads: using profiling hooks for gprof\n");
          if(pthread_create_orig == NULL)
          {
              char *error = dlerror();
              if(error == NULL)
              {
                  error = "pthread_create is NULL";
              }
              fprintf(stderr, "%s\n", error);
              exit(EXIT_FAILURE);
          }
       }

       /* Our data structure passed to the wrapper */
       typedef struct wrapper_s
       {
          void * (*start_routine)(void *);
          void * arg;

          pthread_mutex_t lock;
          pthread_cond_t  wait;

          struct itimerval itimer;

       } wrapper_t;

       /* The wrapper function in charge for setting the itimer value */
       static void * wrapper_routine(void * data)
       {
          /* Put user data in thread-local variables */
          void * (*start_routine)(void *) = ((wrapper_t*)data)->start_routine;
          void * arg = ((wrapper_t*)data)->arg;

          /* Set the profile timer value */
          setitimer(ITIMER_PROF, &((wrapper_t*)data)->itimer, NULL);

          /* Tell the calling thread that we don't need its data anymore */
          pthread_mutex_lock(&((wrapper_t*)data)->lock);
          pthread_cond_signal(&((wrapper_t*)data)->wait);
          pthread_mutex_unlock(&((wrapper_t*)data)->lock);

          /* Call the real function */
          return start_routine(arg);
       }

       /* Our wrapper function for the real pthread_create() */
       int pthread_create(pthread_t *__restrict thread,
                         __const pthread_attr_t *__restrict attr,
                         void * (*start_routine)(void *),
                         void *__restrict arg)
       {
          wrapper_t wrapper_data;
          int i_return;

          /* Initialize the wrapper structure */
          wrapper_data.start_routine = start_routine;
          wrapper_data.arg = arg;
          getitimer(ITIMER_PROF, &wrapper_data.itimer);
          pthread_cond_init(&wrapper_data.wait, NULL);
          pthread_mutex_init(&wrapper_data.lock, NULL);
          pthread_mutex_lock(&wrapper_data.lock);

          /* The real pthread_create call */
          i_return = pthread_create_orig(thread,
                                         attr,
                                         &wrapper_routine,
                                         &wrapper_data);

          /* If the thread was successfully spawned, wait for the data
           * to be released */

       

          if(i_return == 0)
          {
              pthread_cond_wait(&wrapper_data.wait, &wrapper_data.lock);
          }

          pthread_mutex_unlock(&wrapper_data.lock);
          pthread_mutex_destroy(&wrapper_data.lock);
          pthread_cond_destroy(&wrapper_data.wait);

          return i_return;
       }

    end of line.

    * 오픈소스는 Open Innovationa & 윈윈전략을 도모할 지언정 절대 공짜(무료)임을 뜻하지 않는다.치

1 답변 글타래를 보이고 있습니다
  • 글쓴이
    답변
    • #12661
      ELem
      참가자
      • 게시글67
      • 댓글672
      • 총합739
      • ★★
      @Bardisch

      pg옵션은 모르고있던 녀석이네요 ㅎㅎ
      좋은거 알아갑니다 ^^

    • #12662
      인베인
      참가자
      참가자
      • 게시글141
      • 댓글379
      • 총합520
      • ★★
      @leemgs

      최근에 이 -pg ( 프로파일링 옵션)  기능을 이용하여 커널소스의 펑션 트레이싱을 할수 있도록 ftrace  피쳐가 바닐라 커널에도 들어왔읍니다.

       

      * 오픈소스는 Open Innovationa & 윈윈전략을 도모할 지언정 절대 공짜(무료)임을 뜻하지 않는다.치

1 답변 글타래를 보이고 있습니다
  • 답변은 로그인 후 가능합니다.