MVMObject * references_str(MVMThreadContext *tc, MVMHeapSnapshot *s) { /* Produces ; separated sequences of: * kind,idx,to * All of which are integers. */ MVMObject *result; size_t buffer_size = 10 * s->num_references; size_t buffer_pos = 0; char *buffer = MVM_malloc(buffer_size); MVMuint64 i; for (i = 0; i < s->num_references; i++) { char tmp[128]; int item_chars = snprintf(tmp, 128, "%"PRIu64",%"PRIu64",%"PRIu64";", s->references[i].description & ((1 << MVM_SNAPSHOT_REF_KIND_BITS) - 1), s->references[i].description >> MVM_SNAPSHOT_REF_KIND_BITS, s->references[i].collectable_index); if (item_chars < 0) MVM_panic(1, "Failed to save reference in heap snapshot"); if (buffer_pos + item_chars >= buffer_size) { buffer_size += 4096; buffer = MVM_realloc(buffer, buffer_size); } memcpy(buffer + buffer_pos, tmp, item_chars); buffer_pos += item_chars; } if (buffer_pos > 1) buffer[buffer_pos - 1] = 0; /* Cut off the trailing ; for ease of parsing */ buffer[buffer_pos] = 0; result = box_s(tc, vmstr(tc, buffer)); MVM_free(buffer); return result; }
MVMObject * types_str(MVMThreadContext *tc, MVMHeapSnapshotCollection *col) { /* Produces ; separated sequences of: * repr_string_index,type_name_string_index * Both of which are integers. */ MVMObject *result; size_t buffer_size = 10 * col->num_types; size_t buffer_pos = 0; char *buffer = MVM_malloc(buffer_size); MVMuint64 i; for (i = 0; i < col->num_types; i++) { char tmp[256]; int item_chars = snprintf(tmp, 256, "%"PRIu64",%"PRIu64";", col->types[i].repr_name, col->types[i].type_name); if (item_chars < 0) MVM_panic(1, "Failed to save type in heap snapshot"); if (buffer_pos + item_chars >= buffer_size) { buffer_size += 4096; buffer = MVM_realloc(buffer, buffer_size); } memcpy(buffer + buffer_pos, tmp, item_chars); buffer_pos += item_chars; } if (buffer_pos > 1) buffer[buffer_pos - 1] = 0; /* Cut off the trailing ; for ease of parsing */ buffer[buffer_pos] = 0; result = box_s(tc, vmstr(tc, buffer)); MVM_free(buffer); return result; }
MVMObject * collectables_str(MVMThreadContext *tc, MVMHeapSnapshot *s) { /* Produces ; separated sequences of: * kind,type_or_frame_index,collectable_size,unmanaged_size,refs_start,num_refs * All of which are integers. */ MVMObject *result; size_t buffer_size = 20 * s->num_collectables; size_t buffer_pos = 0; char *buffer = MVM_malloc(buffer_size); MVMuint64 i; for (i = 0; i < s->num_collectables; i++) { char tmp[256]; int item_chars = snprintf(tmp, 256, "%"PRIu16",%"PRId32",%"PRIu16",%"PRIu64",%"PRIu64",%"PRIu32";", s->collectables[i].kind, s->collectables[i].type_or_frame_index, s->collectables[i].collectable_size, s->collectables[i].unmanaged_size, s->collectables[i].num_refs ? s->collectables[i].refs_start : (MVMuint64)0, s->collectables[i].num_refs); if (item_chars < 0) MVM_panic(1, "Failed to save collectable in heap snapshot"); if (buffer_pos + item_chars >= buffer_size) { buffer_size += 4096; buffer = MVM_realloc(buffer, buffer_size); } memcpy(buffer + buffer_pos, tmp, item_chars); buffer_pos += item_chars; } if (buffer_pos > 1) buffer[buffer_pos - 1] = 0; /* Cut off the trailing ; for ease of parsing */ buffer[buffer_pos] = 0; result = box_s(tc, vmstr(tc, buffer)); MVM_free(buffer); return result; }
/* Dumps a call graph node. */ static MVMObject * dump_call_graph_node(MVMThreadContext *tc, ProfDumpStrs *pds, const MVMProfileCallNode *pcn) { MVMObject *node_hash = new_hash(tc); MVMuint32 i; /* Let's see if we're dealing with a native call or a regular moar call */ if (pcn->sf) { /* Try to resolve the code filename and line number. */ MVMBytecodeAnnotation *annot = MVM_bytecode_resolve_annotation(tc, &(pcn->sf->body), 0); MVMint32 fshi = annot ? (MVMint32)annot->filename_string_heap_index : -1; /* Add name of code object. */ MVM_repr_bind_key_o(tc, node_hash, pds->name, box_s(tc, pcn->sf->body.name)); /* Add line number and file name. */ if (fshi >= 0 && fshi < pcn->sf->body.cu->body.num_strings) MVM_repr_bind_key_o(tc, node_hash, pds->file, box_s(tc, MVM_cu_string(tc, pcn->sf->body.cu, fshi))); else if (pcn->sf->body.cu->body.filename) MVM_repr_bind_key_o(tc, node_hash, pds->file, box_s(tc, pcn->sf->body.cu->body.filename)); else MVM_repr_bind_key_o(tc, node_hash, pds->file, box_s(tc, tc->instance->str_consts.empty)); MVM_repr_bind_key_o(tc, node_hash, pds->line, box_i(tc, annot ? (MVMint32)annot->line_number : -1)); MVM_free(annot); /* Use static frame memory address to get a unique ID. */ MVM_repr_bind_key_o(tc, node_hash, pds->id, box_i(tc, (MVMint64)pcn->sf)); } else { MVMString *function_name_string = MVM_string_utf8_c8_decode(tc, tc->instance->VMString, pcn->native_target_name, strlen(pcn->native_target_name)); MVM_repr_bind_key_o(tc, node_hash, pds->name, box_s(tc, function_name_string)); MVM_repr_bind_key_o(tc, node_hash, pds->file, box_s(tc, pds->native_lib)); MVM_repr_bind_key_o(tc, node_hash, pds->line, box_i(tc, -2)); /* Use the address of the name string as unique ID. a hack, but oh well. */ MVM_repr_bind_key_o(tc, node_hash, pds->id, box_i(tc, (MVMint64)pcn->native_target_name)); } /* Entry counts. */ if (pcn->total_entries) MVM_repr_bind_key_o(tc, node_hash, pds->entries, box_i(tc, pcn->total_entries)); if (pcn->specialized_entries) MVM_repr_bind_key_o(tc, node_hash, pds->spesh_entries, box_i(tc, pcn->specialized_entries)); if (pcn->jit_entries) MVM_repr_bind_key_o(tc, node_hash, pds->jit_entries, box_i(tc, pcn->jit_entries)); if (pcn->inlined_entries) MVM_repr_bind_key_o(tc, node_hash, pds->inlined_entries, box_i(tc, pcn->inlined_entries)); /* Total (inclusive) time. */ MVM_repr_bind_key_o(tc, node_hash, pds->inclusive_time, box_i(tc, pcn->total_time / 1000)); /* OSR and deopt counts. */ if (pcn->osr_count) MVM_repr_bind_key_o(tc, node_hash, pds->osr, box_i(tc, pcn->osr_count)); if (pcn->deopt_one_count) MVM_repr_bind_key_o(tc, node_hash, pds->deopt_one, box_i(tc, pcn->deopt_one_count)); if (pcn->deopt_all_count) MVM_repr_bind_key_o(tc, node_hash, pds->deopt_all, box_i(tc, pcn->deopt_all_count)); /* Visit successors in the call graph, dumping them and working out the * exclusive time. */ if (pcn->num_succ) { MVMObject *callees = new_array(tc); MVMuint64 exclusive_time = pcn->total_time; for (i = 0; i < pcn->num_succ; i++) { MVM_repr_push_o(tc, callees, dump_call_graph_node(tc, pds, pcn->succ[i])); exclusive_time -= pcn->succ[i]->total_time; } MVM_repr_bind_key_o(tc, node_hash, pds->exclusive_time, box_i(tc, exclusive_time / 1000)); MVM_repr_bind_key_o(tc, node_hash, pds->callees, callees); } else { MVM_repr_bind_key_o(tc, node_hash, pds->exclusive_time, box_i(tc, pcn->total_time / 1000)); } if (pcn->num_alloc) { /* Emit allocations. */ MVMObject *alloc_list = new_array(tc); MVM_repr_bind_key_o(tc, node_hash, pds->allocations, alloc_list); for (i = 0; i < pcn->num_alloc; i++) { MVMObject *alloc_info = new_hash(tc); MVMProfileAllocationCount *alloc = &pcn->alloc[i]; MVMObject *type = pcn->alloc[i].type; MVM_repr_bind_key_o(tc, alloc_info, pds->id, box_i(tc, (MVMint64)type)); MVM_repr_bind_key_o(tc, alloc_info, pds->type, type); if (alloc->allocations_spesh) MVM_repr_bind_key_o(tc, alloc_info, pds->spesh, box_i(tc, alloc->allocations_spesh)); if (alloc->allocations_jit) MVM_repr_bind_key_o(tc, alloc_info, pds->jit, box_i(tc, alloc->allocations_jit)); MVM_repr_bind_key_o(tc, alloc_info, pds->count, box_i(tc, alloc->allocations_interp + alloc->allocations_spesh + alloc->allocations_jit)); MVM_repr_push_o(tc, alloc_list, alloc_info); } } return node_hash; }