1 /*
2 Copyright (C) 2001-2014, Parrot Foundation.
3
4 =head1 NAME
5
6 src/runcore/subprof.c - Parrot's subroutine-level profiler
7
8 =head1 DESCRIPTION
9
10 This compilation unit implements Parrot's subroutine-level profiler.
11
12 =head2 Functions
13
14 =over 4
15
16 =cut
17
18 */
19
20 #include "parrot/runcore_api.h"
21 #include "parrot/runcore_subprof.h"
22
23 #include "parrot/oplib/ops.h"
24 #include "parrot/oplib/core_ops.h"
25 #include "parrot/dynext.h"
26
27 #include "subprof.str"
28
29 #include "pmc/pmc_sub.h"
30 #include "pmc/pmc_callcontext.h"
31
32 /* HEADERIZER HFILE: include/parrot/runcore_subprof.h */
33
34 /* HEADERIZER BEGIN: static */
35 /* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */
36
37 static void buildcallchain(PARROT_INTERP,
38 ARGIN(subprofiledata *spdata),
39 ARGIN_NULLOK(PMC *ctx),
40 ARGIN_NULLOK(PMC *subpmc))
41 __attribute__nonnull__(1)
42 __attribute__nonnull__(2);
43
44 static void createlines(PARROT_INTERP,
45 ARGIN(subprofiledata *spdata),
46 ARGIN(subprofile *sp))
47 __attribute__nonnull__(1)
48 __attribute__nonnull__(2)
49 __attribute__nonnull__(3);
50
51 static void dump_profile_data(PARROT_INTERP, ARGIN(subprofiledata *spdata))
52 __attribute__nonnull__(1)
53 __attribute__nonnull__(2);
54
55 PARROT_CAN_RETURN_NULL
56 static opcode_t * findlineannotations(PARROT_INTERP,
57 subprofiledata *spdata,
58 ARGIN(subprofile *sp),
59 ARGOUT(size_t *cntp))
60 __attribute__nonnull__(1)
61 __attribute__nonnull__(3)
62 __attribute__nonnull__(4)
63 FUNC_MODIFIES(*cntp);
64
65 static void finishcallchain(PARROT_INTERP, ARGIN(subprofiledata *spdata))
66 __attribute__nonnull__(2);
67
68 static void free_profile_data(PARROT_INTERP, ARGIN(subprofiledata *spdata))
69 __attribute__nonnull__(1)
70 __attribute__nonnull__(2);
71
72 static void free_subprofile(PARROT_INTERP, ARGIN(subprofile *sp))
73 __attribute__nonnull__(2);
74
75 PARROT_WARN_UNUSED_RESULT
76 PARROT_CANNOT_RETURN_NULL
77 static subprofiledata * get_subprofiledata(PARROT_INTERP,
78 ARGIN(Parrot_runcore_t *runcore),
79 int type)
80 __attribute__nonnull__(1)
81 __attribute__nonnull__(2);
82
83 PARROT_INLINE
84 static UHUGEINTVAL getticks(void);
85
86 static void Parrot_runcore_subprof_hll_init(PARROT_INTERP)
87 __attribute__nonnull__(1);
88
89 static void Parrot_runcore_subprof_ops_init(PARROT_INTERP)
90 __attribute__nonnull__(1);
91
92 static void Parrot_runcore_subprof_sub_init(PARROT_INTERP)
93 __attribute__nonnull__(1);
94
95 static void popcallchain(PARROT_INTERP, ARGIN(subprofiledata *spdata))
96 __attribute__nonnull__(2);
97
98 static void printspname(PARROT_INTERP,
99 const subprofiledata *spdata,
100 ARGIN(const subprofile *sp))
101 __attribute__nonnull__(1)
102 __attribute__nonnull__(3);
103
104 static void runops_subprof_destroy(PARROT_INTERP,
105 ARGIN(Parrot_runcore_t *runcore))
106 __attribute__nonnull__(1)
107 __attribute__nonnull__(2);
108
109 PARROT_WARN_UNUSED_RESULT
110 PARROT_CAN_RETURN_NULL
111 static opcode_t * runops_subprof_hll_core(PARROT_INTERP,
112 ARGIN(Parrot_runcore_t *runcore),
113 ARGIN(opcode_t *pc))
114 __attribute__nonnull__(1)
115 __attribute__nonnull__(2)
116 __attribute__nonnull__(3);
117
118 PARROT_WARN_UNUSED_RESULT
119 PARROT_CAN_RETURN_NULL
120 static opcode_t * runops_subprof_ops_core(PARROT_INTERP,
121 ARGIN(Parrot_runcore_t *runcore),
122 ARGIN(opcode_t *pc))
123 __attribute__nonnull__(1)
124 __attribute__nonnull__(2)
125 __attribute__nonnull__(3);
126
127 PARROT_WARN_UNUSED_RESULT
128 PARROT_CAN_RETURN_NULL
129 static opcode_t * runops_subprof_sub_core(PARROT_INTERP,
130 ARGIN(Parrot_runcore_t *runcore),
131 ARGIN(opcode_t *pc))
132 __attribute__nonnull__(1)
133 __attribute__nonnull__(2)
134 __attribute__nonnull__(3);
135
136 PARROT_CANNOT_RETURN_NULL
137 static INTVAL * sptodebug(PARROT_INTERP,
138 ARGMOD(subprofiledata *spdata),
139 ARGIN(const subprofile *sp))
140 __attribute__nonnull__(1)
141 __attribute__nonnull__(2)
142 __attribute__nonnull__(3)
143 FUNC_MODIFIES(*spdata);
144
145 PARROT_INLINE
146 PARROT_CANNOT_RETURN_NULL
147 static char * str2cs(PARROT_INTERP, ARGIN_NULLOK(const STRING *s))
148 __attribute__nonnull__(1);
149
150 PARROT_CANNOT_RETURN_NULL
151 static subprofile * sub2subprofile(PARROT_INTERP,
152 ARGIN(subprofiledata *spdata),
153 PMC *ctx,
154 ARGIN(PMC *subpmc))
155 __attribute__nonnull__(1)
156 __attribute__nonnull__(2)
157 __attribute__nonnull__(4);
158
159 static void sync_callchainchange(PARROT_INTERP,
160 ARGIN(subprofiledata *spdata),
161 ARGIN(PMC *ctx),
162 ARGIN_NULLOK(PMC *subpmc))
163 __attribute__nonnull__(1)
164 __attribute__nonnull__(2)
165 __attribute__nonnull__(3);
166
167 PARROT_CANNOT_RETURN_NULL
168 static lineinfo * sync_hll_linechange(PARROT_INTERP,
169 ARGIN(subprofiledata *spdata),
170 ARGIN_NULLOK(opcode_t *pc_op))
171 __attribute__nonnull__(2);
172
173 #define ASSERT_ARGS_buildcallchain __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
174 PARROT_ASSERT_ARG(interp) \
175 , PARROT_ASSERT_ARG(spdata))
176 #define ASSERT_ARGS_createlines __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
177 PARROT_ASSERT_ARG(interp) \
178 , PARROT_ASSERT_ARG(spdata) \
179 , PARROT_ASSERT_ARG(sp))
180 #define ASSERT_ARGS_dump_profile_data __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
181 PARROT_ASSERT_ARG(interp) \
182 , PARROT_ASSERT_ARG(spdata))
183 #define ASSERT_ARGS_findlineannotations __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
184 PARROT_ASSERT_ARG(interp) \
185 , PARROT_ASSERT_ARG(sp) \
186 , PARROT_ASSERT_ARG(cntp))
187 #define ASSERT_ARGS_finishcallchain __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
188 PARROT_ASSERT_ARG(spdata))
189 #define ASSERT_ARGS_free_profile_data __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
190 PARROT_ASSERT_ARG(interp) \
191 , PARROT_ASSERT_ARG(spdata))
192 #define ASSERT_ARGS_free_subprofile __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
193 PARROT_ASSERT_ARG(sp))
194 #define ASSERT_ARGS_get_subprofiledata __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
195 PARROT_ASSERT_ARG(interp) \
196 , PARROT_ASSERT_ARG(runcore))
197 #define ASSERT_ARGS_getticks __attribute__unused__ int _ASSERT_ARGS_CHECK = (0)
198 #define ASSERT_ARGS_Parrot_runcore_subprof_hll_init \
199 __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
200 PARROT_ASSERT_ARG(interp))
201 #define ASSERT_ARGS_Parrot_runcore_subprof_ops_init \
202 __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
203 PARROT_ASSERT_ARG(interp))
204 #define ASSERT_ARGS_Parrot_runcore_subprof_sub_init \
205 __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
206 PARROT_ASSERT_ARG(interp))
207 #define ASSERT_ARGS_popcallchain __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
208 PARROT_ASSERT_ARG(spdata))
209 #define ASSERT_ARGS_printspname __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
210 PARROT_ASSERT_ARG(interp) \
211 , PARROT_ASSERT_ARG(sp))
212 #define ASSERT_ARGS_runops_subprof_destroy __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
213 PARROT_ASSERT_ARG(interp) \
214 , PARROT_ASSERT_ARG(runcore))
215 #define ASSERT_ARGS_runops_subprof_hll_core __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
216 PARROT_ASSERT_ARG(interp) \
217 , PARROT_ASSERT_ARG(runcore) \
218 , PARROT_ASSERT_ARG(pc))
219 #define ASSERT_ARGS_runops_subprof_ops_core __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
220 PARROT_ASSERT_ARG(interp) \
221 , PARROT_ASSERT_ARG(runcore) \
222 , PARROT_ASSERT_ARG(pc))
223 #define ASSERT_ARGS_runops_subprof_sub_core __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
224 PARROT_ASSERT_ARG(interp) \
225 , PARROT_ASSERT_ARG(runcore) \
226 , PARROT_ASSERT_ARG(pc))
227 #define ASSERT_ARGS_sptodebug __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
228 PARROT_ASSERT_ARG(interp) \
229 , PARROT_ASSERT_ARG(spdata) \
230 , PARROT_ASSERT_ARG(sp))
231 #define ASSERT_ARGS_str2cs __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
232 PARROT_ASSERT_ARG(interp))
233 #define ASSERT_ARGS_sub2subprofile __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
234 PARROT_ASSERT_ARG(interp) \
235 , PARROT_ASSERT_ARG(spdata) \
236 , PARROT_ASSERT_ARG(subpmc))
237 #define ASSERT_ARGS_sync_callchainchange __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
238 PARROT_ASSERT_ARG(interp) \
239 , PARROT_ASSERT_ARG(spdata) \
240 , PARROT_ASSERT_ARG(ctx))
241 #define ASSERT_ARGS_sync_hll_linechange __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
242 PARROT_ASSERT_ARG(spdata))
243 /* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */
244 /* HEADERIZER END: static */
245
246
247 /*
248
249 =item C<static INTVAL * sptodebug(PARROT_INTERP, subprofiledata *spdata, const
250 subprofile *sp)>
251
252 Unpacks the debug segment data into an array indexed by the opcode offset.
253 Hashes the result in spdata->seg2debug.
254
255 =cut
256
257 */
258
259 PARROT_CANNOT_RETURN_NULL
260 static INTVAL *
sptodebug(PARROT_INTERP,ARGMOD (subprofiledata * spdata),ARGIN (const subprofile * sp))261 sptodebug(PARROT_INTERP, ARGMOD(subprofiledata *spdata), ARGIN(const subprofile *sp))
262 {
263 ASSERT_ARGS(sptodebug)
264
265 INTVAL *xdebug;
266 size_t di, op;
267 opcode_t *base_pc, *debug_ops;
268 size_t code_size, debug_size;
269
270 if (!spdata->seg2debug)
271 spdata->seg2debug = Parrot_hash_new_pointer_hash(interp);
272 xdebug = (INTVAL *)Parrot_hash_get(interp, spdata->seg2debug, (void*)sp->subattrs->seg);
273 if (xdebug)
274 return xdebug;
275
276 base_pc = sp->subattrs->seg->base.data;
277 code_size = sp->subattrs->seg->base.size;
278 debug_ops = sp->subattrs->seg->debugs->base.data;
279 debug_size = sp->subattrs->seg->debugs->base.size;
280
281 xdebug = (INTVAL *)mem_sys_allocate_zeroed(code_size * sizeof (INTVAL));
282 for (di = 0, op = 0; op < code_size && di < debug_size; di++) {
283 const op_info_t * const op_info = sp->subattrs->seg->op_info_table[*base_pc];
284 opcode_t opsize = op_info->op_count;
285 ADD_OP_VAR_PART(interp, sp->subattrs->seg, base_pc, opsize);
286 base_pc += opsize;
287 xdebug[op++] = *debug_ops >= 0 ? *debug_ops : -1;
288 while (--opsize > 0) {
289 xdebug[op++] = -2;
290 }
291 debug_ops++;
292 }
293 while (op < code_size)
294 xdebug[op++] = -2;
295 Parrot_hash_put(interp, spdata->seg2debug, (void*)sp->subattrs->seg, (void*)xdebug);
296 return xdebug;
297 }
298
299 /*
300
301 =item C<static char * str2cs(PARROT_INTERP, const STRING *s)>
302
303 Convert a STRING* to a char*, or a STRINGNULL to "STRINGNULL".
304
305 =cut
306
307 */
308
309 PARROT_INLINE
310 PARROT_CANNOT_RETURN_NULL
311 static char *
str2cs(PARROT_INTERP,ARGIN_NULLOK (const STRING * s))312 str2cs(PARROT_INTERP, ARGIN_NULLOK(const STRING *s))
313 {
314 ASSERT_ARGS(str2cs)
315
316 if (s == STRINGNULL)
317 return mem_sys_strdup("STRNULL");
318 return Parrot_str_to_cstring(interp, s);
319 }
320
321
322 /*
323
324 =item C<static opcode_t * findlineannotations(PARROT_INTERP, subprofiledata
325 *spdata, subprofile *sp, size_t *cntp)>
326
327 Return a pointer to the first line annotation of the sub and the number
328 of line annotations for this sub.
329
330 The C<spdata> argument is currently unused.
331
332 =cut
333
334 */
335
336 PARROT_CAN_RETURN_NULL
337 static opcode_t *
findlineannotations(PARROT_INTERP,SHIM (subprofiledata * spdata),ARGIN (subprofile * sp),ARGOUT (size_t * cntp))338 findlineannotations(PARROT_INTERP,
339 SHIM(subprofiledata *spdata),
340 ARGIN(subprofile *sp),
341 ARGOUT(size_t *cntp))
342 {
343 ASSERT_ARGS(findlineannotations)
344
345 int i;
346 size_t j,
347 cnt,
348 first;
349
350 PackFile_Annotations *ann = sp->subattrs->seg->annotations;
351 PackFile_Annotations_Key *key;
352 STRING *line_str;
353
354 if (!ann)
355 return NULL;
356
357 line_str = Parrot_str_new_constant(interp, "line");
358
359 /* search for the first line annotation in our sub */
360 for (i = 0; i < ann->num_keys; i++) {
361 STRING * const test_key = ann->code->const_table->str.constants[ann->keys[i].name];
362
363 if (STRING_equal(interp, test_key, line_str))
364 break;
365 }
366
367 if (i == ann->num_keys)
368 return NULL; /* no annotations with this key */
369
370 cnt = 0;
371 first = 0;
372 key = ann->keys + i;
373
374 for (j = key->start; j < key->start + key->len; j++) {
375 if ((size_t)ann->base.data[j * 2 + ANN_ENTRY_OFF] < sp->subattrs->start_offs)
376 continue;
377 if ((size_t)ann->base.data[j * 2 + ANN_ENTRY_OFF] >= sp->subattrs->end_offs)
378 break;
379 if (!cnt++) {
380 first = j;
381 }
382 }
383
384 *cntp = cnt;
385
386 return cnt ? ann->base.data + first * 2 : NULL;
387 }
388
389
390 /*
391
392 =item C<static void createlines(PARROT_INTERP, subprofiledata *spdata,
393 subprofile *sp)>
394
395 Create the lines array from the annotations/debug segment. Every line
396 describes a opcode segment.
397 Also sets sp->srcfile and sp->srcline.
398
399 =cut
400
401 */
402
403 static void
createlines(PARROT_INTERP,ARGIN (subprofiledata * spdata),ARGIN (subprofile * sp))404 createlines(PARROT_INTERP, ARGIN(subprofiledata *spdata), ARGIN(subprofile *sp))
405 {
406 ASSERT_ARGS(createlines)
407
408 if (spdata->profile_type == SUBPROF_TYPE_OPS) {
409 int i, lasti;
410 INTVAL *xdebug = sptodebug(interp, spdata, sp);
411
412 sp->nlines = sp->subattrs->end_offs - sp->subattrs->start_offs;
413 sp->lines = (lineinfo *) mem_sys_allocate_zeroed(
414 ((sp->nlines ? sp->nlines : 1) + 1) * sizeof (lineinfo));
415 sp->lines[0].op_offs = sp->subattrs->start_offs; /* just in case */
416
417 for (i = lasti = 0; i < sp->nlines; i++) {
418 INTVAL line = xdebug[sp->subattrs->start_offs + i];
419
420 if (line != -2) {
421 sp->lines[i].op_offs = sp->subattrs->start_offs + i;
422 sp->lines[lasti + 1].op_offs = sp->subattrs->start_offs + i;
423 lasti = i;
424 }
425 }
426
427 {
428 STRING *filename = Parrot_sub_get_filename_from_pc(interp,
429 sp->subpmc,
430 sp->code_ops
431 + sp->subattrs->start_offs);
432
433 sp->lines[lasti + 1].op_offs = sp->subattrs->end_offs;
434 sp->srcline = xdebug[sp->subattrs->start_offs];
435 sp->srcfile = str2cs(interp, filename);
436 }
437
438 return;
439 }
440
441 if (sp->subattrs->seg->annotations) {
442 PackFile_Annotations *ann = sp->subattrs->seg->annotations;
443 size_t cnt = 0;
444 opcode_t *anndata = findlineannotations(interp, spdata, sp, &cnt);
445
446 if (anndata) {
447 PMC *srcfilepmc;
448 size_t i, j;
449
450 if (spdata->profile_type == SUBPROF_TYPE_SUB) {
451 /* we just need the first annotation for sub profiling */
452 cnt = 1;
453 }
454
455 /* set srcfile and srcline */
456 sp->srcline = anndata[ANN_ENTRY_VAL];
457 /* + 1 needed because Annotations_lookup looks up the annotation _before_ the pc */
458 srcfilepmc = Parrot_pf_annotations_lookup(interp,
459 ann,
460 anndata[ANN_ENTRY_OFF] + 1,
461 Parrot_str_new_constant(interp, "file"));
462
463 if (PMC_IS_NULL(srcfilepmc))
464 sp->srcfile = mem_sys_strdup("???");
465 else
466 sp->srcfile = str2cs(interp, VTABLE_get_string(interp, srcfilepmc));
467
468 sp->lines = (lineinfo *) mem_sys_allocate_zeroed((cnt + 1) * sizeof (lineinfo));
469
470 for (i = j = 0; i < cnt; i++) {
471 if (j && sp->lines[j - 1].op_offs == (size_t)anndata[i * 2 + ANN_ENTRY_OFF]) {
472 /* no empty segments, please */
473 continue;
474 }
475
476 sp->lines[j++].op_offs = anndata[i * 2 + ANN_ENTRY_OFF];
477 }
478
479 sp->lines[0].op_offs = sp->subattrs->start_offs; /* workaround */
480 sp->lines[j].op_offs = sp->subattrs->end_offs;
481
482 if (j > 1 && sp->lines[j - 1].op_offs == sp->subattrs->end_offs)
483 /* no empty segments, please */
484 j--;
485
486 sp->nlines = j;
487 }
488 }
489
490 if (!sp->nlines) {
491 /* no annotations, fall back to debug segment */
492 STRING *filename = Parrot_sub_get_filename_from_pc(interp,
493 sp->subpmc,
494 sp->code_ops
495 + sp->subattrs->start_offs);
496
497 sp->srcline = Parrot_sub_get_line_from_pc(interp,
498 sp->subpmc,
499 sp->code_ops + sp->subattrs->start_offs);
500 sp->srcfile = str2cs(interp, filename);
501 sp->lines = (lineinfo *) mem_sys_allocate_zeroed((1 + 1) * sizeof (lineinfo));
502 sp->lines[0].op_offs = sp->subattrs->start_offs;
503 sp->lines[1].op_offs = sp->subattrs->end_offs;
504 sp->nlines = 1;
505 }
506 }
507
508 /*
509
510 =item C<static subprofile * sub2subprofile(PARROT_INTERP, subprofiledata
511 *spdata, PMC *ctx, PMC *subpmc)>
512
513 ...
514
515 The C<ctx> argument is currently unused.
516
517 =cut
518
519 */
520
521 PARROT_CANNOT_RETURN_NULL
522 static subprofile *
sub2subprofile(PARROT_INTERP,ARGIN (subprofiledata * spdata),SHIM (PMC * ctx),ARGIN (PMC * subpmc))523 sub2subprofile(PARROT_INTERP, ARGIN(subprofiledata *spdata), SHIM(PMC *ctx), ARGIN(PMC *subpmc))
524 {
525 ASSERT_ARGS(sub2subprofile)
526
527 subprofile *sp;
528 Parrot_Sub_attributes *subattrs;
529
530 PMC_get_sub(interp, subpmc, subattrs);
531
532 if (!spdata->sphash)
533 spdata->sphash = Parrot_hash_new_pointer_hash(interp);
534
535 sp = (subprofile *) Parrot_hash_get(interp,
536 spdata->sphash,
537 (void *) (subattrs->seg->base.data
538 + subattrs->start_offs));
539
540 if (!sp) {
541 sp = (subprofile *) mem_sys_allocate_zeroed(sizeof (subprofile));
542 sp->subattrs = subattrs;
543 sp->subpmc = subpmc;
544 sp->code_ops = sp->subattrs->seg->base.data;
545
546 createlines(interp, spdata, sp);
547
548 Parrot_hash_put(interp,
549 spdata->sphash,
550 (void *) (subattrs->seg->base.data + subattrs->start_offs),
551 (void *) sp);
552
553 VTABLE_push_pmc(interp, spdata->markpmcs, subpmc);
554 }
555
556 return sp;
557 }
558
559
560 /*
561
562 =item C<static void popcallchain(PARROT_INTERP, subprofiledata *spdata)>
563
564 ...
565
566 =cut
567
568 */
569
570 static void
popcallchain(SHIM_INTERP,ARGIN (subprofiledata * spdata))571 popcallchain(SHIM_INTERP, ARGIN(subprofiledata *spdata))
572 {
573 ASSERT_ARGS(popcallchain)
574
575 subprofile * const sp = spdata->cursp;
576 subprofile * const csp = sp->caller;
577
578 if (sp->callerci) {
579 sp->callerci->ops += sp->callerops;
580 sp->callerci->ticks += sp->callerticks;
581 }
582
583 if (csp) {
584 csp->callerops += sp->callerops;
585 csp->callerticks += sp->callerticks;
586 }
587
588 sp->caller = NULL;
589 sp->callerci = NULL;
590 sp->ctx = NULL;
591 sp->callerops = 0;
592 sp->callerticks = 0;
593
594 spdata->cursubpmc = csp ? csp->subpmc : NULL;
595 spdata->curctx = csp ? csp->ctx : NULL;
596 spdata->cursp = csp;
597 }
598
599 /*
600
601 =item C<static void finishcallchain(PARROT_INTERP, subprofiledata *spdata)>
602
603 Propagate timing information up the call chain, clearing out old frames during
604 the process.
605
606 =cut
607
608 */
609
610 static void
finishcallchain(SHIM_INTERP,ARGIN (subprofiledata * spdata))611 finishcallchain(SHIM_INTERP, ARGIN(subprofiledata *spdata))
612 {
613 ASSERT_ARGS(finishcallchain)
614
615 subprofile *sp, *csp;
616
617 /* finish all calls */
618 for (sp = spdata->cursp; sp; sp = csp) {
619 csp = sp->caller;
620
621 if (sp->callerci) {
622 sp->callerci->ops += sp->callerops;
623 sp->callerci->ticks += sp->callerticks;
624 }
625
626 if (csp) {
627 csp->callerops += sp->callerops;
628 csp->callerticks += sp->callerticks;
629 }
630
631 sp->caller = NULL;
632 sp->callerci = NULL;
633 sp->ctx = NULL;
634 sp->callerops = 0;
635 sp->callerticks = 0;
636 }
637
638 spdata->cursp = NULL;
639 spdata->curctx = NULL;
640 spdata->cursubpmc = NULL;
641 }
642
643 /*
644
645 =item C<static void buildcallchain(PARROT_INTERP, subprofiledata *spdata, PMC
646 *ctx, PMC *subpmc)>
647
648 ...
649
650 =cut
651
652 */
653
654 static void
buildcallchain(PARROT_INTERP,ARGIN (subprofiledata * spdata),ARGIN_NULLOK (PMC * ctx),ARGIN_NULLOK (PMC * subpmc))655 buildcallchain(PARROT_INTERP,
656 ARGIN(subprofiledata *spdata),
657 ARGIN_NULLOK(PMC *ctx),
658 ARGIN_NULLOK(PMC *subpmc))
659 {
660 ASSERT_ARGS(buildcallchain)
661
662 PMC *cctx;
663 subprofile *sp;
664 lineinfo *li;
665
666 cctx = Parrot_pcc_get_caller_ctx(interp, ctx);
667
668 if (cctx) {
669 PMC * const csubpmc = Parrot_pcc_get_sub(interp, cctx);
670 if (spdata->curctx != cctx || spdata->cursubpmc != csubpmc)
671 buildcallchain(interp, spdata, cctx, csubpmc);
672 }
673
674 if (PMC_IS_NULL(subpmc))
675 return;
676
677 /* find the correct subprofile */
678 sp = sub2subprofile(interp, spdata, ctx, subpmc);
679
680 while (sp->ctx) {
681 /* recursion! */
682 if (!sp->rnext) {
683 subprofile *rsp;
684 rsp = (subprofile *)mem_sys_allocate_zeroed(sizeof (subprofile));
685 rsp->subattrs = sp->subattrs;
686 rsp->subpmc = sp->subpmc;
687 rsp->code_ops = sp->code_ops;
688 rsp->rcnt = sp->rcnt + 1;
689 rsp->srcline = sp->srcline;
690 rsp->srcfile = mem_sys_strdup(sp->srcfile);
691 sp->rnext = rsp;
692 if (sp->nlines) {
693 int i;
694 rsp->lines = (lineinfo *)mem_sys_allocate_zeroed(
695 (sp->nlines + 1) * sizeof (lineinfo));
696 rsp->nlines = sp->nlines;
697 for (i = 0; i < sp->nlines + 1; i++)
698 rsp->lines[i].op_offs = sp->lines[i].op_offs;
699 }
700 }
701 sp = sp->rnext;
702 }
703
704 sp->ctx = ctx;
705 sp->caller = spdata->cursp;
706
707 if (sp->caller) {
708 subprofile * const csp = sp->caller;
709
710 /* get caller pc */
711 opcode_t * const cpc_op = Parrot_pcc_get_pc(interp, csp->ctx);
712 size_t cpc = cpc_op ? cpc_op - csp->code_ops : 0;
713
714 if (cpc > csp->subattrs->start_offs)
715 cpc--;
716
717 /* convert cpc into line */
718 if (spdata->profile_type != SUBPROF_TYPE_OPS) {
719 int i;
720 /* might do a binary seach instead */
721 for (i = 0, li = csp->lines; i < csp->nlines; i++, li++)
722 if (cpc >= li->op_offs && cpc < li[1].op_offs)
723 break;
724
725 if (i >= csp->nlines)
726 li = csp->lines - 1; /* just in case */
727 }
728 else {
729 li = csp->lines + (cpc - csp->subattrs->start_offs);
730
731 while (li > csp->lines && (li->op_offs == 0 || li->op_offs > cpc))
732 li--;
733 }
734 }
735 else {
736 li = &spdata->rootline;
737 }
738
739 if (li) {
740 /* add caller to line */
741 callinfo *ci;
742
743 if (!li->calls) {
744 li->calls = (callinfo *) mem_sys_allocate((1 + 8) * sizeof (*ci));
745 ci = li->calls;
746 ci->callee = NULL;
747 }
748 else {
749 for (ci = li->calls; ci->callee; ci++)
750 if (ci->callee == sp)
751 break;
752
753 if (!ci->callee) {
754 int ncalls = ci - li->calls;
755
756 if ((ncalls & 7) == 0) {
757 li->calls = (callinfo *) mem_sys_realloc(
758 li->calls, (ncalls + (1 + 8)) * sizeof (*ci));
759 ci = li->calls + ncalls;
760 }
761 }
762 }
763
764 if (!ci->callee) {
765 memset(ci, 0, sizeof (*ci));
766 ci->callee = sp;
767 ci[1].callee = NULL;
768 }
769
770 sp->callerci = ci;
771 }
772 else {
773 sp->callerci = NULL;
774 }
775
776 spdata->cursp = sp;
777 spdata->curctx = ctx;
778 spdata->cursubpmc = subpmc;
779 }
780
781 /*
782
783 =item C<static void printspname(PARROT_INTERP, const subprofiledata *spdata,
784 const subprofile *sp)>
785
786 Prints the name of the subprofile given in C<sp>.
787
788 The C<spdata> argument is currently unused.
789
790 =cut
791
792 */
793
794 static void
printspname(PARROT_INTERP,SHIM (const subprofiledata * spdata),ARGIN (const subprofile * sp))795 printspname(PARROT_INTERP, SHIM(const subprofiledata *spdata), ARGIN(const subprofile *sp))
796 {
797 ASSERT_ARGS(printspname)
798
799 char * const cname = str2cs(interp, sp->subattrs->name);
800
801 fprintf(stderr, "%p:%s", sp, cname);
802
803 if (sp->rcnt)
804 fprintf(stderr, "'%d", sp->rcnt);
805
806 mem_sys_free(cname);
807 }
808
809 /*
810
811 =item C<static void dump_profile_data(PARROT_INTERP, subprofiledata *spdata)>
812
813 After the program has completed, print the resulting callgrind-compatible
814 profile to stderr.
815
816 =cut
817
818 */
819
820
821 static void
dump_profile_data(PARROT_INTERP,ARGIN (subprofiledata * spdata))822 dump_profile_data(PARROT_INTERP, ARGIN(subprofiledata *spdata))
823 {
824 ASSERT_ARGS(dump_profile_data)
825
826 unsigned int totalops = 0;
827 UHUGEINTVAL totalticks = 0;
828
829 #ifdef HAS_LONGLONG
830 # define UHUGEINTVAL_FMT "%llu"
831 #else
832 # define UHUGEINTVAL_FMT "%lu"
833 #endif
834
835 if (!spdata->profile_type)
836 return;
837
838 finishcallchain(interp, spdata); /* just in case */
839
840 if (!spdata->sphash)
841 spdata->sphash = Parrot_hash_create(interp, enum_type_ptr, Hash_key_type_PMC_ptr);
842
843 parrot_hash_iterate(spdata->sphash,
844 subprofile *hsp = (subprofile*)_bucket->value;
845 subprofile *sp;
846
847 for (sp = hsp; sp; sp = sp->rnext) {
848 int j;
849 for (j = 0; j < sp->nlines; j++) {
850 totalops += sp->lines[j].ops;
851 totalticks += sp->lines[j].ticks;
852 }
853 });
854
855 fprintf(stderr, "events: ops ticks\n");
856 fprintf(stderr, "summary: %d "UHUGEINTVAL_FMT"\n", totalops, totalticks);
857
858 parrot_hash_iterate(spdata->sphash,
859 subprofile *hsp = (subprofile*)_bucket->value;
860 subprofile *sp;
861
862 for (sp = hsp; sp; sp = sp->rnext) {
863 opcode_t *anndata = NULL;
864 INTVAL *xdebug = NULL;
865 size_t cnt = 0;
866 int i;
867
868 if (spdata->profile_type != SUBPROF_TYPE_OPS)
869 anndata = findlineannotations(interp, spdata, sp, &cnt);
870 else
871 xdebug = sptodebug(interp, spdata, sp);
872
873 fprintf(stderr, "\n");
874 fprintf(stderr, "fl=%s\n", sp->srcfile);
875 fprintf(stderr, "fn=");
876 printspname(interp, spdata, sp);
877 fprintf(stderr, "\n");
878
879 for (i = 0; i < sp->nlines; i++) {
880 lineinfo *li = sp->lines + i;
881 callinfo *ci;
882 INTVAL srcline = -1;
883 if (!li->ops && !li->ticks && !li->calls)
884 continue;
885 if (i == 0) {
886 /* easy for the first annotation */
887 srcline = sp->srcline;
888 }
889 else {
890 if (spdata->profile_type == SUBPROF_TYPE_OPS) {
891 srcline = xdebug[sp->subattrs->start_offs + i];
892 }
893 else if (anndata) {
894 while (cnt > 1 && (size_t) anndata[ANN_ENTRY_OFF + 2] <= li->op_offs) {
895 anndata += 2;
896 cnt--;
897 }
898 srcline = anndata[ANN_ENTRY_VAL];
899 anndata += 2;
900 cnt--;
901 }
902 }
903
904 if (li->ops || li->ticks)
905 fprintf(stderr,
906 "%d %u "UHUGEINTVAL_FMT"\n",
907 (int) srcline,
908 (unsigned int) li->ops,
909 li->ticks);
910
911 for (ci = li->calls; ci && ci->callee; ci++) {
912 subprofile *csp = ci->callee;
913 fprintf(stderr, "cfl=%s\n", csp->srcfile);
914 fprintf(stderr, "cfn=");
915 printspname(interp, spdata, csp);
916 fprintf(stderr, "\n");
917 fprintf(stderr, "calls=%u %d\n", (unsigned int) ci->count, (int) csp->srcline);
918 fprintf(stderr,
919 "%d %u "UHUGEINTVAL_FMT"\n",
920 (int) srcline,
921 (unsigned int) ci->ops,
922 ci->ticks);
923 }
924 }
925 });
926
927 /* also dump profiling root if there are more than one callees */
928 if (spdata->rootline.calls
929 && spdata->rootline.calls[0].callee
930 && spdata->rootline.calls[1].callee) {
931
932 lineinfo *li = &spdata->rootline;
933 callinfo *ci;
934
935 fprintf(stderr, "\n");
936 fprintf(stderr, "fl=\n");
937 fprintf(stderr, "fn=__profiling_root__\n");
938
939 for (ci = li->calls; ci && ci->callee; ci++) {
940 subprofile *csp = ci->callee;
941 fprintf(stderr, "cfl=%s\n", csp->srcfile);
942 fprintf(stderr, "cfn=");
943 printspname(interp, spdata, csp);
944 fprintf(stderr, "\n");
945 fprintf(stderr, "calls=%u %d\n", (unsigned int) ci->count, (int) csp->srcline);
946 fprintf(stderr,
947 "%d %u "UHUGEINTVAL_FMT"\n",
948 0,
949 (unsigned int) ci->ops,
950 ci->ticks);
951 }
952 }
953
954 fprintf(stderr, "\ntotals: %d "UHUGEINTVAL_FMT"\n", totalops, totalticks);
955 }
956
957
958 /*
959
960 =item C<static void free_subprofile(PARROT_INTERP, subprofile *sp)>
961
962 free memory we allocated for this subprofile
963
964 =cut
965
966 */
967
968 static void
free_subprofile(SHIM_INTERP,ARGIN (subprofile * sp))969 free_subprofile(SHIM_INTERP, ARGIN(subprofile *sp))
970 {
971 ASSERT_ARGS(free_subprofile)
972
973 if (sp->srcfile)
974 mem_sys_free(sp->srcfile);
975
976 if (sp->lines) {
977 int i;
978
979 for (i = 0; i < sp->nlines; i++) {
980 lineinfo *li = sp->lines + i;
981
982 if (li->calls)
983 mem_sys_free(li->calls);
984 }
985
986 mem_sys_free(sp->lines);
987 }
988
989 mem_sys_free(sp);
990 }
991
992
993 /*
994
995 =item C<static void free_profile_data(PARROT_INTERP, subprofiledata *spdata)>
996
997 Free all profile data that's been accumulated.
998
999 =cut
1000
1001 */
1002
1003 static void
free_profile_data(PARROT_INTERP,ARGIN (subprofiledata * spdata))1004 free_profile_data(PARROT_INTERP, ARGIN(subprofiledata *spdata))
1005 {
1006 ASSERT_ARGS(free_profile_data)
1007
1008 if (spdata->sphash) {
1009 parrot_hash_iterate(spdata->sphash,
1010 subprofile *sp = (subprofile*)_bucket->value;
1011 subprofile *rsp;
1012 for (; sp; sp = rsp) {
1013 rsp = sp->rnext;
1014 free_subprofile(interp, sp);
1015 });
1016 Parrot_hash_destroy(interp, spdata->sphash);
1017 }
1018 Parrot_pmc_gc_unregister(interp, spdata->markpmcs);
1019 spdata->markpmcs = NULL;
1020
1021 if (spdata->rootline.calls)
1022 mem_sys_free(spdata->rootline.calls);
1023
1024 if (spdata->seg2debug) {
1025 parrot_hash_iterate(spdata->seg2debug,
1026 INTVAL *xdebug = (INTVAL *)_bucket->value;
1027 mem_sys_free(xdebug););
1028 Parrot_hash_destroy(interp, spdata->seg2debug);
1029 }
1030 mem_sys_free(spdata);
1031 }
1032
1033 /*
1034
1035 =item C<static UHUGEINTVAL getticks(void)>
1036
1037 Returns a high-resolution number representing how long Parrot has been running.
1038
1039 Inline operation.
1040
1041 =cut
1042
1043 */
1044
1045 /*
1046
1047 =item C<static UHUGEINTVAL getticks(void)>
1048
1049 Returns a high-resolution number representing how long Parrot has been running.
1050
1051 =cut
1052
1053 */
1054
1055
1056 PARROT_INLINE
1057 static UHUGEINTVAL
getticks(void)1058 getticks(void) {
1059 ASSERT_ARGS(getticks)
1060 #if defined(__GNUC__) && (defined(__i386) || defined(__x86_64))
1061
1062 unsigned lo, hi;
1063 __asm__ __volatile__("rdtsc" : "=a" (lo), "=d" (hi));
1064 return (UHUGEINTVAL) hi << 32 | lo;
1065 #else
1066 return Parrot_hires_get_time();
1067 #endif
1068 }
1069
1070 /*
1071
1072 =item C<static void sync_callchainchange(PARROT_INTERP, subprofiledata *spdata,
1073 PMC *ctx, PMC *subpmc)>
1074
1075 Brings the profile context chain back in sync with the context's call chain.
1076
1077 =cut
1078
1079 */
1080
1081 static void
sync_callchainchange(PARROT_INTERP,ARGIN (subprofiledata * spdata),ARGIN (PMC * ctx),ARGIN_NULLOK (PMC * subpmc))1082 sync_callchainchange(PARROT_INTERP,
1083 ARGIN(subprofiledata *spdata),
1084 ARGIN(PMC *ctx),
1085 ARGIN_NULLOK(PMC *subpmc))
1086 {
1087 ASSERT_ARGS(sync_callchainchange)
1088
1089 subprofile *sp = spdata->cursp;
1090
1091 if (sp) {
1092 /* optimize common cases */
1093 /* did we just return? */
1094 if (sp->caller && sp->caller->subpmc == subpmc && sp->caller->ctx == ctx) {
1095 /* a simple return */
1096 popcallchain(interp, spdata);
1097 }
1098 else {
1099 PMC *cctx = Parrot_pcc_get_caller_ctx(interp, ctx);
1100 PMC *csubpmc = Parrot_pcc_get_sub(interp, cctx);
1101
1102 if (spdata->curctx == cctx && spdata->cursubpmc == csubpmc) {
1103 /* a simple call */
1104 buildcallchain(interp, spdata, ctx, subpmc);
1105 }
1106 else if (sp->caller && sp->caller->subpmc == csubpmc && sp->caller->ctx == cctx) {
1107 /* some kind of tailcall */
1108 popcallchain(interp, spdata);
1109 buildcallchain(interp, spdata, ctx, subpmc);
1110 }
1111 }
1112 }
1113
1114 if (subpmc != spdata->cursubpmc || ctx != spdata->curctx) {
1115 /* out of luck! redo call chain */
1116 finishcallchain(interp, spdata);
1117 buildcallchain(interp, spdata, ctx, subpmc);
1118 }
1119
1120 }
1121
1122
1123 /*
1124
1125 =item C<static lineinfo * sync_hll_linechange(PARROT_INTERP, subprofiledata
1126 *spdata, opcode_t *pc_op)>
1127
1128 bring the line data in sync with the pc
1129
1130 =cut
1131
1132 */
1133
1134 PARROT_CANNOT_RETURN_NULL
1135 static lineinfo *
sync_hll_linechange(SHIM_INTERP,ARGIN (subprofiledata * spdata),ARGIN_NULLOK (opcode_t * pc_op))1136 sync_hll_linechange(SHIM_INTERP, ARGIN(subprofiledata *spdata), ARGIN_NULLOK(opcode_t *pc_op))
1137 {
1138 ASSERT_ARGS(sync_hll_linechange)
1139
1140 const subprofile * const sp = spdata->cursp;
1141 lineinfo *li;
1142
1143 if (sp->nlines > 1) {
1144 const size_t pc = pc_op ? pc_op - sp->code_ops : 0;
1145 int i;
1146
1147 for (i = 0, li = sp->lines; i < sp->nlines; i++, li++)
1148 if (pc >= li->op_offs && pc < li[1].op_offs)
1149 break;
1150
1151 if (i == sp->nlines)
1152 li = sp->lines; /* just in case */
1153 }
1154 else {
1155 li = sp->lines;
1156 }
1157
1158 return li;
1159 }
1160
1161 /*
1162
1163 =item C<static subprofiledata * get_subprofiledata(PARROT_INTERP,
1164 Parrot_runcore_t *runcore, int type)>
1165
1166 Returns the subprofile data for C<runcore>.
1167
1168 The C<type> parameter specifies the type of data to return. Accepted values
1169 are C<SUBPROF_TYPE_SUB>, C<SUBPROF_TYPE_HLL>, or C<SUBPROF_TYPE_OPS>.
1170
1171 =cut
1172
1173 */
1174
1175 PARROT_WARN_UNUSED_RESULT
1176 PARROT_CANNOT_RETURN_NULL
1177 static subprofiledata *
get_subprofiledata(PARROT_INTERP,ARGIN (Parrot_runcore_t * runcore),int type)1178 get_subprofiledata(PARROT_INTERP, ARGIN(Parrot_runcore_t *runcore), int type)
1179 {
1180 ASSERT_ARGS(get_subprofiledata)
1181
1182 Parrot_subprof_runcore_t *core = (Parrot_subprof_runcore_t *) runcore;
1183 subprofiledata *spdata = core->spdata;
1184
1185 if (!spdata) {
1186 spdata = (subprofiledata *) mem_sys_allocate_zeroed(sizeof (subprofiledata));
1187 spdata->profile_type = type;
1188 spdata->interp = interp;
1189 spdata->markpmcs = Parrot_pmc_new(interp, enum_class_ResizablePMCArray);
1190 Parrot_pmc_gc_register(interp, spdata->markpmcs);
1191 core->spdata = spdata;
1192 }
1193
1194 if (spdata->profile_type != type)
1195 Parrot_ex_throw_from_c_noargs(interp, EXCEPTION_INVALID_OPERATION,
1196 "illegal profile type change while profiling");
1197 if (spdata->interp != interp)
1198 Parrot_ex_throw_from_c_noargs(interp, EXCEPTION_INVALID_OPERATION,
1199 "illegal interpreter change while profiling");
1200
1201 return core->spdata;
1202 }
1203
1204
1205 #ifdef code_start
1206 # undef code_start
1207 #endif
1208 #ifdef code_end
1209 # undef code_end
1210 #endif
1211
1212 #define code_start interp->code->base.data
1213 #define code_end (interp->code->base.data + interp->code->base.size)
1214
1215 /*
1216
1217 =item C<static void runops_subprof_destroy(PARROT_INTERP, Parrot_runcore_t
1218 *runcore)>
1219
1220 Destroy callback. We use it to print the profile data.
1221
1222 */
1223
1224 static void
runops_subprof_destroy(PARROT_INTERP,ARGIN (Parrot_runcore_t * runcore))1225 runops_subprof_destroy(PARROT_INTERP, ARGIN(Parrot_runcore_t *runcore))
1226 {
1227 ASSERT_ARGS(runops_subprof_destroy)
1228
1229 Parrot_subprof_runcore_t *core = (Parrot_subprof_runcore_t *)runcore;
1230
1231 if (core->spdata) {
1232 dump_profile_data(interp, core->spdata);
1233 free_profile_data(interp, core->spdata);
1234 core->spdata = NULL;
1235 }
1236 }
1237
1238 /*
1239
1240 =item C<static opcode_t * runops_subprof_sub_core(PARROT_INTERP,
1241 Parrot_runcore_t *runcore, opcode_t *pc)>
1242
1243 Runs the opcodes starting at C<pc> until none remain. Runs bounds checking.
1244
1245 =cut
1246
1247 */
1248
1249 PARROT_WARN_UNUSED_RESULT
1250 PARROT_CAN_RETURN_NULL
1251 static opcode_t *
runops_subprof_sub_core(PARROT_INTERP,ARGIN (Parrot_runcore_t * runcore),ARGIN (opcode_t * pc))1252 runops_subprof_sub_core(PARROT_INTERP, ARGIN(Parrot_runcore_t *runcore), ARGIN(opcode_t *pc))
1253 {
1254 ASSERT_ARGS(runops_subprof_sub_core)
1255
1256 PMC *ctx,
1257 *subpmc;
1258
1259 subprofiledata *spdata = get_subprofiledata(interp, runcore, SUBPROF_TYPE_SUB);
1260 subprofile *sp = spdata->cursp;
1261
1262 while (pc) {
1263 if (pc < code_start || pc >= code_end)
1264 Parrot_ex_throw_from_c_noargs(interp, EXCEPTION_OUT_OF_BOUNDS,
1265 "attempt to access code outside of current code segment");
1266
1267 ctx = CURRENT_CONTEXT(interp);
1268 Parrot_pcc_set_pc(interp, ctx, pc);
1269 subpmc = ((Parrot_Context *) PMC_data_typed(ctx, Parrot_Context *))->current_sub;
1270
1271 if (!PMC_IS_NULL(subpmc)) {
1272 if (subpmc != spdata->cursubpmc || ctx != spdata->curctx) {
1273 /* context changed! either called new sub or returned from sub */
1274
1275 /* finish old ticks */
1276 UHUGEINTVAL tick = getticks();
1277 if (spdata->tickadd) {
1278 UHUGEINTVAL tickdiff = tick - spdata->starttick;
1279 *spdata->tickadd += tickdiff;
1280 *spdata->tickadd2 += tickdiff;
1281 }
1282 sync_callchainchange(interp, spdata, ctx, subpmc);
1283 sp = spdata->cursp;
1284 if (pc == sp->code_ops + sp->subattrs->start_offs) {
1285 /* assume new call */
1286 if (sp->callerci)
1287 sp->callerci->count++;
1288 }
1289 spdata->tickadd = &sp->lines->ticks;
1290 spdata->tickadd2 = &sp->callerticks;
1291 spdata->starttick = getticks();
1292 }
1293
1294 sp->lines->ops++;
1295 sp->callerops++;
1296 }
1297 DO_OP(pc, interp);
1298 }
1299
1300 return pc;
1301 }
1302
1303 /*
1304
1305 =item C<static void Parrot_runcore_subprof_sub_init(PARROT_INTERP)>
1306
1307 Registers the subprof_sub runcore with Parrot.
1308
1309 =cut
1310
1311 */
1312
1313 static void
Parrot_runcore_subprof_sub_init(PARROT_INTERP)1314 Parrot_runcore_subprof_sub_init(PARROT_INTERP)
1315 {
1316 ASSERT_ARGS(Parrot_runcore_subprof_sub_init)
1317
1318 Parrot_subprof_runcore_t * const coredata
1319 = mem_gc_allocate_zeroed_typed(interp, Parrot_subprof_runcore_t);
1320 coredata->name = CONST_STRING(interp, "subprof_sub");
1321 coredata->id = PARROT_SUBPROF_SUB_CORE;
1322 coredata->opinit = PARROT_CORE_OPLIB_INIT;
1323 coredata->runops = runops_subprof_sub_core;
1324 coredata->prepare_run = NULL;
1325 coredata->destroy = runops_subprof_destroy;
1326 coredata->flags = 0;
1327
1328 PARROT_RUNCORE_FUNC_TABLE_SET(coredata);
1329
1330 Parrot_runcore_register(interp, (Parrot_runcore_t *)coredata);
1331 }
1332
1333 /*
1334
1335 =item C<static opcode_t * runops_subprof_hll_core(PARROT_INTERP,
1336 Parrot_runcore_t *runcore, opcode_t *pc)>
1337
1338 Runs the Parrot operations starting at C<pc> until there are no more
1339 operations, with sub-level profiling and bounds checking enabled.
1340
1341 =cut
1342
1343 */
1344
1345 PARROT_WARN_UNUSED_RESULT
1346 PARROT_CAN_RETURN_NULL
1347 static opcode_t *
runops_subprof_hll_core(PARROT_INTERP,ARGIN (Parrot_runcore_t * runcore),ARGIN (opcode_t * pc))1348 runops_subprof_hll_core(PARROT_INTERP, ARGIN(Parrot_runcore_t *runcore), ARGIN(opcode_t *pc))
1349 {
1350 ASSERT_ARGS(runops_subprof_hll_core)
1351
1352 subprofiledata *spdata = get_subprofiledata(interp, runcore, SUBPROF_TYPE_HLL);
1353 subprofile *sp = spdata->cursp;
1354 lineinfo *curline = sp ? sp->lines : NULL;
1355 opcode_t *startop = NULL;
1356 opcode_t *endop = NULL; /* triggers pc >= endop below */
1357
1358 while (pc) {
1359 PMC *ctx;
1360 PMC *subpmc;
1361 if (pc < code_start || pc >= code_end)
1362 Parrot_ex_throw_from_c_noargs(interp, EXCEPTION_OUT_OF_BOUNDS,
1363 "attempt to access code outside of current code segment");
1364
1365 ctx = CURRENT_CONTEXT(interp);
1366 Parrot_pcc_set_pc(interp, ctx, pc);
1367 subpmc = ((Parrot_Context *)PMC_data_typed(ctx, Parrot_Context*))->current_sub;
1368
1369 if (!PMC_IS_NULL(subpmc)) {
1370
1371 if (subpmc != spdata->cursubpmc || ctx != spdata->curctx) {
1372 /* context changed! either called new sub or returned from sub */
1373
1374 /* finish old ticks */
1375 UHUGEINTVAL tick = getticks();
1376 if (spdata->tickadd) {
1377 UHUGEINTVAL tickdiff = tick - spdata->starttick;
1378 *spdata->tickadd += tickdiff;
1379 *spdata->tickadd2 += tickdiff;
1380 }
1381 sync_callchainchange(interp, spdata, ctx, subpmc);
1382 sp = spdata->cursp;
1383 if (pc == sp->code_ops + sp->subattrs->start_offs) {
1384 /* assume new call */
1385 if (sp->callerci)
1386 sp->callerci->count++;
1387 }
1388 curline = sync_hll_linechange(interp, spdata, pc);
1389 spdata->tickadd = &curline->ticks;
1390 spdata->tickadd2 = &sp->callerticks;
1391 startop = sp->code_ops + curline->op_offs;
1392 endop = sp->code_ops + curline[1].op_offs;
1393 spdata->starttick = getticks();
1394 }
1395
1396 if (pc >= endop) {
1397 /* finish old ticks */
1398 UHUGEINTVAL tick = getticks();
1399 if (spdata->tickadd) {
1400 const UHUGEINTVAL tickdiff = tick - spdata->starttick;
1401 *spdata->tickadd += tickdiff;
1402 *spdata->tickadd2 += tickdiff;
1403 }
1404 spdata->starttick = tick;
1405 /* bring curline in sync with the pc */
1406 while (pc >= sp->code_ops + curline[1].op_offs) {
1407 curline++;
1408 }
1409 startop = sp->code_ops + curline->op_offs;
1410 endop = sp->code_ops + curline[1].op_offs;
1411 spdata->tickadd = &curline->ticks;
1412 }
1413 else if (pc < startop) {
1414 /* finish old ticks */
1415 const UHUGEINTVAL tick = getticks();
1416 if (spdata->tickadd) {
1417 UHUGEINTVAL tickdiff = tick - spdata->starttick;
1418 *spdata->tickadd += tickdiff;
1419 *spdata->tickadd2 += tickdiff;
1420 }
1421 spdata->starttick = tick;
1422 /* bring curline in sync with the pc */
1423 while (pc < sp->code_ops + curline->op_offs) {
1424 curline--;
1425 }
1426 startop = sp->code_ops + curline->op_offs;
1427 endop = sp->code_ops + curline[1].op_offs;
1428 spdata->tickadd = &curline->ticks;
1429 }
1430
1431 curline->ops++;
1432 sp->callerops++;
1433 }
1434 DO_OP(pc, interp);
1435 }
1436
1437 return pc;
1438 }
1439
1440 /*
1441
1442 =item C<static void Parrot_runcore_subprof_hll_init(PARROT_INTERP)>
1443
1444 Registers the subprof_hll runcore with Parrot.
1445
1446 =cut
1447
1448 */
1449
1450 static void
Parrot_runcore_subprof_hll_init(PARROT_INTERP)1451 Parrot_runcore_subprof_hll_init(PARROT_INTERP)
1452 {
1453 ASSERT_ARGS(Parrot_runcore_subprof_hll_init)
1454
1455 Parrot_subprof_runcore_t * const coredata
1456 = mem_gc_allocate_zeroed_typed(interp, Parrot_subprof_runcore_t);
1457 coredata->name = CONST_STRING(interp, "subprof_hll");
1458 coredata->id = PARROT_SUBPROF_HLL_CORE;
1459 coredata->opinit = PARROT_CORE_OPLIB_INIT;
1460 coredata->runops = runops_subprof_hll_core;
1461 coredata->prepare_run = NULL;
1462 coredata->destroy = runops_subprof_destroy;
1463 coredata->flags = 0;
1464
1465 PARROT_RUNCORE_FUNC_TABLE_SET(coredata);
1466
1467 Parrot_runcore_register(interp, (Parrot_runcore_t *)coredata);
1468 }
1469
1470
1471 /*
1472
1473 =item C<static opcode_t * runops_subprof_ops_core(PARROT_INTERP,
1474 Parrot_runcore_t *runcore, opcode_t *pc)>
1475
1476 Runs the Parrot operations starting at C<pc> until there are no more
1477 operations, with sub-level profiling and bounds checking enabled.
1478
1479 =cut
1480
1481 */
1482
1483 PARROT_WARN_UNUSED_RESULT
1484 PARROT_CAN_RETURN_NULL
1485 static opcode_t *
runops_subprof_ops_core(PARROT_INTERP,ARGIN (Parrot_runcore_t * runcore),ARGIN (opcode_t * pc))1486 runops_subprof_ops_core(PARROT_INTERP, ARGIN(Parrot_runcore_t *runcore), ARGIN(opcode_t *pc))
1487 {
1488 ASSERT_ARGS(runops_subprof_ops_core)
1489
1490 subprofiledata *spdata = get_subprofiledata(interp, runcore, SUBPROF_TYPE_OPS);
1491 subprofile *sp = spdata->cursp;
1492 opcode_t *startop = sp ? sp->code_ops + sp->subattrs->start_offs : NULL;
1493
1494 while (pc) {
1495 PMC *ctx;
1496 PMC *subpmc;
1497 if (pc < code_start || pc >= code_end)
1498 Parrot_ex_throw_from_c_noargs(interp, EXCEPTION_OUT_OF_BOUNDS,
1499 "attempt to access code outside of current code segment");
1500
1501 ctx = CURRENT_CONTEXT(interp);
1502 Parrot_pcc_set_pc(interp, ctx, pc);
1503 subpmc = ((Parrot_Context *)PMC_data_typed(ctx, Parrot_Context*))->current_sub;
1504
1505 if (!PMC_IS_NULL(subpmc)) {
1506 /* finish old ticks */
1507 const UHUGEINTVAL tick = getticks();
1508 if (spdata->tickadd) {
1509 const UHUGEINTVAL tickdiff = tick - spdata->starttick;
1510 *spdata->tickadd += tickdiff;
1511 *spdata->tickadd2 += tickdiff;
1512 spdata->starttick = tick;
1513 }
1514
1515 if (subpmc != spdata->cursubpmc || ctx != spdata->curctx) {
1516 /* context changed! either called new sub or returned from sub */
1517 sync_callchainchange(interp, spdata, ctx, subpmc);
1518 sp = spdata->cursp;
1519 if (pc == sp->code_ops + sp->subattrs->start_offs) {
1520 /* assume new call */
1521 if (sp->callerci)
1522 sp->callerci->count++;
1523 }
1524 startop = sp->code_ops + sp->subattrs->start_offs;
1525 spdata->tickadd2 = &sp->callerticks;
1526 spdata->starttick = getticks();
1527 }
1528 sp->lines[(int)(pc - startop)].ops++;
1529 sp->callerops++;
1530 spdata->tickadd = &sp->lines[(int)(pc - startop)].ticks;
1531 }
1532 DO_OP(pc, interp);
1533 }
1534
1535 return pc;
1536 }
1537
1538 /*
1539
1540 =item C<static void Parrot_runcore_subprof_ops_init(PARROT_INTERP)>
1541
1542 Registers the subprof_ops runcore with Parrot.
1543
1544 =cut
1545
1546 */
1547
1548 static void
Parrot_runcore_subprof_ops_init(PARROT_INTERP)1549 Parrot_runcore_subprof_ops_init(PARROT_INTERP)
1550 {
1551 ASSERT_ARGS(Parrot_runcore_subprof_ops_init)
1552
1553 Parrot_subprof_runcore_t * const coredata
1554 = mem_gc_allocate_zeroed_typed(interp, Parrot_subprof_runcore_t);
1555 coredata->name = CONST_STRING(interp, "subprof_ops");
1556 coredata->id = PARROT_SUBPROF_OPS_CORE;
1557 coredata->opinit = PARROT_CORE_OPLIB_INIT;
1558 coredata->runops = runops_subprof_ops_core;
1559 coredata->prepare_run = NULL;
1560 coredata->destroy = runops_subprof_destroy;
1561 coredata->flags = 0;
1562
1563 PARROT_RUNCORE_FUNC_TABLE_SET(coredata);
1564
1565 Parrot_runcore_register(interp, (Parrot_runcore_t *) coredata);
1566 }
1567
1568 /*
1569
1570 =item C<void Parrot_runcore_subprof_init(PARROT_INTERP)>
1571
1572 Register all three subprof cores
1573
1574 =cut
1575
1576 */
1577
1578 void
Parrot_runcore_subprof_init(PARROT_INTERP)1579 Parrot_runcore_subprof_init(PARROT_INTERP)
1580 {
1581 ASSERT_ARGS(Parrot_runcore_subprof_init)
1582
1583 Parrot_runcore_subprof_sub_init(interp);
1584 Parrot_runcore_subprof_hll_init(interp);
1585 Parrot_runcore_subprof_ops_init(interp);
1586 }
1587
1588 /*
1589
1590 =back
1591
1592 =cut
1593
1594 */
1595
1596 /*
1597 * Local variables:
1598 * c-file-style: "parrot"
1599 * End:
1600 * vim: expandtab shiftwidth=4 cinoptions='\:2=2' :
1601 */
1602
1603