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/ext/util.c CHANGED
@@ -1,10 +1,13 @@
1
+ #include <stdlib.h>
2
+ #include <time.h>
3
+ #include <util.h>
4
+
5
+ #include <sys/time.h>
6
+
1
7
  /* This is the CRC function used by GNU. Stripped executables may contain a
2
8
  * section .gnu_debuglink which holds the name of an elf object with debug
3
9
  * information and a checksum.
4
- */
5
- #include <stdlib.h>
6
- #include <util.h>
7
- /* !!!! DO NOT MODIFY THIS FUNCTION !!!!
10
+ * !!!! DO NOT MODIFY THIS FUNCTION !!!!
8
11
  * TODO create specs for this!
9
12
  */
10
13
  unsigned long
@@ -71,3 +74,18 @@ gnu_debuglink_crc32(unsigned long crc, unsigned char *buf, size_t len)
71
74
  crc = crc32_table[(crc ^ *buf) & 0xff] ^ (crc >> 8);
72
75
  return ~crc & 0xffffffff;
73
76
  }
77
+
78
+ double
79
+ timeofday()
80
+ {
81
+ struct timeval tv;
82
+ #ifdef CLOCK_MONOTONIC
83
+ struct timespec tp;
84
+
85
+ if (clock_gettime(CLOCK_MONOTONIC, &tp) == 0) {
86
+ return (double)tp.tv_sec + (double)tp.tv_nsec * 1e-9;
87
+ }
88
+ #endif
89
+ gettimeofday(&tv, NULL);
90
+ return (double)tv.tv_sec + (double)tv.tv_usec * 1e-6;
91
+ }
data/ext/util.h CHANGED
@@ -73,4 +73,9 @@ struct memprof_config {
73
73
  unsigned long
74
74
  gnu_debuglink_crc32 (unsigned long crc, unsigned char *buf, size_t len);
75
75
 
76
+ /* Use this function for time tracking. It will (interally) try to use an
77
+ * appropriately granual timing function.
78
+ */
79
+ double
80
+ timeofday();
76
81
  #endif
@@ -27,14 +27,14 @@ arch_insert_st1_tramp(void *start, void *trampee, void *tramp)
27
27
  assert(tramp != NULL);
28
28
 
29
29
  int32_t fn_addr = 0;
30
+ int32_t offset = 0;
30
31
  struct st1_base *check = start;
31
32
 
32
33
  if (check->call == 0xe8) {
33
34
  fn_addr = check->displacement;
34
35
  if ((trampee - (void *)(check + 1)) == fn_addr) {
35
- WRITE_INSTRUCTIONS(&check->displacement,
36
- sizeof(*check),
37
- (check->displacement = (tramp - (void *)(check + 1))));
36
+ offset = tramp - (void *)(check + 1);
37
+ copy_instructions(&check->displacement, &offset, sizeof(offset));
38
38
  return 0;
39
39
  }
40
40
  }
@@ -75,17 +75,4 @@ copy_instructions(void *dest, void *src, size_t count)
75
75
  */
76
76
  return;
77
77
  }
78
-
79
- /*
80
- * WRITE_INSTRUCTIONS - page align start, recalculate len to take into account
81
- * alignment, set the read/write permissions and execute the code stmt.
82
- */
83
- #define WRITE_INSTRUCTIONS(start, len, stmt) do { \
84
- void *aligned_addr = page_align((void *)start); \
85
- int count = ((void *)start) - aligned_addr + len; \
86
- mprotect(aligned_addr, count, PROT_READ | PROT_WRITE | PROT_EXEC); \
87
- stmt; \
88
- mprotect(aligned_addr, count, PROT_READ | PROT_EXEC); \
89
- } while (0)
90
-
91
78
  #endif
