rubinius-profiler 2.0.2 → 2.1

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.
@@ -1,5 +1,5 @@
1
1
  module Rubinius
2
2
  module Profiler
3
- VERSION = "2.0.2"
3
+ VERSION = "2.1"
4
4
  end
5
5
  end
@@ -13,7 +13,6 @@ Gem::Specification.new do |spec|
13
13
 
14
14
  spec.files = `git ls-files`.split($/)
15
15
  spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
16
- spec.extensions = ["ext/rubinius/profiler/extconf.rb"]
17
16
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
18
17
  spec.require_paths = ["lib"]
19
18
 
metadata CHANGED
@@ -1,22 +1,22 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rubinius-profiler
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.2
4
+ version: '2.1'
5
5
  platform: ruby
6
6
  authors:
7
7
  - Brian Shirai
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-05-15 00:00:00.000000000 Z
11
+ date: 2016-05-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: bundler
15
14
  requirement: !ruby/object:Gem::Requirement
16
15
  requirements:
17
16
  - - "~>"
18
17
  - !ruby/object:Gem::Version
19
18
  version: '1.3'
19
+ name: bundler
20
20
  type: :development
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
@@ -25,12 +25,12 @@ dependencies:
25
25
  - !ruby/object:Gem::Version
26
26
  version: '1.3'
27
27
  - !ruby/object:Gem::Dependency
28
- name: rake
29
28
  requirement: !ruby/object:Gem::Requirement
30
29
  requirements:
31
30
  - - "~>"
32
31
  - !ruby/object:Gem::Version
33
32
  version: '10.0'
33
+ name: rake
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
@@ -42,8 +42,7 @@ description: Rubinius profiler.
42
42
  email:
43
43
  - brixen@gmail.com
44
44
  executables: []
45
- extensions:
46
- - ext/rubinius/profiler/extconf.rb
45
+ extensions: []
47
46
  extra_rdoc_files: []
48
47
  files:
49
48
  - ".gitignore"
@@ -51,8 +50,6 @@ files:
51
50
  - LICENSE
52
51
  - README.md
53
52
  - Rakefile
54
- - ext/rubinius/profiler/extconf.rb
55
- - ext/rubinius/profiler/profiler.cpp
56
53
  - lib/rubinius/profiler.rb
57
54
  - lib/rubinius/profiler/profiler.rb
58
55
  - lib/rubinius/profiler/version.rb
@@ -77,7 +74,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
77
74
  version: '0'
78
75
  requirements: []
79
76
  rubyforge_project:
80
- rubygems_version: 2.4.5
77
+ rubygems_version: 2.6.2
81
78
  signing_key:
82
79
  specification_version: 4
83
80
  summary: Rubinius profiler.
