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
@@ -0,0 +1,202 @@
|
|
1
|
+
#include <assert.h>
|
2
|
+
#include <errno.h>
|
3
|
+
#include <stdio.h>
|
4
|
+
#include <stdlib.h>
|
5
|
+
#include <string.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_memory_stats {
|
15
|
+
size_t malloc_bytes_requested;
|
16
|
+
size_t calloc_bytes_requested;
|
17
|
+
size_t realloc_bytes_requested;
|
18
|
+
|
19
|
+
size_t malloc_bytes_actual;
|
20
|
+
size_t calloc_bytes_actual;
|
21
|
+
size_t realloc_bytes_actual;
|
22
|
+
size_t free_bytes_actual;
|
23
|
+
|
24
|
+
size_t malloc_calls;
|
25
|
+
size_t calloc_calls;
|
26
|
+
size_t realloc_calls;
|
27
|
+
size_t free_calls;
|
28
|
+
};
|
29
|
+
|
30
|
+
static struct tracer tracer;
|
31
|
+
static struct memprof_memory_stats stats;
|
32
|
+
static size_t (*malloc_usable_size)(void *ptr);
|
33
|
+
|
34
|
+
static void *
|
35
|
+
malloc_tramp(size_t size)
|
36
|
+
{
|
37
|
+
void *ret = NULL;
|
38
|
+
int err;
|
39
|
+
|
40
|
+
ret = malloc(size);
|
41
|
+
err = errno;
|
42
|
+
|
43
|
+
stats.malloc_bytes_requested += size;
|
44
|
+
stats.malloc_calls++;
|
45
|
+
|
46
|
+
if (ret)
|
47
|
+
stats.malloc_bytes_actual += malloc_usable_size(ret);
|
48
|
+
|
49
|
+
errno = err;
|
50
|
+
return ret;
|
51
|
+
}
|
52
|
+
|
53
|
+
static void *
|
54
|
+
calloc_tramp(size_t nmemb, size_t size)
|
55
|
+
{
|
56
|
+
void *ret = NULL;
|
57
|
+
int err;
|
58
|
+
|
59
|
+
ret = calloc(nmemb, size);
|
60
|
+
err = errno;
|
61
|
+
|
62
|
+
stats.calloc_bytes_requested += (nmemb * size);
|
63
|
+
stats.calloc_calls++;
|
64
|
+
|
65
|
+
if (ret)
|
66
|
+
stats.calloc_bytes_actual += malloc_usable_size(ret);
|
67
|
+
|
68
|
+
errno = err;
|
69
|
+
return ret;
|
70
|
+
}
|
71
|
+
|
72
|
+
static void *
|
73
|
+
realloc_tramp(void *ptr, size_t size)
|
74
|
+
{
|
75
|
+
void *ret = NULL;
|
76
|
+
int err;
|
77
|
+
|
78
|
+
ret = realloc(ptr, size);
|
79
|
+
err = errno;
|
80
|
+
|
81
|
+
stats.realloc_bytes_requested += size;
|
82
|
+
stats.realloc_calls++;
|
83
|
+
|
84
|
+
if (ret)
|
85
|
+
stats.realloc_bytes_actual += malloc_usable_size(ret);
|
86
|
+
|
87
|
+
errno = err;
|
88
|
+
return ret;
|
89
|
+
}
|
90
|
+
|
91
|
+
static void
|
92
|
+
free_tramp(void *ptr)
|
93
|
+
{
|
94
|
+
if (ptr)
|
95
|
+
stats.free_bytes_actual += malloc_usable_size(ptr);
|
96
|
+
|
97
|
+
stats.free_calls++;
|
98
|
+
|
99
|
+
free(ptr);
|
100
|
+
}
|
101
|
+
|
102
|
+
static void
|
103
|
+
malloc_trace_start()
|
104
|
+
{
|
105
|
+
static int inserted = 0;
|
106
|
+
|
107
|
+
if (!inserted)
|
108
|
+
inserted = 1;
|
109
|
+
else
|
110
|
+
return;
|
111
|
+
|
112
|
+
if (!malloc_usable_size) {
|
113
|
+
malloc_usable_size = bin_find_symbol("MallocExtension_GetAllocatedSize", NULL, 1);
|
114
|
+
if (!malloc_usable_size) {
|
115
|
+
dbg_printf("tcmalloc was not found...\n");
|
116
|
+
malloc_usable_size = bin_find_symbol("malloc_usable_size", NULL, 1);
|
117
|
+
}
|
118
|
+
if (!malloc_usable_size) {
|
119
|
+
dbg_printf("malloc_usable_size was not found...\n");
|
120
|
+
malloc_usable_size = bin_find_symbol("malloc_size", NULL, 1);
|
121
|
+
}
|
122
|
+
assert(malloc_usable_size != NULL);
|
123
|
+
dbg_printf("malloc_usable_size: %p\n", malloc_usable_size);
|
124
|
+
}
|
125
|
+
|
126
|
+
insert_tramp("malloc", malloc_tramp);
|
127
|
+
insert_tramp("realloc", realloc_tramp);
|
128
|
+
insert_tramp("calloc", calloc_tramp);
|
129
|
+
insert_tramp("free", free_tramp);
|
130
|
+
}
|
131
|
+
|
132
|
+
static void
|
133
|
+
malloc_trace_stop()
|
134
|
+
{
|
135
|
+
}
|
136
|
+
|
137
|
+
static void
|
138
|
+
malloc_trace_reset()
|
139
|
+
{
|
140
|
+
memset(&stats, 0, sizeof(stats));
|
141
|
+
}
|
142
|
+
|
143
|
+
static void
|
144
|
+
malloc_trace_dump(json_gen gen)
|
145
|
+
{
|
146
|
+
if (stats.malloc_calls > 0) {
|
147
|
+
json_gen_cstr(gen, "malloc");
|
148
|
+
json_gen_map_open(gen);
|
149
|
+
json_gen_cstr(gen, "calls");
|
150
|
+
json_gen_integer(gen, stats.malloc_calls);
|
151
|
+
json_gen_cstr(gen, "requested");
|
152
|
+
json_gen_integer(gen, stats.malloc_bytes_requested);
|
153
|
+
json_gen_cstr(gen, "actual");
|
154
|
+
json_gen_integer(gen, stats.malloc_bytes_actual);
|
155
|
+
json_gen_map_close(gen);
|
156
|
+
}
|
157
|
+
|
158
|
+
if (stats.realloc_calls > 0) {
|
159
|
+
json_gen_cstr(gen, "realloc");
|
160
|
+
json_gen_map_open(gen);
|
161
|
+
json_gen_cstr(gen, "calls");
|
162
|
+
json_gen_integer(gen, stats.realloc_calls);
|
163
|
+
json_gen_cstr(gen, "requested");
|
164
|
+
json_gen_integer(gen, stats.realloc_bytes_requested);
|
165
|
+
json_gen_cstr(gen, "actual");
|
166
|
+
json_gen_integer(gen, stats.realloc_bytes_actual);
|
167
|
+
json_gen_map_close(gen);
|
168
|
+
}
|
169
|
+
|
170
|
+
if (stats.calloc_calls > 0) {
|
171
|
+
json_gen_cstr(gen, "calloc");
|
172
|
+
json_gen_map_open(gen);
|
173
|
+
json_gen_cstr(gen, "calls");
|
174
|
+
json_gen_integer(gen, stats.calloc_calls);
|
175
|
+
json_gen_cstr(gen, "requested");
|
176
|
+
json_gen_integer(gen, stats.calloc_bytes_requested);
|
177
|
+
json_gen_cstr(gen, "actual");
|
178
|
+
json_gen_integer(gen, stats.calloc_bytes_actual);
|
179
|
+
json_gen_map_close(gen);
|
180
|
+
}
|
181
|
+
|
182
|
+
if (stats.free_calls > 0) {
|
183
|
+
json_gen_cstr(gen, "free");
|
184
|
+
json_gen_map_open(gen);
|
185
|
+
json_gen_cstr(gen, "calls");
|
186
|
+
json_gen_integer(gen, stats.free_calls);
|
187
|
+
json_gen_cstr(gen, "actual");
|
188
|
+
json_gen_integer(gen, stats.free_bytes_actual);
|
189
|
+
json_gen_map_close(gen);
|
190
|
+
}
|
191
|
+
}
|
192
|
+
|
193
|
+
void install_malloc_tracer()
|
194
|
+
{
|
195
|
+
tracer.start = malloc_trace_start;
|
196
|
+
tracer.stop = malloc_trace_stop;
|
197
|
+
tracer.reset = malloc_trace_reset;
|
198
|
+
tracer.dump = malloc_trace_dump;
|
199
|
+
tracer.id = "memory";
|
200
|
+
|
201
|
+
trace_insert(&tracer);
|
202
|
+
}
|
data/ext/tracers/mysql.c
ADDED
@@ -0,0 +1,82 @@
|
|
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_mysql_stats {
|
16
|
+
size_t query_calls;
|
17
|
+
double query_time;
|
18
|
+
};
|
19
|
+
|
20
|
+
static struct tracer tracer;
|
21
|
+
static struct memprof_mysql_stats stats;
|
22
|
+
static int (*orig_real_query)(void *mysql, const char *stmt_str, unsigned long length);
|
23
|
+
|
24
|
+
static int
|
25
|
+
real_query_tramp(void *mysql, const char *stmt_str, unsigned long length) {
|
26
|
+
double secs = 0;
|
27
|
+
int ret;
|
28
|
+
|
29
|
+
secs = timeofday();
|
30
|
+
ret = orig_real_query(mysql, stmt_str, length);
|
31
|
+
secs = timeofday() - secs;
|
32
|
+
|
33
|
+
stats.query_time += secs;
|
34
|
+
stats.query_calls++;
|
35
|
+
|
36
|
+
return ret;
|
37
|
+
}
|
38
|
+
|
39
|
+
static void
|
40
|
+
mysql_trace_start() {
|
41
|
+
static int inserted = 0;
|
42
|
+
|
43
|
+
if (!inserted)
|
44
|
+
inserted = 1;
|
45
|
+
else
|
46
|
+
return;
|
47
|
+
|
48
|
+
orig_real_query = bin_find_symbol("mysql_real_query", NULL, 1);
|
49
|
+
if (orig_real_query)
|
50
|
+
insert_tramp("mysql_real_query", real_query_tramp);
|
51
|
+
}
|
52
|
+
|
53
|
+
static void
|
54
|
+
mysql_trace_stop() {
|
55
|
+
}
|
56
|
+
|
57
|
+
static void
|
58
|
+
mysql_trace_reset() {
|
59
|
+
memset(&stats, 0, sizeof(stats));
|
60
|
+
}
|
61
|
+
|
62
|
+
static void
|
63
|
+
mysql_trace_dump(json_gen gen) {
|
64
|
+
if (stats.query_calls > 0) {
|
65
|
+
json_gen_cstr(gen, "queries");
|
66
|
+
json_gen_integer(gen, stats.query_calls);
|
67
|
+
|
68
|
+
json_gen_cstr(gen, "time");
|
69
|
+
json_gen_double(gen, stats.query_time);
|
70
|
+
}
|
71
|
+
}
|
72
|
+
|
73
|
+
void install_mysql_tracer()
|
74
|
+
{
|
75
|
+
tracer.start = mysql_trace_start;
|
76
|
+
tracer.stop = mysql_trace_stop;
|
77
|
+
tracer.reset = mysql_trace_reset;
|
78
|
+
tracer.dump = mysql_trace_dump;
|
79
|
+
tracer.id = "mysql";
|
80
|
+
|
81
|
+
trace_insert(&tracer);
|
82
|
+
}
|
@@ -0,0 +1,160 @@
|
|
1
|
+
#include <assert.h>
|
2
|
+
#include <stdio.h>
|
3
|
+
#include <stdlib.h>
|
4
|
+
#include <string.h>
|
5
|
+
|
6
|
+
#include "arch.h"
|
7
|
+
#include "bin_api.h"
|
8
|
+
#include "json.h"
|
9
|
+
#include "tracer.h"
|
10
|
+
#include "tramp.h"
|
11
|
+
#include "util.h"
|
12
|
+
#include "ruby.h"
|
13
|
+
|
14
|
+
struct memprof_objects_stats {
|
15
|
+
size_t newobj_calls;
|
16
|
+
size_t types[T_MASK+1];
|
17
|
+
};
|
18
|
+
|
19
|
+
static struct tracer tracer;
|
20
|
+
static struct memprof_objects_stats stats;
|
21
|
+
static VALUE (*orig_rb_newobj)();
|
22
|
+
|
23
|
+
static VALUE last_obj = 0;
|
24
|
+
static VALUE gc_hook = 0;
|
25
|
+
|
26
|
+
static void
|
27
|
+
record_last_obj()
|
28
|
+
{
|
29
|
+
if (last_obj) {
|
30
|
+
stats.types[BUILTIN_TYPE(last_obj)]++;
|
31
|
+
last_obj = 0;
|
32
|
+
}
|
33
|
+
}
|
34
|
+
|
35
|
+
static VALUE
|
36
|
+
objects_tramp() {
|
37
|
+
record_last_obj();
|
38
|
+
stats.newobj_calls++;
|
39
|
+
last_obj = orig_rb_newobj();
|
40
|
+
return last_obj;
|
41
|
+
}
|
42
|
+
|
43
|
+
static void
|
44
|
+
objects_trace_start() {
|
45
|
+
static int inserted = 0;
|
46
|
+
|
47
|
+
if (!inserted)
|
48
|
+
inserted = 1;
|
49
|
+
else
|
50
|
+
return;
|
51
|
+
|
52
|
+
orig_rb_newobj = bin_find_symbol("rb_newobj", NULL, 0);
|
53
|
+
assert(orig_rb_newobj != NULL);
|
54
|
+
dbg_printf("orig_rb_newobj: %p\n", orig_rb_newobj);
|
55
|
+
|
56
|
+
insert_tramp("rb_newobj", objects_tramp);
|
57
|
+
}
|
58
|
+
|
59
|
+
static void
|
60
|
+
objects_trace_stop() {
|
61
|
+
}
|
62
|
+
|
63
|
+
static void
|
64
|
+
objects_trace_reset() {
|
65
|
+
memset(&stats, 0, sizeof(stats));
|
66
|
+
last_obj = 0;
|
67
|
+
}
|
68
|
+
|
69
|
+
static inline char*
|
70
|
+
type_string(int type) {
|
71
|
+
switch (type) {
|
72
|
+
case T_NONE:
|
73
|
+
return "none";
|
74
|
+
case T_NIL:
|
75
|
+
return "nil";
|
76
|
+
case T_OBJECT:
|
77
|
+
return "object";
|
78
|
+
case T_CLASS:
|
79
|
+
return "class";
|
80
|
+
case T_ICLASS:
|
81
|
+
return "iclass";
|
82
|
+
case T_MODULE:
|
83
|
+
return "module";
|
84
|
+
case T_FLOAT:
|
85
|
+
return "float";
|
86
|
+
case T_STRING:
|
87
|
+
return "string";
|
88
|
+
case T_REGEXP:
|
89
|
+
return "regexp";
|
90
|
+
case T_ARRAY:
|
91
|
+
return "array";
|
92
|
+
case T_FIXNUM:
|
93
|
+
return "fixnum";
|
94
|
+
case T_HASH:
|
95
|
+
return "hash";
|
96
|
+
case T_STRUCT:
|
97
|
+
return "struct";
|
98
|
+
case T_BIGNUM:
|
99
|
+
return "bignum";
|
100
|
+
case T_FILE:
|
101
|
+
return "file";
|
102
|
+
case T_TRUE:
|
103
|
+
return "true";
|
104
|
+
case T_FALSE:
|
105
|
+
return "false";
|
106
|
+
case T_DATA:
|
107
|
+
return "data";
|
108
|
+
case T_MATCH:
|
109
|
+
return "match";
|
110
|
+
case T_SYMBOL:
|
111
|
+
return "symbol";
|
112
|
+
case T_BLKTAG:
|
113
|
+
return "blktag";
|
114
|
+
case T_UNDEF:
|
115
|
+
return "undef";
|
116
|
+
case T_VARMAP:
|
117
|
+
return "varmap";
|
118
|
+
case T_SCOPE:
|
119
|
+
return "scope";
|
120
|
+
case T_NODE:
|
121
|
+
return "node";
|
122
|
+
default:
|
123
|
+
return "unknown";
|
124
|
+
}
|
125
|
+
}
|
126
|
+
|
127
|
+
static void
|
128
|
+
objects_trace_dump(json_gen gen) {
|
129
|
+
int i;
|
130
|
+
record_last_obj();
|
131
|
+
|
132
|
+
json_gen_cstr(gen, "created");
|
133
|
+
json_gen_integer(gen, stats.newobj_calls);
|
134
|
+
|
135
|
+
json_gen_cstr(gen, "types");
|
136
|
+
json_gen_map_open(gen);
|
137
|
+
for (i=0; i<T_MASK+1; i++) {
|
138
|
+
if (stats.types[i] > 0) {
|
139
|
+
json_gen_cstr(gen, type_string(i));
|
140
|
+
json_gen_integer(gen, stats.types[i]);
|
141
|
+
}
|
142
|
+
}
|
143
|
+
json_gen_map_close(gen);
|
144
|
+
}
|
145
|
+
|
146
|
+
void install_objects_tracer()
|
147
|
+
{
|
148
|
+
if (!gc_hook) {
|
149
|
+
gc_hook = Data_Wrap_Struct(rb_cObject, record_last_obj, NULL, NULL);
|
150
|
+
rb_global_variable(&gc_hook);
|
151
|
+
}
|
152
|
+
|
153
|
+
tracer.start = objects_trace_start;
|
154
|
+
tracer.stop = objects_trace_stop;
|
155
|
+
tracer.reset = objects_trace_reset;
|
156
|
+
tracer.dump = objects_trace_dump;
|
157
|
+
tracer.id = "objects";
|
158
|
+
|
159
|
+
trace_insert(&tracer);
|
160
|
+
}
|
data/ext/tramp.c
CHANGED
@@ -107,7 +107,7 @@ hook_freelist(int entry, void *tramp)
|
|
107
107
|
}
|
108
108
|
|
109
109
|
/* if we've looked at all the bytes in this function... */
|
110
|
-
if (((void *)byte - freelist_inliners[i]) >= sizes[i]) {
|
110
|
+
if ((size_t)((void *)byte - freelist_inliners[i]) >= sizes[i]) {
|
111
111
|
/* move on to the next function */
|
112
112
|
i++;
|
113
113
|
byte = freelist_inliners[i];
|
@@ -123,7 +123,7 @@ hook_freelist(int entry, void *tramp)
|
|
123
123
|
void
|
124
124
|
insert_tramp(const char *trampee, void *tramp)
|
125
125
|
{
|
126
|
-
void *trampee_addr = bin_find_symbol(trampee, NULL,
|
126
|
+
void *trampee_addr = bin_find_symbol(trampee, NULL, 1);
|
127
127
|
int inline_ent = inline_tramp_size;
|
128
128
|
|
129
129
|
if (trampee_addr == NULL) {
|