Added spec:commit task to commit changes to spec/ruby sources.
[rbx.git] / shotgun / lib / cpu_sample.c
blobbd04c49339e8bfacdb7da91629149502f928b6e8
1 #include <time.h>
2 #include <sys/time.h>
4 #include "shotgun/lib/shotgun.h"
5 #include "shotgun/lib/cpu.h"
6 #include "shotgun/lib/methctx.h"
7 #include "shotgun/lib/machine.h"
8 #include "shotgun/lib/tuple.h"
9 #include "shotgun/lib/string.h"
10 #include "shotgun/lib/methctx.h"
12 #define SAMPLE_INCS 1024
14 void cpu_sampler_init(STATE, cpu c) {
15 state->max_samples = SAMPLE_INCS;
16 state->cur_sample = 0;
17 state->samples = NULL;
20 void cpu_sampler_collect(STATE, OBJECT (*cb)(STATE, void*, OBJECT), void *cb_data) {
21 int i;
22 OBJECT obj;
23 if(!state->samples) return;
25 for(i = 0; i < state->cur_sample; i++) {
26 if(REFERENCE_P(state->samples[i])) {
27 obj = cb(state, cb_data, state->samples[i]);
28 state->samples[i] = obj;
33 /* 2 other recorders, not using them currently.
35 void _cpu_sampler_record_method_object(int sig) {
36 STATE;
37 cpu c;
38 state = current_machine->s;
39 c = current_machine->c;
40 state->samples[state->cur_sample++] = cpu_current_method(state, c);
42 if(state->cur_sample == state->max_samples) {
43 state->max_samples += SAMPLE_INCS;
44 state->samples = (OBJECT*)realloc(state->samples, state->max_samples * sizeof(OBJECT));
48 void _cpu_sampler_record_method_name(int sig) {
49 STATE;
50 cpu c;
51 OBJECT tup;
53 state = current_machine->s;
54 c = current_machine->c;
56 if(!state->samples) return;
58 tup = tuple_new2(state, 3, c->self, cpu_current_module(state, c), cpu_current_name(state, c));
59 state->samples[state->cur_sample++] = tup;
61 if(state->cur_sample == state->max_samples) {
62 state->max_samples += SAMPLE_INCS;
63 state->samples = (OBJECT*)realloc(state->samples, state->max_samples * sizeof(OBJECT));
69 void _cpu_sampler_record_context(int sig) {
70 STATE;
71 cpu c;
73 state = current_machine->s;
74 c = current_machine->c;
76 if(!state->samples) return;
78 /* If we weren't doing anything, nothing to do. */
79 if(NIL_P(c->active_context)) return;
81 /* We don't recycle context's even still, but when we do, rather than using
82 this, we should tell the cpu to just disable all recycling while
83 we sample. */
84 methctx_reference(state, c->active_context);
85 if(c->in_primitive) {
86 state->samples[state->cur_sample++] = APPLY_TAG(c->in_primitive, TAG_FIXNUM);
87 } else {
88 state->samples[state->cur_sample++] = c->active_context;
91 /* Add more space for samples. */
92 if(state->cur_sample == state->max_samples) {
93 OBJECT* chunk;
94 state->max_samples += SAMPLE_INCS;
95 chunk = (OBJECT*)realloc(state->samples, state->max_samples * SIZE_OF_OBJECT);
96 if(chunk != state->samples) {
97 // free(state->samples);
99 state->samples = chunk;
104 void cpu_sampler_suspend(STATE) {
105 if(state->samples) {
106 signal(SIGPROF, SIG_IGN);
110 void cpu_sampler_resume(STATE) {
111 if(state->samples) {
112 signal(SIGPROF, _cpu_sampler_record_context);
116 /* move into state. */
117 static int interval;
119 void cpu_sampler_activate(STATE, int hz) {
120 struct itimerval new, old;
121 new.it_interval.tv_usec = 1000000 / hz;
122 new.it_interval.tv_sec = 0;
123 new.it_value.tv_usec = new.it_interval.tv_usec;
124 new.it_value.tv_sec = 0;
126 interval = new.it_interval.tv_usec;
128 state->max_samples = SAMPLE_INCS;
129 state->cur_sample = 0;
130 state->samples = ALLOC_N(OBJECT, state->max_samples);
132 cpu_sampler_resume(state);
133 setitimer(ITIMER_PROF, &new, &old);
136 OBJECT cpu_sampler_disable(STATE) {
137 OBJECT tup;
138 int i;
139 struct itimerval new, old;
140 clock_t fin;
142 fin = clock();
144 new.it_interval.tv_usec = 0;
145 new.it_interval.tv_sec = 0;
146 new.it_value.tv_usec = 0;
147 new.it_value.tv_sec = 0;
149 cpu_sampler_suspend(state);
150 setitimer(ITIMER_PROF, &new, &old);
152 if(!state->samples) return Qnil;
153 tup = tuple_new(state, state->cur_sample);
154 for(i = 0; i < state->cur_sample; i++) {
155 tuple_put(state, tup, i, state->samples[i]);
158 XFREE(state->samples);
159 state->samples = NULL;
161 return tuple_new2(state, 3, tup, I2N((int)fin), I2N(interval));