diff options
Diffstat (limited to 'debug_counter.h')
| -rw-r--r-- | debug_counter.h | 295 |
1 files changed, 186 insertions, 109 deletions
diff --git a/debug_counter.h b/debug_counter.h index f0444d7190..c8d8ed8f11 100644 --- a/debug_counter.h +++ b/debug_counter.h @@ -14,28 +14,67 @@ #ifdef RB_DEBUG_COUNTER -/* - * method cache (mc) counts. - * - * * mc_inline_hit/miss: inline mc hit/miss counts (VM send insn) - * * mc_global_hit/miss: global method cache hit/miss counts - * two types: (1) inline cache miss (VM send insn) - * (2) called from C (rb_funcall). - * * mc_global_state_miss: inline mc miss by global_state miss. - * * mc_class_serial_miss: ... by mc_class_serial_miss - * * mc_cme_complement: callable_method_entry complement counts. - * * mc_cme_complement_hit: callable_method_entry cache hit counts. - * * mc_search_super: search_method() call counts. - */ -RB_DEBUG_COUNTER(mc_inline_hit) -RB_DEBUG_COUNTER(mc_inline_miss) -RB_DEBUG_COUNTER(mc_global_hit) -RB_DEBUG_COUNTER(mc_global_miss) -RB_DEBUG_COUNTER(mc_global_state_miss) -RB_DEBUG_COUNTER(mc_class_serial_miss) -RB_DEBUG_COUNTER(mc_cme_complement) -RB_DEBUG_COUNTER(mc_cme_complement_hit) -RB_DEBUG_COUNTER(mc_search_super) +// method cache (IMC: inline method cache) +RB_DEBUG_COUNTER(mc_inline_hit) // IMC hit +RB_DEBUG_COUNTER(mc_inline_miss_klass) // IMC miss by different class +RB_DEBUG_COUNTER(mc_inline_miss_invalidated) // IMC miss by invalidated ME +RB_DEBUG_COUNTER(mc_inline_miss_empty) // IMC miss because prev is empty slot +RB_DEBUG_COUNTER(mc_inline_miss_same_cc) // IMC miss, but same CC +RB_DEBUG_COUNTER(mc_inline_miss_same_cme) // IMC miss, but same CME +RB_DEBUG_COUNTER(mc_inline_miss_same_def) // IMC miss, but same definition +RB_DEBUG_COUNTER(mc_inline_miss_diff) // IMC miss, different methods + +RB_DEBUG_COUNTER(cvar_write_inline_hit) // cvar cache hit on write +RB_DEBUG_COUNTER(cvar_read_inline_hit) // cvar cache hit on read +RB_DEBUG_COUNTER(cvar_inline_miss) // miss inline cache +RB_DEBUG_COUNTER(cvar_class_invalidate) // invalidate cvar cache when define a cvar that's defined on a subclass +RB_DEBUG_COUNTER(cvar_include_invalidate) // invalidate cvar cache on module include or prepend + +RB_DEBUG_COUNTER(mc_cme_complement) // number of acquiring complement CME +RB_DEBUG_COUNTER(mc_cme_complement_hit) // number of cache hit for complemented CME + +RB_DEBUG_COUNTER(mc_search) // count for method lookup in class tree +RB_DEBUG_COUNTER(mc_search_notfound) // method lookup, but not found +RB_DEBUG_COUNTER(mc_search_super) // total traversed classes + +// callinfo +RB_DEBUG_COUNTER(ci_packed) // number of packed CI +RB_DEBUG_COUNTER(ci_kw) // non-packed CI w/ keywords +RB_DEBUG_COUNTER(ci_nokw) // non-packed CI w/o keywords +RB_DEBUG_COUNTER(ci_runtime) // creating temporary CI + +// callcache +RB_DEBUG_COUNTER(cc_new) // number of CC +RB_DEBUG_COUNTER(cc_temp) // dummy CC (stack-allocated) +RB_DEBUG_COUNTER(cc_found_in_ccs) // count for CC lookup success in CCS +RB_DEBUG_COUNTER(cc_not_found_in_ccs) // count for CC lookup success in CCS + +RB_DEBUG_COUNTER(cc_ent_invalidate) // count for invalidating cc (cc->klass = Qundef) +RB_DEBUG_COUNTER(cc_cme_invalidate) // count for invalidating CME + +RB_DEBUG_COUNTER(cc_invalidate_leaf) // count for invalidating klass if klass has no-subclasses +RB_DEBUG_COUNTER(cc_invalidate_leaf_ccs) // corresponding CCS +RB_DEBUG_COUNTER(cc_invalidate_leaf_callable) // complimented cache (no-subclasses) +RB_DEBUG_COUNTER(cc_invalidate_tree) // count for invalidating klass if klass has subclasses +RB_DEBUG_COUNTER(cc_invalidate_tree_cme) // cme if cme is found in this class or superclasses +RB_DEBUG_COUNTER(cc_invalidate_tree_callable) // complimented cache (subclasses) +RB_DEBUG_COUNTER(cc_invalidate_negative) // count for invalidating negative cache + +RB_DEBUG_COUNTER(ccs_free) // count for free'ing ccs +RB_DEBUG_COUNTER(ccs_maxlen) // maximum length of ccs +RB_DEBUG_COUNTER(ccs_found) // count for finding corresponding ccs on method lookup +RB_DEBUG_COUNTER(ccs_not_found) // count for not found corresponding ccs on method lookup + +// vm_eval.c +RB_DEBUG_COUNTER(call0_public) +RB_DEBUG_COUNTER(call0_other) +RB_DEBUG_COUNTER(gccct_hit) +RB_DEBUG_COUNTER(gccct_miss) +RB_DEBUG_COUNTER(gccct_null) + +// iseq +RB_DEBUG_COUNTER(iseq_num) // number of total created iseq +RB_DEBUG_COUNTER(iseq_cd_num) // number of total created cd (call_data) /* * call cache fastpath usage @@ -49,6 +88,7 @@ RB_DEBUG_COUNTER(ccf_iseq_opt) /* has_opt == TRUE (has optional parameters), but RB_DEBUG_COUNTER(ccf_iseq_kw1) /* vm_call_iseq_setup_kwparm_kwarg() */ RB_DEBUG_COUNTER(ccf_iseq_kw2) /* vm_call_iseq_setup_kwparm_nokwarg() */ RB_DEBUG_COUNTER(ccf_cfunc) +RB_DEBUG_COUNTER(ccf_cfunc_with_frame) RB_DEBUG_COUNTER(ccf_ivar) /* attr_reader */ RB_DEBUG_COUNTER(ccf_attrset) /* attr_writer */ RB_DEBUG_COUNTER(ccf_method_missing) @@ -57,7 +97,16 @@ RB_DEBUG_COUNTER(ccf_bmethod) RB_DEBUG_COUNTER(ccf_opt_send) RB_DEBUG_COUNTER(ccf_opt_call) RB_DEBUG_COUNTER(ccf_opt_block_call) +RB_DEBUG_COUNTER(ccf_opt_struct_aref) +RB_DEBUG_COUNTER(ccf_opt_struct_aset) RB_DEBUG_COUNTER(ccf_super_method) +RB_DEBUG_COUNTER(ccf_cfunc_other) +RB_DEBUG_COUNTER(ccf_cfunc_only_splat) +RB_DEBUG_COUNTER(ccf_cfunc_only_splat_kw) +RB_DEBUG_COUNTER(ccf_iseq_bmethod) +RB_DEBUG_COUNTER(ccf_noniseq_bmethod) +RB_DEBUG_COUNTER(ccf_opt_send_complex) +RB_DEBUG_COUNTER(ccf_opt_send_simple) /* * control frame push counts. @@ -85,30 +134,22 @@ RB_DEBUG_COUNTER(frame_R2C) RB_DEBUG_COUNTER(frame_C2C) RB_DEBUG_COUNTER(frame_C2R) -/* instance variable counts - * - * * ivar_get_ic_hit/miss: ivar_get inline cache (ic) hit/miss counts (VM insn) - * * ivar_get_ic_miss_serial: ivar_get ic miss reason by serial (VM insn) - * * ivar_get_ic_miss_unset: ... by unset (VM insn) - * * ivar_get_ic_miss_noobject: ... by "not T_OBJECT" (VM insn) - * * ivar_set_...: same counts with ivar_set (VM insn) - * * ivar_get/set_base: call counts of "rb_ivar_get/set()". - * because of (1) ic miss. - * (2) direct call by C extensions. - */ -RB_DEBUG_COUNTER(ivar_get_ic_hit) -RB_DEBUG_COUNTER(ivar_get_ic_miss) -RB_DEBUG_COUNTER(ivar_get_ic_miss_serial) -RB_DEBUG_COUNTER(ivar_get_ic_miss_unset) -RB_DEBUG_COUNTER(ivar_get_ic_miss_noobject) -RB_DEBUG_COUNTER(ivar_set_ic_hit) -RB_DEBUG_COUNTER(ivar_set_ic_miss) -RB_DEBUG_COUNTER(ivar_set_ic_miss_serial) -RB_DEBUG_COUNTER(ivar_set_ic_miss_unset) -RB_DEBUG_COUNTER(ivar_set_ic_miss_oorange) -RB_DEBUG_COUNTER(ivar_set_ic_miss_noobject) -RB_DEBUG_COUNTER(ivar_get_base) -RB_DEBUG_COUNTER(ivar_set_base) +/* instance variable counts */ +RB_DEBUG_COUNTER(ivar_get_obj_hit) // Only T_OBJECT hits +RB_DEBUG_COUNTER(ivar_get_obj_miss) // Only T_OBJECT misses +RB_DEBUG_COUNTER(ivar_get_ic_hit) // All hits +RB_DEBUG_COUNTER(ivar_get_ic_miss) // All misses +RB_DEBUG_COUNTER(ivar_set_ic_hit) // All hits +RB_DEBUG_COUNTER(ivar_set_obj_hit) // Only T_OBJECT hits +RB_DEBUG_COUNTER(ivar_set_obj_miss) // Only T_OBJECT misses +RB_DEBUG_COUNTER(ivar_set_ic_miss) // All misses +RB_DEBUG_COUNTER(ivar_set_ic_miss_noobject) // Miss because non T_OBJECT +RB_DEBUG_COUNTER(ivar_get_base) // Calls to `rb_ivar_get` (very slow path) +RB_DEBUG_COUNTER(ivar_set_base) // Calls to `ivar_set` (very slow path) +RB_DEBUG_COUNTER(ivar_get_ic_miss_set) // Misses on IV reads where the cache was wrong +RB_DEBUG_COUNTER(ivar_get_cc_miss_set) // Misses on attr_reader where the cache was wrong +RB_DEBUG_COUNTER(ivar_get_ic_miss_unset) // Misses on IV read where the cache wasn't set +RB_DEBUG_COUNTER(ivar_get_cc_miss_unset) // Misses on attr_reader where the cache wasn't set /* local variable counts * @@ -143,6 +184,11 @@ RB_DEBUG_COUNTER(gc_major_shady) RB_DEBUG_COUNTER(gc_major_force) RB_DEBUG_COUNTER(gc_major_oldmalloc) +RB_DEBUG_COUNTER(gc_enter_start) +RB_DEBUG_COUNTER(gc_enter_continue) +RB_DEBUG_COUNTER(gc_enter_rest) +RB_DEBUG_COUNTER(gc_enter_finalizer) + RB_DEBUG_COUNTER(gc_isptr_trial) RB_DEBUG_COUNTER(gc_isptr_range) RB_DEBUG_COUNTER(gc_isptr_align) @@ -152,7 +198,7 @@ RB_DEBUG_COUNTER(gc_isptr_maybe) * * * obj_newobj: newobj counts * * obj_newobj_slowpath: newobj with slowpath counts - * * obj_newobj_wb_unprotected: newobj for wb_unprotecte. + * * obj_newobj_wb_unprotected: newobj for wb_unprotected. * * obj_free: obj_free() counts * * obj_promote: promoted counts (oldgen) * * obj_wb_unprotect: wb unprotect counts @@ -168,15 +214,14 @@ RB_DEBUG_COUNTER(gc_isptr_maybe) * * [attr] * * _ptr: R?? is not embed. * * _embed: R?? is embed. - * * _transient: R?? uses transient heap. * * type specific attr. * * str_shared: str is shared. * * str_nofree: nofree * * str_fstr: fstr * * hash_empty: hash is empty - * * hash_under4: has under 4 entries - * * hash_ge4: has n entries (4<=n<8) - * * hash_ge8: has n entries (8<=n) + * * hash_1_4: has 1 to 4 entries + * * hash_5_8: has 5 to 8 entries + * * hash_g8: has n entries (n>8) * * match_under4: has under 4 oniguruma regions allocated * * match_ge4: has n regions allocated (4<=n<8) * * match_ge8: has n regions allocated (8<=n) @@ -194,8 +239,8 @@ RB_DEBUG_COUNTER(obj_promote) RB_DEBUG_COUNTER(obj_wb_unprotect) RB_DEBUG_COUNTER(obj_obj_embed) -RB_DEBUG_COUNTER(obj_obj_transient) RB_DEBUG_COUNTER(obj_obj_ptr) +RB_DEBUG_COUNTER(obj_obj_too_complex) RB_DEBUG_COUNTER(obj_str_ptr) RB_DEBUG_COUNTER(obj_str_embed) @@ -204,25 +249,34 @@ RB_DEBUG_COUNTER(obj_str_nofree) RB_DEBUG_COUNTER(obj_str_fstr) RB_DEBUG_COUNTER(obj_ary_embed) -RB_DEBUG_COUNTER(obj_ary_transient) RB_DEBUG_COUNTER(obj_ary_ptr) +RB_DEBUG_COUNTER(obj_ary_extracapa) +/* + ary_shared_create: shared ary by Array#dup and so on. + ary_shared: finished in shard. + ary_shared_root_occupied: shared_root but has only 1 refcnt. + The number (ary_shared - ary_shared_root_occupied) is meaningful. + */ +RB_DEBUG_COUNTER(obj_ary_shared_create) +RB_DEBUG_COUNTER(obj_ary_shared) +RB_DEBUG_COUNTER(obj_ary_shared_root_occupied) RB_DEBUG_COUNTER(obj_hash_empty) -RB_DEBUG_COUNTER(obj_hash_under4) -RB_DEBUG_COUNTER(obj_hash_ge4) -RB_DEBUG_COUNTER(obj_hash_ge8) +RB_DEBUG_COUNTER(obj_hash_1) +RB_DEBUG_COUNTER(obj_hash_2) +RB_DEBUG_COUNTER(obj_hash_3) +RB_DEBUG_COUNTER(obj_hash_4) +RB_DEBUG_COUNTER(obj_hash_5_8) +RB_DEBUG_COUNTER(obj_hash_g8) + +RB_DEBUG_COUNTER(obj_hash_null) RB_DEBUG_COUNTER(obj_hash_ar) RB_DEBUG_COUNTER(obj_hash_st) -RB_DEBUG_COUNTER(obj_hash_transient) - RB_DEBUG_COUNTER(obj_hash_force_convert) RB_DEBUG_COUNTER(obj_struct_embed) -RB_DEBUG_COUNTER(obj_struct_transient) RB_DEBUG_COUNTER(obj_struct_ptr) -RB_DEBUG_COUNTER(obj_regexp_ptr) - RB_DEBUG_COUNTER(obj_data_empty) RB_DEBUG_COUNTER(obj_data_xfree) RB_DEBUG_COUNTER(obj_data_imm_free) @@ -232,26 +286,42 @@ RB_DEBUG_COUNTER(obj_match_under4) RB_DEBUG_COUNTER(obj_match_ge4) RB_DEBUG_COUNTER(obj_match_ge8) RB_DEBUG_COUNTER(obj_match_ptr) -RB_DEBUG_COUNTER(obj_file_ptr) + +RB_DEBUG_COUNTER(obj_iclass_ptr) +RB_DEBUG_COUNTER(obj_class_ptr) +RB_DEBUG_COUNTER(obj_module_ptr) + RB_DEBUG_COUNTER(obj_bignum_ptr) +RB_DEBUG_COUNTER(obj_bignum_embed) +RB_DEBUG_COUNTER(obj_float) +RB_DEBUG_COUNTER(obj_complex) +RB_DEBUG_COUNTER(obj_rational) +RB_DEBUG_COUNTER(obj_regexp_ptr) +RB_DEBUG_COUNTER(obj_file_ptr) RB_DEBUG_COUNTER(obj_symbol) RB_DEBUG_COUNTER(obj_imemo_ment) RB_DEBUG_COUNTER(obj_imemo_iseq) RB_DEBUG_COUNTER(obj_imemo_env) RB_DEBUG_COUNTER(obj_imemo_tmpbuf) -RB_DEBUG_COUNTER(obj_imemo_ast) RB_DEBUG_COUNTER(obj_imemo_cref) RB_DEBUG_COUNTER(obj_imemo_svar) RB_DEBUG_COUNTER(obj_imemo_throw_data) RB_DEBUG_COUNTER(obj_imemo_ifunc) RB_DEBUG_COUNTER(obj_imemo_memo) -RB_DEBUG_COUNTER(obj_imemo_parser_strterm) +RB_DEBUG_COUNTER(obj_imemo_callinfo) +RB_DEBUG_COUNTER(obj_imemo_callcache) +RB_DEBUG_COUNTER(obj_imemo_constcache) +RB_DEBUG_COUNTER(obj_imemo_fields) -RB_DEBUG_COUNTER(obj_iclass_ptr) -RB_DEBUG_COUNTER(obj_class_ptr) -RB_DEBUG_COUNTER(obj_module_ptr) +RB_DEBUG_COUNTER(opt_new_hit) +RB_DEBUG_COUNTER(opt_new_miss) + +/* ar_table */ +RB_DEBUG_COUNTER(artable_hint_hit) +RB_DEBUG_COUNTER(artable_hint_miss) +RB_DEBUG_COUNTER(artable_hint_notfound) /* heap function counts * @@ -261,40 +331,12 @@ RB_DEBUG_COUNTER(heap_xmalloc) RB_DEBUG_COUNTER(heap_xrealloc) RB_DEBUG_COUNTER(heap_xfree) -/* transient_heap */ -RB_DEBUG_COUNTER(theap_alloc) -RB_DEBUG_COUNTER(theap_alloc_fail) -RB_DEBUG_COUNTER(theap_evacuate) - -/* mjit_exec() counts */ -RB_DEBUG_COUNTER(mjit_exec) -RB_DEBUG_COUNTER(mjit_exec_not_added) -RB_DEBUG_COUNTER(mjit_exec_not_added_add_iseq) -RB_DEBUG_COUNTER(mjit_exec_not_ready) -RB_DEBUG_COUNTER(mjit_exec_not_compiled) -RB_DEBUG_COUNTER(mjit_exec_call_func) - -/* MJIT <-> VM frame push counts */ -RB_DEBUG_COUNTER(mjit_frame_VM2VM) -RB_DEBUG_COUNTER(mjit_frame_VM2JT) -RB_DEBUG_COUNTER(mjit_frame_JT2JT) -RB_DEBUG_COUNTER(mjit_frame_JT2VM) - -/* MJIT cancel counters */ -RB_DEBUG_COUNTER(mjit_cancel) -RB_DEBUG_COUNTER(mjit_cancel_ivar_inline) -RB_DEBUG_COUNTER(mjit_cancel_send_inline) -RB_DEBUG_COUNTER(mjit_cancel_opt_insn) /* CALL_SIMPLE_METHOD */ -RB_DEBUG_COUNTER(mjit_cancel_invalidate_all) - -/* rb_mjit_unit_list length */ -RB_DEBUG_COUNTER(mjit_length_unit_queue) -RB_DEBUG_COUNTER(mjit_length_active_units) -RB_DEBUG_COUNTER(mjit_length_compact_units) -RB_DEBUG_COUNTER(mjit_length_stale_units) - -/* Other MJIT counters */ -RB_DEBUG_COUNTER(mjit_compile_failures) +// VM sync +RB_DEBUG_COUNTER(vm_sync_lock) +RB_DEBUG_COUNTER(vm_sync_lock_enter) +RB_DEBUG_COUNTER(vm_sync_lock_enter_nb) +RB_DEBUG_COUNTER(vm_sync_lock_enter_cr) +RB_DEBUG_COUNTER(vm_sync_barrier) /* load (not implemented yet) */ /* @@ -306,43 +348,78 @@ RB_DEBUG_COUNTER(load_path_is_not_realpath) #ifndef RUBY_DEBUG_COUNTER_H #define RUBY_DEBUG_COUNTER_H 1 +#include "ruby/internal/config.h" +#include <stddef.h> /* for size_t */ +#include "ruby/ruby.h" /* for VALUE */ + #if !defined(__GNUC__) && USE_DEBUG_COUNTER #error "USE_DEBUG_COUNTER is not supported by other than __GNUC__" #endif enum rb_debug_counter_type { #define RB_DEBUG_COUNTER(name) RB_DEBUG_COUNTER_##name, -#include __FILE__ +#include "debug_counter.h" RB_DEBUG_COUNTER_MAX #undef RB_DEBUG_COUNTER }; #if USE_DEBUG_COUNTER -#include "ruby/ruby.h" - extern size_t rb_debug_counter[]; +RUBY_EXTERN struct rb_ractor_struct *ruby_single_main_ractor; +RUBY_EXTERN void rb_debug_counter_add_atomic(enum rb_debug_counter_type type, int add); inline static int rb_debug_counter_add(enum rb_debug_counter_type type, int add, int cond) { if (cond) { - rb_debug_counter[(int)type] += add; + if (ruby_single_main_ractor != NULL) { + rb_debug_counter[(int)type] += add; + } + else { + rb_debug_counter_add_atomic(type, add); + } } return cond; } -VALUE rb_debug_counter_reset(void); +inline static int +rb_debug_counter_max(enum rb_debug_counter_type type, unsigned int num) +{ + // TODO: sync + if (rb_debug_counter[(int)type] < num) { + rb_debug_counter[(int)type] = num; + return 1; + } + else { + return 0; + } +} + +VALUE rb_debug_counter_reset(VALUE klass); +VALUE rb_debug_counter_show(VALUE klass); #define RB_DEBUG_COUNTER_INC(type) rb_debug_counter_add(RB_DEBUG_COUNTER_##type, 1, 1) #define RB_DEBUG_COUNTER_INC_UNLESS(type, cond) (!rb_debug_counter_add(RB_DEBUG_COUNTER_##type, 1, !(cond))) -#define RB_DEBUG_COUNTER_INC_IF(type, cond) rb_debug_counter_add(RB_DEBUG_COUNTER_##type, 1, (cond)) +#define RB_DEBUG_COUNTER_INC_IF(type, cond) rb_debug_counter_add(RB_DEBUG_COUNTER_##type, 1, !!(cond)) +#define RB_DEBUG_COUNTER_ADD(type, num) rb_debug_counter_add(RB_DEBUG_COUNTER_##type, (num), 1) +#define RB_DEBUG_COUNTER_SETMAX(type, num) rb_debug_counter_max(RB_DEBUG_COUNTER_##type, (unsigned int)(num)) #else #define RB_DEBUG_COUNTER_INC(type) ((void)0) -#define RB_DEBUG_COUNTER_INC_UNLESS(type, cond) (cond) -#define RB_DEBUG_COUNTER_INC_IF(type, cond) (cond) +#define RB_DEBUG_COUNTER_INC_UNLESS(type, cond) (!!(cond)) +#define RB_DEBUG_COUNTER_INC_IF(type, cond) (!!(cond)) +#define RB_DEBUG_COUNTER_ADD(type, num) ((void)0) +#define RB_DEBUG_COUNTER_SETMAX(type, num) 0 #endif void rb_debug_counter_show_results(const char *msg); +RUBY_SYMBOL_EXPORT_BEGIN + +size_t ruby_debug_counter_get(const char **names_ptr, size_t *counters_ptr); +void ruby_debug_counter_reset(void); +void ruby_debug_counter_show_at_exit(int enable); + +RUBY_SYMBOL_EXPORT_END + #endif /* RUBY_DEBUG_COUNTER_H */ |
