From 05daa8e5f3c8950aa639d3b95a2d4495a5372789 Mon Sep 17 00:00:00 2001 From: ZmnSCPxj jxPCSnmZ Date: Tue, 11 Aug 2020 16:20:27 +0800 Subject: [PATCH] plugins/libplugin-pay.c: Micro-optimization of plugin_is_finished. This was checked with `gcc -S -O2` to see how an optimized build would compile the function. The original code completed calls into each child (and the `.s` file showed that GCC 9.x was not smart enough to do early-out). This modification explicitly does early-out, and avoids call-return stack overhead for the common case where a payment is an ancestor of a long line of single-child payments due to retrying. Changelog-None: pointless micro-optimization --- plugins/libplugin-pay.c | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/plugins/libplugin-pay.c b/plugins/libplugin-pay.c index 30035c6f7..b013c7eaa 100644 --- a/plugins/libplugin-pay.c +++ b/plugins/libplugin-pay.c @@ -1379,13 +1379,26 @@ static void payment_finished(struct payment *p); * child-spawning state and all of its children are in a final state. */ static bool payment_is_finished(const struct payment *p) { +top: if (p->step == PAYMENT_STEP_FAILED || p->step == PAYMENT_STEP_SUCCESS || p->abort) return true; else if (p->step == PAYMENT_STEP_SPLIT || p->step == PAYMENT_STEP_RETRY) { - bool running_children = false; - for (size_t i = 0; i < tal_count(p->children); i++) - running_children |= !payment_is_finished(p->children[i]); - return !running_children; + size_t num_children = tal_count(p->children); + + /* Retry case will almost always have just one child, so avoid + * the overhead of pushing and popping off the C stack and + * tail-recurse manually. */ + if (num_children == 1) { + p = p->children[0]; + goto top; + } + + for (size_t i = 0; i < num_children; i++) + /* In other words: if any child is unfinished, + * we are unfinished. */ + if (!payment_is_finished(p->children[i])) + return false; + return true; } else { return false; }