/
memcache.c
136 lines (119 loc) · 3.44 KB
/
memcache.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
#include <assert.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/time.h>
#include "arch.h"
#include "bin_api.h"
#include "json.h"
#include "tracer.h"
#include "tramp.h"
#include "util.h"
struct memprof_memcache_stats {
size_t get_calls;
size_t get_responses[45];
size_t set_calls;
size_t set_responses[45];
};
static struct tracer tracer;
static struct memprof_memcache_stats stats;
static const char* (*_memcached_lib_version)(void);
static char* (*_memcached_get)(void *ptr, const char *key, size_t key_length, size_t *value_length, uint32_t *flags, void *error);
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);
static char*
memcached_get_tramp(void *ptr, const char *key, size_t key_length, size_t *value_length, uint32_t *flags, void *error)
{
char* ret = _memcached_get(ptr, key, key_length, value_length, flags, error);
stats.get_calls++;
int err = *(int*)error;
stats.get_responses[err > 42 ? 44 : err]++;
return ret;
}
static int
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)
{
int ret = _memcached_set(ptr, key, key_length, value, value_length, expiration, flags);
stats.set_calls++;
stats.set_responses[ret > 42 ? 44 : ret]++;
return ret;
}
static void
memcache_trace_start() {
static int inserted = 0;
if (!inserted)
inserted = 1;
else
return;
_memcached_lib_version = bin_find_symbol("memcached_lib_version", NULL, 1);
if (_memcached_lib_version) {
const char *version = _memcached_lib_version();
if (strcmp(version, "0.32") == 0) {
_memcached_get = bin_find_symbol("memcached_get", NULL, 1);
insert_tramp("memcached_get", memcached_get_tramp);
_memcached_set = bin_find_symbol("memcached_set", NULL, 1);
insert_tramp("memcached_set", memcached_set_tramp);
}
}
}
static void
memcache_trace_stop() {
}
static void
memcache_trace_reset() {
memset(&stats, 0, sizeof(stats));
}
static void
memcache_trace_dump_results(yajl_gen gen, size_t responses[])
{
int i;
yajl_gen_cstr(gen, "responses");
yajl_gen_map_open(gen);
for (i=0; i < 45; i++) {
if (responses[i]) {
switch (i) {
case 0:
yajl_gen_cstr(gen, "success");
break;
case 16:
yajl_gen_cstr(gen, "notfound");
break;
case 44:
yajl_gen_cstr(gen, "unknown");
break;
default:
yajl_gen_format(gen, "%d", i);
}
yajl_gen_integer(gen, responses[i]);
}
}
yajl_gen_map_close(gen);
}
static void
memcache_trace_dump(yajl_gen gen) {
if (stats.get_calls > 0) {
yajl_gen_cstr(gen, "get");
yajl_gen_map_open(gen);
yajl_gen_cstr(gen, "calls");
yajl_gen_integer(gen, stats.get_calls);
memcache_trace_dump_results(gen, stats.get_responses);
yajl_gen_map_close(gen);
}
if (stats.set_calls > 0) {
yajl_gen_cstr(gen, "set");
yajl_gen_map_open(gen);
yajl_gen_cstr(gen, "calls");
yajl_gen_integer(gen, stats.set_calls);
memcache_trace_dump_results(gen, stats.set_responses);
yajl_gen_map_close(gen);
}
}
void install_memcache_tracer()
{
tracer.start = memcache_trace_start;
tracer.stop = memcache_trace_stop;
tracer.reset = memcache_trace_reset;
tracer.dump = memcache_trace_dump;
tracer.id = "memcache";
trace_insert(&tracer);
}