Repository navigation
Ykify bytecode dispatch loop. - #2
Conversation
|
How has this changed performance relative to before this PR? |
relative to master? |
Yes: in the context of this PR, it's only really useful to know if performance gets better/worse relative to master (relative to mruby is a slightly different metric, more relevant to the long term). |
|
The master here is the base mruby. Compared with the compilation config - yk_wordboxing.rb |
|
As I said, that's not a useful base: we need to know relative to ykmruby's master branch. |
|
Not sure I understand, Its comparing this PR with mruby@2a4167e in mruby |
|
|
||
| /* mrb_yk_iseq_gen increased whenever an iseq is freed. | ||
| Its used as idempotent key for bytecode fetching in the dispatch loop.*/ | ||
| extern uint32_t mrb_yk_iseq_gen; |
There was a problem hiding this comment.
How rapidly does this number tend to increase? Is 32 bits enough?
There was a problem hiding this comment.
It depends on the program, It hasn't been an issue with AWFY benchmarks, but I agree it should be u64 because a long running process could overflow 32 bits
There was a problem hiding this comment.
It's important not to change this blindly: for all I know, this only increments relative to the number of classes in a program at which point 13 (or probably even 16!) bits would be the right number. A quick investigation will sort this out.
There was a problem hiding this comment.
The counter increments once per irep free call. This happens when code compiled at runtime (e.g. eval or load) becomes garbage.
AWFY benchmarks barely touch it, but a long-running app that evals heavily could free a lot.
uint64_t costs essentially nothing, so I'd keep it.
There was a problem hiding this comment.
A Proc is a basic mruby object (struct RProc), every call frame executes a Proc. The irep is the compiled bytecode that a Proc points to.
When the GC collects a Proc, it drops the Proc reference to its irep. If that was the last reference, the irep is freed through mrb_irep_free. This is what I mean by "irep free call".
In AWFY this doesnt happen while the benchmark runs, even on objectheavy benchmark (Storage, List, Json). The GC collect many Procs, but every irep is still reachable from the program's top-level irep so no count reaches 0. And nothing is dynamically compiled at runtime either.
So we don't really need this counter for AWFY becnchmarks, but we do need it for a general use of long running programs that execute dynamic evals.
mrb_irep_free is what I mean by "irep free call"
There was a problem hiding this comment.
So basically this is the counter that is incremented every time we create (or free?) a "function-esque thing"? If so, I agree it rarely increments, but it's better to use 64 bits.
FWIW, in yklua I recently realised that it's better to increment this on creation rather than deletion (ykjit/yklua#164).
|
Can we (at least) split this PR in two? One commit just doing the |
ok will do |
Done: #3 |
|
Please squash. |
Add a control point to mrb_vm_exec. The pc is kept in a local and promoted while tracing, the opcode and operands are read through yk_idempotent loads. Locations are created for backward jump only,
f4c54de to
f17eedd
Compare
|
Squashed f17eedd |
This is a follow-up from #1.
This change adds a controlpoint to
mrb_vm_exec.The pc is kept in a local and promoted while tracing, the opcode and operands are read through
yk_idempotent, so traces see bytecode as constants. The loads are keyed on(pc, iseq generation), bumped when aniseqis freed, so a reused address cannot be used for bytecode load. Locations are created for backward jumps only.Two workarounds:
AWFY Benchmarks comparing with base mruby
Five benchmarks get faster by 27-53% (Sieve, Queens, Permute, Mandelbrot, List). Seven are slow 6-25% (Bounce, Json, NBody, Richards), 2x (Storage, CD) and 4.3x (Towers). Havlak and DeltaBlue are flat.
The wins are on tight arithmetic loops. The slowdowns come mainly from sends and recursion, which will be addressed in follow-up PRs.
haste.zip