From 310ef9f40b350957a1a6d6236ce453ff9f73e81d Mon Sep 17 00:00:00 2001 From: Takashi Kokubun Date: Mon, 13 Apr 2020 20:32:59 -0700 Subject: Make vm_call_cfunc_with_frame a fastpath (#3027) when there's no need to call CALLER_SETUP_ARG and CALLER_REMOVE_EMPTY_KW_SPLAT (i.e. !rb_splat_or_kwargs_p(ci) && !calling->kw_splat). Micro benchmark: ``` $ benchmark-driver -v --rbenv 'before;after' benchmark/vm_send_cfunc.yml --repeat-count=4 before: ruby 2.8.0dev (2020-04-13T23:45:05Z master b9d3ceee8f) [x86_64-linux] after: ruby 2.8.0dev (2020-04-14T00:48:52Z no-splat-fastpath 418d363722) [x86_64-linux] Calculating ------------------------------------- before after vm_send_cfunc 69.585M 88.724M i/s - 100.000M times in 1.437097s 1.127096s Comparison: vm_send_cfunc after: 88723605.2 i/s before: 69584737.1 i/s - 1.28x slower ``` Optcarrot: ``` $ benchmark-driver -v --rbenv 'before;after' benchmark.yml --repeat-count=12 --output=all before: ruby 2.8.0dev (2020-04-13T23:45:05Z master b9d3ceee8f) [x86_64-linux] after: ruby 2.8.0dev (2020-04-14T00:48:52Z no-splat-fastpath 418d363722) [x86_64-linux] Calculating ------------------------------------- before after Optcarrot Lan_Master.nes 50.76119601545175 42.73858236484051 fps 50.76388649761503 51.04211379912850 50.80930672252514 51.39455790755538 50.90236000778749 51.75656936556145 51.01744746340430 51.86875277356489 51.06495279015112 51.88692482485558 51.07785337168974 51.93429603190578 51.20163525187862 51.95768145071314 51.34671771913112 52.45577266040274 51.35918340835583 52.53163888762858 51.46641337418146 52.62172484121034 51.50835463462257 52.85064021113239 ``` --- vm_insnhelper.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'vm_insnhelper.c') diff --git a/vm_insnhelper.c b/vm_insnhelper.c index 21b5e93ca3..a4edd9a797 100644 --- a/vm_insnhelper.c +++ b/vm_insnhelper.c @@ -1964,6 +1964,13 @@ rb_iseq_only_kwparam_p(const rb_iseq_t *iseq) iseq->body->param.flags.has_block == FALSE; } +// If true, cc->call needs to include `CALLER_SETUP_ARG` (i.e. can't be skipped in fastpath) +MJIT_STATIC bool +rb_splat_or_kwargs_p(const struct rb_callinfo *restrict ci) +{ + return IS_ARGS_SPLAT(ci) || IS_ARGS_KW_OR_KW_SPLAT(ci); +} + static inline void CALLER_SETUP_ARG(struct rb_control_frame_struct *restrict cfp, @@ -2508,6 +2515,7 @@ vm_method_cfunc_entry(const rb_callable_method_entry_t *me) static VALUE vm_call_cfunc_with_frame(rb_execution_context_t *ec, rb_control_frame_t *reg_cfp, struct rb_calling_info *calling, struct rb_call_data *cd) { + RB_DEBUG_COUNTER_INC(ccf_cfunc_with_frame); const struct rb_callinfo *ci = cd->ci; const struct rb_callcache *cc = cd->cc; VALUE val; @@ -2555,6 +2563,7 @@ vm_call_cfunc(rb_execution_context_t *ec, rb_control_frame_t *reg_cfp, struct rb CALLER_SETUP_ARG(reg_cfp, calling, ci); CALLER_REMOVE_EMPTY_KW_SPLAT(reg_cfp, calling, ci); + CC_SET_FASTPATH(cd->cc, vm_call_cfunc_with_frame, !rb_splat_or_kwargs_p(ci) && !calling->kw_splat); return vm_call_cfunc_with_frame(ec, reg_cfp, calling, cd); } -- cgit v1.2.3