精确得到apache每个页面运行时间,以便优化程序性能

from: http://www.loveopensource.com/?p=34
by linux_prog
Apache提供的logFormat选项中对页面执行时间%T只能精确到秒。
写了个模块,能够精确到毫秒,利用这个模块可以很方便的进行系统的性能诊断,找出有瓶颈的程序,进行优化,有需要的话可以参考。
/*
mod_responseCost for apache2.
Author:Seamus
To compute a HTTP request cost time.
Install:
./bin/apxs -c ./mod_responseCost.c
./bin/apxs -a -i -n responseCost ./mod_responseCost.la

add to logFormat:
\”%{responseCost}n\”
*/

#include  <time.h>
#include <stdlib.h>
#include “apr.h”
#include “apr_lib.h”
#include “apr_strings.h”

#define APR_WANT_STRFUNC
#include “apr_want.h”
#include “httpd.h”
#include “http_config.h”
#include “http_core.h”
#include “http_request.h”
#include “ap_mpm.h”

typedef long long n64_t;
#define NOTE_NAME “responseCost”

n64_t *time_array;
module AP_MODULE_DECLARE_DATA responseCost_module;

static apr_status_t responseCost_cleanup(void *not_used)
{
fprintf(stderr, “pid:%d, exiting…\n”, getpid());
free(time_array);
return OK;
}

static void responseCostInit(apr_pool_t *p, server_rec *s)
{
fprintf(stderr, “pid:%d starting…”, getpid());
    int is_threaded = 0, hard_thread_limit = 0, max_threads = 0;  
    ap_mpm_query(AP_MPMQ_IS_THREADED, &is_threaded);
    if (is_threaded)
    {
        ap_mpm_query(AP_MPMQ_HARD_LIMIT_THREADS, &hard_thread_limit);
        ap_mpm_query(AP_MPMQ_MAX_THREADS, &max_threads);
        max_threads = max_threads < hard_thread_limit ? max_threads : hard_thread_limit;
    }
    else
    {
        max_threads = 1;
    }
time_array = (n64_t *)malloc(sizeof(n64_t)*max_threads);
    apr_pool_cleanup_register(p, (void *)&max_threads, responseCost_cleanup, apr_pool_cleanup_null);
}

static int compute_time(request_rec *r)
{
    int is_threaded = 0, hard_thread_limit = 0, max_threads = 0;  
    ap_mpm_query(AP_MPMQ_IS_THREADED, &is_threaded);
    if (is_threaded)
    {
        ap_mpm_query(AP_MPMQ_HARD_LIMIT_THREADS, &hard_thread_limit);
        ap_mpm_query(AP_MPMQ_MAX_THREADS, &max_threads);
        max_threads = max_threads < hard_thread_limit ? max_threads : hard_thread_limit;
    }
    else
    {
        max_threads = 1;
    }  
    struct timeval t;
gettimeofday(&t, NULL);
    n64_t now_time  = t.tv_sec * 1000000LL + t.tv_usec;
    n64_t cost_time = now_time - time_array[r->connection->id % hard_thread_limit];
    char timechar[256];
    snprintf(timechar, sizeof(timechar), “cost %lld ms”, cost_time/1000);
    apr_table_setn(r->notes, NOTE_NAME, apr_pstrdup(r->pool, timechar));
    return OK;
}

static int record_time(request_rec *r)
{
    int is_threaded = 0, hard_thread_limit = 0, max_threads = 0;  
    ap_mpm_query(AP_MPMQ_IS_THREADED, &is_threaded);
    if (is_threaded)
    {
        ap_mpm_query(AP_MPMQ_HARD_LIMIT_THREADS, &hard_thread_limit);
        ap_mpm_query(AP_MPMQ_MAX_THREADS, &max_threads);
        max_threads = max_threads < hard_thread_limit ? max_threads : hard_thread_limit;
    }
    else
    {
        max_threads = 1;
    }  
    struct timeval t;
gettimeofday(&t, NULL);
    time_array[r->connection->id % hard_thread_limit] = t.tv_sec * 1000000LL + t.tv_usec;
    return OK;
}

static void register_hooks(apr_pool_t *p)
{
    /* init global array */
    ap_hook_child_init(responseCostInit, NULL, NULL, APR_HOOK_MIDDLE);
    /* record begin time */
ap_hook_fixups(record_time, NULL, NULL, APR_HOOK_MIDDLE);
/* set response time */
ap_hook_log_transaction(compute_time, NULL, NULL, APR_HOOK_FIRST);
return;
}

/* module structure */
module AP_MODULE_DECLARE_DATA responseCost_module = {
    STANDARD20_MODULE_STUFF,
    NULL,                        /* dir config creater                    */
    NULL,                        /* dir merger — default is to override */
    NULL,                /* server config                         */
    NULL,                        /* merge server configs                  */
    NULL,                   /* command apr_table_t                   */
    register_hooks           /* register hooks                        */
};