Hi,
chromatic wrote:
3) PCC argument processing is slow. I've looked over Parrot_pass_args and
Parrot_process_args several times in the past few months, and I didn't see
any obvious speedups or tricks. However, we do spend a lot of time shuffling data back and forth, and something (instinct, blind desire, lower blood sugar than normal) suggests that we already *know* some of this information already. That is, at the point of a call we know if there are slurpy or named arguments and if the invoked function wants to bind slurpy or named parameters. It seems like we could have a fast path for that common operation... somehow.
I thought that detecting when the signature on the caller and callee
side were identical and fast-tracking that might help. I stuck in
something to count how many times this happened. It was the case in 23%
of calls while compiling Rakudo. So I did the optimisation in the
attached patch, which basically just copies arguments from one set of
registers to the other about as efficiently as I can see how to do it.
The end result? I can't actually detect enough of a difference to make
me think I've really improved anything. Not in the compilation time of
Rakudo's actions.pm, nor when I took a Perl 6 Ackerman's function
implementation and ran it under Rakudo.
Jonathan
Index: src/inter_call.c
===================================================================
--- src/inter_call.c (revision 26955)
+++ src/inter_call.c (working copy)
@@ -1520,12 +1520,45 @@
Parrot_init_arg_indexes_and_sig_pmc(interp, dest_ctx, dest_indexes,
dest_signature, &st.dest);
- Parrot_process_args(interp, &st, param_or_result);
+ if (st.src.u.op.signature == st.dest.u.op.signature &&
!PMC_IS_NULL(st.src.u.op.signature)) {
+ /* Identical signatures, so we can fast-track it. */
+ PMC *sig = st.src.u.op.signature;
+ int sig_length = st.src.n;
+ opcode_t *src_idxs = st.src.u.op.pc;
+ opcode_t *dest_idxs = st.dest.u.op.pc;
+ int i;
+ for (i = 0; i < sig_length; i++) {
+ const int constant = PARROT_ARG_CONSTANT_ISSET(SIG_ITEM(sig, i));
+ int src_idx = src_idxs[i];
+ int dest_idx = dest_idxs[i];
+ switch (PARROT_ARG_TYPE_MASK_MASK(SIG_ITEM(sig, i))) {
+ case PARROT_ARG_INTVAL:
+ CTX_REG_INT(st.dest.ctx, dest_idx) = constant ?
+ src_idx : CTX_REG_INT(st.src.ctx, src_idx);
+ break;
+ case PARROT_ARG_STRING:
+ CTX_REG_STR(st.dest.ctx, dest_idx) = constant ?
+ st.src.ctx->constants[src_idx]->u.string :
CTX_REG_STR(st.src.ctx, src_idx);
+ break;
+ case PARROT_ARG_FLOATVAL:
+ CTX_REG_NUM(st.dest.ctx, dest_idx) = constant ?
+ st.src.ctx->constants[src_idx]->u.number :
CTX_REG_NUM(st.src.ctx, src_idx);
+ break;
+ case PARROT_ARG_PMC:
+ CTX_REG_PMC(st.dest.ctx, dest_idx) = constant ?
+ st.src.ctx->constants[src_idx]->u.key :
CTX_REG_PMC(st.src.ctx, src_idx);
+ break;
+ }
+ }
+ }
+ else {
+ Parrot_process_args(interp, &st, param_or_result);
- /* If we created a slurpy, we had to DOD register it so it did not get
- * collected during arg processing; we'll now unregister it. */
- if (st.dest.slurp)
- dod_unregister_pmc(interp, st.dest.slurp);
+ /* If we created a slurpy, we had to DOD register it so it did not get
+ * collected during arg processing; we'll now unregister it. */
+ if (st.dest.slurp)
+ dod_unregister_pmc(interp, st.dest.slurp);
+ }
}