Ruby 3.2.4p170 (2024-04-23 revision af471c0e0127eea0cafa6f308c0425bbfab0acf5)
debug_counter.h
1/**********************************************************************
2
3 debug_counter.h -
4
5 created at: Tue Feb 21 16:51:18 2017
6
7 Copyright (C) 2017 Koichi Sasada
8
9**********************************************************************/
10
11#ifndef USE_DEBUG_COUNTER
12#define USE_DEBUG_COUNTER 0
13#endif
14
15#ifdef RB_DEBUG_COUNTER
16
17// method cache (IMC: inline method cache)
18RB_DEBUG_COUNTER(mc_inline_hit) // IMC hit
19RB_DEBUG_COUNTER(mc_inline_miss_klass) // IMC miss by different class
20RB_DEBUG_COUNTER(mc_inline_miss_invalidated) // IMC miss by invalidated ME
21RB_DEBUG_COUNTER(mc_inline_miss_empty) // IMC miss because prev is empty slot
22RB_DEBUG_COUNTER(mc_inline_miss_same_cc) // IMC miss, but same CC
23RB_DEBUG_COUNTER(mc_inline_miss_same_cme) // IMC miss, but same CME
24RB_DEBUG_COUNTER(mc_inline_miss_same_def) // IMC miss, but same definition
25RB_DEBUG_COUNTER(mc_inline_miss_diff) // IMC miss, different methods
26
27RB_DEBUG_COUNTER(cvar_write_inline_hit) // cvar cache hit on write
28RB_DEBUG_COUNTER(cvar_read_inline_hit) // cvar cache hit on read
29RB_DEBUG_COUNTER(cvar_inline_miss) // miss inline cache
30RB_DEBUG_COUNTER(cvar_class_invalidate) // invalidate cvar cache when define a cvar that's defined on a subclass
31RB_DEBUG_COUNTER(cvar_include_invalidate) // invalidate cvar cache on module include or prepend
32
33RB_DEBUG_COUNTER(mc_cme_complement) // number of acquiring complement CME
34RB_DEBUG_COUNTER(mc_cme_complement_hit) // number of cache hit for complemented CME
35
36RB_DEBUG_COUNTER(mc_search) // count for method lookup in class tree
37RB_DEBUG_COUNTER(mc_search_notfound) // method lookup, but not found
38RB_DEBUG_COUNTER(mc_search_super) // total traversed classes
39
40// callinfo
41RB_DEBUG_COUNTER(ci_packed) // number of packed CI
42RB_DEBUG_COUNTER(ci_kw) // non-packed CI w/ keywords
43RB_DEBUG_COUNTER(ci_nokw) // non-packed CI w/o keywords
44RB_DEBUG_COUNTER(ci_runtime) // creating temporary CI
45
46// callcache
47RB_DEBUG_COUNTER(cc_new) // number of CC
48RB_DEBUG_COUNTER(cc_temp) // dummy CC (stack-allocated)
49RB_DEBUG_COUNTER(cc_found_in_ccs) // count for CC lookup success in CCS
50RB_DEBUG_COUNTER(cc_not_found_in_ccs) // count for CC lookup success in CCS
51
52RB_DEBUG_COUNTER(cc_ent_invalidate) // count for invalidating cc (cc->klass = 0)
53RB_DEBUG_COUNTER(cc_cme_invalidate) // count for invalidating CME
54
55RB_DEBUG_COUNTER(cc_invalidate_leaf) // count for invalidating klass if klass has no-subclasses
56RB_DEBUG_COUNTER(cc_invalidate_leaf_ccs) // corresponding CCS
57RB_DEBUG_COUNTER(cc_invalidate_leaf_callable) // complimented cache (no-subclasses)
58RB_DEBUG_COUNTER(cc_invalidate_tree) // count for invalidating klass if klass has subclasses
59RB_DEBUG_COUNTER(cc_invalidate_tree_cme) // cme if cme is found in this class or superclasses
60RB_DEBUG_COUNTER(cc_invalidate_tree_callable) // complimented cache (subclasses)
61RB_DEBUG_COUNTER(cc_invalidate_negative) // count for invalidating negative cache
62
63RB_DEBUG_COUNTER(ccs_free) // count for free'ing ccs
64RB_DEBUG_COUNTER(ccs_maxlen) // maximum length of ccs
65RB_DEBUG_COUNTER(ccs_found) // count for finding corresponding ccs on method lookup
66RB_DEBUG_COUNTER(ccs_not_found) // count for not found corresponding ccs on method lookup
67
68// vm_eval.c
69RB_DEBUG_COUNTER(call0_public)
70RB_DEBUG_COUNTER(call0_other)
71RB_DEBUG_COUNTER(gccct_hit)
72RB_DEBUG_COUNTER(gccct_miss)
73RB_DEBUG_COUNTER(gccct_null)
74
75// iseq
76RB_DEBUG_COUNTER(iseq_num) // number of total created iseq
77RB_DEBUG_COUNTER(iseq_cd_num) // number of total created cd (call_data)
78
79/*
80 * call cache fastpath usage
81 */
82RB_DEBUG_COUNTER(ccf_general)
83RB_DEBUG_COUNTER(ccf_iseq_setup)
84RB_DEBUG_COUNTER(ccf_iseq_setup_0start)
85RB_DEBUG_COUNTER(ccf_iseq_setup_tailcall_0start)
86RB_DEBUG_COUNTER(ccf_iseq_fix) /* several functions created with tool/mk_call_iseq_optimized.rb */
87RB_DEBUG_COUNTER(ccf_iseq_opt) /* has_opt == TRUE (has optional parameters), but other flags are FALSE */
88RB_DEBUG_COUNTER(ccf_iseq_kw1) /* vm_call_iseq_setup_kwparm_kwarg() */
89RB_DEBUG_COUNTER(ccf_iseq_kw2) /* vm_call_iseq_setup_kwparm_nokwarg() */
90RB_DEBUG_COUNTER(ccf_cfunc)
91RB_DEBUG_COUNTER(ccf_cfunc_with_frame)
92RB_DEBUG_COUNTER(ccf_ivar) /* attr_reader */
93RB_DEBUG_COUNTER(ccf_attrset) /* attr_writer */
94RB_DEBUG_COUNTER(ccf_method_missing)
95RB_DEBUG_COUNTER(ccf_zsuper)
96RB_DEBUG_COUNTER(ccf_bmethod)
97RB_DEBUG_COUNTER(ccf_opt_send)
98RB_DEBUG_COUNTER(ccf_opt_call)
99RB_DEBUG_COUNTER(ccf_opt_block_call)
100RB_DEBUG_COUNTER(ccf_opt_struct_aref)
101RB_DEBUG_COUNTER(ccf_opt_struct_aset)
102RB_DEBUG_COUNTER(ccf_super_method)
103
104/*
105 * control frame push counts.
106 *
107 * * frame_push: frame push counts.
108 * * frame_push_*: frame push counts per each type.
109 * * frame_R2R: Ruby frame to Ruby frame
110 * * frame_R2C: Ruby frame to C frame
111 * * frame_C2C: C frame to C frame
112 * * frame_C2R: C frame to Ruby frame
113 */
114RB_DEBUG_COUNTER(frame_push)
115RB_DEBUG_COUNTER(frame_push_method)
116RB_DEBUG_COUNTER(frame_push_block)
117RB_DEBUG_COUNTER(frame_push_class)
118RB_DEBUG_COUNTER(frame_push_top)
119RB_DEBUG_COUNTER(frame_push_cfunc)
120RB_DEBUG_COUNTER(frame_push_ifunc)
121RB_DEBUG_COUNTER(frame_push_eval)
122RB_DEBUG_COUNTER(frame_push_rescue)
123RB_DEBUG_COUNTER(frame_push_dummy)
124
125RB_DEBUG_COUNTER(frame_R2R)
126RB_DEBUG_COUNTER(frame_R2C)
127RB_DEBUG_COUNTER(frame_C2C)
128RB_DEBUG_COUNTER(frame_C2R)
129
130/* instance variable counts
131 *
132 * * ivar_get_ic_hit/miss: ivar_get inline cache (ic) hit/miss counts (VM insn)
133 * * ivar_get_ic_miss_unset: ... by unset (VM insn)
134 * * ivar_get_ic_miss_noobject: ... by "not T_OBJECT" (VM insn)
135 * * ivar_set_...: same counts with ivar_set (VM insn)
136 * * ivar_get/set_base: call counts of "rb_ivar_get/set()".
137 * because of (1) ic miss.
138 * (2) direct call by C extensions.
139 */
140RB_DEBUG_COUNTER(ivar_get_ic_hit)
141RB_DEBUG_COUNTER(ivar_get_ic_miss)
142RB_DEBUG_COUNTER(ivar_get_ic_miss_noobject)
143RB_DEBUG_COUNTER(ivar_set_ic_hit)
144RB_DEBUG_COUNTER(ivar_set_ic_miss)
145RB_DEBUG_COUNTER(ivar_set_ic_miss_iv_hit)
146RB_DEBUG_COUNTER(ivar_set_ic_miss_noobject)
147RB_DEBUG_COUNTER(ivar_get_base)
148RB_DEBUG_COUNTER(ivar_set_base)
149RB_DEBUG_COUNTER(ivar_get_ic_miss_set)
150RB_DEBUG_COUNTER(ivar_get_cc_miss_set)
151RB_DEBUG_COUNTER(ivar_get_ic_miss_unset)
152RB_DEBUG_COUNTER(ivar_get_cc_miss_unset)
153
154/* local variable counts
155 *
156 * * lvar_get: total lvar get counts (VM insn)
157 * * lvar_get_dynamic: lvar get counts if accessing upper env (VM insn)
158 * * lvar_set*: same as "get"
159 * * lvar_set_slowpath: counts using vm_env_write_slowpath()
160 */
161RB_DEBUG_COUNTER(lvar_get)
162RB_DEBUG_COUNTER(lvar_get_dynamic)
163RB_DEBUG_COUNTER(lvar_set)
164RB_DEBUG_COUNTER(lvar_set_dynamic)
165RB_DEBUG_COUNTER(lvar_set_slowpath)
166
167/* GC counts:
168 *
169 * * count: simple count
170 * * _minor: minor gc
171 * * _major: major gc
172 * * other suffix is corresponding to last_gc_info or
173 * gc_profile_record_flag in gc.c.
174 */
175RB_DEBUG_COUNTER(gc_count)
176RB_DEBUG_COUNTER(gc_minor_newobj)
177RB_DEBUG_COUNTER(gc_minor_malloc)
178RB_DEBUG_COUNTER(gc_minor_method)
179RB_DEBUG_COUNTER(gc_minor_capi)
180RB_DEBUG_COUNTER(gc_minor_stress)
181RB_DEBUG_COUNTER(gc_major_nofree)
182RB_DEBUG_COUNTER(gc_major_oldgen)
183RB_DEBUG_COUNTER(gc_major_shady)
184RB_DEBUG_COUNTER(gc_major_force)
185RB_DEBUG_COUNTER(gc_major_oldmalloc)
186
187RB_DEBUG_COUNTER(gc_enter_start)
188RB_DEBUG_COUNTER(gc_enter_mark_continue)
189RB_DEBUG_COUNTER(gc_enter_sweep_continue)
190RB_DEBUG_COUNTER(gc_enter_rest)
191RB_DEBUG_COUNTER(gc_enter_finalizer)
192
193RB_DEBUG_COUNTER(gc_isptr_trial)
194RB_DEBUG_COUNTER(gc_isptr_range)
195RB_DEBUG_COUNTER(gc_isptr_align)
196RB_DEBUG_COUNTER(gc_isptr_maybe)
197
198/* object allocation counts:
199 *
200 * * obj_newobj: newobj counts
201 * * obj_newobj_slowpath: newobj with slowpath counts
202 * * obj_newobj_wb_unprotected: newobj for wb_unprotected.
203 * * obj_free: obj_free() counts
204 * * obj_promote: promoted counts (oldgen)
205 * * obj_wb_unprotect: wb unprotect counts
206 *
207 * * obj_[type]_[attr]: *free'ed counts* for each type.
208 * Note that it is not a allocated counts.
209 * * [type]
210 * * _obj: T_OBJECT
211 * * _str: T_STRING
212 * * _ary: T_ARRAY
213 * * _xxx: T_XXX (hash, struct, ...)
214 *
215 * * [attr]
216 * * _ptr: R?? is not embed.
217 * * _embed: R?? is embed.
218 * * _transient: R?? uses transient heap.
219 * * type specific attr.
220 * * str_shared: str is shared.
221 * * str_nofree: nofree
222 * * str_fstr: fstr
223 * * hash_empty: hash is empty
224 * * hash_1_4: has 1 to 4 entries
225 * * hash_5_8: has 5 to 8 entries
226 * * hash_g8: has n entries (n>8)
227 * * match_under4: has under 4 oniguruma regions allocated
228 * * match_ge4: has n regions allocated (4<=n<8)
229 * * match_ge8: has n regions allocated (8<=n)
230 * * data_empty: T_DATA but no memory free.
231 * * data_xfree: free'ed by xfree().
232 * * data_imm_free: free'ed immediately.
233 * * data_zombie: free'ed with zombie.
234 * * imemo_*: T_IMEMO with each type.
235 */
236RB_DEBUG_COUNTER(obj_newobj)
237RB_DEBUG_COUNTER(obj_newobj_slowpath)
238RB_DEBUG_COUNTER(obj_newobj_wb_unprotected)
239RB_DEBUG_COUNTER(obj_free)
240RB_DEBUG_COUNTER(obj_promote)
241RB_DEBUG_COUNTER(obj_wb_unprotect)
242
243RB_DEBUG_COUNTER(obj_obj_embed)
244RB_DEBUG_COUNTER(obj_obj_transient)
245RB_DEBUG_COUNTER(obj_obj_ptr)
246RB_DEBUG_COUNTER(obj_obj_too_complex)
247
248RB_DEBUG_COUNTER(obj_str_ptr)
249RB_DEBUG_COUNTER(obj_str_embed)
250RB_DEBUG_COUNTER(obj_str_shared)
251RB_DEBUG_COUNTER(obj_str_nofree)
252RB_DEBUG_COUNTER(obj_str_fstr)
253
254RB_DEBUG_COUNTER(obj_ary_embed)
255RB_DEBUG_COUNTER(obj_ary_transient)
256RB_DEBUG_COUNTER(obj_ary_ptr)
257RB_DEBUG_COUNTER(obj_ary_extracapa)
258/*
259 ary_shared_create: shared ary by Array#dup and so on.
260 ary_shared: finished in shard.
261 ary_shared_root_occupied: shared_root but has only 1 refcnt.
262 The number (ary_shared - ary_shared_root_occupied) is meaningful.
263 */
264RB_DEBUG_COUNTER(obj_ary_shared_create)
265RB_DEBUG_COUNTER(obj_ary_shared)
266RB_DEBUG_COUNTER(obj_ary_shared_root_occupied)
267
268RB_DEBUG_COUNTER(obj_hash_empty)
269RB_DEBUG_COUNTER(obj_hash_1)
270RB_DEBUG_COUNTER(obj_hash_2)
271RB_DEBUG_COUNTER(obj_hash_3)
272RB_DEBUG_COUNTER(obj_hash_4)
273RB_DEBUG_COUNTER(obj_hash_5_8)
274RB_DEBUG_COUNTER(obj_hash_g8)
275
276RB_DEBUG_COUNTER(obj_hash_null)
277RB_DEBUG_COUNTER(obj_hash_ar)
278RB_DEBUG_COUNTER(obj_hash_st)
279RB_DEBUG_COUNTER(obj_hash_transient)
280RB_DEBUG_COUNTER(obj_hash_force_convert)
281
282RB_DEBUG_COUNTER(obj_struct_embed)
283RB_DEBUG_COUNTER(obj_struct_transient)
284RB_DEBUG_COUNTER(obj_struct_ptr)
285
286RB_DEBUG_COUNTER(obj_data_empty)
287RB_DEBUG_COUNTER(obj_data_xfree)
288RB_DEBUG_COUNTER(obj_data_imm_free)
289RB_DEBUG_COUNTER(obj_data_zombie)
290
291RB_DEBUG_COUNTER(obj_match_under4)
292RB_DEBUG_COUNTER(obj_match_ge4)
293RB_DEBUG_COUNTER(obj_match_ge8)
294RB_DEBUG_COUNTER(obj_match_ptr)
295
296RB_DEBUG_COUNTER(obj_iclass_ptr)
297RB_DEBUG_COUNTER(obj_class_ptr)
298RB_DEBUG_COUNTER(obj_module_ptr)
299
300RB_DEBUG_COUNTER(obj_bignum_ptr)
301RB_DEBUG_COUNTER(obj_bignum_embed)
302RB_DEBUG_COUNTER(obj_float)
303RB_DEBUG_COUNTER(obj_complex)
304RB_DEBUG_COUNTER(obj_rational)
305
306RB_DEBUG_COUNTER(obj_regexp_ptr)
307RB_DEBUG_COUNTER(obj_file_ptr)
308RB_DEBUG_COUNTER(obj_symbol)
309
310RB_DEBUG_COUNTER(obj_imemo_ment)
311RB_DEBUG_COUNTER(obj_imemo_iseq)
312RB_DEBUG_COUNTER(obj_imemo_env)
313RB_DEBUG_COUNTER(obj_imemo_tmpbuf)
314RB_DEBUG_COUNTER(obj_imemo_ast)
315RB_DEBUG_COUNTER(obj_imemo_cref)
316RB_DEBUG_COUNTER(obj_imemo_svar)
317RB_DEBUG_COUNTER(obj_imemo_throw_data)
318RB_DEBUG_COUNTER(obj_imemo_ifunc)
319RB_DEBUG_COUNTER(obj_imemo_memo)
320RB_DEBUG_COUNTER(obj_imemo_parser_strterm)
321RB_DEBUG_COUNTER(obj_imemo_callinfo)
322RB_DEBUG_COUNTER(obj_imemo_callcache)
323RB_DEBUG_COUNTER(obj_imemo_constcache)
324
325/* ar_table */
326RB_DEBUG_COUNTER(artable_hint_hit)
327RB_DEBUG_COUNTER(artable_hint_miss)
328RB_DEBUG_COUNTER(artable_hint_notfound)
329
330/* heap function counts
331 *
332 * * heap_xmalloc/realloc/xfree: call counts
333 */
334RB_DEBUG_COUNTER(heap_xmalloc)
335RB_DEBUG_COUNTER(heap_xrealloc)
336RB_DEBUG_COUNTER(heap_xfree)
337
338/* transient_heap */
339RB_DEBUG_COUNTER(theap_alloc)
340RB_DEBUG_COUNTER(theap_alloc_fail)
341RB_DEBUG_COUNTER(theap_evacuate)
342
343// VM sync
344RB_DEBUG_COUNTER(vm_sync_lock)
345RB_DEBUG_COUNTER(vm_sync_lock_enter)
346RB_DEBUG_COUNTER(vm_sync_lock_enter_nb)
347RB_DEBUG_COUNTER(vm_sync_lock_enter_cr)
348RB_DEBUG_COUNTER(vm_sync_barrier)
349
350/* load (not implemented yet) */
351/*
352RB_DEBUG_COUNTER(load_files)
353RB_DEBUG_COUNTER(load_path_is_not_realpath)
354*/
355#endif
356
357#ifndef RUBY_DEBUG_COUNTER_H
358#define RUBY_DEBUG_COUNTER_H 1
359
360#include "ruby/internal/config.h"
361#include <stddef.h> /* for size_t */
362#include "ruby/ruby.h" /* for VALUE */
363
364#if !defined(__GNUC__) && USE_DEBUG_COUNTER
365#error "USE_DEBUG_COUNTER is not supported by other than __GNUC__"
366#endif
367
368enum rb_debug_counter_type {
369#define RB_DEBUG_COUNTER(name) RB_DEBUG_COUNTER_##name,
370#include __FILE__
371 RB_DEBUG_COUNTER_MAX
372#undef RB_DEBUG_COUNTER
373};
374
375#if USE_DEBUG_COUNTER
376extern size_t rb_debug_counter[];
377RUBY_EXTERN struct rb_ractor_struct *ruby_single_main_ractor;
378RUBY_EXTERN void rb_debug_counter_add_atomic(enum rb_debug_counter_type type, int add);
379
380inline static int
381rb_debug_counter_add(enum rb_debug_counter_type type, int add, int cond)
382{
383 if (cond) {
384 if (ruby_single_main_ractor != NULL) {
385 rb_debug_counter[(int)type] += add;
386 }
387 else {
388 rb_debug_counter_add_atomic(type, add);
389 }
390 }
391 return cond;
392}
393
394inline static int
395rb_debug_counter_max(enum rb_debug_counter_type type, unsigned int num)
396{
397 // TODO: sync
398 if (rb_debug_counter[(int)type] < num) {
399 rb_debug_counter[(int)type] = num;
400 return 1;
401 }
402 else {
403 return 0;
404 }
405}
406
407VALUE rb_debug_counter_reset(VALUE klass);
408VALUE rb_debug_counter_show(VALUE klass);
409
410#define RB_DEBUG_COUNTER_INC(type) rb_debug_counter_add(RB_DEBUG_COUNTER_##type, 1, 1)
411#define RB_DEBUG_COUNTER_INC_UNLESS(type, cond) (!rb_debug_counter_add(RB_DEBUG_COUNTER_##type, 1, !(cond)))
412#define RB_DEBUG_COUNTER_INC_IF(type, cond) rb_debug_counter_add(RB_DEBUG_COUNTER_##type, 1, !!(cond))
413#define RB_DEBUG_COUNTER_ADD(type, num) rb_debug_counter_add(RB_DEBUG_COUNTER_##type, (num), 1)
414#define RB_DEBUG_COUNTER_SETMAX(type, num) rb_debug_counter_max(RB_DEBUG_COUNTER_##type, (unsigned int)(num))
415
416#else
417#define RB_DEBUG_COUNTER_INC(type) ((void)0)
418#define RB_DEBUG_COUNTER_INC_UNLESS(type, cond) (!!(cond))
419#define RB_DEBUG_COUNTER_INC_IF(type, cond) (!!(cond))
420#define RB_DEBUG_COUNTER_ADD(type, num) ((void)0)
421#define RB_DEBUG_COUNTER_SETMAX(type, num) 0
422#endif
423
424void rb_debug_counter_show_results(const char *msg);
425
426RUBY_SYMBOL_EXPORT_BEGIN
427
428size_t ruby_debug_counter_get(const char **names_ptr, size_t *counters_ptr);
429void ruby_debug_counter_reset(void);
430void ruby_debug_counter_show_at_exit(int enable);
431
432RUBY_SYMBOL_EXPORT_END
433
434#endif /* RUBY_DEBUG_COUNTER_H */
#define RUBY_EXTERN
Declaration of externally visible global variables.
Definition dllexport.h:47
VALUE type(ANYARGS)
ANYARGS-ed function type.
uintptr_t VALUE
Type that represents a Ruby object.
Definition value.h:40