summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKevin Newton <kddnewton@gmail.com>2022-04-05 16:37:00 -0400
committerGitHub <noreply@github.com>2022-04-05 16:37:00 -0400
commit8ee4a82e8cfe6f39abeb60013447bdd2a3a3c61f (patch)
tree98de69b8cf48b6af86e980897c4563514280af0f
parent5571ca3aa2029789e968fe8b13e176fa98fcea36 (diff)
downloadruby-8ee4a82e8cfe6f39abeb60013447bdd2a3a3c61f.tar.gz
RubyVM.stat constant cache metrics (#5766)
Before the new constant cache behavior, caches were invalidated by a single global variable. You could inspect the value of this variable with RubyVM.stat(:global_constant_state). This was mostly useful to verify the behavior of the VM or to test constant loading like in Rails. With the new constant cache behavior, we introduced RubyVM.stat(:constant_cache) which returned a hash with symbol keys and integer values that represented the number of live constant caches associated with the given symbol. Additionally, we removed the old RubyVM.stat(:global_constant_state). This was proven to be not very useful, so it doesn't help you diagnose constant loading issues. So, instead we added the global constant state back into the RubyVM output. However, that number can be misleading as now when you invalidate something like `Foo::Bar::Baz` you're actually invalidating 3 different lists of inline caches. This commit attempts to get the best of both worlds. We remove RubyVM.stat(:global_constant_state) like we did originally, as it doesn't have the same semantic meaning and it could be confusing going forward. Instead we add RubyVM.stat(:constant_cache_invalidations) and RubyVM.stat(:constant_cache_misses). These two metrics should provide enough information to diagnose any constant loading issues, as well as provide a replacement for the old global constant state.
-rw-r--r--insns.def1
-rw-r--r--vm.c43
-rw-r--r--vm_insnhelper.h3
-rw-r--r--vm_method.c2
4 files changed, 15 insertions, 34 deletions
diff --git a/insns.def b/insns.def
index cdec216cfe..b5dea9c10c 100644
--- a/insns.def
+++ b/insns.def
@@ -1044,6 +1044,7 @@ opt_getinlinecache
JUMP(dst);
}
else {
+ ruby_vm_constant_cache_misses++;
val = Qnil;
}
}
diff --git a/vm.c b/vm.c
index c02d502f37..720d26256e 100644
--- a/vm.c
+++ b/vm.c
@@ -428,7 +428,8 @@ rb_event_flag_t ruby_vm_event_flags;
rb_event_flag_t ruby_vm_event_enabled_global_flags;
unsigned int ruby_vm_event_local_num;
-rb_serial_t ruby_vm_global_constant_state = 1;
+rb_serial_t ruby_vm_constant_cache_invalidations = 0;
+rb_serial_t ruby_vm_constant_cache_misses = 0;
rb_serial_t ruby_vm_class_serial = 1;
rb_serial_t ruby_vm_global_cvar_state = 1;
@@ -496,16 +497,6 @@ rb_dtrace_setup(rb_execution_context_t *ec, VALUE klass, ID id,
return FALSE;
}
-// Iterator function to loop through each entry in the constant cache and add
-// its associated size into the given Hash.
-static enum rb_id_table_iterator_result
-vm_stat_constant_cache_i(ID id, VALUE table, void *constant_cache)
-{
- st_index_t size = ((st_table *) table)->num_entries;
- rb_hash_aset((VALUE) constant_cache, ID2SYM(id), LONG2NUM(size));
- return ID_TABLE_CONTINUE;
-}
-
/*
* call-seq:
* RubyVM.stat -> Hash
@@ -517,8 +508,10 @@ vm_stat_constant_cache_i(ID id, VALUE table, void *constant_cache)
* This hash includes information about method/constant caches:
*
* {
- * :constant_cache=>{:RubyVM=>3},
- * :class_serial=>9029
+ * :constant_cache_invalidations=>2,
+ * :constant_cache_misses=>14,
+ * :class_serial=>546,
+ * :global_cvar_state=>27
* }
*
* The contents of the hash are implementation specific and may be changed in
@@ -529,7 +522,7 @@ vm_stat_constant_cache_i(ID id, VALUE table, void *constant_cache)
static VALUE
vm_stat(int argc, VALUE *argv, VALUE self)
{
- static VALUE sym_global_constant_state, sym_constant_cache, sym_class_serial, sym_global_cvar_state;
+ static VALUE sym_constant_cache_invalidations, sym_constant_cache_misses, sym_class_serial, sym_global_cvar_state;
VALUE arg = Qnil;
VALUE hash = Qnil, key = Qnil;
@@ -547,8 +540,8 @@ vm_stat(int argc, VALUE *argv, VALUE self)
}
#define S(s) sym_##s = ID2SYM(rb_intern_const(#s))
- S(global_constant_state);
- S(constant_cache);
+ S(constant_cache_invalidations);
+ S(constant_cache_misses);
S(class_serial);
S(global_cvar_state);
#undef S
@@ -559,26 +552,12 @@ vm_stat(int argc, VALUE *argv, VALUE self)
else if (hash != Qnil) \
rb_hash_aset(hash, sym_##name, SERIALT2NUM(attr));
- SET(global_constant_state, ruby_vm_global_constant_state);
+ SET(constant_cache_invalidations, ruby_vm_constant_cache_invalidations);
+ SET(constant_cache_misses, ruby_vm_constant_cache_misses);
SET(class_serial, ruby_vm_class_serial);
SET(global_cvar_state, ruby_vm_global_cvar_state);
#undef SET
- // Here we're going to set up the constant cache hash that has key-value
- // pairs of { name => count }, where name is a Symbol that represents the
- // ID in the cache and count is an Integer representing the number of inline
- // constant caches associated with that Symbol.
- if (key == sym_constant_cache || hash != Qnil) {
- VALUE constant_cache = rb_hash_new();
- rb_id_table_foreach(GET_VM()->constant_cache, vm_stat_constant_cache_i, (void *) constant_cache);
-
- if (key == sym_constant_cache) {
- return constant_cache;
- } else {
- rb_hash_aset(hash, sym_constant_cache, constant_cache);
- }
- }
-
if (!NIL_P(key)) { /* matched key should return above */
rb_raise(rb_eArgError, "unknown key: %"PRIsVALUE, rb_sym2str(key));
}
diff --git a/vm_insnhelper.h b/vm_insnhelper.h
index 5506fca4d6..126867025f 100644
--- a/vm_insnhelper.h
+++ b/vm_insnhelper.h
@@ -14,7 +14,8 @@
MJIT_SYMBOL_EXPORT_BEGIN
RUBY_EXTERN VALUE ruby_vm_const_missing_count;
-RUBY_EXTERN rb_serial_t ruby_vm_global_constant_state;
+RUBY_EXTERN rb_serial_t ruby_vm_constant_cache_invalidations;
+RUBY_EXTERN rb_serial_t ruby_vm_constant_cache_misses;
RUBY_EXTERN rb_serial_t ruby_vm_class_serial;
RUBY_EXTERN rb_serial_t ruby_vm_global_cvar_state;
diff --git a/vm_method.c b/vm_method.c
index 81e88a32c1..36a2c15e4b 100644
--- a/vm_method.c
+++ b/vm_method.c
@@ -144,10 +144,10 @@ rb_clear_constant_cache_for_id(ID id)
if (rb_id_table_lookup(vm->constant_cache, id, (VALUE *) &ics)) {
st_foreach(ics, rb_clear_constant_cache_for_id_i, (st_data_t) NULL);
+ ruby_vm_constant_cache_invalidations += ics->num_entries;
}
rb_yjit_constant_state_changed();
- ruby_vm_global_constant_state++;
}
static void