Otto Moerbeek <o...@drijf.net> writes: > > That day came sooner than expected. > > The root cause of the speed difference is that my dc/bc compute in > binary, while the others compute in base 10. So they basically do not > need to do a conversion for outputting in base 10. > > By avoiding a lot of memory allocations and using specialized > conversion routines for base 10 and base 16 things speed up nicely for > me for those bases (from about 1.5 hour to 5m20s for base 10, and to > 28s for base 16 (there the conversion is nearly free). > > Don't forget to rebuild bc as as well after applying the diff for dc. > > -Otto
ok semarie@ thanks. > Index: inout.c > =================================================================== > RCS file: /home/cvs/src/usr.bin/dc/inout.c,v > diff -u -p -r1.23 inout.c > --- inout.c 8 Mar 2023 04:43:10 -0000 1.23 > +++ inout.c 3 Nov 2024 20:19:28 -0000 > @@ -38,7 +38,7 @@ static void src_freestring(struct source > static void flushwrap(FILE *); > static void putcharwrap(FILE *, int); > static void printwrap(FILE *, const char *); > -static char *get_digit(u_long, int, u_int); > +static void get_digit(u_long, int, u_int, char *, size_t); > > static struct vtable stream_vtable = { > src_getcharstream, > @@ -264,20 +264,17 @@ read_string(struct source *src) > return p; > } > > -static char * > -get_digit(u_long num, int digits, u_int base) > +static void > +get_digit(u_long num, int digits, u_int base, char *buf, size_t sz) > { > - char *p; > - > if (base <= 16) { > - p = bmalloc(2); > - p[0] = num >= 10 ? num + 'A' - 10 : num + '0'; > - p[1] = '\0'; > + buf[0] = num >= 10 ? num + 'A' - 10 : num + '0'; > + buf[1] = '\0'; > } else { > - if (asprintf(&p, "%0*lu", digits, num) == -1) > - err(1, NULL); > + int ret = snprintf(buf, sz, "%0*lu", digits, num); > + if (ret < 0 || (size_t)ret >= sz) > + err(1, "truncation %d %zu", ret, sz); > } > - return p; > } > > void > @@ -285,11 +282,10 @@ printnumber(FILE *f, const struct number > { > struct number *int_part, *fract_part; > int digits; > - char buf[11]; > - size_t sz; > + char buf[12], *str, *p; > + size_t allocated; > int i; > - struct stack stack; > - char *p; > + BN_ULONG *mem; > > charcount = 0; > lastchar = -1; > @@ -307,24 +303,49 @@ printnumber(FILE *f, const struct number > } > split_number(b, int_part->number, fract_part->number); > > - i = 0; > - stack_init(&stack); > - while (!BN_is_zero(int_part->number)) { > - BN_ULONG rem = BN_div_word(int_part->number, base); > - stack_pushstring(&stack, get_digit(rem, digits, base)); > - i++; > - } > - sz = i; > - if (BN_is_negative(b->number)) > - putcharwrap(f, '-'); > - for (i = 0; i < sz; i++) { > - p = stack_popstring(&stack); > - if (base > 16) > - putcharwrap(f, ' '); > - printwrap(f, p); > - free(p); > + if (base == 10 && !BN_is_zero(int_part->number)) { > + str = BN_bn2dec(int_part->number); > + bn_checkp(str); > + p = str; > + while (*p) > + putcharwrap(f, *p++); > + free(str); > + } else if (base == 16 && !BN_is_zero(int_part->number)) { > + str = BN_bn2hex(int_part->number); > + bn_checkp(str); > + p = str; > + if (*p == '-') > + putcharwrap(f, *p++); > + /* skip leading zero's */ > + while (*p == '0') > + p++; > + while (*p) > + putcharwrap(f, *p++); > + free(str); > + } else { > + i = 0; > + allocated = 1; > + mem = breallocarray(NULL, allocated, sizeof(BN_ULONG)); > + while (!BN_is_zero(int_part->number)) { > + if (i >= allocated) { > + allocated *= 2; > + mem = breallocarray(mem, allocated, > + sizeof(BN_ULONG)); > + } > + mem[i++] = BN_div_word(int_part->number, base); > + } > + if (BN_is_negative(b->number)) > + putcharwrap(f, '-'); > + for (i = i - 1; i >= 0; i--) { > + get_digit(mem[i], digits, base, buf, > + sizeof(buf)); > + if (base > 16) > + putcharwrap(f, ' '); > + printwrap(f, buf); > + } > + free(mem); > } > - stack_clear(&stack); > + > if (b->scale > 0) { > struct number *num_base; > BIGNUM *mult, *stop; > @@ -352,13 +373,12 @@ printnumber(FILE *f, const struct number > bmachine_scale()); > split_number(fract_part, int_part->number, NULL); > rem = BN_get_word(int_part->number); > - p = get_digit(rem, digits, base); > + get_digit(rem, digits, base, buf, sizeof(buf)); > int_part->scale = 0; > normalize(int_part, fract_part->scale); > bn_check(BN_sub(fract_part->number, fract_part->number, > int_part->number)); > - printwrap(f, p); > - free(p); > + printwrap(f, buf); > bn_check(BN_mul_word(mult, base)); > } > free_number(num_base); > -- Sebastien Marie