perftools.rb 0.4.5 → 0.4.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (3) hide show
  1. data/ext/perftools.c +48 -29
  2. data/perftools.rb.gemspec +1 -1
  3. metadata +13 -4
data/ext/perftools.c CHANGED
@@ -1,3 +1,5 @@
1
+ #include <ruby.h> // include this before anything else, as it defines _GNU_SOURCE etc
2
+
1
3
  #ifndef _GNU_SOURCE
2
4
  #define _GNU_SOURCE
3
5
  #endif
@@ -6,13 +8,13 @@
6
8
  #endif
7
9
 
8
10
  #include <assert.h>
9
- #include <ruby.h>
10
11
 
11
12
  void ProfilerGcMark(void (*cb)(VALUE));
12
- int ProfilerStart(const char*);
13
+ int ProfilerStart(const char*);
13
14
  void ProfilerStop();
14
15
  void ProfilerFlush();
15
16
  void ProfilerRecord(int, void*, void*);
17
+ int ProfilingIsEnabledForAllThreads();
16
18
 
17
19
  static VALUE Iallocate;
18
20
  static VALUE I__send__;
@@ -213,6 +215,7 @@ static VALUE objprofiler_teardown();
213
215
 
214
216
  static VALUE cPerfTools;
215
217
  static VALUE cCpuProfiler;
218
+ static VALUE eError;
216
219
  static VALUE bProfilerRunning;
217
220
  static VALUE gc_hook;
218
221
 
@@ -229,12 +232,10 @@ cpuprofiler_stop(VALUE self)
229
232
  return Qfalse;
230
233
 
231
234
  bProfilerRunning = Qfalse;
235
+ objprofiler_teardown();
232
236
  ProfilerStop();
233
237
  ProfilerFlush();
234
238
 
235
- if (getenv("CPUPROFILE_OBJECTS"))
236
- objprofiler_teardown();
237
-
238
239
  return Qtrue;
239
240
  }
240
241
 
@@ -244,13 +245,16 @@ cpuprofiler_start(VALUE self, VALUE filename)
244
245
  StringValue(filename);
245
246
 
246
247
  if (bProfilerRunning)
247
- return Qfalse;
248
+ rb_raise(eError, "profiler is already running");
248
249
 
249
250
  if (getenv("CPUPROFILE_OBJECTS"))
250
251
  objprofiler_setup();
251
252
 
252
- ProfilerStart(RSTRING_PTR(filename));
253
- bProfilerRunning = Qtrue;
253
+ if (ProfilerStart(RSTRING_PTR(filename))) {
254
+ bProfilerRunning = Qtrue;
255
+ } else {
256
+ rb_raise(eError, "profiler could not be started");
257
+ }
254
258
 
