HOWTO: using gprof with multithreaded applications

原文地址: http://sam.zoy.org/writings/programming/gprof.html 

 

HOWTO: using gprof with multithreaded applications

What is gprof?

gprof is the GNU Profiler, a tool used when tracking which functions are eating CPU in your program. Anyway, you should already be familiar with it if you got interested in this page.

One problem with gprof under certain kernels (such as Linux) is that it doesn’t behave correctly with multithreaded applications. It actually only profiles the main thread, which is quite useless.

Workaround

There is an easy, but surprisingly not very widespread fix for this annoying gprof behaviour. Basically, gprof uses the internal ITIMER_PROF timer which makes the kernel deliver a signal to the application whenever it expires. So we just need to pass this timer data to all spawned threads.

Example

It wouldn’t be too hard to put a call to setitimer in each function spawned by a thread, but I thought it would be more elegant to implement a wrapper forpthread_create.

Daniel Jönsson enhanced my code so that it could be used in a preload library without having to modify the program. It can also be very useful for libraries that spawn threads without warning, such as libSDL. The result code is shown below and can be downloaded (gprof-helper.c):

/* gprof-helper.c -- preload library to profile pthread-enabled programs
 *
 * Authors: Sam Hocevar <sam at zoy dot org>
 *          Daniel Jönsson <danieljo at fagotten dot org>
 *
 *  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 <sys/time.h>
#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>
#include <pthread.h>

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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
gprof是GCC编译器套件中包含的一个性能分析工具,它通过统计程序中各个函数的调用次数和执行时间来帮助开发者优化代码。下面将详细介绍gprof的下载与安装过程: 1. **检查GCC安装**: - 由于gprof是GCC编译器的一部分,确保你的系统中已经安装了GCC。在终端输入 `gcc --version` 或 `g++ --version` 来检查GCC是否已安装以及其版本信息。 2. **安装GCC**: - 如果你的系统中尚未安装GCC,可通过系统的包管理器进行安装。对于基于Debian的系统(如Ubuntu),可以使用命令 `sudo apt-get install build-essential` 来安装。对于基于RHEL的系统(如CentOS),使用命令 `sudo yum groupinstall "Development Tools"`。 3. **验证gprof安装**: - 安装完GCC后,可使用命令 `gprof --version` 来检查gprof是否随之安装。如果命令返回版本信息,则表示gprof已正确安装。 4. **编译程序时启用gprof**: - 在编译需要分析的程序时,需要在编译命令中加入 `-pg` 选项,例如 `gcc -pg -o myprogram myprogram.c`。这样做会在编译的程序中插入特殊的标记,用于后续的性能分析。 5. **运行程序并生成分析数据**: - 运行编译后的程序,它将在执行过程中生成性能数据文件,通常是以 `gmon.out` 命名的。 6. **使用gprof分析数据**: - 使用命令 `gprof myprogram gmon.out > analysis.txt` 对程序的性能数据进行分析,并将结果输出到 `analysis.txt` 文件中。 7. **查看分析结果**: - 打开 `analysis.txt` 文件,查看各个函数的调用次数、执行时间等性能指标,以便识别程序中的性能瓶颈。 8. **根据分析结果进行优化**: - 根据gprof提供的分析结果,定位到程序中执行效率较低的部分,进行相应的代码优化。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值