I wrote a simple code to test mystrlen by comparing it to the standard library strlen on a 2089360 byte string. I used two versions of mystrlen and both are very far from the standard strlen runtime, about 93x slower on single execution. what makes the standard strlen so fast?
I compiled all test with
gcc file.c -Ofast
here is my main:
#include <sys/time.h>
#include <string.h>
#include <stdio.h>
int main ()
{
double time = 0;
struct timeval start, end;
const char *s = myBigString;
for (int j = 0; j < 50; ++j)
{
gettimeofday(&start, NULL);
// int k = mystrlen2(s1);
int k = strlen(s1);
gettimeofday(&end, NULL);
time += end.tv_sec + end.tv_usec / 1e6 - start.tv_sec - start.tv_usec / 1e6; // in seconds
printf("%d\n", k);
}
printf("average time program took %f seconds to execute 50 times\n", time / 50);
return 0;
}
mystrlen1 code:
size_t mystrlen1(const char *s)
{
size_t i = 0;
while (s[i])
i++;
return i;
}
mystrlen2 code:
size_t mystrlen2(const char *s)
{
size_t i = 0;
while (s[i])
i += 2;
if (!s[i - 1])
i--;
return i;
}
as expected mystrlen2 is better than mystrlen1:
$ ./mystrlen1
average time program took 0.001149 seconds to execute 50 times
$ ./mystrlen2
average time program took 0.000446 seconds to execute 50 times
but now see the output of library strlen:
$ ./libstrlen
average time program took 0.000000 seconds to execute 50 times
what happened here? how it's possible it run in 0 sec?
EDIT:
after couple of tests I found out the problem is the printf instruction that take "lot of" time. If I remove that the runtime will be the same for each function.
time += ((end.tv_sec - start.tv_sec) * 1000000) + (end.tv_usec - start.tv_usec); // in micro seconds
the output is:
$ ./mystrlen1
average time program took 0.020000 microseconds to execute 50 times
$ ./mystrlen2
average time program took 0.020000 microseconds to execute 50 times
$ ./libstrlen
average time program took 0.020000 microseconds to execute 50 times
Check the assembly generated by your program. I think you'll find that your compiler replaced
with
You can see this in effect here, where
results in
In fact, we see that the compiler in question realizes that
mystring1is equivalent tostrlen, soresults in
It's not worth discussing
mystrlen2since it's incorrect and results in undefined behaviour when provided an odd-length string.Use a value generated at run time to see how your functions actually perform.
Still, it's entirely possible that you still won't actually be benchmarking your own code if you do this. Again, this other demo using a variable string still shows the compiler in question realizes that
mystring1is equivalent tostrlen, and just replaces calls tomystrlen1with a call tostrlen.