Project

General

Profile

Feature #14954

Add :wait option to RubyVM::MJIT.pause

Added by k0kubun (Takashi Kokubun) 4 months ago. Updated 3 months ago.

Status:
Closed
Priority:
Normal
Assignee:
-
Target version:
-
[ruby-core:88228]

Description

Problem

To measure an MJIT-generated code's performance, currently we need to do sleep ...; RubyVM::MJIT.pause and it's hard to decide an appropriate sleep seconds.

Solution

Add an :wait option (default: true) and:

# Wait for finishing all of queued compilations, and pause MJIT worker (different from the current behavior).
# This will be convenient for most of micro benchmarks. So I wanna make it default. It will be breaking but MJIT.pause is not released anywhere.
RubyVM::MJIT.pause
RubyVM::MJIT.pause(wait: true)

# Wait only for a currently-compiled method, and pause MJIT worker immediately (the current behavior).
# This will be convenient when there are many methods, like on Rails.
RubyVM::MJIT.pause(wait: false)

Related issues

Related to Ruby trunk - Feature #14830: RubyVM::MJIT.pause / RubyVM::MJIT.resumeClosed

History

#1 Updated by k0kubun (Takashi Kokubun) 4 months ago

  • Related to Feature #14830: RubyVM::MJIT.pause / RubyVM::MJIT.resume added

#2 [ruby-core:88384] Updated by k0kubun (Takashi Kokubun) 3 months ago

  • Status changed from Open to Closed

committed in r64250

#3 [ruby-core:88385] Updated by Eregon (Benoit Daloze) 3 months ago

Just a thought:
Pausing MJIT for benchmarks, even microbenchmarks, might have quite unintended effects once there is some profiling (e.g. branch profiling, type profiling, value profiling, etc) or if the JIT is sensitive to the calling context (for example with inlining).
With any of those, the actual measurement phase might look different than the warmup phase to the JIT and as a result run the benchmarked method(s) with the non-JIT version of the method(s).
Ideally the warmup phase looks identical to the measurement phase but this is quite tricky to achieve and there certainly are differences in e.g. benchmark-driver and benchmark-ips currently.

#4 [ruby-core:88395] Updated by k0kubun (Takashi Kokubun) 3 months ago

once there is some profiling (e.g. branch profiling, type profiling, value profiling, etc)

This part didn't make sense, probably because such profiling is not introduced yet. Could you provide some example?

or if the JIT is sensitive to the calling context (for example with inlining).

I can understand what you mean, but I believe it doesn't matter if we don't replace calling context by OSR.

Even with those issues, what MJIT.pause is solving can't be solved without MJIT.pause, and we would just need to make effort to prepare an appropreate warmup script.

With any of those, the actual measurement phase might look different than the warmup phase to the JIT and as a result run the benchmarked method(s) with the non-JIT version of the method(s).

To measure MJIT's performance correctly, the measured entity needs to be the same method(s) anyway. So the entity should be already JIT-ed on the measurement phase regardless of whether MJIT worker is paused or not.

Ideally the warmup phase looks identical to the measurement phase but this is quite tricky to achieve and there certainly are differences in e.g. benchmark-driver and benchmark-ips currently.

In benchmark-driver whose measured entity is a top-level script (never JIT-ed anyway for now), this doesn't matter for the above reasons. For benchmark-ips whose measured entity is a block, I believe the block is identical in warmup and measurement phase, and thus the same block is already JIT-ed on warmup and pausing it doesn't prevent the block on measurement phase from being JIT-ed, if my assumption about benchmark-ips is correct.

Also available in: Atom PDF