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

Reply via email to