2 * This program is licensed under the GNU General Public License,
3 * version 2. A copy of the license can be found in the accompanying
6 **********************************************************************
8 * Simple program to limit the cpu usage of a process
9 * If you modify this code, send me a copy please
11 * Author: Angelo Marletta
15 * Modifications and updates by: Jesse Smith
19 * Version 1.2 and newer
21 * Modifications and updates by: Hasnain Lakhani
32 #include <sys/types.h>
35 #include <sys/types.h>
37 #include <sys/resource.h>
42 #include <limits.h> // for compatibility
45 #include <mach/clock.h>
46 #include <mach/mach.h>
54 #include <sys/param.h>
55 #include <sys/sysctl.h>
60 //kernel time resolution (inverse of one jiffy interval) in Hertz
61 //i don't know how to detect it, then define to the default (not very clean!)
65 #define min(a,b) (a<b?a:b)
66 #define max(a,b) (a>b?a:b)
68 // For platforms without PATH_MAX
73 #define BEST_PRIORITY -10
86 //pid of the controlled process
88 pid_t my_pid; // this process's PID
90 //executable file name
96 // is higher priority nice possible?
99 // number of CPUs we detected
105 // What signal should we send to the watched process
106 // when cpulimit exits?
107 int send_signal = SIGCONT;
109 //reverse byte search
110 // void *memrchr(const void *s, int c, size_t n);
113 const char *SIGNAL_NAME[MAX_SIGNAL] = { "SIGHUP", "SIGINT", "SIGQUIT",
114 "SIGKILL", "SIGTERM", "SIGSTOP", "SIGCONT" };
115 const int SIGNAL_VALUE[MAX_SIGNAL] = { SIGHUP, SIGINT, SIGQUIT,
116 SIGKILL, SIGTERM, SIGSTOP, SIGCONT };
119 //return ta-tb in microseconds (no overflow checks!)
120 inline long timediff(const struct timespec *ta,const struct timespec *tb) {
121 unsigned long us = (ta->tv_sec-tb->tv_sec)*1000000 + (ta->tv_nsec/1000 - tb->tv_nsec/1000);
127 int Check_Us(pid_t target_pid)
132 if (this_pid == target_pid)
134 fprintf(stderr, "We cannot throttle ourselves.\n");
141 int waitforpid(int pid) {
142 //switch to low priority
143 // if (setpriority(PRIO_PROCESS,getpid(),19)!=0) {
145 if ( (nice_lim < INT_MAX) &&
146 (setpriority(PRIO_PROCESS, my_pid, 19) != 0) ) {
147 printf("Warning: cannot renice\n");
157 //open a directory stream to /proc directory
158 if ((dip = opendir("/proc")) == NULL) {
163 //read in from /proc and seek for process dirs
164 while ((dit = readdir(dip)) != NULL) {
166 if (pid==atoi(dit->d_name)) {
169 if (kill(pid,SIGSTOP)==0 && kill(pid,SIGCONT)==0) {
171 if (closedir(dip) == -1) {
178 fprintf(stderr,"Error: Process %d detected, but you don't have permission to control it\n",pid);
183 //close the dir stream and check for errors
184 if (closedir(dip) == -1) {
189 //no suitable target found
192 fprintf(stderr,"No process found\n");
196 fprintf(stderr, "Warning: no target process found. Waiting for it...\n");
206 printf("Process %d detected\n",pid);
207 //now set high priority, if possible
208 // if (setpriority(PRIO_PROCESS,getpid(),-20)!=0) {
210 if ( (nice_lim < INT_MAX) &&
211 (setpriority(PRIO_PROCESS, my_pid, nice_lim) != 0) ) {
212 printf("Warning: cannot renice.\nTo work better you should run this program as root.\n");
219 //this function periodically scans process list and looks for executable path names
220 //it should be executed in a low priority context, since precise timing does not matter
221 //if a process is found then its pid is returned
222 //process: the name of the wanted process, can be an absolute path name to the executable file
223 // or simply its name
224 //return: pid of the found process
225 int getpidof(const char *process) {
228 // if (setpriority(PRIO_PROCESS,getpid(),19)!=0) {
230 if ( (nice_lim < INT_MAX) &&
231 (setpriority(PRIO_PROCESS, my_pid, 19) != 0) ) {
232 printf("Warning: cannot renice\n");
236 char exepath[PATH_MAX+1];
245 //open a directory stream to /proc directory
246 if ((dip = opendir("/proc")) == NULL) {
251 //read in from /proc and seek for process dirs
252 while ((dit = readdir(dip)) != NULL) {
254 pid=atoi(dit->d_name);
256 sprintf(exelink,"/proc/%d/exe",pid);
257 int size=readlink(exelink,exepath,sizeof(exepath));
260 if (process[0]=='/' && strncmp(exepath,process,size)==0 && size==strlen(process)) {
261 //process starts with / then it's an absolute path
265 //process is the name of the executable file
266 if (strncmp(exepath+size-strlen(process),process,strlen(process))==0) {
272 if (kill(pid,SIGSTOP)==0 && kill(pid,SIGCONT)==0) {
274 if (closedir(dip) == -1) {
281 fprintf(stderr,"Error: Process %d detected, but you don't have permission to control it\n",pid);
288 //close the dir stream and check for errors
289 if (closedir(dip) == -1) {
294 //no suitable target found
297 fprintf(stderr,"No process found\n");
301 fprintf(stderr, "Warning: no target process found. Waiting for it...\n");
311 printf("Process %d detected\n",pid);
312 //now set high priority, if possible
313 // if (setpriority(PRIO_PROCESS,getpid(),-20)!=0) {
315 if ( (nice_lim < INT_MAX) &&
316 (setpriority(PRIO_PROCESS, my_pid, nice_lim) != 0) ) {
317 printf("Warning: cannot renice.\nTo work better you should run this program as root.\n");
324 //SIGINT and SIGTERM signal handler
326 //let the process continue if we are stopped
327 kill(pid, send_signal);
328 printf("Exiting...\n");
332 // Handle a child process quitting
333 void Child_Done(int sig)
336 caught_child = waitpid(-1, NULL, WNOHANG);
337 printf("Caught child process: %d\n", (int) caught_child);
338 printf("%d\n", errno);
339 if (caught_child == pid)
341 printf("Child process is finished, exiting...\n");
348 //get jiffies count from /proc filesystem
349 int getjiffies(int pid)
351 kvm_t *my_kernel = NULL;
352 struct kinfo_proc *process_data = NULL;
356 my_kernel = kvm_open(0, 0, 0, O_RDONLY, "kvm_open");
359 fprintf(stderr, "Error opening kernel vm. You should be running as root.\n");
363 process_data = kvm_getprocs(my_kernel, KERN_PROC_PID, pid, &processes);
364 if ( (process_data) && (processes >= 1) )
365 my_jiffies = process_data->ki_runtime;
367 kvm_close(my_kernel);
376 int getjiffies(int pid) {
377 static char stat[20];
378 static char buffer[1024];
380 sprintf(stat,"/proc/%d/stat",pid);
381 FILE *f=fopen(stat,"r");
382 if (f==NULL) return -1;
383 p = fgets(buffer,sizeof(buffer),f);
388 p=memchr(p+1,')',sizeof(buffer)-(p-buffer));
391 p=memchr(p+1,' ',sizeof(buffer)-(p-buffer));
394 p=memchr(p+1,' ',sizeof(buffer)-(p-buffer));
395 //kernel mode jiffies
399 // could not read info
405 //process instant photo
406 struct process_screenshot {
407 struct timespec when; //timestamp
408 int jiffies; //jiffies count of the process
409 int cputime; //microseconds of work from previous screenshot to current
412 //extracted process statistics
418 //this function is an autonomous dynamic system
419 //it works with static variables (state variables of the system), that keep memory of recent past
420 //its aim is to estimate the cpu usage of the process
421 //to work properly it should be called in a fixed periodic way
422 //perhaps i will put it in a separate thread...
423 int compute_cpu_usage(int pid,int last_working_quantum,struct cpu_usage *pusage) {
425 //circular buffer containing last MEM_ORDER process screenshots
426 static struct process_screenshot ps[MEM_ORDER];
427 //the last screenshot recorded in the buffer
429 //the oldest screenshot recorded in the buffer
433 //reinit static variables
439 //let's advance front index and save the screenshot
440 front=(front+1)%MEM_ORDER;
441 int j=getjiffies(pid);
442 if (j>=0) ps[front].jiffies=j;
443 else return -1; //error: pid does not exist
446 // OS X does not have clock_gettime, use clock_get_time
449 host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &cclock);
450 clock_get_time(cclock, &mts);
451 mach_port_deallocate(mach_task_self(), cclock);
452 ps[front].when.tv_sec = mts.tv_sec;
453 ps[front].when.tv_nsec = mts.tv_nsec;
456 // Linux and BSD can use real time
457 clock_gettime(CLOCK_REALTIME,&(ps[front].when));
458 ps[front].cputime=last_working_quantum;
460 //buffer actual size is: (front-tail+MEM_ORDER)%MEM_ORDER+1
461 int size=(front-tail+MEM_ORDER)%MEM_ORDER+1;
464 //not enough samples taken (it's the first one!), return -1
466 pusage->workingrate=1;
470 //now we can calculate cpu usage, interval dt and dtwork are expressed in microseconds
471 long dt=timediff(&(ps[front].when),&(ps[tail].when));
473 int i=(tail+1)%MEM_ORDER;
474 int max=(front+1)%MEM_ORDER;
476 dtwork+=ps[i].cputime;
479 int used=ps[front].jiffies-ps[tail].jiffies;
480 float usage=(used*1000000.0/HZ)/dtwork;
481 pusage->workingrate=1.0*dtwork/dt;
482 pusage->pcpu=usage*pusage->workingrate;
484 tail=(tail+1)%MEM_ORDER;
490 void print_caption() {
491 printf("\n%%CPU\twork quantum\tsleep quantum\tactive rate\n");
495 void increase_priority()
497 //find the best available nice value
498 int old_priority = getpriority(PRIO_PROCESS, 0);
499 int priority = old_priority;
500 while ( (setpriority(PRIO_PROCESS, 0, priority-1) == 0) &&
501 (priority > BEST_PRIORITY) )
505 if (priority != old_priority) {
506 if (verbose) printf("Priority changed to %d\n", priority);
509 if (verbose) printf("Warning: Cannot change priority. Run as root or renice for best results.\n");
517 void print_usage(FILE *stream,int exit_code) {
518 fprintf(stream, "CPUlimit version %1.1f\n", VERSION);
519 fprintf(stream, "Usage: %s TARGET [OPTIONS...] [-- PROGRAM]\n",program_name);
520 fprintf(stream, " TARGET must be exactly one of these:\n");
521 fprintf(stream, " -p, --pid=N pid of the process\n");
522 fprintf(stream, " -e, --exe=FILE name of the executable program file\n");
523 fprintf(stream, " The -e option only works when\n");
524 fprintf(stream, " cpulimit is run with admin rights.\n");
525 fprintf(stream, " -P, --path=PATH absolute path name of the\n");
526 fprintf(stream, " executable program file\n");
527 fprintf(stream, " OPTIONS\n");
528 fprintf(stream, " -b --background run in background\n");
529 fprintf(stream, " -f --foreground launch target process in foreground and wait for it to exit\n");
530 fprintf(stream, " -c --cpu=N override the detection of CPUs on the machine.\n");
531 fprintf(stream, " -l, --limit=N percentage of cpu allowed from 1 up.\n");
532 fprintf(stream, " Usually 1 - %d00, but can be higher\n", NCPU);
533 fprintf(stream, " on multi-core CPUs (mandatory)\n");
534 fprintf(stream, " -q, --quiet run in quiet mode (only print errors).\n");
535 fprintf(stream, " -k, --kill kill processes going over their limit\n");
536 fprintf(stream, " instead of just throttling them.\n");
537 fprintf(stream, " -r, --restore Restore processes after they have\n");
538 fprintf(stream, " been killed. Works with the -k flag.\n");
539 fprintf(stream, " -s, --signal=SIG Send this signal to the watched process when cpulimit exits.\n");
540 fprintf(stream, " Signal should be specificed as a number or \n");
541 fprintf(stream, " SIGTERM, SIGCONT, SIGSTOP, etc. SIGCONT is the default.\n");
542 fprintf(stream, " -v, --verbose show control statistics\n");
543 fprintf(stream, " -z, --lazy exit if there is no suitable target process,\n");
544 fprintf(stream, " or if it dies\n");
545 fprintf(stream, " -- This is the final CPUlimit option. All following\n");
546 fprintf(stream, " options are for another program we will launch.\n");
547 fprintf(stream, " -h, --help display this help and exit\n");
553 // Get the number of CPU cores on this machine.
557 #ifdef _SC_NPROCESSORS_ONLN
558 ncpu = sysconf(_SC_NPROCESSORS_ONLN);
564 // This function attempts to figure out what signal we should send
565 // target processes based on a command line paramter. First we check
566 // for text such as SIGINT, SIGCONT, SIGSTOP, etc. If no match is found
567 // then we assume the value given is a number and use that.
568 int Translate_Signal(char *my_signal)
571 int index = 0, found = FALSE;
572 // first check to see if we were passed a string
573 while ( (index < MAX_SIGNAL) && (! found) )
575 if (! strcmp(my_signal, SIGNAL_NAME[index]) )
578 signal_value = SIGNAL_VALUE[index];
584 // no value found, try a number
586 signal_value = atoi(my_signal);
593 int main(int argc, char **argv) {
596 // char *p=(char*)memrchr(argv[0],(unsigned int)'/',strlen(argv[0]));
597 // program_name = p==NULL?argv[0]:(p+1);
598 program_name = argv[0];
599 int run_in_background = FALSE;
602 /* A string listing valid short options letters. */
603 const char* short_options="p:e:P:l:c:s:bfqkrvzh";
604 /* An array describing valid long options. */
605 const struct option long_options[] = {
606 { "pid", required_argument, NULL, 'p' },
607 { "exe", required_argument, NULL, 'e' },
608 { "path", required_argument, NULL, 'P' },
609 { "limit", required_argument, NULL, 'l' },
610 { "background", no_argument, NULL, 'b' },
611 { "foreground", no_argument, NULL, 'f' },
612 { "quiet", no_argument, NULL, 'q' },
613 { "verbose", no_argument, NULL, 'v' },
614 { "lazy", no_argument, NULL, 'z' },
615 { "help", no_argument, NULL, 'h' },
616 { "cpu", required_argument, NULL, 'c'},
617 { "signal", required_argument, NULL, 's'},
621 const char *exe=NULL;
622 const char *path=NULL;
625 int process_ok = FALSE;
626 int limit_ok = FALSE;
627 int last_known_argument = 0;
628 int kill_process = FALSE; // kill process instead of stopping it
629 int restore_process = FALSE; // restore killed process
630 int run_child_in_background = TRUE; // run cpulimit in background when
631 // we launch new process
632 // struct rlimit maxlimit;
636 opterr = 0; // avoid unwanted error messages for unknown parameters
638 next_option = getopt_long (argc, argv, short_options,long_options, NULL);
639 switch(next_option) {
641 run_in_background = TRUE;
642 last_known_argument++;
645 run_child_in_background = FALSE;
646 run_in_background = FALSE;
647 last_known_argument++;
651 if (pid) // valid PID
656 last_known_argument += 2;
661 last_known_argument += 2;
666 last_known_argument += 2;
669 perclimit=atoi(optarg);
671 last_known_argument += 2;
675 last_known_argument += 2;
678 send_signal = Translate_Signal(optarg);
679 if ( (send_signal < 1) || (send_signal > 35) )
681 fprintf(stderr, "Specified exit signal is not recognized or not within bounds (1-35). Using SIGCONT.\n");
682 send_signal = SIGCONT;
684 last_known_argument += 2;
687 last_known_argument++;
690 restore_process = TRUE;
691 last_known_argument++;
696 last_known_argument++;
700 last_known_argument++;
704 last_known_argument++;
707 print_usage (stdout, 1);
708 last_known_argument++;
711 last_known_argument++;
715 print_usage (stderr, 1);
716 last_known_argument++;
723 } while(next_option != -1);
725 signal(SIGCHLD, Child_Done);
727 // try to launch a program passed on the command line
728 // But only if we do not already have a PID to watch
729 if ( (last_known_argument + 1 < argc) && (pid_ok == FALSE) )
731 last_known_argument++;
732 // if we stopped on "--" jump to the next parameter
733 if ( (last_known_argument + 1 < argc) && (! strcmp(argv[last_known_argument], "--") ) )
734 last_known_argument++;
736 // try to launch remaining arguments
739 int index = last_known_argument;
740 printf("Launching %s", argv[index]);
741 for (index = last_known_argument + 1; index < argc; index++)
742 printf(" %s", argv[index]);
743 printf(" with limit %d\n", perclimit);
746 if (forked_pid == -1) // error
748 printf("Failed to launch specified process.\n");
751 else if (forked_pid == 0) // target child
753 execvp(argv[last_known_argument],
754 &(argv[last_known_argument]) );
757 else // parent who will now fork the throttler
760 // if we are planning to kill a process, give it
761 // a running head start to avoid death at start-up
765 /* The following block assumes we want to run cpulimit in the
766 background. This is the default behaviour.
768 if (run_child_in_background)
771 if (limit_pid == 0) // child cpulimit process running in background
773 pid = forked_pid; // the first child, target process
777 printf("Throttling process %d\n", (int) pid);
779 else // parent cpulimit process which can quit
781 } // end of running in background
787 run_in_background = FALSE;
788 } // end of running in foreground
790 } // end of parent that launched target
792 } // end of launching child process
794 if (!process_ok && !pid_ok) {
795 fprintf(stderr,"Error: You must specify a target process\n");
796 print_usage (stderr, 1);
799 if ((exe!=NULL && path!=NULL) || (pid_ok && (exe!=NULL || path!=NULL))) {
800 fprintf(stderr,"Error: You must specify exactly one target process\n");
801 print_usage (stderr, 1);
805 fprintf(stderr,"Error: You must specify a cpu limit\n");
806 print_usage (stderr, 1);
809 float limit=perclimit/100.0;
810 if ( (limit <= 0.00) || (limit > NCPU) )
812 fprintf(stderr,"Error: limit must be in the range of 1 to %d00\n", NCPU);
813 print_usage (stderr, 1);
817 // check to see if we should fork
818 if (run_in_background)
833 //parameters are all ok!
835 signal(SIGTERM,quit);
839 printf("%d CPUs detected.\n", NCPU);
843 //time quantum in microseconds. it's splitted in a working period and a sleeping one
845 struct timespec twork,tsleep; //working and sleeping intervals
846 memset(&twork,0,sizeof(struct timespec));
847 memset(&tsleep,0,sizeof(struct timespec));
851 //look for the target process..or wait for it
854 else if (path != NULL)
860 //process detected...let's play
862 //init compute_cpu_usage internal stuff
863 compute_cpu_usage(0,0,NULL);
867 struct timespec startwork,endwork;
868 long workingtime=0; //last working time in microseconds
870 if (verbose) print_caption();
874 //here we should already have high priority, for time precision
877 //estimate how much the controlled process is using the cpu in its working interval
879 if (compute_cpu_usage(pid,workingtime,&cu)==-1) {
881 fprintf(stderr,"Process %d dead!\n",pid);
883 //wait until our process appears
884 goto wait_for_process;
887 //cpu actual usage of process (range 0-1)
889 //rate at which we are keeping active the process (range 0-1)
890 float workingrate=cu.workingrate;
892 //adjust work and sleep time slices
894 twork.tv_nsec=min(period*limit*1000/pcpu*workingrate,period*1000);
897 twork.tv_nsec=period*1000;
900 //not yet a valid idea of cpu usage
903 twork.tv_nsec=min(period*limit*1000,period*1000);
905 tsleep.tv_nsec=period*1000-twork.tv_nsec;
907 //update average usage
908 pcpu_avg=(pcpu_avg*i+pcpu)/(i+1);
910 if (verbose && i%10==0 && i>0) {
911 printf("%0.2f%%\t%6ld us\t%6ld us\t%0.2f%%\n",pcpu*100,twork.tv_nsec/1000,tsleep.tv_nsec/1000,workingrate*100);
916 // if (limit<1 && limit>0) {
917 // printf("Comparing %f to %f\n", pcpu, limit);
920 // printf("Continue\n");
922 if (kill(pid,SIGCONT)!=0) {
924 fprintf(stderr,"Process %d dead!\n",pid);
926 //wait until our process appears
927 goto wait_for_process;
932 // OS X does not have clock_gettime, use clock_get_time
935 host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &cclock);
936 clock_get_time(cclock, &mts);
937 mach_port_deallocate(mach_task_self(), cclock);
938 startwork.tv_sec = mts.tv_sec;
939 startwork.tv_nsec = mts.tv_nsec;
942 clock_gettime(CLOCK_REALTIME,&startwork);
945 nanosleep(&twork,NULL); //now process is working
947 // OS X does not have clock_gettime, use clock_get_time
948 // clock_serv_t cclock;
949 // mach_timespec_t mts;
950 host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &cclock);
951 clock_get_time(cclock, &mts);
952 mach_port_deallocate(mach_task_self(), cclock);
953 endwork.tv_sec = mts.tv_sec;
954 endwork.tv_nsec = mts.tv_nsec;
957 clock_gettime(CLOCK_REALTIME,&endwork);
959 workingtime=timediff(&endwork,&startwork);
962 // printf("Checking %f vs %f\n", pcpu, limit);
965 // When over our limit we may run into
966 // situations where we want to kill
967 // the offending process, then restart it
972 fprintf(stderr, "Process %d killed.\n", pid);
973 if ( (lazy) && (! restore_process) )
975 // restart killed process
979 new_process = fork();
980 if (new_process == -1)
982 fprintf(stderr, "Failed to restore killed process.\n");
984 else if (new_process == 0)
986 // child which becomes new process
988 printf("Relaunching %s\n",
989 argv[last_known_argument]);
990 execvp(argv[last_known_argument],
991 &(argv[last_known_argument]) );
995 // we need to track new process
997 // avoid killing child process
1002 // do not kill process, just throttle it
1006 // printf("Stop\n");
1007 //stop process, it has worked enough
1008 if (kill(pid,SIGSTOP)!=0) {
1010 fprintf(stderr,"Process %d dead!\n", pid);
1012 //wait until our process appears
1013 goto wait_for_process;
1015 nanosleep(&tsleep,NULL); //now process is sleeping
1016 } // end of throttle process
1017 } // end of process using too much CPU