Hi, I've implemented the overflow checks and made some benchmarks and the ipow() version became slower except with some specific inputs (base 0 for example). It's true that the new auxiliary functions could be optimized, but I don't think it makes sense to keep working on them just to match pow() speed.
I'm attaching both patches in case someone wants to have a look but I would go with the simpler solution (pgbench_pow_v10.patch). Regards, -- *Raúl Marín Rodríguez *carto.com
From 28bc71f657fa967bafc03c015e5e2405c427a711 Mon Sep 17 00:00:00 2001 From: Raul Marin <rmrodrig...@cartodb.com> Date: Thu, 21 Dec 2017 20:28:02 +0100 Subject: [PATCH] Add pow() support to pgbench --- doc/src/sgml/ref/pgbench.sgml | 7 +++++++ src/bin/pgbench/exprparse.y | 6 ++++++ src/bin/pgbench/pgbench.c | 16 ++++++++++++++++ src/bin/pgbench/pgbench.h | 3 ++- src/bin/pgbench/t/001_pgbench_with_server.pl | 22 +++++++++++++++++++++- 5 files changed, 52 insertions(+), 2 deletions(-) diff --git a/doc/src/sgml/ref/pgbench.sgml b/doc/src/sgml/ref/pgbench.sgml index 4431fc3eb7..1519fe78ef 100644 --- a/doc/src/sgml/ref/pgbench.sgml +++ b/doc/src/sgml/ref/pgbench.sgml @@ -1069,6 +1069,13 @@ pgbench <optional> <replaceable>options</replaceable> </optional> <replaceable>d <entry><literal>pi()</literal></entry> <entry><literal>3.14159265358979323846</literal></entry> </row> + <row> + <entry><literal><function>pow(<replaceable>x</replaceable>, <replaceable>y</replaceable>)</function>, <function>power(<replaceable>x</replaceable>, <replaceable>y</replaceable>)</function></literal></entry> + <entry>double</entry> + <entry>exponentiation</entry> + <entry><literal>pow(2.0, 10)</literal>, <literal>power(2.0, 10)</literal></entry> + <entry><literal>1024.0</literal></entry> + </row> <row> <entry><literal><function>random(<replaceable>lb</replaceable>, <replaceable>ub</replaceable>)</function></literal></entry> <entry>integer</entry> diff --git a/src/bin/pgbench/exprparse.y b/src/bin/pgbench/exprparse.y index 25d5ad48e5..74ffe5e7a7 100644 --- a/src/bin/pgbench/exprparse.y +++ b/src/bin/pgbench/exprparse.y @@ -194,6 +194,12 @@ static const struct { "random_zipfian", 3, PGBENCH_RANDOM_ZIPFIAN }, + { + "pow", 2, PGBENCH_POW + }, + { + "power", 2, PGBENCH_POW + }, /* keep as last array element */ { NULL, 0, 0 diff --git a/src/bin/pgbench/pgbench.c b/src/bin/pgbench/pgbench.c index 7ce6f607f5..5b444765dd 100644 --- a/src/bin/pgbench/pgbench.c +++ b/src/bin/pgbench/pgbench.c @@ -1850,6 +1850,22 @@ evalFunc(TState *thread, CState *st, return true; } + case PGBENCH_POW: + { + PgBenchValue *lval = &vargs[0]; + PgBenchValue *rval = &vargs[1]; + + Assert(nargs == 2); + + if (!coerceToDouble(lval, &ld) || + !coerceToDouble(rval, &rd)) + return false; + + setDoubleValue(retval, pow(ld, rd)); + + return true; + } + default: /* cannot get here */ Assert(0); diff --git a/src/bin/pgbench/pgbench.h b/src/bin/pgbench/pgbench.h index 83fee1ae74..0e92882a4c 100644 --- a/src/bin/pgbench/pgbench.h +++ b/src/bin/pgbench/pgbench.h @@ -76,7 +76,8 @@ typedef enum PgBenchFunction PGBENCH_RANDOM, PGBENCH_RANDOM_GAUSSIAN, PGBENCH_RANDOM_EXPONENTIAL, - PGBENCH_RANDOM_ZIPFIAN + PGBENCH_RANDOM_ZIPFIAN, + PGBENCH_POW } PgBenchFunction; typedef struct PgBenchExpr PgBenchExpr; diff --git a/src/bin/pgbench/t/001_pgbench_with_server.pl b/src/bin/pgbench/t/001_pgbench_with_server.pl index e3cdf28628..9cbeb2fc11 100644 --- a/src/bin/pgbench/t/001_pgbench_with_server.pl +++ b/src/bin/pgbench/t/001_pgbench_with_server.pl @@ -232,7 +232,17 @@ pgbench( qr{command=19.: double 19\b}, qr{command=20.: double 20\b}, qr{command=21.: int 9223372036854775807\b}, - qr{command=23.: int [1-9]\b}, ], + qr{command=23.: int [1-9]\b}, + qr{command=24.: double -27\b}, + qr{command=25.: double 1024\b}, + qr{command=26.: double 1\b}, + qr{command=27.: double 1\b}, + qr{command=28.: double -0.125\b}, + qr{command=29.: double -0.125\b}, + qr{command=30.: double -0.00032\b}, + qr{command=31.: double 8.50705917302346e\+37\b}, + qr{command=32.: double 1e\+30\b}, + ], 'pgbench expressions', { '001_pgbench_expressions' => q{-- integer functions \set i1 debug(random(1, 100)) @@ -264,6 +274,16 @@ pgbench( \set i1 0 -- yet another integer function \set id debug(random_zipfian(1, 9, 1.3)) +--- pow and power +\set poweri debug(pow(-3,3)) +\set powerd debug(pow(2.0,10)) +\set poweriz debug(pow(0,0)) +\set powerdz debug(pow(0.0,0.0)) +\set powernegi debug(pow(-2,-3)) +\set powernegd debug(pow(-2.0,-3.0)) +\set powernegd2 debug(power(-5.0,-5.0)) +\set powerov debug(pow(9223372036854775807, 2)) +\set powerov2 debug(pow(10,30)) } }); # backslash commands -- 2.15.1
From 6cb8fb1a3eaffe680b85913b0acf0068dcb0d2a7 Mon Sep 17 00:00:00 2001 From: Raul Marin <rmrodrig...@cartodb.com> Date: Thu, 21 Dec 2017 20:28:02 +0100 Subject: [PATCH] Add pow() support to pgbench --- doc/src/sgml/ref/pgbench.sgml | 7 ++ src/bin/pgbench/exprparse.y | 6 ++ src/bin/pgbench/pgbench.c | 100 +++++++++++++++++++++++++++ src/bin/pgbench/pgbench.h | 3 +- src/bin/pgbench/t/001_pgbench_with_server.pl | 22 +++++- 5 files changed, 136 insertions(+), 2 deletions(-) diff --git a/doc/src/sgml/ref/pgbench.sgml b/doc/src/sgml/ref/pgbench.sgml index 4431fc3eb7..1519fe78ef 100644 --- a/doc/src/sgml/ref/pgbench.sgml +++ b/doc/src/sgml/ref/pgbench.sgml @@ -1069,6 +1069,13 @@ pgbench <optional> <replaceable>options</replaceable> </optional> <replaceable>d <entry><literal>pi()</literal></entry> <entry><literal>3.14159265358979323846</literal></entry> </row> + <row> + <entry><literal><function>pow(<replaceable>x</replaceable>, <replaceable>y</replaceable>)</function>, <function>power(<replaceable>x</replaceable>, <replaceable>y</replaceable>)</function></literal></entry> + <entry>double</entry> + <entry>exponentiation</entry> + <entry><literal>pow(2.0, 10)</literal>, <literal>power(2.0, 10)</literal></entry> + <entry><literal>1024.0</literal></entry> + </row> <row> <entry><literal><function>random(<replaceable>lb</replaceable>, <replaceable>ub</replaceable>)</function></literal></entry> <entry>integer</entry> diff --git a/src/bin/pgbench/exprparse.y b/src/bin/pgbench/exprparse.y index 25d5ad48e5..74ffe5e7a7 100644 --- a/src/bin/pgbench/exprparse.y +++ b/src/bin/pgbench/exprparse.y @@ -194,6 +194,12 @@ static const struct { "random_zipfian", 3, PGBENCH_RANDOM_ZIPFIAN }, + { + "pow", 2, PGBENCH_POW + }, + { + "power", 2, PGBENCH_POW + }, /* keep as last array element */ { NULL, 0, 0 diff --git a/src/bin/pgbench/pgbench.c b/src/bin/pgbench/pgbench.c index 7ce6f607f5..07436af5a7 100644 --- a/src/bin/pgbench/pgbench.c +++ b/src/bin/pgbench/pgbench.c @@ -911,6 +911,64 @@ getZipfianRand(TState *thread, int64 min, int64 max, double s) : computeHarmonicZipfian(thread, n, s)); } +/* Position of the most significant bit */ +static int64 +ffs_i64(int64 i) +{ + int64 bits = 0; + + if (i < 0) + i = -i; + while (i) + { + i>>=1; + bits++; + } + + return bits; +} + +/* Heuristic to check for ipow overflow */ +static bool +ipow_check_overflow(int64 base, int64 exp) +{ + int64 msb_base, + msb_base_sqr; + + Assert(exp >= 0); + if (base == 0 || base == 1 || base == -1 || exp <= 1) + return false; + + msb_base = ffs_i64(base); + if (msb_base >= 32) + return true; + + msb_base_sqr = ffs_i64(base * base); + if (msb_base_sqr <= msb_base) + return true; + + return (msb_base + (msb_base_sqr - msb_base) * (exp -1)) > 63; +} + +/* Faster power function for integer values with exp >= 0 */ +static int64 +ipow(int64 base, int64 exp) +{ + int64 result = 1; + + Assert(exp >= 0); + + while (exp) + { + if (exp & 1) + result *= base; + exp >>= 1; + base *= base; + } + + return result; +} + /* * Initialize the given SimpleStats struct to all zeroes */ @@ -1850,6 +1908,48 @@ evalFunc(TState *thread, CState *st, return true; } + case PGBENCH_POW: + { + PgBenchValue *lval = &vargs[0]; + PgBenchValue *rval = &vargs[1]; + + Assert(nargs == 2); + + /* + * If both operands are int, exp >= 0 and the output + * fits in an int64 use the faster ipow(), else use pow() + */ + if (lval->type == PGBT_INT && + rval->type == PGBT_INT) + { + + int64 li, + ri; + + if (!coerceToInt(lval, &li) || + !coerceToInt(rval, &ri)) + return false; + + if (ri >= 0 && + !ipow_check_overflow(li,ri)) + setDoubleValue(retval, ipow(li, ri)); + else + setDoubleValue(retval, pow(li, ri)); + } + else + { + double ld, + rd; + + if (!coerceToDouble(lval, &ld) || + !coerceToDouble(rval, &rd)) + return false; + + setDoubleValue(retval, pow(ld, rd)); + } + return true; + } + default: /* cannot get here */ Assert(0); diff --git a/src/bin/pgbench/pgbench.h b/src/bin/pgbench/pgbench.h index 83fee1ae74..0e92882a4c 100644 --- a/src/bin/pgbench/pgbench.h +++ b/src/bin/pgbench/pgbench.h @@ -76,7 +76,8 @@ typedef enum PgBenchFunction PGBENCH_RANDOM, PGBENCH_RANDOM_GAUSSIAN, PGBENCH_RANDOM_EXPONENTIAL, - PGBENCH_RANDOM_ZIPFIAN + PGBENCH_RANDOM_ZIPFIAN, + PGBENCH_POW } PgBenchFunction; typedef struct PgBenchExpr PgBenchExpr; diff --git a/src/bin/pgbench/t/001_pgbench_with_server.pl b/src/bin/pgbench/t/001_pgbench_with_server.pl index e3cdf28628..9cbeb2fc11 100644 --- a/src/bin/pgbench/t/001_pgbench_with_server.pl +++ b/src/bin/pgbench/t/001_pgbench_with_server.pl @@ -232,7 +232,17 @@ pgbench( qr{command=19.: double 19\b}, qr{command=20.: double 20\b}, qr{command=21.: int 9223372036854775807\b}, - qr{command=23.: int [1-9]\b}, ], + qr{command=23.: int [1-9]\b}, + qr{command=24.: double -27\b}, + qr{command=25.: double 1024\b}, + qr{command=26.: double 1\b}, + qr{command=27.: double 1\b}, + qr{command=28.: double -0.125\b}, + qr{command=29.: double -0.125\b}, + qr{command=30.: double -0.00032\b}, + qr{command=31.: double 8.50705917302346e\+37\b}, + qr{command=32.: double 1e\+30\b}, + ], 'pgbench expressions', { '001_pgbench_expressions' => q{-- integer functions \set i1 debug(random(1, 100)) @@ -264,6 +274,16 @@ pgbench( \set i1 0 -- yet another integer function \set id debug(random_zipfian(1, 9, 1.3)) +--- pow and power +\set poweri debug(pow(-3,3)) +\set powerd debug(pow(2.0,10)) +\set poweriz debug(pow(0,0)) +\set powerdz debug(pow(0.0,0.0)) +\set powernegi debug(pow(-2,-3)) +\set powernegd debug(pow(-2.0,-3.0)) +\set powernegd2 debug(power(-5.0,-5.0)) +\set powerov debug(pow(9223372036854775807, 2)) +\set powerov2 debug(pow(10,30)) } }); # backslash commands -- 2.15.1