@@ -1,3 +0,0 @@
1
- require 'mkmf'
2
-
3
- create_makefile 'rubinius/profiler/ext/profiler'
@@ -1,1059 +0,0 @@
1
- #include <rbxti.hpp>
2
- #include <rbxti/atomic.hpp>
3
- #include <rbx_config.h>
4
-
5
- #include <stdint.h>
6
- #include <stdio.h>
7
-
8
- #include <list>
9
- #include <stack>
10
- #include <map>
11
- #ifdef RBX_HAVE_TR1
12
- #include <tr1/unordered_map>
13
- #define std_unordered_map std::tr1::unordered_map
14
- #else
15
- #include <unordered_map>
16
- #define std_unordered_map std::unordered_map
17
- #endif
18
-
19
- #include <time.h>
20
-
21
- #include <sstream>
22
- #include <iostream>
23
- #include <vector>
24
- #include <algorithm>
25
-
26
- typedef uint64_t method_id;
27
-
28
- #if defined(RBX_HAVE_TR1) && !defined(RBX_HAVE_TR1_HASH)
29
- namespace std {
30
- namespace tr1 {
31
- template <>
32
- struct hash<method_id> {
33
- size_t operator()(const method_id id) const {
34
- return id;
35
- }
36
- };
37
- }
38
- }
39
- #endif
40
-
41
- using namespace rbxti;
42
-
43
- namespace profiler {
44
-
45
- enum Kind {
46
- kNormal,
47
- kSingleton,
48
- kBlock,
49
- kYoungGC,
50
- kMatureGC,
51
- kNormalJIT,
52
- kSingletonJIT,
53
- kBlockJIT,
54
- kFinalizers,
55
- kScript,
56
- kRoot
57
- };
58
-
59
- class VM;
60
- class Profiler;
61
- class Method;
62
- class Node;
63
- typedef std_unordered_map<Method*, rinteger> KeyMap;
64
- typedef std_unordered_map<method_id, Method*> MethodMap;
65
-
66
- /* An accumulating increment timer. Keeps track of the maximum and minimum
67
- * intervals recorded. Calculates a cumulative moving average according to
68
- * the formula:
69
- *
70
- * x(i+1) + i*CA(i)
71
- * CA(i+1) = -----------------
72
- * i + 1
73
- *
74
- * where:
75
- *
76
- * CA(n) is the nth cumulative average
77
- * x(n) is the nth measured value of x
78
- * i is the number of measurements
79
- */
80
- class Timer {
81
- protected:
82
-
83
- uint64_t total_;
84
- uint64_t timings_;
85
- uint64_t max_;
86
- uint64_t min_;
87
- uint64_t last_;
88
- uint64_t start_;
89
- double moving_average_;
90
- bool started_;
91
-
92
- public:
93
-
94
- Timer()
95
- : total_(0)
96
- , timings_(0)
97
- , max_(0)
98
- , min_(0)
99
- , last_(0)
100
- , start_(0)
101
- , moving_average_(0.0)
102
- , started_(false)
103
- { }
104
-
105
- bool started() {
106
- return started_;
107
- }
108
-
109
- uint64_t total() {
110
- return total_;
111
- }
112
-
113
- uint64_t timings() {
114
- return timings_;
115
- }
116
-
117
- uint64_t max() {
118
- return max_;
119
- }
120
-
121
- uint64_t min() {
122
- return min_;
123
- }
124
-
125
- double moving_average() {
126
- return moving_average_;
127
- }
128
-
129
- void start(Env* env) {
130
- if(started_) return;
131
-
132
- started_ = true;
133
- start_ = env->time_current_ns();
134
- }
135
-
136
- void stop(Env* env, uint64_t cur) {
137
- if(!started_) return;
138
-
139
- started_ = false;
140
-
141
- last_ = cur - start_;
142
- total_ += last_;
143
-
144
- if(min_ == 0 || min_ > last_) min_ = last_;
145
- if(max_ == 0 || max_ < last_) max_ = last_;
146
-
147
- moving_average_ = (last_ + timings_ * moving_average_) / (timings_ + 1);
148
- ++timings_;
149
- }
150
- };
151
-
152
- class StackTimer : public Timer {
153
- size_t entered_;
154
- uint64_t count_;
155
-
156
- public:
157
- StackTimer()
158
- : entered_(0)
159
- , count_(0)
160
- { }
161
-
162
- uint64_t count() {
163
- return count_;
164
- }
165
-
166
- void start(Env* env) {
167
- ++entered_;
168
- Timer::start(env);
169
- }
170
-
171
- void stop(Env* env, uint64_t cur) {
172
- if(!started_) return;
173
-
174
- ++count_;
175
- if(--entered_ == 0) Timer::stop(env, cur);
176
- }
177
- };
178
-
179
- class Node {
180
- int id_;
181
- int called_;
182
- uint64_t total_;
183
- Method* method_;
184
-
185
- Node* sibling_;
186
- Node* first_sub_node_;
187
-
188
- public:
189
- Node(Method* method, int id)
190
- : id_(id)
191
- , called_(0)
192
- , total_(0)
193
- , method_(method)
194
- , sibling_(0)
195
- , first_sub_node_(0)
196
- { }
197
-
198
- int id() {
199
- return id_;
200
- }
201
-
202
- Method* method() {
203
- return method_;
204
- }
205
-
206
- uint64_t total() {
207
- return total_;
208
- }
209
-
210
- int called() {
211
- return called_;
212
- }
213
-
214
- Node* sub_nodes() {
215
- return first_sub_node_;
216
- }
217
-
218
- int count_sub_nodes() {
219
- int count = 0;
220
- Node* node = first_sub_node_;
221
- while(node) {
222
- ++count;
223
- node = node->sibling();
224
- }
225
-
226
- return count;
227
- }
228
-
229
- Node* sibling() {
230
- return sibling_;
231
- }
232
-
233
- void set_sibling(Node* node) {
234
- sibling_ = node;
235
- }
236
-
237
- void accumulate(uint64_t time) {
238
- total_ += time;
239
- called_++;
240
- }
241
-
242
- Node* find_sub_node(Profiler* profiler, Method* method);
243
- };
244
-
245
- class Method {
246
- private:
247
- method_id id_;
248
- rsymbol name_;
249
- rsymbol container_;
250
- Kind kind_;
251
- rsymbol file_;
252
- int line_;
253
- uint64_t total_;
254
-
255
- public:
256
- StackTimer timer;
257
-
258
- public:
259
- Method(method_id id, rsymbol name, rsymbol container, Kind kind=kNormal)
260
- : id_(id)
261
- , name_(name)
262
- , container_(container)
263
- , kind_(kind)
264
- , file_(0)
265
- , line_(0)
266
- , total_(0)
267
- { }
268
-
269
- method_id id() {
270
- return id_;
271
- }
272
-
273
- rsymbol container() {
274
- return container_;
275
- }
276
-
277
- rsymbol name() {
278
- return name_;
279
- }
280
-
281
- Kind kind() {
282
- return kind_;
283
- }
284
-
285
- rstring to_s(Env* env);
286
-
287
- rsymbol file() {
288
- return file_;
289
- }
290
-
291
- int line() {
292
- return line_;
293
- }
294
-
295
- void set_position(rsymbol file, int line) {
296
- file_ = file;
297
- line_ = line;
298
- }
299
-
300
- uint64_t total() {
301
- return total_;
302
- }
303
-
304
- void accumulate(uint64_t time) {
305
- total_ += time;
306
- }
307
- };
308
-
309
- class Profiler;
310
-
311
- /** Created when a method is being called. Contains a timer that tracks
312
- * how much time is spent in the method. When the MethodEntry instance
313
- * goes out of scope, the destructor records the elapsed time and updates
314
- * the Method and Node objects.
315
- */
316
- class MethodEntry {
317
- Method* method_;
318
- Node* node_;
319
- MethodEntry* previous_me_;
320
- Timer timer_;
321
-
322
- public:
323
-
324
- MethodEntry(Method* method, Node* node=0)
325
- : method_(method)
326
- , node_(node)
327
- , previous_me_(0)
328
- {}
329
-
330
- void start(Profiler* profiler, Env* env);
331
- void stop(Profiler* profiler, Env* env);
332
- void stop_all(Profiler* profiler, Env* env, uint64_t end_time);
333
- };
334
-
335
- class Profiler {
336
- MethodMap methods_;
337
- Node* root_;
338
- MethodEntry* current_me_;
339
- int nodes_;
340
- uint32_t threshold_;
341
- uint64_t start_time_;
342
- uint64_t end_time_;
343
- int id_;
344
- bool attached_;
345
-
346
- rbxti::SpinLock lock_;
347
-
348
- public:
349
- Profiler(Env* env);
350
-
351
- ~Profiler();
352
-
353
- void lock() {
354
- lock_.lock();
355
- }
356
-
357
- void unlock() {
358
- lock_.unlock();
359
- }
360
-
361
- MethodEntry* current_me() {
362
- return current_me_;
363
- }
364
-
365
- void set_current_me(MethodEntry* me) {
366
- current_me_ = me;
367
- }
368
-
369
- int next_node_id() {
370
- return nodes_++;
371
- }
372
-
373
- uint64_t start_time() {
374
- return start_time_;
375
- }
376
-
377
- uint64_t end_time() {
378
- return end_time_;
379
- }
380
-
381
- uint64_t runtime() {
382
- return end_time_ - start_time_;
383
- }
384
-
385
- void finish(Env* env, uint64_t end_time) {
386
- if(end_time_ == 0) {
387
- end_time_ = end_time;
388
-
389
- current_me_->stop_all(this, env, end_time);
390
- }
391
- }
392
-
393
- void detach(Env* env, uint64_t end_time) {
394
- finish(env, end_time);
395
- attached_ = false;
396
- }
397
-
398
- bool attached_p() {
399
- return attached_;
400
- }
401
-
402
- int id() {
403
- return id_;
404
- }
405
-
406
- method_id create_id(Env* env, rcompiled_code ccode,
407
- rsymbol container, rsymbol name, Kind kind);
408
- Method* find_method(Env* env, rcompiled_code ccode,
409
- rsymbol container, rsymbol name, Kind kind);
410
-
411
-
412
- Method* enter_method(Env* env, robject recv, rsymbol name, rmodule mod,
413
- rcompiled_code ccode);
414
- Method* enter_block(Env* env, rsymbol name, rmodule module,
415
- rcompiled_code ccode);
416
- Method* get_method(Env* env, rcompiled_code ccode, rsymbol name,
417
- rsymbol container, Kind kind);
418
-
419
- void results(Env* env, rtable profile, rtable nodes, rtable methods,
420
- KeyMap& keys, uint64_t runtime);
421
- };
422
-
423
- rstring Method::to_s(Env* env) {
424
- std::stringstream ss;
425
- char data[1024];
426
-
427
- if(kind() == kScript) {
428
- ss << "script:";
429
- if(file_) {
430
- env->symbol_cstr(file_, data, 1024);
431
- ss << data;
432
- } else {
433
- ss << "--unknown-file--";
434
- ss << ":" << line_;
435
- }
436
-
437
- return env->string_new(ss.str().c_str());
438
- }
439
-
440
- if(!env->is_nil(container())) {
441
- env->symbol_cstr(container_, data, 1024);
442
- ss << data;
443
- } else {
444
- ss << "<anonymous>";
445
- }
446
-
447
- env->symbol_cstr(name(), data, 1024);
448
-
449
- switch(kind()) {
450
- case kNormal:
451
- ss << "#" << data;
452
- break;
453
- case kNormalJIT:
454
- ss << "#" << data << " <jit>";
455
- break;
456
- case kSingleton:
457
- case kYoungGC:
458
- case kMatureGC:
459
- case kFinalizers:
460
- ss << "." << data;
461
- break;
462
- case kSingletonJIT:
463
- ss << "." << data << " <jit>";
464
- break;
465
- case kBlock:
466
- ss << "::" << data << "<" << line_ << "> {}";
467
- break;
468
- case kBlockJIT:
469
- ss << "::" << data << " {" << line_ << "} <jit>";
470
- break;
471
- case kRoot:
472
- break;
473
- case kScript:
474
- // handled above, just here to make gcc happy.
475
- abort();
476
- }
477
-
478
- return env->string_new(ss.str().c_str());
479
- }
480
-
481
- Node* Node::find_sub_node(Profiler* profiler, Method* method) {
482
- Node* sub = first_sub_node_;
483
-
484
- while(sub) {
485
- if(sub->method() == method) return sub;
486
- sub = sub->sibling();
487
- }
488
-
489
- Node* node = new Node(method, profiler->next_node_id());
490
- node->set_sibling(first_sub_node_);
491
- first_sub_node_ = node;
492
-
493
- return node;
494
- }
495
-
496
- void MethodEntry::start(Profiler* profiler, Env* env) {
497
- previous_me_ = profiler->current_me();
498
-
499
- node_ = previous_me_->node_->find_sub_node(profiler, method_);
500
-
501
- profiler->set_current_me(this);
502
-
503
- method_->timer.start(env);
504
- timer_.start(env);
505
- }
506
-
507
- void MethodEntry::stop(Profiler* profiler, Env* env) {
508
- uint64_t cur = env->time_current_ns();
509
-
510
- method_->timer.stop(env, cur);
511
- timer_.stop(env, cur);
512
-
513
- method_->accumulate(timer_.total());
514
- node_->accumulate(timer_.total());
515
-
516
- if(previous_me_) {
517
- profiler->set_current_me(previous_me_);
518
- }
519
- }
520
-
521
- void MethodEntry::stop_all(Profiler* profiler, Env* env, uint64_t end_time) {
522
- method_->timer.stop(env, end_time);
523
- timer_.stop(env, end_time);
524
-
525
- method_->accumulate(timer_.total());
526
- node_->accumulate(timer_.total());
527
-
528
- if(previous_me_) previous_me_->stop_all(profiler, env, end_time);
529
- }
530
-
531
- Profiler::Profiler(Env* env)
532
- : root_(0)
533
- , current_me_(0)
534
- , nodes_(0)
535
- , threshold_((uint32_t)env->config_get_int("profiler.threshold"))
536
- , start_time_(env->time_current_ns())
537
- , end_time_(0)
538
- , id_(env->current_thread_id())
539
- , attached_(true)
540
- {
541
- Method* root_me = new Method(0, 0, 0, kRoot);
542
- root_ = new Node(root_me, next_node_id());
543
- current_me_ = new MethodEntry(root_me, root_);
544
- }
545
-
546
- Method* Profiler::enter_block(Env* env, rsymbol name, rmodule module,
547
- rcompiled_code ccode)
548
- {
549
- return get_method(env, ccode, name, env->module_name(module), kBlock);
550
- }
551
-
552
- Method* Profiler::enter_method(Env* env, robject recv, rsymbol name, rmodule mod,
553
- rcompiled_code ccode)
554
- {
555
- if(env->module_is_metaclass(mod)) {
556
- robject attached = env->metaclass_attached_instance(mod);
557
-
558
- rmodule as_module = env->cast_to_rmodule(attached);
559
- if(as_module) {
560
- return get_method(env, ccode, name, env->module_name(as_module), kSingleton);
561
- } else {
562
- rstring str = env->to_s(mod);
563
- return get_method(env, ccode, name, env->string_to_symbol(str), kSingleton);
564
- }
565
- } else {
566
- return get_method(env, ccode, name, env->module_name(mod), kNormal);
567
- }
568
- }
569
-
570
- Method* Profiler::get_method(Env* env, rcompiled_code ccode, rsymbol name,
571
- rsymbol container, Kind kind)
572
- {
573
- Method* method = find_method(env, ccode, container, name, kind);
574
-
575
- if(!method->file() && ccode && !env->is_nil(ccode)) {
576
- method->set_position(env->method_file(ccode), env->method_line(ccode));
577
- }
578
-
579
- return method;
580
- }
581
-
582
- method_id Profiler::create_id(Env* env, rcompiled_code ccode, rsymbol name,
583
- rsymbol container, Kind kind)
584
- {
585
- // If we have a CompiledCode, use it's method id.
586
- if(ccode && !env->is_nil(ccode)) {
587
- r_mint i = env->method_id(ccode);
588
- if(i) return i;
589
- }
590
-
591
- // | -- 32 bits of container -- | -- 29 bits of name -- | -- 2 bits of kind -- | 0
592
-
593
- uint32_t c = env->symbol_id(container) & 0xffffffff;
594
- uint32_t n = env->symbol_id(name) & 0x1fffffff;
595
- uint32_t k = kind & 0x3;
596
-
597
- return (((uint64_t)c) << 32) |
598
- (n << 3) |
599
- k << 1;
600
- }
601
-
602
- Method* Profiler::find_method(Env* env, rcompiled_code ccode, rsymbol container,
603
- rsymbol name, Kind kind)
604
- {
605
- method_id id = create_id(env, ccode, container, name, kind);
606
-
607
- Method* method;
608
-
609
- MethodMap::iterator iter = methods_.find(id);
610
-
611
- if(iter == methods_.end()) {
612
- method = new Method(id, name, container, kind);
613
- methods_[method->id()] = method;
614
- } else {
615
- method = iter->second;
616
- }
617
-
618
- return method;
619
- }
620
-
621
- typedef std::vector<Node*> WorkList;
622
-
623
- static rinteger make_key(Env* env, Method* meth, KeyMap& keys) {
624
- KeyMap::iterator iter = keys.find(meth);
625
-
626
- if(iter == keys.end()) {
627
- rinteger key = env->integer_new(keys.size());
628
- keys[meth] = key;
629
- return key;
630
- }
631
-
632
- return iter->second;
633
- }
634
-
635
- static rinteger add_method(Env* env, rtable methods, Method* meth,
636
- KeyMap& keys)
637
- {
638
- rinteger key = make_key(env, meth, keys);
639
-
640
- // We already have the method, skip this.
641
- bool fetched = false;
642
- env->table_fetch(methods, key, &fetched);
643
- if(fetched) return env->cast_to_rinteger(key);
644
-
645
- rsymbol cumulative_sym = env->symbol("cumulative");
646
- rsymbol total_sym = env->symbol("total");
647
- rsymbol called_sym = env->symbol("called");
648
-
649
- rtable method = env->table_new();
650
- env->table_store(methods, key, method);
651
-
652
- env->table_store(method, env->symbol("name"), meth->to_s(env));
653
- env->table_store(method, cumulative_sym, env->integer_new(meth->timer.total()));
654
- env->table_store(method, total_sym, env->integer_new(meth->total()));
655
- env->table_store(method, called_sym, env->integer_new(meth->timer.count()));
656
-
657
- if(meth->file()) {
658
- if(env->is_nil(meth->file())) {
659
- env->table_store(method, env->symbol("file"), env->string_new("unknown file"));
660
- } else {
661
- env->table_store(method, env->symbol("file"),
662
- env->symbol_to_string(meth->file()));
663
- }
664
-
665
- env->table_store(method, env->symbol("line"), env->integer_new(meth->line()));
666
- }
667
-
668
- return key;
669
- }
670
-
671
- static void add_node(Env* env, rtable nodes, rtable methods, Node* node,
672
- WorkList& work, KeyMap& keys, uint32_t threshold)
673
- {
674
- // We haven't exited this method yet, so its stats won't be accurate
675
- if(node->method()->timer.started()) return;
676
-
677
- rinteger key = env->integer_new(node->id());
678
-
679
- rarray tbl = env->array_new(5);
680
-
681
- env->table_store(nodes, key, tbl);
682
-
683
- robject meth_key = add_method(env, methods, node->method(), keys);
684
-
685
- env->array_set(tbl, 0, meth_key);
686
- env->array_set(tbl, 1, env->integer_new(node->total()));
687
- env->array_set(tbl, 2, env->integer_new(node->called()));
688
-
689
- int count = node->count_sub_nodes();
690
- env->array_set(tbl, 3, env->integer_new(count));
691
-
692
- rarray ary = env->array_new(count);
693
-
694
- int idx = 0;
695
-
696
- Node* sub = node->sub_nodes();
697
-
698
- while(sub) {
699
- if(sub->total() >= threshold) {
700
- env->array_set(ary, idx++, env->integer_new(sub->id()));
701
- work.push_back(sub);
702
- }
703
-
704
- sub = sub->sibling();
705
- }
706
-
707
- env->array_set(tbl, 4, ary);
708
- }
709
-
710
- void Profiler::results(Env* env, rtable profile, rtable nodes, rtable methods,
711
- KeyMap& keys, uint64_t runtime)
712
- {
713
-
714
- WorkList work;
715
-
716
- // If we haven't even gone for a total of longer than 10x the threshold,
717
- // just disable the threshold.
718
- if(runtime < 10 * threshold_) threshold_ = 0;
719
-
720
- env->table_store(profile, env->symbol("total_nodes"), env->integer_new(nodes_));
721
-
722
- rarray roots = env->array_new(root_->count_sub_nodes());
723
- env->table_store(profile, env->symbol("roots"), roots);
724
-
725
- int idx = 0;
726
- Node* sub = root_->sub_nodes();
727
-
728
- while(sub) {
729
- if(sub->total() >= threshold_) {
730
- env->array_set(roots, idx++, env->integer_new(sub->id()));
731
- work.push_back(sub);
732
- }
733
-
734
- sub = sub->sibling();
735
- }
736
-
737
- while(work.size() > 0) {
738
- Node* node = work.back();
739
- work.pop_back();
740
-
741
- add_node(env, nodes, methods, node, work, keys, threshold_);
742
- }
743
- }
744
-
745
- Profiler::~Profiler() {
746
- for(MethodMap::iterator i = methods_.begin();
747
- i != methods_.end();
748
- i++) {
749
- delete i->second;
750
- }
751
-
752
- WorkList work;
753
-
754
- work.push_back(root_);
755
-
756
- while(work.size() > 0) {
757
- Node* node = work.back();
758
- work.pop_back();
759
-
760
- Node* sub = node->sub_nodes();
761
-
762
- while(sub) {
763
- work.push_back(sub);
764
- sub = sub->sibling();
765
- }
766
-
767
- delete node;
768
- }
769
- }
770
-
771
- struct GlobalState {
772
- Profiler* main_profiler;
773
- std::list<Profiler*> profilers;
774
-
775
- GlobalState()
776
- : main_profiler(0)
777
- {}
778
-
779
- void add(Profiler* prof) {
780
- profilers.push_back(prof);
781
- }
782
- };
783
-
784
- static int cProfileToolID = -1;
785
-
786
- namespace {
787
- void tool_enable(Env* env) {
788
- // Ignore if we are already enabled
789
- if(env->global_tool_data()) return;
790
-
791
- GlobalState* st = new GlobalState;
792
- env->set_global_tool_data(st);
793
-
794
- Profiler* profiler = new Profiler(env);
795
- st->main_profiler = profiler;
796
-
797
- env->thread_tool_set_data(cProfileToolID, profiler);
798
- st->add(profiler);
799
-
800
- env->enable_thread_tooling();
801
- }
802
-
803
- void* tool_enter_method(Env* env, robject recv, rsymbol name, rmodule mod,
804
- rcompiled_code ccode)
805
- {
806
- Profiler* profiler = (Profiler*)env->thread_tool_data(cProfileToolID);
807
- if(!profiler) return 0;
808
-
809
- profiler->lock();
810
-
811
- Method* method = profiler->enter_method(env, recv, name, mod, ccode);
812
- MethodEntry* me = new MethodEntry(method);
813
- me->start(profiler, env);
814
-
815
- profiler->unlock();
816
-
817
- return me;
818
- }
819
-
820
- void tool_leave_entry(Env* env, void* tag) {
821
- MethodEntry* me = (MethodEntry*)tag;
822
-
823
- Profiler* profiler = (Profiler*)env->thread_tool_data(cProfileToolID);
824
- if(!profiler) return;
825
-
826
- profiler->lock();
827
-
828
- me->stop(profiler, env);
829
-
830
- profiler->unlock();
831
-
832
- delete me;
833
- }
834
-
835
- void* tool_enter_block(Env* env, rsymbol name, rmodule module, rcompiled_code ccode) {
836
- Profiler* profiler = (Profiler*)env->thread_tool_data(cProfileToolID);
837
- if(!profiler) return 0;
838
-
839
- profiler->lock();
840
-
841
- Method* method = profiler->enter_block(env, name, module, ccode);
842
- MethodEntry* me = new MethodEntry(method);
843
- me->start(profiler, env);
844
-
845
- profiler->unlock();
846
-
847
- return me;
848
- }
849
-
850
- void* tool_enter_gc(Env* env, int level) {
851
- Profiler* profiler = (Profiler*)env->thread_tool_data(cProfileToolID);
852
- if(!profiler) return 0;
853
-
854
- rsymbol container = env->symbol("GC");
855
- rsymbol name;
856
-
857
- Kind kind;
858
-
859
- switch(level) {
860
- case GCYoung:
861
- kind = kYoungGC;
862
- name = env->symbol("collect_young");
863
- break;
864
- case GCMature:
865
- kind = kMatureGC;
866
- name = env->symbol("collect_mature");
867
- break;
868
- case GCFinalizer:
869
- kind = kFinalizers;
870
- name = env->symbol("run_finalizers");
871
- break;
872
- default:
873
- kind = kFinalizers;
874
- name = env->symbol("unknown");
875
- break;
876
- }
877
-
878
- profiler->lock();
879
-
880
- Method* method = profiler->get_method(env, NULL, name, container, kind);
881
- MethodEntry* me = new MethodEntry(method);
882
- me->start(profiler, env);
883
-
884
- profiler->unlock();
885
-
886
- return me;
887
- }
888
-
889
- void* tool_enter_script(Env* env, rcompiled_code ccode) {
890
- Profiler* profiler = (Profiler*)env->thread_tool_data(cProfileToolID);
891
- if(!profiler) return 0;
892
-
893
- profiler->lock();
894
-
895
- Kind kind = kScript;
896
- rsymbol container = env->symbol("unknown");
897
- rsymbol name = container;
898
-
899
- Method* method = profiler->get_method(env, ccode, name, container, kind);
900
- MethodEntry* me = new MethodEntry(method);
901
- me->start(profiler, env);
902
-
903
- profiler->unlock();
904
-
905
- return me;
906
- }
907
-
908
- void tool_shutdown(Env* env) {
909
- GlobalState* st = (GlobalState*)env->global_tool_data();
910
- if(!st) return;
911
-
912
- env->set_global_tool_data(0);
913
-
914
- for(std::list<Profiler*>::iterator i = st->profilers.begin();
915
- i != st->profilers.end();
916
- ++i) {
917
-
918
- Profiler* prof = *i;
919
- if(!prof->attached_p()) delete prof;
920
- }
921
-
922
- delete st;
923
- }
924
-
925
- void tool_start_thread(Env* env) {
926
- GlobalState* st = (GlobalState*)env->global_tool_data();
927
-
928
- // No GlobalState means that the tool isn't currently enabled.
929
- if(!st) return;
930
-
931
- Profiler* profiler = new Profiler(env);
932
- profiler->lock();
933
-
934
- st->add(profiler);
935
-
936
- env->thread_tool_set_data(cProfileToolID, profiler);
937
-
938
- env->enable_thread_tooling();
939
-
940
- profiler->unlock();
941
- }
942
-
943
- void tool_stop_thread(Env* env) {
944
- Profiler* profiler = (Profiler*)env->thread_tool_data(cProfileToolID);
945
- if(!profiler) return;
946
-
947
- profiler->lock();
948
-
949
- env->thread_tool_set_data(cProfileToolID, 0);
950
- profiler->detach(env, env->time_current_ns());
951
-
952
- env->disable_thread_tooling();
953
-
954
- profiler->unlock();
955
- }
956
-
957
- void tool_at_gc(Env* env) {
958
- Profiler* profiler = (Profiler*)env->thread_tool_data(cProfileToolID);
959
- if(!profiler) return;
960
-
961
- profiler->lock();
962
-
963
- // The main thread finished profiling, so we've already stopped
964
- // doing our work, so we can safely bail.
965
- if(profiler->end_time() > 0) {
966
- env->thread_tool_set_data(cProfileToolID, 0);
967
- delete profiler;
968
- return;
969
- }
970
-
971
- profiler->unlock();
972
- }
973
-
974
- robject tool_results(Env* env) {
975
- uint64_t fin = env->time_current_ns();
976
-
977
- GlobalState* st = (GlobalState*)env->global_tool_data();
978
-
979
- // If we are already shutting down, ignore this
980
- if(!st) return env->nil();
981
-
982
- Profiler* profiler = (Profiler*)env->thread_tool_data(cProfileToolID);
983
-
984
- // Ignore results requests that don't come from the thread that
985
- // started profiling.
986
- if(st->main_profiler != profiler) return env->nil();
987
-
988
- profiler->detach(env, fin);
989
-
990
- env->thread_tool_set_data(cProfileToolID, 0);
991
-
992
- rtable profile = env->table_new();
993
-
994
- for(std::list<Profiler*>::iterator i = st->profilers.begin();
995
- i != st->profilers.end();
996
- ++i) {
997
-
998
- Profiler* prof = *i;
999
-
1000
- prof->lock();
1001
-
1002
- prof->finish(env, fin);
1003
-
1004
- rtable thread = env->table_new();
1005
-
1006
- env->table_store(profile, env->integer_new(prof->id()), thread);
1007
-
1008
- rtable methods = env->table_new();
1009
- rtable nodes = env->table_new();
1010
-
1011
- env->table_store(thread, env->symbol("methods"), methods);
1012
- env->table_store(thread, env->symbol("nodes"), nodes);
1013
-
1014
- uint64_t runtime = prof->runtime();
1015
- env->table_store(thread, env->symbol("runtime"), env->integer_new(runtime));
1016
-
1017
- KeyMap keys;
1018
- prof->results(env, thread, nodes, methods, keys, runtime);
1019
-
1020
- prof->unlock();
1021
- }
1022
-
1023
- tool_shutdown(env);
1024
-
1025
- env->disable_thread_tooling();
1026
- return profile;
1027
- }
1028
-
1029
- }
1030
-
1031
- extern "C" int Tool_Init(Env* env) {
1032
- env->config_set("tool.require", "tooling/profiler/profiler.rb");
1033
-
1034
- cProfileToolID = env->thread_tool_new_id();
1035
-
1036
- env->set_tool_results(tool_results);
1037
- env->set_tool_enable(tool_enable);
1038
-
1039
- env->set_tool_enter_method(tool_enter_method);
1040
- env->set_tool_leave_method(tool_leave_entry);
1041
-
1042
- env->set_tool_enter_block(tool_enter_block);
1043
- env->set_tool_leave_block(tool_leave_entry);
1044
-
1045
- env->set_tool_enter_gc(tool_enter_gc);
1046
- env->set_tool_leave_gc(tool_leave_entry);
1047
-
1048
- env->set_tool_enter_script(tool_enter_script);
1049
- env->set_tool_leave_script(tool_leave_entry);
1050
-
1051
- env->set_tool_shutdown(tool_shutdown);
1052
-
1053
- env->set_tool_thread_start(tool_start_thread);
1054
- env->set_tool_thread_stop(tool_stop_thread);
1055
-
1056
- return 1;
1057
- }
1058
-
1059
- }