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
) {
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) {
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) {
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
) {
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
84 methctx_reference(state
, c
->active_context
);
86 state
->samples
[state
->cur_sample
++] = APPLY_TAG(c
->in_primitive
, TAG_FIXNUM
);
88 state
->samples
[state
->cur_sample
++] = c
->active_context
;
91 /* Add more space for samples. */
92 if(state
->cur_sample
== state
->max_samples
) {
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
) {
106 signal(SIGPROF
, SIG_IGN
);
110 void cpu_sampler_resume(STATE
) {
112 signal(SIGPROF
, _cpu_sampler_record_context
);
116 /* move into state. */
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
) {
139 struct itimerval
new, old
;
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
));