On Thu, Aug 4, 2011 at 22:36, Nick Mathewson <ni...@freehaven.net> wrote: > * Make no changes in the code, but suggest to people that they should > be using EVENT_BASE_FLAG_NO_CACHE_TIME if they are running on a > platform where time checking is very quick and they care about very > accurate timing.
I've measures gettimeofday and clock_gettime for linux and freebsd (file was built with -O2), time iis in nanoseconds: Linux 2.6.24 (openvz): darkk@kitana:~$ uname -a Linux kitana 2.6.24-23-openvzyandex #2 SMP Fri Apr 24 18:54:48 MSD 2009 x86_64 GNU/Linux darkk@kitana:~$ ./gettimeofday-cost (CLOCK_REALTIME) gtod: 690.867596 (CLOCK_REALTIME) clock(mono): 685.391339 (CLOCK_REALTIME) clock(monoraw): 62.287522 (CLOCK_REALTIME) memcpy: 2.917304 (CLOCK_REALTIME) assign: 1.309508 (CLOCK_MONOTONIC) gtod: 684.626865 (CLOCK_MONOTONIC) clock(mono): 676.373822 (CLOCK_MONOTONIC) clock(monoraw): 62.847293 (CLOCK_MONOTONIC) memcpy: 2.918910 (CLOCK_MONOTONIC) assign: 1.250632 (CLOCK_PROCESS_CPUTIME_ID) gtod: 690.960662 (CLOCK_PROCESS_CPUTIME_ID) clock(mono): 673.605924 (CLOCK_PROCESS_CPUTIME_ID) clock(monoraw): 62.411515 (CLOCK_PROCESS_CPUTIME_ID) memcpy: 2.912745 (CLOCK_PROCESS_CPUTIME_ID) assign: 1.295240 Linux 2.6.32: darkk@golem-test2:~$ uname -a ; gcc -v 2>&1 | tail -1 Linux golem-test2 2.6.32-31-server #61-Ubuntu SMP Fri Apr 8 19:44:42 UTC 2011 x86_64 GNU/Linux gcc version 4.4.3 (Ubuntu 4.4.3-4ubuntu5) darkk@golem-test2:~$ ./gettimeofday-cost (CLOCK_REALTIME) gtod: 40.447892 (CLOCK_REALTIME) clock(mono): 37.522405 (CLOCK_REALTIME) memcpy: 2.502965 (CLOCK_MONOTONIC) gtod: 40.443445 (CLOCK_MONOTONIC) clock(mono): 37.513386 (CLOCK_MONOTONIC) memcpy: 2.500064 (CLOCK_PROCESS_CPUTIME_ID) gtod: 40.365945 (CLOCK_PROCESS_CPUTIME_ID) clock(mono): 37.450675 (CLOCK_PROCESS_CPUTIME_ID) memcpy: 2.496287 Linux 3.0: darkk@darkk-ya-thinkpad $ uname -a; gcc -v 2>&1 | tail -1 Linux darkk-ya-thinkpad 3.0.0-7-generic #9-Ubuntu SMP Fri Jul 29 21:27:24 UTC 2011 x86_64 x86_64 x86_64 GNU/Linux gcc version 4.5.2 (Ubuntu/Linaro 4.5.2-8ubuntu4) darkk@darkk-ya-thinkpad $ ./gettimeofday-cost (CLOCK_REALTIME) gtod: 31.854696 (CLOCK_REALTIME) clock(mono): 19.328140 (CLOCK_REALTIME) clock(monoraw): 60.396497 (CLOCK_REALTIME) memcpy: 2.092423 (CLOCK_MONOTONIC) gtod: 21.440780 (CLOCK_MONOTONIC) clock(mono): 20.001421 (CLOCK_MONOTONIC) clock(monoraw): 60.250465 (CLOCK_MONOTONIC) memcpy: 2.198552 (CLOCK_PROCESS_CPUTIME_ID) gtod: 21.392047 (CLOCK_PROCESS_CPUTIME_ID) clock(mono): 19.416045 (CLOCK_PROCESS_CPUTIME_ID) clock(monoraw): 60.534821 (CLOCK_PROCESS_CPUTIME_ID) memcpy: 2.062982 FreeBSD 8.2 [darkk@daisy2 ~]$ uname -a ; gcc -v 2>&1 | tail -1 FreeBSD daisy2 8.2-STABLE FreeBSD 8.2-STABLE #0 r221983M: Mon Jul 11 18:02:06 MSD 2011 root@...:/place/mkdump_workdir/obj/place/GIT-repos/FreeBSD-8-stable/sys/stable8-amd64-dtrace amd64 gcc version 4.2.2 20070831 prerelease [FreeBSD] [darkk@daisy2 ~]$ ./gettimeofday-cost (CLOCK_REALTIME) gtod: 1318.387523 (CLOCK_REALTIME) clock(mono): 1326.159892 (CLOCK_REALTIME) memcpy: 2.132994 (CLOCK_MONOTONIC) gtod: 1305.614699 (CLOCK_MONOTONIC) clock(mono): 1294.905029 (CLOCK_MONOTONIC) memcpy: 2.132156 > * Probe somehow (probably at runtime) to determine whether we're > someplace that has fast time checking or not. I think, that libevent may provide some sort of heuristics to check speed of timing and let the user decide. But I see, that gettimeofday is still 10 times more expensive than simple memcpy from cached value (and 40 times more expensive than struct assignment via operator=), so I don't think, that disabling value caching is the best option for absolutely every workload. On the other hand, this microbenchmark may be pointless because of, for example, CPU caches - I'm not benchmarking guru at all. 2.6.24 result is really surprising me. -- WBRBW, Leonid Evdokimov xmpp:l...@darkk.net.ru && http://darkk.net.ru tel:+79816800702 && tel:+79050965222
#define _USE_BSD 1 // for timersub() on Linux #include <stdlib.h> #include <stdio.h> #include <assert.h> #include <sys/time.h> #include <time.h> #include <string.h> #include <stdint.h> #include <sched.h> volatile struct timeval reference = { 1312617263, 123456 }; void gettimeofday_memcpy(struct timeval* tv, struct timezone* tz) { (void)tz; memcpy(tv, &reference, sizeof(struct timeval)); } void test(const char* csname, int clocksource, int count) { struct timespec begin, end, ahi; struct timeval a; uint64_t scale_nano = 1000 * 1000 * 1000; uint64_t gtod_cost, monoclock_cost, memcpy_cost, monoraw_cost; int i; #define testcase(dest_cost, function, args) do { \ clock_gettime(clocksource, &begin); \ for (i = 0; i < count; ++i) { \ function args; \ } \ clock_gettime(clocksource, &end); \ dest_cost = (end.tv_sec - begin.tv_sec)*scale_nano + (end.tv_nsec - begin.tv_nsec); \ } while (0) testcase(gtod_cost, gettimeofday, (&a, 0)); testcase(memcpy_cost, gettimeofday_memcpy, (&a, 0)); testcase(monoclock_cost, clock_gettime, (CLOCK_MONOTONIC, &ahi)); #ifdef CLOCK_MONOTONIC_RAW testcase(monoraw_cost, clock_gettime, (CLOCK_MONOTONIC_RAW, &ahi)); #endif // CLOCK_MONOTONIC_RAW printf("(%s) gtod: %f\n", csname, (double)1.0 * gtod_cost / count); printf("(%s) clock(mono): %f\n", csname, (double)1.0 * monoclock_cost / count); #ifdef CLOCK_MONOTONIC_RAW printf("(%s) clock(monoraw): %f\n", csname, (double)1.0 * monoraw_cost / count); #endif printf("(%s) memcpy: %f\n", csname, (double)1.0 * memcpy_cost / count); } #define testmacro(cs, count) test(#cs, cs, count) int main(int argc, char* argv[]) { int count = 1000000; if (argc > 1) { count = atoi(argv[1]); } testmacro(CLOCK_REALTIME, count); testmacro(CLOCK_MONOTONIC, count); #ifdef CLOCK_PROCESS_CPUTIME_ID testmacro(CLOCK_PROCESS_CPUTIME_ID, count); #endif return 0; }