Thread: Quick speed test

  1. #1
    Registered User awsdert's Avatar
    Join Date
    Jan 2015
    Posts
    1,733

    Quick speed test

    So I thought of a different method for reading in numbers and to check it was actually faster (which I strongly suspected) I decided to run a speed test only the resulting difference was so vast I thought maybe I did something wrong in the second that was taking more time than needed, here's a link to the files I used:
    base62_speedtest.tar.gz - Google Drive
    And here's my output:
    Code:
    make base62.run
    cc -fPIC -Wall -Wno-multichar  -shared -o ./libnext.so -c next.c
    cc -fPIC -Wall -Wno-multichar  -D OUT=base62.elf -o ./base62.elf base62.c ./libnext.so
    base62.c: In function ‘main’:
    base62.c:270:24: warning: format ‘%llu’ expects argument of type ‘long long unsigned int’, but argument 2 has type ‘counter_t’ {aka ‘volatile long unsigned int’} [-Wformat=]
      270 |  printf("Method 0 = %llu, Method 1 = %llu\n", method0, method1 );
          |                     ~~~^                      ~~~~~~~
          |                        |                      |
          |                        long long unsigned int counter_t {aka volatile long unsigned int}
          |                     %lu
    base62.c:270:41: warning: format ‘%llu’ expects argument of type ‘long long unsigned int’, but argument 3 has type ‘counter_t’ {aka ‘volatile long unsigned int’} [-Wformat=]
      270 |  printf("Method 0 = %llu, Method 1 = %llu\n", method0, method1 );
          |                                      ~~~^              ~~~~~~~
          |                                         |              |
          |                                         |              counter_t {aka volatile long unsigned int}
          |                                         long long unsigned int
          |                                      %lu
    ./base62.elf
    07 = 7
    999 = 999
    0b101 = 5
    0x5f5e0ff = 99999999
    9stop = 9
    Method 0 = 213564, Method 1 = 18446727230073051771
    rm base62.elf libnext.so
    Compilation finished successfully.
    Could a few people run this ("make base.run" is the command) and show me their results please.

  2. #2
    misoturbutc Hodor's Avatar
    Join Date
    Nov 2013
    Posts
    1,787
    If you fix the printf warnings the output is more like:

    Code:
    7 = 7
    999 = 999
    0b101 = 5
    0x5f5e0ff = 99999999
    9stop = 9
    Method 0 = 18446744073705503012, Method 1 = 18446713453979999608

  3. #3
    misoturbutc Hodor's Avatar
    Join Date
    Nov 2013
    Posts
    1,787
    Note that 'stop' is not initialised at this point:

    Code:
        while ( unit_tests[i] ) {
            ret = test_method( unit_tests[i], 0 );
            if ( ret != EXIT_SUCCESS ) {
                FAIL( stderr, ret, "" );
                return EXIT_FAILURE;
            }
            ++i;
        }
        KILL_TSC(&stop); // line 257
    However, it is used unitialised on line 36 (the subtraction at the end; *cptr is pointing to something that isn't initialised)

    Code:
        *cptr = (a | ((uint64_t)d << 32)) - *cptr;; // line 36; *cptr is not initalised, therefore undefined behaviour
    The implication of this is that method0 (and therefore method1 as well!) is calculated using an unitialised variable. I'm not really sure what line 36 is trying to do anyway, but if you change it to
    Code:
        *cptr = (a | ((uint64_t)d << 32)); // line 36
    so that no unitialised stuff is being used you get the more reasonable (in the sense that they're not so gigantic, but whether they're correct or not is a different question but at least they're not relying on UB now) output of:

    Code:
    Method 0 = 65630368, Method 1 = 886766
    -------------------------------------------------------------
    Addendum: output of valgrind (unmodified source)
    Code:
    =5971== Memcheck, a memory error detector
    ==5971== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
    ==5971== Using Valgrind-3.15.0 and LibVEX; rerun with -h for copyright info
    ==5971== Command: ./speedtest
    ==5971== 
    07 = 7
    999 = 999
    0b101 = 5
    0x5f5e0ff = 99999999
    9stop = 9
    ==5971== Use of uninitialised value of size 8
    ==5971==    at 0x48B857B: _itoa_word (in /usr/lib64/libc-2.29.so)
    ==5971==    by 0x48D2533: __vfprintf_internal (in /usr/lib64/libc-2.29.so)
    ==5971==    by 0x48BE38E: printf (in /usr/lib64/libc-2.29.so)
    ==5971==    by 0x401D81: main (base62.c:270)
    ==5971== 
    ==5971== Conditional jump or move depends on uninitialised value(s)
    ==5971==    at 0x48B858D: _itoa_word (in /usr/lib64/libc-2.29.so)
    ==5971==    by 0x48D2533: __vfprintf_internal (in /usr/lib64/libc-2.29.so)
    ==5971==    by 0x48BE38E: printf (in /usr/lib64/libc-2.29.so)
    ==5971==    by 0x401D81: main (base62.c:270)
    ==5971== 
    ==5971== Conditional jump or move depends on uninitialised value(s)
    ==5971==    at 0x48D31A0: __vfprintf_internal (in /usr/lib64/libc-2.29.so)
    ==5971==    by 0x48BE38E: printf (in /usr/lib64/libc-2.29.so)
    ==5971==    by 0x401D81: main (base62.c:270)
    ==5971== 
    ==5971== Conditional jump or move depends on uninitialised value(s)
    ==5971==    at 0x48D26A3: __vfprintf_internal (in /usr/lib64/libc-2.29.so)
    ==5971==    by 0x48BE38E: printf (in /usr/lib64/libc-2.29.so)
    ==5971==    by 0x401D81: main (base62.c:270)
    ==5971== 
    Method 0 = 50033554, Method 1 = 18446709696057156788
    Last edited by Hodor; 10-07-2019 at 06:21 PM.

  4. #4
    misoturbutc Hodor's Avatar
    Join Date
    Nov 2013
    Posts
    1,787
    Umm, the whole point is kind of moot anyway because

    Code:
    while ( unit_tests[i] ) { // line 260
    Because that loop is never executed (because by this point unit_tests[i] is already NULL), so the second method is actually never tested at all.

    Changing this line to what's below will make the second test actually be performed (I put the i = 0 on the same line just so line numbers don't get mixed up)

    Code:
    i = 0; while ( unit_tests[i] ) {
    Now that the test is actually being executed, according to callgrind ubase62() is faster than ubase62_loopstr()
    Last edited by Hodor; 10-07-2019 at 06:56 PM.

  5. #5
    Registered User awsdert's Avatar
    Join Date
    Jan 2015
    Posts
    1,733
    Thank you hodor, yeah I noticed those warnings only after I posted but figured that was a minor deal compared to the ridicules output, good to know my suspicions were correct though, unfortunately encountered a bug when converting to a library for other mini-projects to use, eventually gonna put it all in one library to cover general input / output of characters, also decided that the whole dst & leng thing in the reader functions was actually a slow down since it had to check there was enough space, I instead typedef'd a char8_t fixed size array and swaped out the 2 parameters for just one using the typedef and use it directly when converting into UTF-8 or simply reading UTF-8, also finally found out what I should use for ide characters and am now working on adding that, I'm also trying to merge the unit tests of both numbers and characters into one now to give me an idea of how to handle detecting either in preperation for expression handling. As a final note I'm also planning on adding array access support for string literals to make detecting underlying types easier or something else I'm sure others will think of before me, I'm thinking the usual [ # ] is good enough, any thoughts for other stuff while I'm at it?

  6. #6
    Registered User awsdert's Avatar
    Join Date
    Jan 2015
    Posts
    1,733
    As it turns out the bug was in a different function, it was simply caught in ubase62

  7. #7
    misoturbutc Hodor's Avatar
    Join Date
    Nov 2013
    Posts
    1,787
    Quote Originally Posted by awsdert View Post
    As it turns out the bug was in a different function, it was simply caught in ubase62
    Which bug?

  8. #8
    misoturbutc Hodor's Avatar
    Join Date
    Nov 2013
    Posts
    1,787
    Also, I meant to mention the other day that the "speed" reported by your program, for each of the functions, depends on the order they are tested. If you test method0 first and then method1, the program reports method1 as being fastest. If you swap the tests around and test method1 first and method0 second it reports method0 as being "faster". I don't think testing things in the same program like this is reliable (maybe separate the tests using #if directives so only one runs at a time, then recompile and test the other function; or use something like valgrind instead if it's really that important). If the very small slowdown in speed is a problem then using the less portable non-loop version of the function might be worth it.

    Also, from memory, both the loop and non-loop versions have a bug in them for bases >= 36 which I didn't mention the other day because I forgot and I couldn't work out how to demonstrate the bug anyway. [strike]I don't have the code anymore but a bool used to choose between lower and upper case characters for the conversion is not initialised (I think it was called highashigh or lowaslow or highaslow or something like that)[/strike]. Edit: actually base62.c is in your new archive for the other current question and the unitialised variable is called lowislow
    Last edited by Hodor; 10-10-2019 at 08:34 PM.

  9. #9
    Registered User awsdert's Avatar
    Join Date
    Jan 2015
    Posts
    1,733
    Quote Originally Posted by Hodor View Post
    Which bug?
    Quote Originally Posted by awsdert View Post
    ...unfortunately encountered a bug when converting to a library for other mini-projects to use
    Quote Originally Posted by Hodor View Post
    If the very small slowdown in speed is a problem then using the less portable non-loop version of the function might be worth it.

    Also, from memory, both the loop and non-loop versions have a bug in them for bases >= 36 which I didn't mention the other day because I forgot and I couldn't work out how to demonstrate the bug anyway. [strike]I don't have the code anymore but a bool used to choose between lower and upper case characters for the conversion is not initialised (I think it was called highashigh or lowaslow or highaslow or something like that)[/strike]. Edit: actually base62.c is in your new archive for the other current question and the unitialised variable is called lowislow
    Hmm, given lowislow is a parameter of the function I doubt that it could ever be uninitialised, unless the one I uploaded is different to the version I have now:
    Code:
    int ubase62(
    	NEXTC *_nextc, uint_least64_t *dst, int base,
    	bool lowislow, size_t min_len, size_t max_len )
    {
    	int ret = nextc_validate(_nextc), c;
    	size_t i = 0, l, h;
    	uint_least64_t num = 0;
    	if ( !max_len ) max_len = -2;
    	if ( ret != EXIT_SUCCESS )
    		goto ubase62_done;
    	else if ( base < 2 ) {
    		ret = ERANGE;
    		FAIL( stderr, ret, "base is too low!" );
    		goto ubase62_done;
    	}
    	else if ( base <= 36 ) { l = 10; h = 10; }
    	else if ( base > 62 ) {
    		ret = ERANGE;
    		FAIL( stderr, ret, "base is too high!" );
    		goto ubase62_done;
    	}
    	else if ( lowislow ) { l = 10; h = 36; }
    	else { l = 36; h = 10; }
    	do {
    		c = _nextc->c[0];
    		if ( c >= U'0' && c <= U'9' )
    			c -= U'0';
    		else if ( c >= U'A' && c <= U'Z' )
    			{ c -= U'A'; c += h; }
    		else if ( c >= U'a' && c <= U'z' )
    			{ c -= U'a'; c += l; }
    		else break;
    		if ( c >= base || i >= max_len ) break;
    		num *= base;
    		num += c;
    		++i;
    	} while ( (ret = nextc(_nextc)) == EXIT_SUCCESS );
    	if ( ret != EXIT_SUCCESS )
    		FAIL( stderr, ret, "" );
    	if ( i < min_len ) {
    		ret = ERANGE;
    		FAIL( stderr, ret, "Not enough digits" );
    		fprintf( stderr,
    			"c = '%c', i = %zu, min_len = %zu, max_len = %zu\n",
    			_nextc->c[0], i, min_len, max_len );
    	}
    	ubase62_done:
    	if ( dst ) *dst = num;
    	return ret;
    }
    Btw what kind of bug did you experience above base 36? I never tested that high cause I didn't expect there to be issues when it uses the same handling just with a larger range

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Interesting speed test
    By awsdert in forum C Programming
    Replies: 10
    Last Post: 09-04-2019, 05:33 AM
  2. Execution speed test in c++
    By nick2price in forum C++ Programming
    Replies: 1
    Last Post: 03-12-2009, 04:23 PM
  3. Speed test result
    By audinue in forum C Programming
    Replies: 4
    Last Post: 07-07-2008, 05:18 AM
  4. Test your speed
    By DISGUISED in forum A Brief History of Cprogramming.com
    Replies: 15
    Last Post: 01-22-2004, 11:53 PM
  5. Just a quick test of your knowledge
    By Necrodeemer in forum C++ Programming
    Replies: 10
    Last Post: 01-20-2003, 08:32 PM

Tags for this Thread