Hi,
Separately allocating a new BN_CTX every time one is needed seems to be
missing the point of this object, which is meant to be shared across as
many function calls as possible. At the cost of a slight increase in
average memory consumption, enabling such sharing by declaring a single
global context and using it everywhere yields a significant performance
gain, especially in the case of long sequences of simple and repetitive
operations, which can become up to 60% faster.
$ echo 1 >script
$ jot -b 1/ 1048576 >>script
$ time dc script
0m03.20s real 0m03.20s user 0m00.00s system
$ time ./dc script
0m01.25s real 0m01.25s user 0m00.00s system
Index: bcode.c
===================================================================
RCS file: /cvs/src/usr.bin/dc/bcode.c,v
retrieving revision 1.58
diff -u -p -r1.58 bcode.c
--- bcode.c 2 Dec 2017 12:43:18 -0000 1.58
+++ bcode.c 3 Dec 2017 07:06:47 -0000
@@ -133,6 +133,8 @@ struct jump_entry {
opcode_function f;
};
+static BN_CTX *ctx;
+
static opcode_function jump_table[UCHAR_MAX + 1];
static const struct jump_entry jump_table_data[] = {
@@ -226,6 +228,9 @@ init_bmachine(bool extended_registers)
{
int i;
+ ctx = BN_CTX_new();
+ bn_checkp(ctx);
+
bmachine.extended_regs = extended_registers;
bmachine.reg_array_size = bmachine.extended_regs ?
REG_ARRAY_SIZE_BIG : REG_ARRAY_SIZE_SMALL;
@@ -361,14 +366,11 @@ scale_number(BIGNUM *n, int s)
(void)BN_div_word(n, factors[abs_scale]);
} else {
BIGNUM *a, *p;
- BN_CTX *ctx;
a = BN_new();
bn_checkp(a);
p = BN_new();
bn_checkp(p);
- ctx = BN_CTX_new();
- bn_checkp(ctx);
bn_check(BN_set_word(a, 10));
bn_check(BN_set_word(p, abs_scale));
@@ -377,7 +379,6 @@ scale_number(BIGNUM *n, int s)
bn_check(BN_mul(n, n, a, ctx));
else
bn_check(BN_div(n, NULL, n, a, ctx));
- BN_CTX_free(ctx);
BN_free(a);
BN_free(p);
}
@@ -399,20 +400,16 @@ split_number(const struct number *n, BIG
bn_check(BN_set_word(f, rem));
} else {
BIGNUM *a, *p;
- BN_CTX *ctx;
a = BN_new();
bn_checkp(a);
p = BN_new();
bn_checkp(p);
- ctx = BN_CTX_new();
- bn_checkp(ctx);
bn_check(BN_set_word(a, 10));
bn_check(BN_set_word(p, n->scale));
bn_check(BN_exp(a, a, p, ctx));
bn_check(BN_div(i, f, n->number, a, ctx));
- BN_CTX_free(ctx);
BN_free(a);
BN_free(p);
}
@@ -699,7 +696,6 @@ static u_int
count_digits(const struct number *n)
{
BIGNUM *int_part, *a, *p;
- BN_CTX *ctx;
uint d;
const uint64_t c = 1292913986; /* floor(2^32 * log_10(2)) */
int bits;
@@ -724,8 +720,6 @@ count_digits(const struct number *n)
/* If close to a possible rounding error fix if needed */
if (d != (c * (bits - 1)) >> 32) {
- ctx = BN_CTX_new();
- bn_checkp(ctx);
a = BN_new();
bn_checkp(a);
p = BN_new();
@@ -738,7 +732,6 @@ count_digits(const struct number *n)
if (BN_ucmp(int_part, a) >= 0)
d++;
- BN_CTX_free(ctx);
BN_free(a);
BN_free(p);
} else
@@ -1039,17 +1032,12 @@ bsub(void)
void
bmul_number(struct number *r, struct number *a, struct number *b, u_int scale)
{
- BN_CTX *ctx;
-
/* Create copies of the scales, since r might be equal to a or b */
u_int ascale = a->scale;
u_int bscale = b->scale;
u_int rscale = ascale + bscale;
- ctx = BN_CTX_new();
- bn_checkp(ctx);
bn_check(BN_mul(r->number, a->number, b->number, ctx));
- BN_CTX_free(ctx);
r->scale = rscale;
if (rscale > bmachine.scale && rscale > ascale && rscale > bscale)
@@ -1085,7 +1073,6 @@ bdiv(void)
struct number *a, *b;
struct number *r;
u_int scale;
- BN_CTX *ctx;
a = pop_number();
if (a == NULL)
@@ -1106,10 +1093,7 @@ bdiv(void)
normalize(a, scale);
normalize(b, scale + r->scale);
- ctx = BN_CTX_new();
- bn_checkp(ctx);
bn_check(BN_div(r->number, NULL, b->number, a->number, ctx));
- BN_CTX_free(ctx);
}
push_number(r);
free_number(a);
@@ -1122,7 +1106,6 @@ bmod(void)
struct number *a, *b;
struct number *r;
u_int scale;
- BN_CTX *ctx;
a = pop_number();
if (a == NULL)
@@ -1143,10 +1126,7 @@ bmod(void)
normalize(a, scale);
normalize(b, scale + bmachine.scale);
- ctx = BN_CTX_new();
- bn_checkp(ctx);
bn_check(BN_mod(r->number, b->number, a->number, ctx));
- BN_CTX_free(ctx);
}
push_number(r);
free_number(a);
@@ -1159,7 +1139,6 @@ bdivmod(void)
struct number *a, *b;
struct number *rdiv, *rmod;
u_int scale;
- BN_CTX *ctx;
a = pop_number();
if (a == NULL)
@@ -1182,11 +1161,8 @@ bdivmod(void)
normalize(a, scale);
normalize(b, scale + bmachine.scale);
- ctx = BN_CTX_new();
- bn_checkp(ctx);
bn_check(BN_div(rdiv->number, rmod->number,
b->number, a->number, ctx));
- BN_CTX_free(ctx);
}
push_number(rdiv);
push_number(rmod);
@@ -1273,14 +1249,11 @@ bexp(void)
}
if (neg) {
- BN_CTX *ctx;
BIGNUM *one;
one = BN_new();
bn_checkp(one);
bn_check(BN_one(one));
- ctx = BN_CTX_new();
- bn_checkp(ctx);
scale_number(one, r->scale + rscale);
if (BN_is_zero(r->number))
@@ -1289,7 +1262,6 @@ bexp(void)
bn_check(BN_div(r->number, NULL, one,
r->number, ctx));
BN_free(one);
- BN_CTX_free(ctx);
r->scale = rscale;
} else
normalize(r, rscale);
@@ -1306,7 +1278,6 @@ bsqrt(void)
struct number *r;
BIGNUM *x, *y, *t;
u_int scale, onecount;
- BN_CTX *ctx;
onecount = 0;
n = pop_number();
@@ -1325,8 +1296,6 @@ bsqrt(void)
bn_check(BN_rshift(x, x, BN_num_bits(x)/2));
y = BN_new();
bn_checkp(y);
- ctx = BN_CTX_new();
- bn_checkp(ctx);
do {
bn_check(BN_div(y, NULL, n->number, x, ctx));
bn_check(BN_add(y, x, y));
@@ -1341,7 +1310,6 @@ bsqrt(void)
r->scale = scale;
r->number = y;
BN_free(x);
- BN_CTX_free(ctx);
push_number(r);
}
Regards,
kshe