/* Statistics are stored per static frame. This data structure is only ever * read/written by the specializer thread. */ struct MVMSpeshStats { /* Statistics on a per-callsite basis. */ MVMSpeshStatsByCallsite *by_callsite; /* The number of entries in by_callsite. */ MVMuint32 num_by_callsite; /* The number of entries in static_values. */ MVMuint32 num_static_values; /* Total calls across all callsites. */ MVMuint32 hits; /* Total OSR hits across all callsites. */ MVMuint32 osr_hits; /* The latest version of the statistics when this was updated. Used to * help decide when to throw out data that is no longer evolving, to * reduce memory use. */ MVMuint32 last_update; }; /* Statistics by callsite. */ struct MVMSpeshStatsByCallsite { /* The callsite, or NULL for the case of no interned callsite. */ MVMCallsite *cs; /* Statistics aggregated by parameter type information. */ MVMSpeshStatsByType *by_type; /* The number of entries in by_type. Zero if cs == NULL. */ MVMuint32 num_by_type; /* Total calls to this callsite. */ MVMuint32 hits; /* Total OSR hits for this callsite. */ MVMuint32 osr_hits; /* The maximum callstack depth we observed this at. */ MVMuint32 max_depth; }; /* Statistics by type. */ struct MVMSpeshStatsByType { /* Argument type information. Length of this is determined by the callsite * of the specialization. */ MVMSpeshStatsType *arg_types; /* Total calls with this callsite/type combination. */ MVMuint32 hits; /* Total OSR hits for this callsite/type combination. */ MVMuint32 osr_hits; /* Logged type and logged value counts, by bytecode offset. */ MVMSpeshStatsByOffset *by_offset; /* Number of stats by offset we have. */ MVMuint32 num_by_offset; /* The maximum callstack depth we observed this at. */ MVMuint32 max_depth; }; /* Type statistics. */ struct MVMSpeshStatsType { /* The type logged. */ MVMObject *type; /* If applicable, and if the type is a container type, the type of the * value logged inside of it. */ MVMObject *decont_type; /* Whether the type and decont type were concrete. */ MVMuint8 type_concrete; MVMuint8 decont_type_concrete; /* If there is a container type, whether it must be rw. */ MVMuint8 rw_cont; }; /* Statistics by bytecode offset. */ struct MVMSpeshStatsByOffset { /* The bytecode offset these types/values were recorded at. */ MVMuint32 bytecode_offset; /* Number of types recorded, with counts. */ MVMuint32 num_types; MVMSpeshStatsTypeCount *types; /* Number of invocation targets recorded, with counts. */ MVMSpeshStatsInvokeCount *invokes; MVMuint32 num_invokes; /* Number of type tuples recorded, with counts. (Type tuples are actually * recorded by the callee, and then also accumulated at the callsite of * the caller.) */ MVMuint32 num_type_tuples; MVMSpeshStatsTypeTupleCount *type_tuples; /* Number of times spesh dispatch results were recorded. */ MVMSpeshStatsDispatchResultCount *dispatch_results; MVMuint32 num_dispatch_results; }; /* Counts of a given type that has shown up at a bytecode offset. */ struct MVMSpeshStatsTypeCount { /* The type and its concreteness. */ MVMObject *type; MVMuint8 type_concrete; /* The number of times we've seen it. */ MVMuint32 count; }; /* Counts of a given static frame that was invoked at a bytecode offset. */ struct MVMSpeshStatsInvokeCount { /* The static frame. */ MVMStaticFrame *sf; /* The number of times the caller frame was also the outer frame. */ MVMuint32 caller_is_outer_count; /* The number of times we've seen it. */ MVMuint32 count; }; /* Counts of a given type tuple has shown up at the callsite at a bytecode * offset. */ struct MVMSpeshStatsTypeTupleCount { /* The callsite. */ MVMCallsite *cs; /* The type tuple. */ MVMSpeshStatsType *arg_types; /* The number of times we've seen it. */ MVMuint32 count; }; /* Counts of a given dispatch result index. */ struct MVMSpeshStatsDispatchResultCount { /* The index of the dispatch result in the inline cache entry. */ MVMuint32 result_index; /* The number of times we've seen it. */ MVMuint32 count; }; /* Static values table entry. */ struct MVMSpeshStatsStatic { /* The value. */ MVMObject *value; /* The bytecode offset it was recorded at. */ MVMuint32 bytecode_offset; }; /* The maximum number of spesh stats updates before we consider a frame's * stats out of date and throw them out. */ #define MVM_SPESH_STATS_MAX_AGE 10 /* Logs are linear recordings marked with frame correlation IDs. We need to * simulate the call stack as part of the analysis. This is the model for the * stack simulation. */ struct MVMSpeshSimStack { /* Array of frames. */ MVMSpeshSimStackFrame *frames; /* Current frame index and allocated space. */ MVMuint32 used; MVMuint32 limit; /* Current stack depth. */ MVMuint32 depth; }; /* This is the model of a frame on the simulated stack. */ struct MVMSpeshSimStackFrame { /* The static frame. */ MVMStaticFrame *sf; /* Spesh stats for the stack frame. */ MVMSpeshStats *ss; /* Correlation ID. */ MVMuint32 cid; /* Callsite stats index (not pointer in case of realloc). */ MVMuint32 callsite_idx; /* Type stats index (not pointer in case of realloc); -1 if not yet set. * This is resolved once using arg_types, and then remembered, so we can * correlate the statistics across spesh log buffers. */ MVMint32 type_idx; /* Argument types logged. Sized by number of callsite flags. */ MVMSpeshStatsType *arg_types; /* Spesh log entries for types and values, for later processing. */ MVMSpeshLogEntry **offset_logs; MVMuint32 offset_logs_used; MVMuint32 offset_logs_limit; /* Type tuples observed at a given callsite offset, for later * processing. */ MVMSpeshSimCallType *call_type_info; MVMuint32 call_type_info_used; MVMuint32 call_type_info_limit; /* Number of times we crossed an OSR point. */ MVMuint32 osr_hits; /* The last bytecode offset and static frame seen in an invoke recording; * used for producing callsite type stats based on callee type tuples. */ MVMuint32 last_invoke_offset; MVMStaticFrame *last_invoke_sf; }; /* We associate recoded type tuples in callees with their caller's callsites. * This is kept as a flat view, and then folded in when the caller's sim * frame (see next) is popped. */ struct MVMSpeshSimCallType { MVMuint32 bytecode_offset; MVMCallsite *cs; MVMSpeshStatsType *arg_types; }; void MVM_spesh_stats_update(MVMThreadContext *tc, MVMSpeshLog *sl, MVMObject *sf_newly_seen, MVMObject *sf_updated, MVMuint64 *newly_seen, MVMuint64 *updated); void MVM_spesh_stats_cleanup(MVMThreadContext *tc, MVMObject *check_frames); void MVM_spesh_stats_gc_mark(MVMThreadContext *tc, MVMSpeshStats *ss, MVMGCWorklist *worklist); void MVM_spesh_stats_gc_describe(MVMThreadContext *tc, MVMHeapSnapshotState *snapshot, MVMSpeshStats *ss); void MVM_spesh_stats_destroy(MVMThreadContext *tc, MVMSpeshStats *ss); void MVM_spesh_sim_stack_gc_mark(MVMThreadContext *tc, MVMSpeshSimStack *sims, MVMGCWorklist *worklist); void MVM_spesh_sim_stack_gc_describe(MVMThreadContext *tc, MVMHeapSnapshotState *ss, MVMSpeshSimStack *sims); void MVM_spesh_sim_stack_destroy(MVMThreadContext *tc, MVMSpeshSimStack *sims);