From dfde4646746b2a867797d3969956f6a9c89b816b Mon Sep 17 00:00:00 2001 From: Stiopa Koltsov Date: Sun, 6 Dec 2020 21:24:59 +0000 Subject: [PATCH] Starlark: optimize StarlarkInt.Big comparison to StarlarkInt.Int{32,64} Perform comparison without conversion of smaller integers to `BigInteger`. `StarlarkInt.compareTo` does not allocate now. For this benchmark: ``` def test(): x = 17 << 77 for i in range(10): print(i) for j in range(10000000): x > 1 test() ``` ``` A: n=27 mean=4.262 std=0.203 se=0.039 min=4.036 med=4.193 B: n=27 mean=4.113 std=0.172 se=0.033 min=3.859 med=4.049 B/A: 0.965 0.941..0.990 (95% conf) ``` Speed up is about 7% when comparing to an integer outside of `BigInteger` cached range (-16..16). Finally, `StarlarkInt.Big` to `StarlarkInt.Big` comparison performance seems to stay the same (within 95% confidence interval after 100 test iterations). --- .../net/starlark/java/eval/StarlarkInt.java | 29 ++++++++++++++----- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/src/main/java/net/starlark/java/eval/StarlarkInt.java b/src/main/java/net/starlark/java/eval/StarlarkInt.java index d63186ba92cf29..f5d00ecea21c53 100644 --- a/src/main/java/net/starlark/java/eval/StarlarkInt.java +++ b/src/main/java/net/starlark/java/eval/StarlarkInt.java @@ -436,17 +436,30 @@ public int compareTo(StarlarkInt x) { /** Returns a value whose signum is equal to x - y. */ public static int compare(StarlarkInt x, StarlarkInt y) { - if (x instanceof Int32 && y instanceof Int32) { - return Integer.compare(((Int32) x).v, ((Int32) y).v); - } - try { - return Long.compare(x.toLongFast(), y.toLongFast()); + long xl = x.toLongFast(); + try { + long yl = y.toLongFast(); + // both x and y are within long range + return Long.compare(xl, yl); + } catch (Overflow unused) { + // minlong <= x <= maxlong + // y is Big: y < minlong || y > maxlong + // so compare(x, y) == -y.signum() + return -((Big) y).v.signum(); + } } catch (Overflow unused) { - /* fall through */ + try { + y.toLongFast(); + // x is Big: x < minlong || x > maxlong + // minlong <= y <= maxlong + // so compare(x, y) == x.signum() + return ((Big) x).v.signum(); + } catch (Overflow unused2) { + // both x and y are Big + return ((Big) x).v.compareTo(((Big) y).v); + } } - - return x.toBigInteger().compareTo(y.toBigInteger()); } /** Returns x + y. */