@@ -0,0 +1,34 @@
1
+ begin
2
+ require File.expand_path('../../memprof', __FILE__)
3
+ rescue LoadError
4
+ require File.expand_path('../../../ext/memprof', __FILE__)
5
+ end
6
+
7
+ module Memprof
8
+ # Middleware for tracing requests
9
+ #
10
+ # require 'memprof/tracer'
11
+ # config.middleware.use(Memprof::Tracer)
12
+ class Tracer
13
+ def initialize(app)
14
+ @app=app
15
+ end
16
+ def call(env)
17
+ Memprof.trace_filename ||= "/tmp/memprof_tracer-#{Process.pid}.json"
18
+ Memprof.trace_request(env){ @app.call(env) }
19
+ end
20
+ end
21
+
22
+ # Legacy filter for tracing requests on Rails 2.2
23
+ #
24
+ # require 'memprof/tracer'
25
+ # around_filter(Memprof::Filter)
26
+ module Filter
27
+ def self.filter(controller)
28
+ env = controller.request.env
29
+ info = controller.request.path_parameters
30
+ Memprof.trace_filename ||= "/tmp/memprof_tracer-#{Process.pid}.json"
31
+ Memprof.trace_request(env.merge('action_controller.request.path_parameters' => info)){ yield }
32
+ end
33
+ end
34
+ end
@@ -1,6 +1,6 @@
1
1
  spec = Gem::Specification.new do |s|
2
2
  s.name = 'memprof'
3
- s.version = '0.3.2'
3
+ s.version = '0.3.3'
4
4
  s.date = '2010-04-13'
5
5
  s.summary = 'Ruby Memory Profiler'
6
6
  s.description = "Ruby memory profiler similar to bleak_house, but without patches to the Ruby VM"
@@ -61,10 +61,10 @@ describe Memprof do
61
61
  1.23+1
62
62
  Memprof.dump(filename)
63
63
 
64
- filedata.should =~ /"file": "#{__FILE__}"/
65
- filedata.should =~ /"line": #{__LINE__-4}/
66
- filedata.should =~ /"type": "float"/
67
- filedata.should =~ /"data": 2\.23/
64
+ filedata.should =~ /"file":"#{__FILE__}"/
65
+ filedata.should =~ /"line":#{__LINE__-4}/
66
+ filedata.should =~ /"type":"float"/
67
+ filedata.should =~ /"data":2\.23/
68
68
  end
69
69
 
70
70
  should 'raise error when calling ::stats or ::dump without ::start' do
@@ -72,6 +72,14 @@ describe Memprof do
72
72
  lambda{ Memprof.dump }.should.raise(RuntimeError).message.should =~ /Memprof.start/
73
73
  end
74
74
 
75
+ should 'dump objects created for block' do
76
+ Memprof.dump(filename) do
77
+ 2.45+1
78
+ end
79
+
80
+ filedata.should =~ /"data":3\.45/
81
+ end
82
+
75
83
  should 'dump out the entire heap' do
76
84
  Memprof.stop
77
85
  Memprof.dump_all(filename)