255
259
  if (rb_block_given_p()) {
256
260
  rb_yield(Qnil);
@@ -292,35 +296,36 @@ page_align(void *addr) {
292
296
  }
293
297
 
294
298
  static void
295
- unprotect_page(void *addr) {
299
+ unprotect_page(char *addr) {
296
300
  assert(addr != NULL);
297
- void *aligned_addr = page_align(addr);
301
+ char *aligned_addr = page_align(addr);
298
302
  if (mprotect(aligned_addr, (addr - aligned_addr), PROT_READ|PROT_WRITE|PROT_EXEC) != 0)
299
303
  perror("mprotect");
300
304
  }
301
305
 
302
- static inline void**
306
+ static inline char**
303
307
  uc_get_ip(ucontext_t *uc) {
304
- #if defined(__FreeBSD__)
305
- return (void**)&uc->uc_mcontext.mc_rip;
306
- #elif defined(__dietlibc__)
307
- return (void**)&uc->uc_mcontext.rip;
308
- #elif defined(__APPLE__)
309
- #if defined(__LP64__)
310
- return (void**)&uc->uc_mcontext->__ss.__rip;
311
- #else
312
- return (void**)&uc->uc_mcontext->__ss.__eip;
313
- #endif
314
- #else
315
- return (void**)&uc->uc_mcontext.gregs[REG_RIP];
316
- #endif
308
+ # if defined(__FreeBSD__)
309
+ # define program_counter uc_mcontext.mc_rip
310
+ # elif defined(__dietlibc__)
311
+ # define program_counter uc_mcontext.rip
312
+ # elif defined(__APPLE__)
313
+ # ifdef __LP64__
314
+ # define program_counter uc_mcontext->__ss.__rip
315
+ # else
316
+ # define program_counter uc_mcontext->__ss.__eip
317
+ # endif
318
+ # else
319
+ # define program_counter uc_mcontext.gregs[REG_RIP]
320
+ # endif
321
+ return (char**)&uc->program_counter;
317
322
  }
318
323
 
319
324
  static void
320
325
  trap_handler(int sig, siginfo_t *info, void *data) {
321
326
  int i;
322
327
  ucontext_t *uc = (ucontext_t *)data;
323
- void **ip = uc_get_ip(uc);
328
+ char **ip = uc_get_ip(uc);
324
329
 
325
330
  // printf("signal: %d, addr: %p, ip: %p\n", signal, info->si_addr, *ip);
326
331
 
@@ -355,10 +360,10 @@ objprofiler_setup()
355
360
  sigemptyset(&sig.sa_mask);
356
361
  sigaction(SIGTRAP, &sig, NULL);
357
362
 
358
- unprotect_page(rb_newobj);
363
+ unprotect_page((char*)rb_newobj);
359
364
 
360
365
  for (i=0; i<NUM_ORIG_BYTES; i++) {
361
- orig_bytes[i].location = (char *)(rb_newobj + i);
366
+ orig_bytes[i].location = (char *)rb_newobj + i;
362
367
  orig_bytes[i].value = ((unsigned char*)rb_newobj)[i];
363
368
  orig_bytes[i].location[0] = '\xCC';
364
369
  }
@@ -390,10 +395,17 @@ objprofiler_teardown()
390
395
 
391
396
  /* Init */
392
397
 
398
+ static void
399
+ profiler_at_exit(VALUE self)
400
+ {
401
+ cpuprofiler_stop(self);
402
+ }
403
+
393
404
  void
394
405
  Init_perftools()
395
406
  {
396
407
  cPerfTools = rb_define_class("PerfTools", rb_cObject);
408
+ eError = rb_define_class_under(cPerfTools, "Error", rb_eStandardError);
397
409
  cCpuProfiler = rb_define_class_under(cPerfTools, "CpuProfiler", rb_cObject);
398
410
 
399
411
  Iallocate = rb_intern("allocate");
@@ -409,6 +421,13 @@ Init_perftools()
409
421
  gc_hook = Data_Wrap_Struct(cCpuProfiler, cpuprofiler_gc_mark, NULL, NULL);
410
422
  rb_global_variable(&gc_hook);
411
423
 
412
- if (getenv("CPUPROFILE") && getenv("CPUPROFILE_OBJECTS"))
413
- objprofiler_setup();
424
+ if (ProfilingIsEnabledForAllThreads()) { // profiler is already running?
425
+ bProfilerRunning = Qtrue;
426
+
427
+ if (getenv("CPUPROFILE_OBJECTS")) { // want to profile objects
428
+ objprofiler_setup();
429
+ }
430
+
431
+ rb_set_end_proc(profiler_at_exit, 0); // make sure to cleanup before the VM shuts down
432
+ }
414
433
  }
data/perftools.rb.gemspec CHANGED
@@ -1,6 +1,6 @@
1
1
  spec = Gem::Specification.new do |s|
2
2
  s.name = 'perftools.rb'
3
- s.version = '0.4.5'
3
+ s.version = '0.4.6'
4
4
  s.date = '2010-08-03'
5
5
  s.rubyforge_project = 'perftools-rb'
6
6
  s.summary = 'google-perftools for ruby code'
metadata CHANGED
@@ -1,7 +1,12 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: perftools.rb
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.5
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 4
8
+ - 6
9
+ version: 0.4.6
5
10
  platform: ruby
6
11
  authors:
7
12
  - Aman Gupta
@@ -49,21 +54,25 @@ rdoc_options: []
49
54
  require_paths:
50
55
  - lib
51
56
  required_ruby_version: !ruby/object:Gem::Requirement
57
+ none: false
52
58
  requirements:
53
59
  - - ">="
54
60
  - !ruby/object:Gem::Version
61
+ segments:
62
+ - 0
55
63
  version: "0"
56
- version:
57
64
  required_rubygems_version: !ruby/object:Gem::Requirement
65
+ none: false
58
66
  requirements:
59
67
  - - ">="
60
68
  - !ruby/object:Gem::Version
69
+ segments:
70
+ - 0
61
71
  version: "0"
62
- version:
63
72
  requirements: []
64
73
 
65
74
  rubyforge_project: perftools-rb
66
- rubygems_version: 1.3.5
75
+ rubygems_version: 1.3.7
67
76
  signing_key:
68
77
  specification_version: 3
69
78
  summary: google-perftools for ruby code