-
Notifications
You must be signed in to change notification settings - Fork 204
/
ngx_google_perftools_module.c
145 lines (110 loc) · 3.67 KB
/
ngx_google_perftools_module.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
// annotated by chrono since 2016
//
// sudo apt-get install google-perftools
// ./configure --with-google_perftools_module
// google_perftools_profiles /tmp/ngx.perf;
// pprof --pdf /usr/local/nginx/sbin/nginx ./ngx.perf.17449 > a.pdf
/*
* Copyright (C) Igor Sysoev
* Copyright (C) Nginx, Inc.
*/
#include <ngx_config.h>
#include <ngx_core.h>
/*
* declare Profiler interface here because
* <google/profiler.h> is C++ header file
*/
int ProfilerStart(u_char* fname);
void ProfilerStop(void);
void ProfilerRegisterThread(void);
static void *ngx_google_perftools_create_conf(ngx_cycle_t *cycle);
static ngx_int_t ngx_google_perftools_worker(ngx_cycle_t *cycle);
// 配置结构体,存储profile的文件名
typedef struct {
ngx_str_t profiles;
} ngx_google_perftools_conf_t;
// 在配置文件里配置
// 例如:google_perftools_profiles /tmp/ngx.perf;
static ngx_command_t ngx_google_perftools_commands[] = {
{ ngx_string("google_perftools_profiles"),
NGX_MAIN_CONF|NGX_DIRECT_CONF|NGX_CONF_TAKE1,
ngx_conf_set_str_slot,
0,
offsetof(ngx_google_perftools_conf_t, profiles),
NULL },
ngx_null_command
};
static ngx_core_module_t ngx_google_perftools_module_ctx = {
ngx_string("google_perftools"),
ngx_google_perftools_create_conf,
NULL
};
ngx_module_t ngx_google_perftools_module = {
NGX_MODULE_V1,
&ngx_google_perftools_module_ctx, /* module context */
ngx_google_perftools_commands, /* module directives */
NGX_CORE_MODULE, /* module type */
NULL, /* init master */
NULL, /* init module */
ngx_google_perftools_worker, /* init process */
NULL, /* init thread */
NULL, /* exit thread */
NULL, /* exit process */
NULL, /* exit master */
NGX_MODULE_V1_PADDING
};
static void *
ngx_google_perftools_create_conf(ngx_cycle_t *cycle)
{
ngx_google_perftools_conf_t *gptcf;
gptcf = ngx_pcalloc(cycle->pool, sizeof(ngx_google_perftools_conf_t));
if (gptcf == NULL) {
return NULL;
}
/*
* set by ngx_pcalloc()
*
* gptcf->profiles = { 0, NULL };
*/
return gptcf;
}
// worker进程启动时开始profiler
static ngx_int_t
ngx_google_perftools_worker(ngx_cycle_t *cycle)
{
u_char *profile;
ngx_google_perftools_conf_t *gptcf;
// 取配置
gptcf = (ngx_google_perftools_conf_t *)
ngx_get_conf(cycle->conf_ctx, ngx_google_perftools_module);
// 没有文件名则不会profiler
if (gptcf->profiles.len == 0) {
return NGX_OK;
}
// 真正的文件名需要加上进程号
// 分配一个临时的内存
profile = ngx_alloc(gptcf->profiles.len + NGX_INT_T_LEN + 2, cycle->log);
if (profile == NULL) {
return NGX_OK;
}
// 避免外部的环境变量干扰
if (getenv("CPUPROFILE")) {
/* disable inherited Profiler enabled in master process */
ProfilerStop();
}
// 实际产生的文件名,加进程号
ngx_sprintf(profile, "%V.%d%Z", &gptcf->profiles, ngx_pid);
// 启动profiler
if (ProfilerStart(profile)) {
/* start ITIMER_PROF timer */
// 多线程支持
ProfilerRegisterThread();
} else {
ngx_log_error(NGX_LOG_CRIT, cycle->log, ngx_errno,
"ProfilerStart(%s) failed", profile);
}
// 文件名不再需要,释放
ngx_free(profile);
return NGX_OK;
}
/* ProfilerStop() is called on Profiler destruction */