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.
@@ -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__ */
@@ -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->dump();
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
+ }
@@ -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
@@ -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
+ }
@@ -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
+ }