// $Id: clock1.c,v 1.20 2013/07/06 20:25:22 pdc Exp $ // fake userland clock #include #include #ifndef noreplace #include #include #include typedef int clock_gettime_t(clockid_t, struct timespec *); typedef int usleep_t(useconds_t); typedef ssize_t read_t(int, void *, size_t); static clock_gettime_t *clock_gettime_addr; static usleep_t *usleep_addr; // not used yet static read_t *read_addr; static void* system_libc; static int initialized=0; #define MAXTP 20 struct timespec tp0[MAXTP], tplast[MAXTP]; extern void my_z_init() { printf("clock1.so: init\n"); void* system_libc= dlopen("libc.so", RTLD_NOW|RTLD_GLOBAL ); printf("libc: %08x \n",system_libc); } int read_calls[2]; static int calls_total=0; // clock_gettime count static int calls_clock_gettime[MAXTP]; // per-clock count static int last_clock_gettime[MAXTP]; // per-clock count for diff static int every_a=0; // printf skip counter int show_every=100000; static int skip_calls=200; // skipping target - calls to skip before actual syscall static int skip_calls10=10; // skipping target for clock_id=10 int clock10=0; // skip counter int clock12=0; // skip counter void print_stats(){ dprintf(2,"clock1.so: read() %d calls, %d read(3,) failed\n", read_calls[0], read_calls[1]); } void my_do_exit(){ dprintf(2,"Exiting... \n"); print_stats(); } int my_init_dl() { if(system_libc == NULL) { system_libc= dlopen("libc.so.7", RTLD_NOW|RTLD_GLOBAL ); } ; if(system_libc == NULL) { system_libc= dlopen("libc.so", RTLD_NOW|RTLD_GLOBAL ); } ; if(system_libc == NULL) { dprintf(2,"clock1.so: error load libc: %d\n",errno); return -1; } else { dprintf(2,"clock1.so: libc @ %08x \n",system_libc); clock_gettime_addr = (clock_gettime_t *) dlfunc(system_libc, "clock_gettime"); usleep_addr = (usleep_t *) dlfunc(system_libc, "usleep"); read_addr = (read_t *) dlfunc(system_libc, "read"); dprintf(2,"clock1.so: clock_gettime @ %08x, usleep @ %08x\n", clock_gettime_addr, usleep_addr); } initialized=1; atexit(&my_do_exit); return 0; } int clock_gettime(clockid_t clock_id, struct timespec *tp) { //tp->tv_sec=123; //tp->tv_nsec=456; if(clock_id>MAXTP) { dprintf(2,"!!!! clock_id=%d > %d", clock_id,MAXTP); return -1; } calls_total++; calls_clock_gettime[clock_id]++; every_a--; if(!initialized) { dprintf(2,"clock1.so: clock_gettime(%d)\n", clock_id); int r; r=my_init_dl(); if(r!=0) { return r; }; }; int first=0; if( clock_id==12 || clock_id==110 || clock_id==113 ) { // fast timers if(clock12-->0 ) { // skip if(tp0[clock_id].tv_sec>0) { // dont skip first calls tp0[clock_id].tv_nsec+=50000; // simulate clock ticks *tp=tp0[clock_id]; //usleep(1); return 0; } else { first=1; }; } clock12=skip_calls; //usleep(1); // avoid too many syscalls -- bad to games } // usleep(1000000); // 1 sec wait TEST if( clock_id==10 || clock_id==110 || clock_id==113 ) { // fast timers if(clock10-->0 ) { // skip if(tp0[clock_id].tv_sec>0) { // dont skip first calls tp0[clock_id].tv_nsec+=50000; // simulate clock ticks *tp=tp0[clock_id]; //usleep(1); return 0; } else { first=1; }; } clock10=skip_calls10; //usleep(1); // avoid too many syscalls -- bad to games } // usleep(1000000); // 1 sec wait TEST if(clock_gettime_addr !=NULL) { struct timespec tp1 = tp0[clock_id]; // synt int res=clock_gettime_addr(clock_id, &tp0[clock_id]); // real if(first) { last_clock_gettime[clock_id] = calls_clock_gettime[clock_id]; tplast[clock_id] = tp0[clock_id]; every_a=-1; } if(every_a<0) { double t0 = (tp0[clock_id].tv_sec + tp0[clock_id].tv_nsec/1e9); double t1 = (tp1.tv_sec + tp1.tv_nsec/1e9); double tl = (tplast[clock_id].tv_sec + tplast[clock_id].tv_nsec/1e9); int c1 = calls_clock_gettime[clock_id] - last_clock_gettime[clock_id]; print_stats(); tplast[clock_id] = tp0[clock_id]; last_clock_gettime[clock_id] = calls_clock_gettime[clock_id]; dprintf(2,"%d/%d\tclock_gettime(%d)=%d.%09d\t% 0.7f\t%6d / %0.4f = %0.0f\n", calls_total, calls_clock_gettime[clock_id], clock_id, tp0[clock_id].tv_sec, tp0[clock_id].tv_nsec, // real t0-t1, // synt drift c1, t1-tl, c1/(t1-tl)); /* dprintf(2,"%d/%d\tclock_gettime(%d)=%d.%09d\t~%d.%09d\t%6d / %0.4f\n", calls_total, calls_clock_gettime[clock_id], clock_id, tp0[clock_id].tv_sec, tp0[clock_id].tv_nsec, // real tp1.tv_sec, tp1.tv_nsec, // synt c1, t1); */ every_a=show_every; } *tp=tp0[clock_id]; return res; } return -1; // err } ssize_t read (int d, void *buf, size_t nbytes) { if(!initialized) { dprintf(2,"clock1.so: read(%d)\n", d); int r; r=my_init_dl(); if(r!=0) { return r; }; }; if(read_addr !=NULL) { int r= read_addr(d, buf, nbytes); int e= errno; read_calls[0]++; if(d==3 && r==-1) { read_calls[1]++; //dprintf(2,"clock1.so: read(%d,,%d)\tRET read %d errno %d\t%d\n", d,nbytes,r,e,read_calls); //usleep(1); // 40311 opera 10.640797 CALL read(0x3,0x80554202c,0x1000) // 40311 opera 10.640800 RET read -1 errno 35 Resource temporarily unavailable errno=e; } return r; } return -1; // err } #endif #ifdef runtest int main() { struct timespec tp; int res,i; for(i=0; i<1000000; i++) { res=clock_gettime(0xc, &tp); } printf("sec %d nsec %d\n", tp.tv_sec, tp.tv_nsec); return 0; } #endif /* env LD_PRELOAD=/root/bin/clock1.so opera gcc -fPIC -Wl,-x -shared -Wl,-soname,clock1.so -o clock1.so clock1.c env LD_PRELOAD=./clock1.so /bin/date env LD_PRELOAD=./clock1.so /bin/cat gcc -Druntest -Dnoreplace -o clock1.out clock1.c -g3 env LD_PRELOAD=./clock1.so ./clock1.out clock1.so: clock_gettime(12) clock1.so: libc @ 00639800 clock1.so: clock_gettime @ 00b2abd0, usleep @ 00b2a8c0 clock_gettime(12)=79190.946516116 sec 79190 nsec 946516116 http://en.wikipedia.org/wiki/Dynamic_loading http://www.ilikejam.org/blog/2011/02/ld-preload-hackery.html I use the following to preload all the libraries: LD_PRELOAD="`find ../Qt/ -type f -name \*.so\* -printf "%p "`" kdump | g CALL|sort -u kdump -Ef /var/tmp/ktrace-opera.out | g -11 getti kdump -Ef /var/tmp/ktrace-opera.out | g -11 getti | G '^...... opera 1\.' |wc 79996 448306 4641584 start dialog: 1/125000 sec между = .000008 19202 opera 12.129267 CALL clock_gettime(0xd,0x7fffffffcad0) 19202 opera 12.129271 RET clock_gettime 0 19202 opera 12.129275 CALL clock_gettime(0xd,0x7fffffffcad0) 19202 opera 12.129279 RET clock_gettime 0 19202 opera 12.129283 CALL clock_gettime(0xc,0x7fffffffcbf0) 19202 opera 12.129288 RET clock_gettime 0 19202 opera 12.129293 CALL clock_gettime(0xc,0x7fffffffced0) 19202 opera 12.129298 RET clock_gettime 0 19772 opera 10.626977 CALL read(0x3,0x804ca602c,0x1000) 19772 opera 10.626986 RET read -1 errno 35 Resource temporarily unavailable 19772 opera 10.633991 CALL read(0x3,0x804ca602c,0x1000) 19772 opera 10.634000 RET read -1 errno 35 Resource temporarily unavailable 19772 opera 10.640975 CALL read(0x3,0x804ca602c,0x1000) 19772 opera 10.640985 RET read -1 errno 35 Resource temporarily unavailable 19772 opera 10.648069 CALL read(0x3,0x804ca602c,0x1000) 19772 opera 10.648078 RET read -1 errno 35 Resource temporarily unavailable 19772 opera 0 v c rw------- 11 746551 - /dev/pts/43 19772 opera 1 v c rw------- 11 746551 - /dev/pts/43 19772 opera 2 v c rw------- 11 746551 - /dev/pts/43 19772 opera 3 s - rw---n--- 1 0 UDS /tmp/.X11-unix/X0 19772 opera 4 v r rw------- 1 0 - /var/tmp/home/opera/.opera/lock 19772 opera 5 s - rw---n--- 1 0 UDS /tmp/.X11-unix/X0 245# kdump -E | g 'read(0x3' | g '^...... opera 10'|wc 477 2385 29097 246# kdump -E | g 'read(0x3' | g '^...... opera 20' | wc 600 3000 36600 247# kdump -E | g 'read(0x3' | g '^...... opera 19' | wc 481 2405 29341 kdump -E | g 'read(' | g -v 'read(0x[35],' | g '^...... opera ' /usr/include/time.h #define CLOCK_REALTIME 0 #ifdef __BSD_VISIBLE #define CLOCK_VIRTUAL 1 #define CLOCK_PROF 2 #endif #define CLOCK_MONOTONIC 4 #define CLOCK_UPTIME 5 #define CLOCK_UPTIME_PRECISE 7 #define CLOCK_UPTIME_FAST 8 #define CLOCK_REALTIME_PRECISE 9 #define CLOCK_REALTIME_FAST 10 #define CLOCK_MONOTONIC_PRECISE 11 #define CLOCK_MONOTONIC_FAST 12 #define CLOCK_SECOND 13 #define CLOCK_THREAD_CPUTIME_ID 14 total/clock_id 881244/757164 clock_gettime(12)=82046.545517106 882439/53650 clock_gettime(13)=1324144977.0 882451/70090 clock_gettime(10)=1324144978.780468441 882464/70100 clock_gettime(10)=1324144979.128468037 882477/70110 clock_gettime(10)=1324144979.495469197 219201596/215602226 clock_gettime(12)=141582.078515777 219202808/215603428 clock_gettime(12)=141582.162515965 219204020/215604628 clock_gettime(12)=141582.559517677 219204886/215605483 clock_gettime(12)=141582.696530914 219206098/215606678 clock_gettime(12)=141582.905517495 5400/s 10804818/26237 clock_gettime(4)=162454.743938822 1.3935672 728 / 248.3199 = 3 11004832/113422 clock_gettime(10)=1324225636.486788463 0.0321479 10004 / 2286.7360 = 4 11204975/10795309 clock_gettime(12)=162957.985725714 0.6202132 769428 / 1015.4580 = 758 11405041/10986058 clock_gettime(12)=163211.106514941 -0.0080025 190749 / 253.1288 = 754 11605079/282843 clock_gettime(13)=1324226391.000000000 1.0000000 107849 / 3953.0000 = 27 11805152/117655 clock_gettime(10)=1324226660.900791762 0.6511505 4233 / 1023.7629 = 4 12005153/295081 clock_gettime(13)=1324226944.000000000 0.0000000 12238 / 553.0000 = 22 */