Skip to content

Commit b22eb0e

Browse files
authored
ZJIT: Add --zjit-stats (ruby#14034)
1 parent a66e4f2 commit b22eb0e

File tree

17 files changed

+210
-23
lines changed

17 files changed

+210
-23
lines changed

configure.ac

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3976,7 +3976,7 @@ AS_CASE(["${YJIT_SUPPORT}"],
39763976

39773977
ZJIT_LIBS=
39783978
AS_CASE(["${ZJIT_SUPPORT}"],
3979-
[yes|dev|dev_nodebug], [
3979+
[yes|dev|dev_nodebug|stats], [
39803980
AS_IF([test x"$RUSTC" = "xno"],
39813981
AC_MSG_ERROR([rustc is required. Installation instructions available at https://www.rust-lang.org/tools/install])
39823982
)
@@ -3987,11 +3987,16 @@ AS_CASE(["${ZJIT_SUPPORT}"],
39873987
[dev], [
39883988
rb_cargo_features="$rb_cargo_features,disasm"
39893989
JIT_CARGO_SUPPORT=dev
3990-
AC_DEFINE(RUBY_DEBUG, 1)
3990+
AC_DEFINE(RUBY_DEBUG, 1)
39913991
],
39923992
[dev_nodebug], [
39933993
rb_cargo_features="$rb_cargo_features,disasm"
39943994
JIT_CARGO_SUPPORT=dev_nodebug
3995+
AC_DEFINE(ZJIT_STATS, 1)
3996+
],
3997+
[stats], [
3998+
JIT_CARGO_SUPPORT=stats
3999+
AC_DEFINE(ZJIT_STATS, 1)
39954000
])
39964001
39974002
ZJIT_LIBS="target/release/libzjit.a"

internal/vm.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ VALUE rb_block_call2(VALUE obj, ID mid, int argc, const VALUE *argv, rb_block_ca
7979
struct vm_ifunc *rb_current_ifunc(void);
8080
VALUE rb_gccct_clear_table(VALUE);
8181

82-
#if USE_YJIT
82+
#if USE_YJIT || USE_ZJIT
8383
/* vm_exec.c */
8484
extern uint64_t rb_vm_insns_count;
8585
#endif

vm.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@
3535
#include "iseq.h"
3636
#include "symbol.h" // This includes a macro for a more performant rb_id2sym.
3737
#include "yjit.h"
38+
#include "insns.inc"
39+
#include "zjit.h"
3840
#include "ruby/st.h"
3941
#include "ruby/vm.h"
4042
#include "vm_core.h"
@@ -45,8 +47,6 @@
4547
#include "ractor_core.h"
4648
#include "vm_sync.h"
4749
#include "shape.h"
48-
#include "insns.inc"
49-
#include "zjit.h"
5050

5151
#include "builtin.h"
5252

vm_exec.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@
1111

1212
#include <math.h>
1313

14-
#if USE_YJIT
15-
// The number of instructions executed on vm_exec_core. --yjit-stats uses this.
14+
#if USE_YJIT || USE_ZJIT
15+
// The number of instructions executed on vm_exec_core. --yjit-stats and --zjit-stats use this.
1616
uint64_t rb_vm_insns_count = 0;
1717
#endif
1818

vm_insnhelper.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ RUBY_EXTERN rb_serial_t ruby_vm_constant_cache_invalidations;
1616
RUBY_EXTERN rb_serial_t ruby_vm_constant_cache_misses;
1717
RUBY_EXTERN rb_serial_t ruby_vm_global_cvar_state;
1818

19-
#if USE_YJIT && YJIT_STATS // We want vm_insns_count only on stats builds.
19+
#if YJIT_STATS || ZJIT_STATS // We want vm_insns_count only on stats builds.
2020
// Increment vm_insns_count for --yjit-stats. We increment this even when
2121
// --yjit or --yjit-stats is not used because branching to skip it is slower.
2222
// We also don't use ATOMIC_INC for performance, allowing inaccuracy on Ractors.

yjit.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,13 @@
2323
#include "insns_info.inc"
2424
#include "vm_sync.h"
2525
#include "yjit.h"
26+
#include "zjit.h"
2627
#include "vm_insnhelper.h"
2728
#include "probes.h"
2829
#include "probes_helper.h"
2930
#include "iseq.h"
3031
#include "ruby/debug.h"
3132
#include "internal/cont.h"
32-
#include "zjit.h"
3333

3434
// For mmapp(), sysconf()
3535
#ifndef _WIN32

yjit.h

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,9 @@
99
#include "vm_core.h"
1010
#include "method.h"
1111

12-
// YJIT_STATS controls whether to support runtime counters in generated code
13-
// and in the interpreter.
12+
// YJIT_STATS controls whether to support runtime counters in the interpreter
1413
#ifndef YJIT_STATS
15-
# define YJIT_STATS RUBY_DEBUG
14+
# define YJIT_STATS (USE_YJIT && RUBY_DEBUG)
1615
#endif
1716

1817
#if USE_YJIT

zjit.c

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,14 @@
1515
#include "builtin.h"
1616
#include "insns.inc"
1717
#include "insns_info.inc"
18+
#include "zjit.h"
1819
#include "vm_sync.h"
1920
#include "vm_insnhelper.h"
2021
#include "probes.h"
2122
#include "probes_helper.h"
2223
#include "iseq.h"
2324
#include "ruby/debug.h"
2425
#include "internal/cont.h"
25-
#include "zjit.h"
2626

2727
// For mmapp(), sysconf()
2828
#ifndef _WIN32
@@ -331,9 +331,6 @@ rb_iseq_set_zjit_payload(const rb_iseq_t *iseq, void *payload)
331331
iseq->body->zjit_payload = payload;
332332
}
333333

334-
// Primitives used by zjit.rb
335-
VALUE rb_zjit_assert_compiles(rb_execution_context_t *ec, VALUE self);
336-
337334
void
338335
rb_zjit_print_exception(void)
339336
{
@@ -349,5 +346,10 @@ rb_zjit_shape_obj_too_complex_p(VALUE obj)
349346
return rb_shape_obj_too_complex_p(obj);
350347
}
351348

349+
// Primitives used by zjit.rb. Don't put other functions below, which wouldn't use them.
350+
VALUE rb_zjit_assert_compiles(rb_execution_context_t *ec, VALUE self);
351+
VALUE rb_zjit_stats(rb_execution_context_t *ec, VALUE self);
352+
VALUE rb_zjit_stats_enabled_p(rb_execution_context_t *ec, VALUE self);
353+
352354
// Preprocessed zjit.rb generated during build
353355
#include "zjit.rbinc"

zjit.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,11 @@
44
// This file contains definitions ZJIT exposes to the CRuby codebase
55
//
66

7+
// ZJIT_STATS controls whether to support runtime counters in the interpreter
8+
#ifndef ZJIT_STATS
9+
# define ZJIT_STATS (USE_ZJIT && RUBY_DEBUG)
10+
#endif
11+
712
#if USE_ZJIT
813
extern bool rb_zjit_enabled_p;
914
extern uint64_t rb_zjit_call_threshold;

zjit.rb

Lines changed: 56 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,61 @@
1+
# frozen_string_literal: true
2+
3+
# This module allows for introspection of \ZJIT, CRuby's just-in-time compiler.
4+
# Everything in the module is highly implementation specific and the API might
5+
# be less stable compared to the standard library.
6+
#
7+
# This module may not exist if \ZJIT does not support the particular platform
8+
# for which CRuby is built.
19
module RubyVM::ZJIT
10+
# Avoid calling a Ruby method here to avoid interfering with compilation tests
11+
if Primitive.rb_zjit_stats_enabled_p
12+
at_exit { print_stats }
13+
end
14+
end
15+
16+
class << RubyVM::ZJIT
17+
# Return ZJIT statistics as a Hash
18+
def stats
19+
stats = Primitive.rb_zjit_stats
20+
21+
if stats.key?(:vm_insns_count) && stats.key?(:zjit_insns_count)
22+
stats[:total_insns_count] = stats[:vm_insns_count] + stats[:zjit_insns_count]
23+
stats[:ratio_in_zjit] = 100.0 * stats[:zjit_insns_count] / stats[:total_insns_count]
24+
end
25+
26+
stats
27+
end
28+
29+
# Get the summary of ZJIT statistics as a String
30+
def stats_string
31+
buf = +''
32+
stats = self.stats
33+
34+
[
35+
:total_insns_count,
36+
:vm_insns_count,
37+
:zjit_insns_count,
38+
:ratio_in_zjit,
39+
].each do |key|
40+
value = stats[key]
41+
if key == :ratio_in_zjit
42+
value = '%0.1f%%' % value
43+
end
44+
buf << "#{'%-18s' % "#{key}:"} #{value}\n"
45+
end
46+
buf
47+
end
48+
249
# Assert that any future ZJIT compilation will return a function pointer
3-
def self.assert_compiles
50+
def assert_compiles # :nodoc:
451
Primitive.rb_zjit_assert_compiles
552
end
53+
54+
# :stopdoc:
55+
private
56+
57+
# Print ZJIT stats
58+
def print_stats
59+
$stderr.write stats_string
60+
end
661
end

0 commit comments

Comments
 (0)