From 2cedae93e934830d3096ab8a1bfe2716c15097aa Mon Sep 17 00:00:00 2001 From: Stiopa Koltsov Date: Sat, 5 Dec 2020 23:59:50 +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 | 26 ++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/src/main/java/net/starlark/java/eval/StarlarkInt.java b/src/main/java/net/starlark/java/eval/StarlarkInt.java index b40f35307cc5a4..284f6c4575b22e 100644 --- a/src/main/java/net/starlark/java/eval/StarlarkInt.java +++ b/src/main/java/net/starlark/java/eval/StarlarkInt.java @@ -203,6 +203,11 @@ public int signum() { return Integer.signum(v); } + @Override + protected int orderOfMagnitude() { + return Integer.signum(v); + } + @Override public void repr(Printer printer) { printer.append(v); @@ -253,6 +258,11 @@ public int signum() { return Long.signum(v); } + @Override + protected int orderOfMagnitude() { + return Long.signum(v) * 2; + } + @Override public void repr(Printer printer) { printer.append(v); @@ -293,6 +303,11 @@ public int signum() { return v.signum(); } + @Override + protected int orderOfMagnitude() { + return v.signum() * 3; + } + @Override public void repr(Printer printer) { printer.append(v.toString()); @@ -316,6 +331,9 @@ public boolean equals(Object that) { /** Returns the signum of this StarlarkInt (-1, 0, or +1). */ public abstract int signum(); + /** Return 0 for 0, +/-1 for non-zero Int32, +/-2 for Int64, +/-3 for Big. */ + protected abstract int orderOfMagnitude(); + /** Returns this StarlarkInt as a string of decimal digits. */ @Override public String toString() { @@ -446,7 +464,13 @@ public static int compare(StarlarkInt x, StarlarkInt y) { /* fall through */ } - return x.toBigInteger().compareTo(y.toBigInteger()); + int xo = x.orderOfMagnitude(); + int yo = y.orderOfMagnitude(); + if (xo != yo) { + return Integer.compare(xo, yo); + } + + return ((Big) x).v.compareTo(((Big) y).v); } /** Returns x + y. */