]> gitweb.factorcode.org Git - factor.git/blob - vm/sampling_profiler.cpp
vm: count samples from foreign threads
[factor.git] / vm / sampling_profiler.cpp
1 #include "master.hpp"
2
3 namespace factor
4 {
5
6 profiling_sample::profiling_sample(factor_vm *vm,
7         cell sample_count,
8         cell gc_sample_count,
9         cell foreign_sample_count,
10         cell foreign_thread_sample_count,
11         context *ctx)
12         :
13         sample_count(sample_count),
14         gc_sample_count(gc_sample_count),
15         foreign_sample_count(foreign_sample_count),
16         foreign_thread_sample_count(foreign_thread_sample_count),
17         ctx(ctx)
18 {
19         vm->record_callstack_sample(&callstack_begin, &callstack_end);
20 }
21
22 void factor_vm::record_sample()
23 {
24         cell recorded_sample_count;
25         cell recorded_gc_sample_count;
26         cell recorded_foreign_sample_count;
27         cell recorded_foreign_thread_sample_count;
28
29         FACTOR_MEMORY_BARRIER();
30         recorded_sample_count = safepoint_sample_count;
31         recorded_gc_sample_count = safepoint_gc_sample_count;
32         recorded_foreign_sample_count = safepoint_foreign_sample_count;
33         recorded_foreign_thread_sample_count = safepoint_foreign_thread_sample_count;
34         if (recorded_sample_count
35                 + recorded_gc_sample_count
36                 + recorded_foreign_sample_count
37                 + recorded_foreign_thread_sample_count
38                 == 0)
39                 return;
40
41         /* Another sample signal could be raised while we record these counts */
42         FACTOR_ATOMIC_SUB(&safepoint_sample_count, recorded_sample_count);
43         FACTOR_ATOMIC_SUB(&safepoint_gc_sample_count, recorded_gc_sample_count);
44         FACTOR_ATOMIC_SUB(&safepoint_foreign_sample_count, recorded_foreign_sample_count);
45         FACTOR_ATOMIC_SUB(&safepoint_foreign_thread_sample_count, recorded_foreign_thread_sample_count);
46
47         samples.push_back(profiling_sample(
48                 this,
49                 recorded_sample_count,
50                 recorded_gc_sample_count,
51                 recorded_foreign_sample_count,
52                 recorded_foreign_thread_sample_count,
53                 ctx
54         ));
55 }
56
57 void factor_vm::record_callstack_sample(cell *begin, cell *end)
58 {
59         *begin = sample_callstacks.size();
60         stack_frame *frame = ctx->bottom_frame();
61
62         while (frame >= ctx->callstack_top) {
63                 sample_callstacks.push_back(frame_code(frame));
64                 frame = frame_successor(frame);
65         }
66
67         *end = sample_callstacks.size();
68 }
69
70 void factor_vm::set_sampling_profiler(bool sampling_p)
71 {
72         if (sampling_p == sampling_profiler_p)
73                 return;
74         
75         if (sampling_p)
76                 start_sampling_profiler();
77         else
78                 end_sampling_profiler();
79 }
80
81 void factor_vm::clear_samples()
82 {
83         // Swapping into temporaries releases the vector's allocated storage,
84         // whereas clear() would leave the allocation as-is
85         std::vector<profiling_sample> sample_graveyard;
86         std::vector<code_block*> sample_callstack_graveyard;
87         samples.swap(sample_graveyard);
88         sample_callstacks.swap(sample_callstack_graveyard);
89 }
90
91 void factor_vm::start_sampling_profiler()
92 {
93         safepoint_sample_count = 0;
94         safepoint_gc_sample_count = 0;
95         clear_samples();
96         samples.reserve(10*FACTOR_PROFILE_SAMPLES_PER_SECOND);
97         sample_callstacks.reserve(100*FACTOR_PROFILE_SAMPLES_PER_SECOND);
98         sampling_profiler_p = true;
99         start_sampling_profiler_timer();
100 }
101
102 void factor_vm::end_sampling_profiler()
103 {
104         end_sampling_profiler_timer();
105         record_sample();
106         sampling_profiler_p = false;
107 }
108
109 void factor_vm::primitive_sampling_profiler()
110 {
111         set_sampling_profiler(to_boolean(ctx->pop()));
112 }
113
114 void factor_vm::primitive_get_samples()
115 {
116         if (sampling_profiler_p || samples.empty()) {
117                 ctx->push(false_object);
118         } else {
119                 data_root<array> samples_array(allot_array(samples.size(), false_object),this);
120                 std::vector<profiling_sample>::const_iterator from_iter = samples.begin();
121                 cell to_i = 0;
122
123                 for (; from_iter != samples.end(); ++from_iter, ++to_i)
124                 {
125                         data_root<array> sample(allot_array(6, false_object),this);
126
127                         set_array_nth(sample.untagged(),0,from_unsigned_cell(from_iter->sample_count));
128                         set_array_nth(sample.untagged(),1,from_unsigned_cell(from_iter->gc_sample_count));
129                         set_array_nth(sample.untagged(),2,from_unsigned_cell(from_iter->foreign_sample_count));
130                         set_array_nth(sample.untagged(),3,from_unsigned_cell(from_iter->foreign_thread_sample_count));
131                         set_array_nth(sample.untagged(),4,allot_alien((void*)from_iter->ctx));
132
133                         cell callstack_size = from_iter->callstack_end - from_iter->callstack_begin;
134                         data_root<array> callstack(allot_array(callstack_size,false_object),this);
135
136                         std::vector<code_block*>::const_iterator
137                                 callstacks_begin = sample_callstacks.begin(),
138                                 c_from_iter = callstacks_begin + from_iter->callstack_begin,
139                                 c_from_iter_end = callstacks_begin + from_iter->callstack_end;
140                         cell c_to_i = 0;
141
142                         for (; c_from_iter != c_from_iter_end; ++c_from_iter, ++c_to_i)
143                                 set_array_nth(callstack.untagged(),c_to_i,(*c_from_iter)->owner);
144
145                         set_array_nth(sample.untagged(),5,callstack.value());
146
147                         set_array_nth(samples_array.untagged(),to_i,sample.value());
148                 }
149                 ctx->push(samples_array.value());
150         }
151 }
152
153 void factor_vm::primitive_clear_samples()
154 {
155         clear_samples();
156 }
157
158 }