From 5d80c02a4a14e22a948195a9894c5a095282deaa Mon Sep 17 00:00:00 2001 From: Vitaly _Vi Shukela Date: Tue, 29 Nov 2011 20:52:55 +0300 Subject: [PATCH] Strace-based speed limiter Apply to strace-4.6 Set env SPEEDLIMIT_READ=1000 and slow down other process with strace Example: SPEEDLIMIT_READ=$((200*1024)) ./strace -o /dev/null -p `pidof wget` --- strace.c | 15 +++++++++++++++ syscall.c | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+), 0 deletions(-) diff --git a/strace.c b/strace.c index 774d172..6dab71f 100644 --- a/strace.c +++ b/strace.c @@ -199,6 +199,11 @@ usage: strace [-CdDffhiqrtttTvVxx] [-a column] [-e expr] ... [-o file]\n\ " /* this is broken, so don't document it -z -- print only succeeding syscalls\n\ */ +"Set SPEEDLIMIT_READ or SPEEDLIMIT_WRITE environment variables to\n\ + bytes per seconds to slow down I/O of the traced process by\n\ + sleeping after each successfull read/write-like syscall.\n\ + SPEEDLIMIT_SLEEP sets delay for all other syscalls\n\ +" , DEFAULT_ACOLUMN, DEFAULT_STRLEN, DEFAULT_SORTBY); exit(exitval); } @@ -914,6 +919,16 @@ main(int argc, char *argv[]) } } + extern int speedlimit_read; + extern int speedlimit_write; + extern int general_usleep; + speedlimit_read=0; + speedlimit_write=0; + general_usleep=0; + if(getenv("SPEEDLIMIT_READ")) sscanf(getenv("SPEEDLIMIT_READ"), "%i", &speedlimit_read); + if(getenv("SPEEDLIMIT_WRITE")) sscanf(getenv("SPEEDLIMIT_WRITE"), "%i", &speedlimit_write); + if(getenv("SPEEDLIMIT_SLEEP")) sscanf(getenv("SPEEDLIMIT_SLEEP"), "%i", &general_usleep); + if ((optind == argc) == !pflag_seen) usage(stderr, 1); diff --git a/syscall.c b/syscall.c index e66ac0a..cc9e0af 100644 --- a/syscall.c +++ b/syscall.c @@ -168,6 +168,10 @@ static const int nerrnos2 = sizeof errnoent2 / sizeof errnoent2[0]; const char *const *errnoent; int nerrnos; +int speedlimit_read; +int speedlimit_write; +int general_usleep; + int current_personality; #ifndef PERSONALITY0_WORDSIZE @@ -2556,6 +2560,36 @@ trace_syscall_exiting(struct tcb *tcp) } printtrailer(); + if (sysent[tcp->scno].sys_func == sys_read || + sysent[tcp->scno].sys_func == sys_pread || + sysent[tcp->scno].sys_func == sys_pread64 || + sysent[tcp->scno].sys_func == sys_recv || + sysent[tcp->scno].sys_func == sys_recvfrom || + sysent[tcp->scno].sys_func == sys_readv) { + + long long int ret = tcp->u_rval; + if (ret > 0 && speedlimit_read>0) { + usleep(ret * 1000000 / speedlimit_read); + } + } else + if (sysent[tcp->scno].sys_func == sys_write || + sysent[tcp->scno].sys_func == sys_pwrite || + sysent[tcp->scno].sys_func == sys_pwrite64 || + sysent[tcp->scno].sys_func == sys_send || + sysent[tcp->scno].sys_func == sys_sendto || + sysent[tcp->scno].sys_func == sys_writev) { + + long long int ret = tcp->u_rval; + if (ret > 0 && speedlimit_write>0) { + usleep(ret * 1000000 / speedlimit_write); + } + } else { + if (general_usleep > 0) { + usleep(general_usleep); + } + } + + dumpio(tcp); if (fflush(tcp->outf) == EOF) return -1; -- 1.7.6.4