memprof 0.3.2 → 0.3.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/bin/memprof +16 -0
- data/ext/elf.c +31 -29
- data/ext/extconf.rb +11 -5
- data/ext/i386.h +2 -2
- data/ext/json.c +53 -0
- data/ext/json.h +48 -0
- data/ext/mach.c +442 -159
- data/ext/memprof.c +565 -459
- data/ext/mmap.h +73 -0
- data/ext/tracer.c +20 -2
- data/ext/tracer.h +14 -1
- data/ext/tracers/fd.c +204 -0
- data/ext/tracers/gc.c +79 -0
- data/ext/tracers/memcache.c +136 -0
- data/ext/tracers/memory.c +202 -0
- data/ext/tracers/mysql.c +82 -0
- data/ext/tracers/objects.c +160 -0
- data/ext/tramp.c +2 -2
- data/ext/util.c +22 -4
- data/ext/util.h +5 -0
- data/ext/x86_gen.c +3 -3
- data/ext/x86_gen.h +0 -13
- data/lib/memprof/tracer.rb +34 -0
- data/memprof.gemspec +1 -1
- data/spec/memprof_spec.rb +12 -4
- data/spec/tracing_spec.rb +135 -0
- metadata +14 -4
- data/ext/tracers/malloc.c +0 -163
data/ext/mmap.h
ADDED
@@ -0,0 +1,73 @@
|
|
1
|
+
/*
|
2
|
+
* Following code taken from http://thebends.googlecode.com/svn/trunk/mach-o/mmap.c
|
3
|
+
* Copyright: Allen Porter <allen@thebends.org>
|
4
|
+
*/
|
5
|
+
#ifndef __MMAP_H__
|
6
|
+
#define __MMAP_H__
|
7
|
+
|
8
|
+
#include <assert.h>
|
9
|
+
#include <errno.h>
|
10
|
+
#include <fcntl.h>
|
11
|
+
#include <mach/vm_param.h>
|
12
|
+
#include <stdlib.h>
|
13
|
+
#include <stdio.h>
|
14
|
+
#include <sys/stat.h>
|
15
|
+
#include <sys/mman.h>
|
16
|
+
#include <unistd.h>
|
17
|
+
|
18
|
+
/*
|
19
|
+
* Simple utililty methods for mmaping files.
|
20
|
+
*/
|
21
|
+
|
22
|
+
struct mmap_info {
|
23
|
+
const char *name; /* filename */
|
24
|
+
int fd; /* file descriptor */
|
25
|
+
size_t data_size; /* size of file */
|
26
|
+
void* data; /* mmap'd writable contents of file */
|
27
|
+
};
|
28
|
+
|
29
|
+
/*
|
30
|
+
* Open a file, memory map its contents, and populate mmap_info. Requires a
|
31
|
+
* filename.
|
32
|
+
*/
|
33
|
+
int mmap_file_open(struct mmap_info *file_info) {
|
34
|
+
assert(file_info != NULL);
|
35
|
+
file_info->fd = open(file_info->name, O_RDONLY);
|
36
|
+
if (file_info->fd < 0) {
|
37
|
+
perror("open");
|
38
|
+
return -1;
|
39
|
+
}
|
40
|
+
struct stat sb;
|
41
|
+
if (fstat(file_info->fd, &sb) < 0) {
|
42
|
+
perror("fstat");
|
43
|
+
return -1;
|
44
|
+
}
|
45
|
+
file_info->data_size = (size_t)sb.st_size;
|
46
|
+
size_t map_size = file_info->data_size;
|
47
|
+
file_info->data = mmap(0, map_size,
|
48
|
+
PROT_READ,
|
49
|
+
MAP_FILE | MAP_SHARED,
|
50
|
+
file_info->fd, /* offset */0);
|
51
|
+
if (file_info->data == MAP_FAILED) {
|
52
|
+
perror("mmap");
|
53
|
+
return -1;
|
54
|
+
}
|
55
|
+
return 0;
|
56
|
+
}
|
57
|
+
|
58
|
+
/*
|
59
|
+
* Unmemory map and close the file in file_info.
|
60
|
+
*/
|
61
|
+
int munmap_file(struct mmap_info *file_info) {
|
62
|
+
if (munmap(file_info->data, file_info->data_size) < 0) {
|
63
|
+
perror("munmap");
|
64
|
+
return -1;
|
65
|
+
}
|
66
|
+
if (close(file_info->fd) < 0) {
|
67
|
+
perror("close");
|
68
|
+
return -1;
|
69
|
+
}
|
70
|
+
return 0;
|
71
|
+
}
|
72
|
+
|
73
|
+
#endif /* __MMAP_H__ */
|
data/ext/tracer.c
CHANGED
@@ -1,10 +1,14 @@
|
|
1
1
|
#include <assert.h>
|
2
|
+
#include <stdio.h>
|
2
3
|
#include <stdlib.h>
|
3
4
|
#include <string.h>
|
4
5
|
|
6
|
+
#include "json.h"
|
5
7
|
#include "tracer.h"
|
6
8
|
#include "util.h"
|
7
9
|
|
10
|
+
static json_gen tracing_json_gen = NULL;
|
11
|
+
|
8
12
|
/*
|
9
13
|
XXX if we ever need a linked list for anything else ever, remove this crap
|
10
14
|
and switch to a generic macro-based linked list implementation
|
@@ -38,7 +42,6 @@ trace_remove(const char *id)
|
|
38
42
|
while (tmp) {
|
39
43
|
if (strcmp(id, tmp->tracer->id) == 0) {
|
40
44
|
tmp->next = tmp->next;
|
41
|
-
free(tmp->tracer->id);
|
42
45
|
free(tmp->tracer);
|
43
46
|
free(tmp);
|
44
47
|
return 0;
|
@@ -64,7 +67,10 @@ do_trace_invoke(struct tracer *trace, trace_fn fn)
|
|
64
67
|
trace->reset();
|
65
68
|
break;
|
66
69
|
case TRACE_DUMP:
|
67
|
-
trace->
|
70
|
+
json_gen_cstr(tracing_json_gen, trace->id);
|
71
|
+
json_gen_map_open(tracing_json_gen);
|
72
|
+
trace->dump(tracing_json_gen);
|
73
|
+
json_gen_map_close(tracing_json_gen);
|
68
74
|
break;
|
69
75
|
default:
|
70
76
|
dbg_printf("invoked a non-existant trace function type: %d", fn);
|
@@ -97,3 +103,15 @@ trace_invoke(const char *id, trace_fn fn)
|
|
97
103
|
}
|
98
104
|
return 0;
|
99
105
|
}
|
106
|
+
|
107
|
+
void
|
108
|
+
trace_set_output(json_gen gen)
|
109
|
+
{
|
110
|
+
tracing_json_gen = gen;
|
111
|
+
}
|
112
|
+
|
113
|
+
json_gen
|
114
|
+
trace_get_output()
|
115
|
+
{
|
116
|
+
return tracing_json_gen;
|
117
|
+
}
|
data/ext/tracer.h
CHANGED
@@ -1,12 +1,14 @@
|
|
1
1
|
#if !defined(__TRACER__H_)
|
2
2
|
#define __TRACER__H_
|
3
3
|
|
4
|
+
#include "json.h"
|
5
|
+
|
4
6
|
struct tracer {
|
5
7
|
char *id;
|
6
8
|
void (*start)();
|
7
9
|
void (*stop)();
|
8
10
|
void (*reset)();
|
9
|
-
void (*dump)();
|
11
|
+
void (*dump)(json_gen);
|
10
12
|
};
|
11
13
|
|
12
14
|
typedef enum {
|
@@ -28,6 +30,17 @@ trace_invoke_all(trace_fn fn);
|
|
28
30
|
int
|
29
31
|
trace_invoke(const char *id, trace_fn fn);
|
30
32
|
|
33
|
+
void
|
34
|
+
trace_set_output(json_gen gen);
|
35
|
+
|
36
|
+
json_gen
|
37
|
+
trace_get_output();
|
38
|
+
|
31
39
|
/* for now, these will live here */
|
32
40
|
extern void install_malloc_tracer();
|
41
|
+
extern void install_gc_tracer();
|
42
|
+
extern void install_fd_tracer();
|
43
|
+
extern void install_mysql_tracer();
|
44
|
+
extern void install_objects_tracer();
|
45
|
+
extern void install_memcache_tracer();
|
33
46
|
#endif
|
data/ext/tracers/fd.c
ADDED
@@ -0,0 +1,204 @@
|
|
1
|
+
#include <assert.h>
|
2
|
+
#include <errno.h>
|
3
|
+
#include <stdio.h>
|
4
|
+
#include <stdlib.h>
|
5
|
+
#include <string.h>
|
6
|
+
#include <sys/select.h>
|
7
|
+
#include <sys/socket.h>
|
8
|
+
#include <sys/time.h>
|
9
|
+
#include <unistd.h>
|
10
|
+
|
11
|
+
#include "arch.h"
|
12
|
+
#include "bin_api.h"
|
13
|
+
#include "json.h"
|
14
|
+
#include "tracer.h"
|
15
|
+
#include "tramp.h"
|
16
|
+
#include "util.h"
|
17
|
+
|
18
|
+
struct memprof_fd_stats {
|
19
|
+
size_t read_calls;
|
20
|
+
double read_time;
|
21
|
+
size_t read_requested_bytes;
|
22
|
+
size_t read_actual_bytes;
|
23
|
+
|
24
|
+
size_t write_calls;
|
25
|
+
double write_time;
|
26
|
+
size_t write_requested_bytes;
|
27
|
+
size_t write_actual_bytes;
|
28
|
+
|
29
|
+
size_t connect_calls;
|
30
|
+
double connect_time;
|
31
|
+
|
32
|
+
size_t select_calls;
|
33
|
+
double select_time;
|
34
|
+
};
|
35
|
+
|
36
|
+
static struct tracer tracer;
|
37
|
+
static struct memprof_fd_stats stats;
|
38
|
+
|
39
|
+
static ssize_t
|
40
|
+
read_tramp(int fildes, void *buf, size_t nbyte) {
|
41
|
+
double secs = 0;
|
42
|
+
int err;
|
43
|
+
ssize_t ret;
|
44
|
+
|
45
|
+
secs = timeofday();
|
46
|
+
ret = read(fildes, buf, nbyte);
|
47
|
+
err = errno;
|
48
|
+
secs = timeofday() - secs;
|
49
|
+
|
50
|
+
stats.read_time += secs;
|
51
|
+
stats.read_calls++;
|
52
|
+
stats.read_requested_bytes += nbyte;
|
53
|
+
if (ret > 0)
|
54
|
+
stats.read_actual_bytes += ret;
|
55
|
+
|
56
|
+
errno = err;
|
57
|
+
return ret;
|
58
|
+
}
|
59
|
+
|
60
|
+
static ssize_t
|
61
|
+
write_tramp(int fildes, const void *buf, size_t nbyte) {
|
62
|
+
double secs = 0;
|
63
|
+
int err;
|
64
|
+
ssize_t ret;
|
65
|
+
|
66
|
+
secs = timeofday();
|
67
|
+
ret = write(fildes, buf, nbyte);
|
68
|
+
err = errno;
|
69
|
+
secs = timeofday() - secs;
|
70
|
+
|
71
|
+
stats.write_time += secs;
|
72
|
+
stats.write_calls++;
|
73
|
+
stats.write_requested_bytes += nbyte;
|
74
|
+
if (ret > 0)
|
75
|
+
stats.write_actual_bytes += ret;
|
76
|
+
|
77
|
+
errno = err;
|
78
|
+
return ret;
|
79
|
+
}
|
80
|
+
|
81
|
+
static int
|
82
|
+
connect_tramp(int socket, const struct sockaddr *address, socklen_t address_len) {
|
83
|
+
double secs = 0;
|
84
|
+
int err, ret;
|
85
|
+
|
86
|
+
secs = timeofday();
|
87
|
+
ret = connect(socket, address, address_len);
|
88
|
+
err = errno;
|
89
|
+
secs = timeofday() - secs;
|
90
|
+
|
91
|
+
stats.connect_time += secs;
|
92
|
+
stats.connect_calls++;
|
93
|
+
|
94
|
+
errno = err;
|
95
|
+
return ret;
|
96
|
+
}
|
97
|
+
|
98
|
+
static int
|
99
|
+
select_tramp(int nfds, fd_set *readfds, fd_set *writefds, fd_set *errorfds, struct timeval *timeout)
|
100
|
+
{
|
101
|
+
double secs = 0;
|
102
|
+
int ret, err;
|
103
|
+
|
104
|
+
secs = timeofday();
|
105
|
+
ret = select(nfds, readfds, writefds, errorfds, timeout);
|
106
|
+
err = errno;
|
107
|
+
secs = timeofday() - secs;
|
108
|
+
|
109
|
+
stats.select_time += secs;
|
110
|
+
stats.select_calls++;
|
111
|
+
|
112
|
+
errno = err;
|
113
|
+
return ret;
|
114
|
+
}
|
115
|
+
|
116
|
+
static void
|
117
|
+
fd_trace_start() {
|
118
|
+
static int inserted = 0;
|
119
|
+
|
120
|
+
if (!inserted)
|
121
|
+
inserted = 1;
|
122
|
+
else
|
123
|
+
return;
|
124
|
+
|
125
|
+
insert_tramp("read", read_tramp);
|
126
|
+
insert_tramp("write", write_tramp);
|
127
|
+
insert_tramp("connect", connect_tramp);
|
128
|
+
#ifdef HAVE_MACH
|
129
|
+
insert_tramp("select$DARWIN_EXTSN", select_tramp);
|
130
|
+
#else
|
131
|
+
insert_tramp("select", select_tramp);
|
132
|
+
#endif
|
133
|
+
}
|
134
|
+
|
135
|
+
static void
|
136
|
+
fd_trace_stop() {
|
137
|
+
}
|
138
|
+
|
139
|
+
static void
|
140
|
+
fd_trace_reset() {
|
141
|
+
memset(&stats, 0, sizeof(stats));
|
142
|
+
}
|
143
|
+
|
144
|
+
static void
|
145
|
+
fd_trace_dump(json_gen gen) {
|
146
|
+
if (stats.read_calls > 0) {
|
147
|
+
json_gen_cstr(gen, "read");
|
148
|
+
json_gen_map_open(gen);
|
149
|
+
json_gen_cstr(gen, "calls");
|
150
|
+
json_gen_integer(gen, stats.read_calls);
|
151
|
+
json_gen_cstr(gen, "time");
|
152
|
+
json_gen_double(gen, stats.read_time);
|
153
|
+
json_gen_cstr(gen, "requested");
|
154
|
+
json_gen_integer(gen, stats.read_requested_bytes);
|
155
|
+
json_gen_cstr(gen, "actual");
|
156
|
+
json_gen_integer(gen, stats.read_actual_bytes);
|
157
|
+
json_gen_map_close(gen);
|
158
|
+
}
|
159
|
+
|
160
|
+
if (stats.write_calls > 0) {
|
161
|
+
json_gen_cstr(gen, "write");
|
162
|
+
json_gen_map_open(gen);
|
163
|
+
json_gen_cstr(gen, "calls");
|
164
|
+
json_gen_integer(gen, stats.write_calls);
|
165
|
+
json_gen_cstr(gen, "time");
|
166
|
+
json_gen_double(gen, stats.write_time);
|
167
|
+
json_gen_cstr(gen, "requested");
|
168
|
+
json_gen_integer(gen, stats.write_requested_bytes);
|
169
|
+
json_gen_cstr(gen, "actual");
|
170
|
+
json_gen_integer(gen, stats.write_actual_bytes);
|
171
|
+
json_gen_map_close(gen);
|
172
|
+
}
|
173
|
+
|
174
|
+
if (stats.connect_calls > 0) {
|
175
|
+
json_gen_cstr(gen, "connect");
|
176
|
+
json_gen_map_open(gen);
|
177
|
+
json_gen_cstr(gen, "calls");
|
178
|
+
json_gen_integer(gen, stats.connect_calls);
|
179
|
+
json_gen_cstr(gen, "time");
|
180
|
+
json_gen_double(gen, stats.connect_time);
|
181
|
+
json_gen_map_close(gen);
|
182
|
+
}
|
183
|
+
|
184
|
+
if (stats.select_calls > 0) {
|
185
|
+
json_gen_cstr(gen, "select");
|
186
|
+
json_gen_map_open(gen);
|
187
|
+
json_gen_cstr(gen, "calls");
|
188
|
+
json_gen_integer(gen, stats.select_calls);
|
189
|
+
json_gen_cstr(gen, "time");
|
190
|
+
json_gen_double(gen, stats.select_time);
|
191
|
+
json_gen_map_close(gen);
|
192
|
+
}
|
193
|
+
}
|
194
|
+
|
195
|
+
void install_fd_tracer()
|
196
|
+
{
|
197
|
+
tracer.start = fd_trace_start;
|
198
|
+
tracer.stop = fd_trace_stop;
|
199
|
+
tracer.reset = fd_trace_reset;
|
200
|
+
tracer.dump = fd_trace_dump;
|
201
|
+
tracer.id = "fd";
|
202
|
+
|
203
|
+
trace_insert(&tracer);
|
204
|
+
}
|
data/ext/tracers/gc.c
ADDED
@@ -0,0 +1,79 @@
|
|
1
|
+
#include <assert.h>
|
2
|
+
#include <stdio.h>
|
3
|
+
#include <stdlib.h>
|
4
|
+
#include <string.h>
|
5
|
+
#include <sys/time.h>
|
6
|
+
|
7
|
+
#include "arch.h"
|
8
|
+
#include "bin_api.h"
|
9
|
+
#include "json.h"
|
10
|
+
#include "tracer.h"
|
11
|
+
#include "tramp.h"
|
12
|
+
#include "util.h"
|
13
|
+
|
14
|
+
struct memprof_gc_stats {
|
15
|
+
size_t gc_calls;
|
16
|
+
double gc_time;
|
17
|
+
};
|
18
|
+
|
19
|
+
static struct tracer tracer;
|
20
|
+
static struct memprof_gc_stats stats;
|
21
|
+
static void (*orig_garbage_collect)();
|
22
|
+
|
23
|
+
static void
|
24
|
+
gc_tramp()
|
25
|
+
{
|
26
|
+
double secs = 0;
|
27
|
+
|
28
|
+
secs = timeofday();
|
29
|
+
orig_garbage_collect();
|
30
|
+
secs = timeofday() - secs;
|
31
|
+
|
32
|
+
stats.gc_time += secs;
|
33
|
+
stats.gc_calls++;
|
34
|
+
}
|
35
|
+
|
36
|
+
static void
|
37
|
+
gc_trace_start() {
|
38
|
+
static int inserted = 0;
|
39
|
+
|
40
|
+
if (!inserted)
|
41
|
+
inserted = 1;
|
42
|
+
else
|
43
|
+
return;
|
44
|
+
|
45
|
+
orig_garbage_collect = bin_find_symbol("garbage_collect", NULL, 0);
|
46
|
+
assert(orig_garbage_collect != NULL);
|
47
|
+
dbg_printf("orig_garbage_collect: %p\n", orig_garbage_collect);
|
48
|
+
|
49
|
+
insert_tramp("garbage_collect", gc_tramp);
|
50
|
+
}
|
51
|
+
|
52
|
+
static void
|
53
|
+
gc_trace_stop() {
|
54
|
+
}
|
55
|
+
|
56
|
+
static void
|
57
|
+
gc_trace_reset() {
|
58
|
+
memset(&stats, 0, sizeof(stats));
|
59
|
+
}
|
60
|
+
|
61
|
+
static void
|
62
|
+
gc_trace_dump(json_gen gen) {
|
63
|
+
json_gen_cstr(gen, "calls");
|
64
|
+
json_gen_integer(gen, stats.gc_calls);
|
65
|
+
|
66
|
+
json_gen_cstr(gen, "time");
|
67
|
+
json_gen_double(gen, stats.gc_time);
|
68
|
+
}
|
69
|
+
|
70
|
+
void install_gc_tracer()
|
71
|
+
{
|
72
|
+
tracer.start = gc_trace_start;
|
73
|
+
tracer.stop = gc_trace_stop;
|
74
|
+
tracer.reset = gc_trace_reset;
|
75
|
+
tracer.dump = gc_trace_dump;
|
76
|
+
tracer.id = "gc";
|
77
|
+
|
78
|
+
trace_insert(&tracer);
|
79
|
+
}
|
@@ -0,0 +1,136 @@
|
|
1
|
+
#include <assert.h>
|
2
|
+
#include <errno.h>
|
3
|
+
#include <stdio.h>
|
4
|
+
#include <stdlib.h>
|
5
|
+
#include <string.h>
|
6
|
+
#include <sys/time.h>
|
7
|
+
|
8
|
+
#include "arch.h"
|
9
|
+
#include "bin_api.h"
|
10
|
+
#include "json.h"
|
11
|
+
#include "tracer.h"
|
12
|
+
#include "tramp.h"
|
13
|
+
#include "util.h"
|
14
|
+
|
15
|
+
struct memprof_memcache_stats {
|
16
|
+
size_t get_calls;
|
17
|
+
size_t get_responses[45];
|
18
|
+
|
19
|
+
size_t set_calls;
|
20
|
+
size_t set_responses[45];
|
21
|
+
};
|
22
|
+
|
23
|
+
static struct tracer tracer;
|
24
|
+
static struct memprof_memcache_stats stats;
|
25
|
+
static const char* (*_memcached_lib_version)(void);
|
26
|
+
static char* (*_memcached_get)(void *ptr, const char *key, size_t key_length, size_t *value_length, uint32_t *flags, void *error);
|
27
|
+
static int (*_memcached_set)(void *ptr, const char *key, size_t key_length, const char *value, size_t value_length, time_t expiration, uint32_t flags);
|
28
|
+
|
29
|
+
static char*
|
30
|
+
memcached_get_tramp(void *ptr, const char *key, size_t key_length, size_t *value_length, uint32_t *flags, void *error)
|
31
|
+
{
|
32
|
+
char* ret = _memcached_get(ptr, key, key_length, value_length, flags, error);
|
33
|
+
stats.get_calls++;
|
34
|
+
int err = *(int*)error;
|
35
|
+
stats.get_responses[err > 42 ? 44 : err]++;
|
36
|
+
return ret;
|
37
|
+
}
|
38
|
+
|
39
|
+
static int
|
40
|
+
memcached_set_tramp(void *ptr, const char *key, size_t key_length, const char *value, size_t value_length, time_t expiration, uint32_t flags)
|
41
|
+
{
|
42
|
+
int ret = _memcached_set(ptr, key, key_length, value, value_length, expiration, flags);
|
43
|
+
stats.set_calls++;
|
44
|
+
stats.set_responses[ret > 42 ? 44 : ret]++;
|
45
|
+
return ret;
|
46
|
+
}
|
47
|
+
|
48
|
+
static void
|
49
|
+
memcache_trace_start() {
|
50
|
+
static int inserted = 0;
|
51
|
+
|
52
|
+
if (!inserted)
|
53
|
+
inserted = 1;
|
54
|
+
else
|
55
|
+
return;
|
56
|
+
|
57
|
+
_memcached_lib_version = bin_find_symbol("memcached_lib_version", NULL, 1);
|
58
|
+
if (_memcached_lib_version) {
|
59
|
+
const char *version = _memcached_lib_version();
|
60
|
+
if (strcmp(version, "0.32") == 0) {
|
61
|
+
_memcached_get = bin_find_symbol("memcached_get", NULL, 1);
|
62
|
+
insert_tramp("memcached_get", memcached_get_tramp);
|
63
|
+
|
64
|
+
_memcached_set = bin_find_symbol("memcached_set", NULL, 1);
|
65
|
+
insert_tramp("memcached_set", memcached_set_tramp);
|
66
|
+
}
|
67
|
+
}
|
68
|
+
}
|
69
|
+
|
70
|
+
static void
|
71
|
+
memcache_trace_stop() {
|
72
|
+
}
|
73
|
+
|
74
|
+
static void
|
75
|
+
memcache_trace_reset() {
|
76
|
+
memset(&stats, 0, sizeof(stats));
|
77
|
+
}
|
78
|
+
|
79
|
+
static void
|
80
|
+
memcache_trace_dump_results(json_gen gen, size_t responses[])
|
81
|
+
{
|
82
|
+
int i;
|
83
|
+
json_gen_cstr(gen, "responses");
|
84
|
+
json_gen_map_open(gen);
|
85
|
+
for (i=0; i < 45; i++) {
|
86
|
+
if (responses[i]) {
|
87
|
+
switch (i) {
|
88
|
+
case 0:
|
89
|
+
json_gen_cstr(gen, "success");
|
90
|
+
break;
|
91
|
+
case 16:
|
92
|
+
json_gen_cstr(gen, "notfound");
|
93
|
+
break;
|
94
|
+
case 44:
|
95
|
+
json_gen_cstr(gen, "unknown");
|
96
|
+
break;
|
97
|
+
default:
|
98
|
+
json_gen_format(gen, "%d", i);
|
99
|
+
}
|
100
|
+
json_gen_integer(gen, responses[i]);
|
101
|
+
}
|
102
|
+
}
|
103
|
+
json_gen_map_close(gen);
|
104
|
+
}
|
105
|
+
|
106
|
+
static void
|
107
|
+
memcache_trace_dump(json_gen gen) {
|
108
|
+
if (stats.get_calls > 0) {
|
109
|
+
json_gen_cstr(gen, "get");
|
110
|
+
json_gen_map_open(gen);
|
111
|
+
json_gen_cstr(gen, "calls");
|
112
|
+
json_gen_integer(gen, stats.get_calls);
|
113
|
+
memcache_trace_dump_results(gen, stats.get_responses);
|
114
|
+
json_gen_map_close(gen);
|
115
|
+
}
|
116
|
+
|
117
|
+
if (stats.set_calls > 0) {
|
118
|
+
json_gen_cstr(gen, "set");
|
119
|
+
json_gen_map_open(gen);
|
120
|
+
json_gen_cstr(gen, "calls");
|
121
|
+
json_gen_integer(gen, stats.set_calls);
|
122
|
+
memcache_trace_dump_results(gen, stats.set_responses);
|
123
|
+
json_gen_map_close(gen);
|
124
|
+
}
|
125
|
+
}
|
126
|
+
|
127
|
+
void install_memcache_tracer()
|
128
|
+
{
|
129
|
+
tracer.start = memcache_trace_start;
|
130
|
+
tracer.stop = memcache_trace_stop;
|
131
|
+
tracer.reset = memcache_trace_reset;
|
132
|
+
tracer.dump = memcache_trace_dump;
|
133
|
+
tracer.id = "memcache";
|
134
|
+
|
135
|
+
trace_insert(&tracer);
|
136
|
+
}
|