/* Dumps the statistics associated with a particular callsite object. */ void dump_stats_by_callsite(MVMThreadContext *tc, DumpStr *ds, MVMSpeshStatsByCallsite *css) { MVMuint32 i, j, k; if (css->cs) dump_callsite(tc, ds, css->cs); else append(ds, "No interned callsite\n"); appendf(ds, " Callsite hits: %d\n\n", css->hits); if (css->osr_hits) appendf(ds, " OSR hits: %d\n\n", css->osr_hits); appendf(ds, " Maximum stack depth: %d\n\n", css->max_depth); for (i = 0; i < css->num_by_type; i++) { MVMSpeshStatsByType *tss = &(css->by_type[i]); appendf(ds, " Type tuple %d\n", i); dump_stats_type_tuple(tc, ds, css->cs, tss->arg_types, " "); appendf(ds, " Hits: %d\n", tss->hits); if (tss->osr_hits) appendf(ds, " OSR hits: %d\n", tss->osr_hits); appendf(ds, " Maximum stack depth: %d\n", tss->max_depth); if (tss->num_by_offset) { append(ds, " Logged at offset:\n"); for (j = 0; j < tss->num_by_offset; j++) { MVMSpeshStatsByOffset *oss = &(tss->by_offset[j]); appendf(ds, " %d:\n", oss->bytecode_offset); for (k = 0; k < oss->num_types; k++) appendf(ds, " %d x type %s (%s)\n", oss->types[k].count, MVM_6model_get_stable_debug_name(tc, oss->types[k].type->st), (oss->types[k].type_concrete ? "Conc" : "TypeObj")); for (k = 0; k < oss->num_invokes; k++) { char *body_name = MVM_string_utf8_encode_C_string(tc, oss->invokes[k].sf->body.name); char *body_cuuid = MVM_string_utf8_encode_C_string(tc, oss->invokes[k].sf->body.cuuid); appendf(ds, " %d x static frame '%s' (%s) (caller is outer: %d, multi %d)\n", oss->invokes[k].count, body_name, body_cuuid, oss->invokes[k].caller_is_outer_count, oss->invokes[k].was_multi_count); MVM_free(body_name); MVM_free(body_cuuid); } for (k = 0; k < oss->num_type_tuples; k++) { appendf(ds, " %d x type tuple:\n", oss->type_tuples[k].count); dump_stats_type_tuple(tc, ds, oss->type_tuples[k].cs, oss->type_tuples[k].arg_types, " "); } for (k = 0; k < oss->num_plugin_guards; k++) appendf(ds, " %d x spesh plugin guard index %d\n", oss->plugin_guards[k].count, oss->plugin_guards[k].guard_index); } } append(ds, "\n"); } }
/* Dump a spesh graph into string form, for debugging purposes. */ char * MVM_spesh_dump(MVMThreadContext *tc, MVMSpeshGraph *g) { MVMSpeshBB *cur_bb; /* Allocate buffer. */ DumpStr ds; ds.alloc = 8192; ds.buffer = MVM_malloc(ds.alloc); ds.pos = 0; /* Dump name and CUID. */ append(&ds, "Spesh of '"); append_str(tc, &ds, g->sf->body.name); append(&ds, "' (cuid: "); append_str(tc, &ds, g->sf->body.cuuid); append(&ds, ", file: "); dump_fileinfo(tc, &ds, g); append(&ds, ")\n"); if (g->cs) dump_callsite(tc, &ds, g); if (g->num_arg_guards) dump_arg_guards(tc, &ds, g); if (!g->cs && !g->num_arg_guards) append(&ds, "\n"); /* Go over all the basic blocks and dump them. */ cur_bb = g->entry; while (cur_bb) { dump_bb(tc, &ds, g, cur_bb); cur_bb = cur_bb->linear_next; } /* Dump facts. */ append(&ds, "\nFacts:\n"); dump_facts(tc, &ds, g); if (g->num_spesh_slots || g->num_log_slots) { append(&ds, "\nStats:\n"); appendf(&ds, " %d spesh slots\n", g->num_spesh_slots); appendf(&ds, " %d log slots\n", g->num_log_slots); } if (g->num_log_slots) { dump_log_values(tc, &ds, g); } append(&ds, "\n"); append_null(&ds); return ds.buffer; }
/* Dumps a planned specialization into a string. */ char * MVM_spesh_dump_planned(MVMThreadContext *tc, MVMSpeshPlanned *p) { DumpStr ds; ds.alloc = 8192; ds.buffer = MVM_malloc(ds.alloc); ds.pos = 0; /* Dump kind of specialization and target. */ switch (p->kind) { case MVM_SPESH_PLANNED_CERTAIN: append(&ds, "Certain"); break; case MVM_SPESH_PLANNED_OBSERVED_TYPES: append(&ds, "Observed type"); break; case MVM_SPESH_PLANNED_DERIVED_TYPES: append(&ds, "Derived type"); break; } append(&ds, " specialization of '"); append_str(tc, &ds, p->sf->body.name); append(&ds, "' (cuid: "); append_str(tc, &ds, p->sf->body.cuuid); append(&ds, ", file: "); dump_fileinfo(tc, &ds, p->sf); append(&ds, ")\n\n"); /* Dump the callsite of the specialization. */ if (p->cs_stats->cs) { append(&ds, "The specialization is for the callsite:\n"); dump_callsite(tc, &ds, p->cs_stats->cs); } else { append(&ds, "The specialization is for when there is no interned callsite.\n"); } /* Dump reasoning. */ switch (p->kind) { case MVM_SPESH_PLANNED_CERTAIN: if (p->cs_stats->hits >= MVM_spesh_threshold(tc, p->sf)) appendf(&ds, "It was planned due to the callsite receiving %u hits.\n", p->cs_stats->hits); else if (p->cs_stats->osr_hits >= MVM_SPESH_PLAN_CS_MIN_OSR) appendf(&ds, "It was planned due to the callsite receiving %u OSR hits.\n", p->cs_stats->osr_hits); else append(&ds, "It was planned for unknown reasons.\n"); if (!p->sf->body.specializable) append(&ds, "The body contains no specializable instructions.\n"); break; case MVM_SPESH_PLANNED_OBSERVED_TYPES: { MVMCallsite *cs = p->cs_stats->cs; MVMuint32 hit_percent = p->cs_stats->hits ? (100 * p->type_stats[0]->hits) / p->cs_stats->hits : 0; MVMuint32 osr_hit_percent = p->cs_stats->osr_hits ? (100 * p->type_stats[0]->osr_hits) / p->cs_stats->osr_hits : 0; append(&ds, "It was planned for the type tuple:\n"); dump_stats_type_tuple(tc, &ds, cs, p->type_tuple, " "); if (osr_hit_percent >= MVM_SPESH_PLAN_TT_OBS_PERCENT_OSR) appendf(&ds, "Which received %u OSR hits (%u%% of the %u callsite OSR hits).\n", p->type_stats[0]->osr_hits, osr_hit_percent, p->cs_stats->osr_hits); else if (hit_percent >= MVM_SPESH_PLAN_TT_OBS_PERCENT) appendf(&ds, "Which received %u hits (%u%% of the %u callsite hits).\n", p->type_stats[0]->hits, hit_percent, p->cs_stats->hits); else append(&ds, "For unknown reasons.\n"); break; } case MVM_SPESH_PLANNED_DERIVED_TYPES: break; } appendf(&ds, "\nThe maximum stack depth is %d.\n\n", p->max_depth); append_null(&ds); return ds.buffer; }
/* Dump a spesh graph into string form, for debugging purposes. */ char * MVM_spesh_dump(MVMThreadContext *tc, MVMSpeshGraph *g) { MVMSpeshBB *cur_bb; SpeshGraphSizeStats stats; InlineIndexStack inline_stack; DumpStr ds; stats.total_size = 0; stats.inlined_size = 0; inline_stack.cur_depth = -1; /* Allocate buffer. */ ds.alloc = 8192; ds.buffer = MVM_malloc(ds.alloc); ds.pos = 0; /* Dump name and CUID. */ append(&ds, "Spesh of '"); append_str(tc, &ds, g->sf->body.name); append(&ds, "' (cuid: "); append_str(tc, &ds, g->sf->body.cuuid); append(&ds, ", file: "); dump_fileinfo(tc, &ds, g->sf); append(&ds, ")\n"); if (g->cs) dump_callsite(tc, &ds, g->cs); if (!g->cs) append(&ds, "\n"); /* Go over all the basic blocks and dump them. */ cur_bb = g->entry; while (cur_bb) { dump_bb(tc, &ds, g, cur_bb, &stats, &inline_stack); cur_bb = cur_bb->linear_next; } /* Dump facts. */ if (g->facts) { append(&ds, "\nFacts:\n"); dump_facts(tc, &ds, g); } /* Dump spesh slots. */ if (g->num_spesh_slots) { MVMuint32 i; append(&ds, "\nSpesh slots:\n"); for (i = 0; i < g->num_spesh_slots; i++) { MVMCollectable *value = g->spesh_slots[i]; if (value == NULL) appendf(&ds, " %d = NULL\n", i); else if (value->flags & MVM_CF_STABLE) appendf(&ds, " %d = STable (%s)\n", i, MVM_6model_get_stable_debug_name(tc, (MVMSTable *)value)); else if (value->flags & MVM_CF_TYPE_OBJECT) appendf(&ds, " %d = Type Object (%s)\n", i, MVM_6model_get_debug_name(tc, (MVMObject *)value)); else { MVMObject *obj = (MVMObject *)value; MVMuint32 repr_id = REPR(obj)->ID; appendf(&ds, " %d = Instance (%s)", i, MVM_6model_get_debug_name(tc, obj)); if (repr_id == MVM_REPR_ID_MVMStaticFrame || repr_id == MVM_REPR_ID_MVMCode) { MVMStaticFrameBody *body; char *name_str; char *cuuid_str; if (repr_id == MVM_REPR_ID_MVMCode) { MVMCodeBody *code_body = (MVMCodeBody *)OBJECT_BODY(obj); obj = (MVMObject *)code_body->sf; } body = (MVMStaticFrameBody *)OBJECT_BODY(obj); name_str = MVM_string_utf8_encode_C_string(tc, body->name); cuuid_str = MVM_string_utf8_encode_C_string(tc, body->cuuid); appendf(&ds, " - '%s' (%s)", name_str, cuuid_str); MVM_free(name_str); MVM_free(cuuid_str); } appendf(&ds, "\n"); } } } /* Dump materialization deopt into. */ dump_deopt_pea(tc, &ds, g); append(&ds, "\n"); /* Print out frame size */ if (stats.inlined_size) appendf(&ds, "Frame size: %u bytes (%u from inlined frames)\n", stats.total_size, stats.inlined_size); else appendf(&ds, "Frame size: %u bytes\n", stats.total_size); append_null(&ds); return ds.buffer; }