@@ -0,0 +1,135 @@
1
+ require File.dirname(__FILE__) + "/../ext/memprof"
2
+
3
+ require 'rubygems'
4
+ require 'bacon'
5
+ Bacon.summary_on_exit
6
+
7
+ require 'tempfile'
8
+
9
+ # XXX must require upfront before tracers are installed
10
+ require 'socket'
11
+ require 'open-uri'
12
+ begin; require 'mysql'; rescue LoadError; end
13
+ begin; require 'memcached'; rescue LoadError; end
14
+
15
+ describe 'Memprof tracers' do
16
+ @tempfile = Tempfile.new('tracing_spec')
17
+
18
+ def filename
19
+ @tempfile.path
20
+ end
21
+
22
+ def filedata
23
+ File.read(filename)
24
+ end
25
+
26
+ should 'trace i/o for block' do
27
+ Memprof.trace(filename) do
28
+ open("http://google.com").read
29
+ end
30
+
31
+ filedata.should =~ /"read":\{"calls":\d+/
32
+ filedata.should =~ /"write":\{"calls":\d+/
33
+ filedata.should =~ /"connect":\{"calls":\d+/
34
+ end
35
+
36
+ should 'trace select for block' do
37
+ Memprof.trace(filename) do
38
+ select(nil, nil, nil, 0.15)
39
+ end
40
+
41
+ filedata.should =~ /"select":\{"calls":1,"time":0\.1[567]/
42
+ time = filedata[/"select":\{"calls":\d+,"time":([\d.]+)/, 1].to_f
43
+ time.should.be.close(0.15, 0.1)
44
+ end
45
+
46
+ should 'trace objects created for block' do
47
+ Memprof.trace(filename) do
48
+ 10.times{1.1+1.2}
49
+ end
50
+
51
+ filedata.should =~ /"float":10/
52
+ end
53
+
54
+ should 'trace gc runs for block' do
55
+ Memprof.trace(filename) do
56
+ 10.times{GC.start}
57
+ end
58
+
59
+ filedata.should =~ /"gc":\{"calls":10,"time":[\d.]+/
60
+ end
61
+
62
+ should 'trace memory allocation for block' do
63
+ Memprof.trace(filename) do
64
+ 10.times{ "abc" << "def" }
65
+ end
66
+
67
+ filedata.should =~ /"malloc":\{"calls":10/
68
+ filedata.should =~ /"realloc":\{"calls":10/
69
+ end
70
+
71
+ if defined? Mysql
72
+ begin
73
+ conn = Mysql.connect('localhost', 'root')
74
+
75
+ should 'trace mysql calls for block' do
76
+ Memprof.trace(filename) do
77
+ 5.times{ conn.query("select sleep(0.05)") }
78
+ end
79
+
80
+ filedata.should =~ /"mysql":\{"queries":5,"time":([\d.]+)/
81
+ time = filedata[/"mysql":\{"queries":5,"time":([\d.]+)/, 1].to_f
82
+ time.should.be.close(0.25, 0.1)
83
+ end
84
+ rescue Mysql::Error => e
85
+ raise unless e.message =~ /connect/
86
+ end
87
+ end
88
+
89
+ if defined? Memcached
90
+ begin
91
+ conn = Memcached.new("localhost:11211", :show_backtraces => true)
92
+ conn.stats
93
+
94
+ should 'trace memcached calls for block' do
95
+ Memprof.trace(filename) do
96
+ conn.delete("memprof") rescue nil
97
+ conn.get("memprof") rescue nil
98
+ conn.set("memprof", "is cool")
99
+ conn.get("memprof")
100
+ end
101
+
102
+ filedata.should =~ /"memcache":\{"get":\{"calls":2,"responses":\{"success":1,"notfound":1/
103
+ filedata.should =~ /"set":\{"calls":1,"responses":\{"success":1/
104
+ end
105
+ rescue Memcached::SomeErrorsWereReported
106
+ end
107
+ end
108
+ end
109
+
110
+ describe 'Memprof request tracing' do
111
+ @tempfile = Tempfile.new('tracing_spec')
112
+
113
+ def filename
114
+ @tempfile.path
115
+ end
116
+
117
+ def filedata
118
+ File.read(filename)
119
+ end
120
+
121
+ should 'trace request env' do
122
+ env = {"REQUEST_PATH" => "value"}
123
+
124
+ Memprof.trace_filename = filename
125
+ Memprof.trace_filename.should == filename
126
+
127
+ Memprof.trace_request(env) do
128
+ end
129
+
130
+ Memprof.trace_filename = nil
131
+ Memprof.trace_filename.should.be.nil
132
+
133
+ filedata.should =~ /"REQUEST_PATH":"value"/
134
+ end
135
+ end
metadata CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
5
5
  segments:
6
6
  - 0
7
7
  - 3
8
- - 2
9
- version: 0.3.2
8
+ - 3
9
+ version: 0.3.3
10
10
  platform: ruby
11
11
  authors:
12
12
  - Joe Damato
@@ -17,7 +17,7 @@ autorequire:
17
17
  bindir: bin
18
18
  cert_chain: []
19
19
 
20
- date: 2010-04-13 00:00:00 -04:00
20
+ date: 2010-04-13 00:00:00 -07:00
21
21
  default_executable:
22
22
  dependencies:
23
23
  - !ruby/object:Gem::Dependency
@@ -68,14 +68,22 @@ files:
68
68
  - ext/extconf.rb
69
69
  - ext/i386.c
70
70
  - ext/i386.h
71
+ - ext/json.c
72
+ - ext/json.h
71
73
  - ext/mach.c
72
74
  - ext/memprof.c
75
+ - ext/mmap.h
73
76
  - ext/src/libdwarf-20091118.tar.gz
74
77
  - ext/src/libelf-0.8.13.tar.gz
75
78
  - ext/src/yajl-1.0.9.tar.gz
76
79
  - ext/tracer.c
77
80
  - ext/tracer.h
78
- - ext/tracers/malloc.c
81
+ - ext/tracers/fd.c
82
+ - ext/tracers/gc.c
83
+ - ext/tracers/memcache.c
84
+ - ext/tracers/memory.c
85
+ - ext/tracers/mysql.c
86
+ - ext/tracers/objects.c
79
87
  - ext/tramp.c
80
88
  - ext/tramp.h
81
89
  - ext/util.c
@@ -86,9 +94,11 @@ files:
86
94
  - ext/x86_gen.h
87
95
  - lib/memprof/middleware.rb
88
96
  - lib/memprof/signal.rb
97
+ - lib/memprof/tracer.rb
89
98
  - memprof.gemspec
90
99
  - spec/memprof_spec.rb
91
100
  - spec/memprof_uploader_spec.rb
101
+ - spec/tracing_spec.rb
92
102
  has_rdoc: true
93
103
  homepage: http://github.com/ice799/memprof
94
104
  licenses: []
@@ -1,163 +0,0 @@
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 "tracer.h"
9
- #include "util.h"
10
-
11
- struct memprof_malloc_stats {
12
- size_t malloc_bytes_requested;
13
- size_t calloc_bytes_requested;
14
- size_t realloc_bytes_requested;
15
-
16
- size_t malloc_bytes_actual;
17
- size_t calloc_bytes_actual;
18
- size_t realloc_bytes_actual;
19
- size_t free_bytes_actual;
20
-
21
- size_t malloc_calls;
22
- size_t calloc_calls;
23
- size_t realloc_calls;
24
- size_t free_calls;
25
- };
26
-
27
- static struct tracer tracer;
28
- static struct memprof_malloc_stats memprof_malloc_stats;
29
- static void *(*orig_malloc)(size_t), *(*orig_realloc)(void *, size_t),
30
- *(*orig_calloc)(size_t, size_t), (*orig_free)(void *);
31
- static size_t (*malloc_usable_size)(void *ptr);
32
-
33
- static void *
34
- malloc_tramp(size_t size)
35
- {
36
- void *ret = NULL;
37
- memprof_malloc_stats.malloc_bytes_requested += size;
38
- memprof_malloc_stats.malloc_calls++;
39
- ret = orig_malloc(size);
40
- memprof_malloc_stats.malloc_bytes_actual += malloc_usable_size(ret);
41
- return ret;
42
- }
43
-
44
- static void *
45
- calloc_tramp(size_t nmemb, size_t size)
46
- {
47
- void *ret = NULL;
48
- memprof_malloc_stats.calloc_bytes_requested += (nmemb * size);
49
- memprof_malloc_stats.calloc_calls++;
50
- ret = (*orig_calloc)(nmemb, size);
51
- memprof_malloc_stats.calloc_bytes_actual += malloc_usable_size(ret);
52
- return ret;
53
- }
54
-
55
- static void *
56
- realloc_tramp(void *ptr, size_t size)
57
- {
58
- /* TODO need to check malloc_usable_size of before/after i guess? */
59
- void *ret = NULL;
60
- memprof_malloc_stats.realloc_bytes_requested += size;
61
- memprof_malloc_stats.realloc_calls++;
62
- ret = orig_realloc(ptr, size);
63
- memprof_malloc_stats.realloc_bytes_actual += malloc_usable_size(ptr);
64
- return ret;
65
- }
66
-
67
- static void
68
- free_tramp(void *ptr)
69
- {
70
- memprof_malloc_stats.free_bytes_actual += malloc_usable_size(ptr);
71
- memprof_malloc_stats.free_calls++;
72
- orig_free(ptr);
73
- }
74
-
75
- static void
76
- malloc_trace_stop()
77
- {
78
- struct tramp_st2_entry tmp;
79
-
80
- tmp.addr = orig_malloc;
81
- bin_update_image("malloc", &tmp, NULL);
82
-
83
- tmp.addr = orig_realloc;
84
- bin_update_image("realloc", &tmp, NULL);
85
-
86
- if (orig_calloc) {
87
- tmp.addr = orig_calloc;
88
- bin_update_image("calloc", &tmp, NULL);
89
- }
90
-
91
- tmp.addr = orig_free;
92
- bin_update_image("free", &tmp, NULL);
93
- }
94
-
95
- static void
96
- malloc_trace_reset()
97
- {
98
- memset(&memprof_malloc_stats, 0, sizeof(memprof_malloc_stats));
99
- }
100
-
101
- static void
102
- malloc_trace_dump()
103
- {
104
- fprintf(stderr, "================ Requested ====================\n");
105
- fprintf(stderr, "Malloced: %zd, Realloced: %zd, Calloced: %zd\n",
106
- memprof_malloc_stats.malloc_bytes_requested, memprof_malloc_stats.realloc_bytes_requested,
107
- memprof_malloc_stats.calloc_bytes_requested);
108
- fprintf(stderr, "================ Actual ====================\n");
109
- fprintf(stderr, "Malloced: %zd, Realloced: %zd, Calloced: %zd, Freed: %zd\n",
110
- memprof_malloc_stats.malloc_bytes_actual, memprof_malloc_stats.realloc_bytes_actual,
111
- memprof_malloc_stats.calloc_bytes_actual, memprof_malloc_stats.free_bytes_actual);
112
- fprintf(stderr, "================ Call count ====================\n");
113
- fprintf(stderr, "Calls to malloc: %zd, realloc: %zd, calloc: %zd, free: %zd\n",
114
- memprof_malloc_stats.malloc_calls,
115
- memprof_malloc_stats.realloc_calls,
116
- memprof_malloc_stats.calloc_calls,
117
- memprof_malloc_stats.free_calls);
118
- }
119
-
120
- static void
121
- malloc_trace_start()
122
- {
123
- struct tramp_st2_entry tmp;
124
-
125
- if (!malloc_usable_size) {
126
- if ((malloc_usable_size =
127
- bin_find_symbol("MallocExtension_GetAllocatedSize", NULL, 1)) == NULL) {
128
- malloc_usable_size = bin_find_symbol("malloc_usable_size", NULL, 1);
129
- dbg_printf("tcmalloc was not found...\n");
130
- }
131
- assert(malloc_usable_size != NULL);
132
- dbg_printf("malloc_usable_size: %p\n", malloc_usable_size);
133
- }
134
-
135
- tmp.addr = malloc_tramp;
136
- bin_update_image("malloc", &tmp, (void **)(&orig_malloc));
137
- assert(orig_malloc != NULL);
138
- dbg_printf("orig_malloc: %p\n", orig_malloc);
139
-
140
- tmp.addr = realloc_tramp;
141
- bin_update_image("realloc", &tmp,(void **)(&orig_realloc));
142
- dbg_printf("orig_realloc: %p\n", orig_realloc);
143
-
144
- tmp.addr = calloc_tramp;
145
- bin_update_image("calloc", &tmp, (void **)(&orig_calloc));
146
- dbg_printf("orig_calloc: %p\n", orig_calloc);
147
-
148
- tmp.addr = free_tramp;
149
- bin_update_image("free", &tmp, (void **)(&orig_free));
150
- assert(orig_free != NULL);
151
- dbg_printf("orig_free: %p\n", orig_free);
152
- }
153
-
154
- void install_malloc_tracer()
155
- {
156
- tracer.start = malloc_trace_start;
157
- tracer.stop = malloc_trace_stop;
158
- tracer.reset = malloc_trace_reset;
159
- tracer.dump = malloc_trace_dump;
160
- tracer.id = strdup("malloc_tracer");
161
-
162
- trace_insert(&tracer);
163
- }