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