271cd3f19532bc70825296bb19c5562ee80b2e1c
[debian/cpulimit.git] / cpulimit.c
1 /**
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
4  * LICENSE file.
5  *
6  **********************************************************************
7  *
8  * Simple program to limit the cpu usage of a process
9  * If you modify this code, send me a copy please
10  *
11  * Author:  Angelo Marletta
12  * Date:    26/06/2005
13  * Version: 1.1
14  *
15  * Modifications and updates by: Jesse Smith
16  * Date: May 4, 2011
17  * Version 1.2 
18  * Date: Jan 29, 2013
19  * Version 1.2 and newer
20  *
21  */
22
23
24 #include <getopt.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <time.h>
28 #include <sys/time.h>
29 #include <sys/types.h>
30 #include <sys/wait.h>
31 #include <unistd.h>
32 #include <sys/types.h>
33 #include <signal.h>
34 #include <sys/resource.h>
35 #include <string.h>
36 #include <dirent.h>
37 #include <errno.h>
38 #include <string.h>
39 #include <limits.h>    // for compatibility
40
41 #ifdef __APPLE__
42 #include <mach/clock.h>
43 #include <mach/mach.h>
44 #endif
45
46
47 #ifdef FREEBSD
48 #include <fcntl.h>
49 #include <kvm.h>
50 #include <paths.h>
51 #include <sys/param.h>
52 #include <sys/sysctl.h>
53 #include <sys/user.h>
54 #endif
55
56
57 //kernel time resolution (inverse of one jiffy interval) in Hertz
58 //i don't know how to detect it, then define to the default (not very clean!)
59 #define HZ 100
60
61 //some useful macro
62 #define min(a,b) (a<b?a:b)
63 #define max(a,b) (a>b?a:b)
64
65 // For platforms without PATH_MAX
66 #ifndef PATH_MAX
67 #define PATH_MAX 4096
68 #endif
69
70 #define BEST_PRIORITY -10
71
72 #ifndef TRUE
73 #define TRUE 1
74 #endif
75 #ifndef FALSE
76 #define FALSE 0
77 #endif
78
79 #ifndef VERSION
80 #define VERSION 2.0
81 #endif
82
83 //pid of the controlled process
84 pid_t pid = 0;
85 pid_t my_pid;     // this process's PID
86
87 //executable file name
88 char *program_name;
89 //verbose mode
90 int verbose = FALSE;
91 //lazy mode
92 int lazy = FALSE;
93 // is higher priority nice possible?
94 int nice_lim;
95
96 // number of CPUs we detected
97 int NCPU;
98
99 //reverse byte search
100 // void *memrchr(const void *s, int c, size_t n);
101
102
103
104 //return ta-tb in microseconds (no overflow checks!)
105 inline long timediff(const struct timespec *ta,const struct timespec *tb) {
106     unsigned long us = (ta->tv_sec-tb->tv_sec)*1000000 + (ta->tv_nsec/1000 - tb->tv_nsec/1000);
107     return us;
108 }
109
110
111
112 int Check_Us(pid_t target_pid)
113 {
114    pid_t this_pid;
115
116    this_pid = getpid();
117    if (this_pid == target_pid)
118    {
119       printf("We cannot throttle ourselves.\n");
120       exit(7);
121    }
122    return TRUE;
123 }
124
125
126 int waitforpid(int pid) {
127         //switch to low priority
128         // if (setpriority(PRIO_PROCESS,getpid(),19)!=0) {
129         /*
130         if ( (nice_lim < INT_MAX) && 
131              (setpriority(PRIO_PROCESS, my_pid, 19) != 0) ) {
132                 printf("Warning: cannot renice\n");
133         }
134         */
135         int i=0;
136
137         while(1) {
138
139                 DIR *dip;
140                 struct dirent *dit;
141
142                 //open a directory stream to /proc directory
143                 if ((dip = opendir("/proc")) == NULL) {
144                         perror("opendir");
145                         return -1;
146                 }
147
148                 //read in from /proc and seek for process dirs
149                 while ((dit = readdir(dip)) != NULL) {
150                         //get pid
151                         if (pid==atoi(dit->d_name)) {
152                                 //pid detected
153                                 Check_Us(pid);
154                                 if (kill(pid,SIGSTOP)==0 &&  kill(pid,SIGCONT)==0) {
155                                         //process is ok!
156                                         if (closedir(dip) == -1) {
157                                            perror("closedir");
158                                            return -1;
159                                         }
160                                         goto done;
161                                 }
162                                 else {
163                                         fprintf(stderr,"Error: Process %d detected, but you don't have permission to control it\n",pid);
164                                 }
165                         }
166                 }
167
168                 //close the dir stream and check for errors
169                 if (closedir(dip) == -1) {
170                         perror("closedir");
171                         return -1;
172                 }
173
174                 //no suitable target found
175                 if (i++==0) {
176                         if (lazy) {
177                                 fprintf(stderr,"No process found\n");
178                                 exit(2);
179                         }
180                         else {
181                                 printf("Warning: no target process found. Waiting for it...\n");
182                         }
183                 }
184
185                 //sleep for a while
186                 sleep(2);
187         }
188
189 done:
190         printf("Process %d detected\n",pid);
191         //now set high priority, if possible
192         // if (setpriority(PRIO_PROCESS,getpid(),-20)!=0) {
193         /*
194         if ( (nice_lim < INT_MAX) &&
195              (setpriority(PRIO_PROCESS, my_pid, nice_lim) != 0) ) {
196                 printf("Warning: cannot renice.\nTo work better you should run this program as root.\n");
197         }
198         */
199         return 0;
200
201 }
202
203 //this function periodically scans process list and looks for executable path names
204 //it should be executed in a low priority context, since precise timing does not matter
205 //if a process is found then its pid is returned
206 //process: the name of the wanted process, can be an absolute path name to the executable file
207 //         or simply its name
208 //return: pid of the found process
209 int getpidof(const char *process) {
210
211         //set low priority
212         // if (setpriority(PRIO_PROCESS,getpid(),19)!=0) {
213         /*
214         if ( (nice_lim < INT_MAX) &&
215              (setpriority(PRIO_PROCESS, my_pid, 19) != 0) ) {
216                 printf("Warning: cannot renice\n");
217         }
218         */
219         char exelink[20];
220         char exepath[PATH_MAX+1];
221         int pid=0;
222         int i=0;
223
224         while(1) {
225
226                 DIR *dip;
227                 struct dirent *dit;
228
229                 //open a directory stream to /proc directory
230                 if ((dip = opendir("/proc")) == NULL) {
231                         perror("opendir");
232                         return -1;
233                 }
234
235                 //read in from /proc and seek for process dirs
236                 while ((dit = readdir(dip)) != NULL) {
237                         //get pid
238                         pid=atoi(dit->d_name);
239                         if (pid>0) {
240                                 sprintf(exelink,"/proc/%d/exe",pid);
241                                 int size=readlink(exelink,exepath,sizeof(exepath));
242                                 if (size>0) {
243                                         int found=0;
244                                         if (process[0]=='/' && strncmp(exepath,process,size)==0 && size==strlen(process)) {
245                                                 //process starts with / then it's an absolute path
246                                                 found=1;
247                                         }
248                                         else {
249                                                 //process is the name of the executable file
250                                                 if (strncmp(exepath+size-strlen(process),process,strlen(process))==0) {
251                                                         found=1;
252                                                 }
253                                         }
254                                         if (found==1) {
255                                         Check_Us(pid);
256                                                 if (kill(pid,SIGSTOP)==0 &&  kill(pid,SIGCONT)==0) {
257                                                         //process is ok!
258                                                         if (closedir(dip) == -1) {
259                                                           perror("closedir");
260                                                           return -1;
261                                                         }
262                                                         goto done;
263                                                 }
264                                                 else {
265                                                         fprintf(stderr,"Error: Process %d detected, but you don't have permission to control it\n",pid);
266                                                 }
267                                         }
268                                 }
269                         }
270                 }
271
272                 //close the dir stream and check for errors
273                 if (closedir(dip) == -1) {
274                         perror("closedir");
275                         return -1;
276                 }
277
278                 //no suitable target found
279                 if (i++==0) {
280                         if (lazy) {
281                                 fprintf(stderr,"No process found\n");
282                                 exit(2);
283                         }
284                         else {
285                                 printf("Warning: no target process found. Waiting for it...\n");
286                         }
287                 }
288
289                 //sleep for a while
290                 sleep(2);
291         }
292
293 done:
294         printf("Process %d detected\n",pid);
295         //now set high priority, if possible
296         // if (setpriority(PRIO_PROCESS,getpid(),-20)!=0) {
297         /*
298         if ( (nice_lim < INT_MAX) &&
299              (setpriority(PRIO_PROCESS, my_pid, nice_lim) != 0) ) {
300                 printf("Warning: cannot renice.\nTo work better you should run this program as root.\n");
301         }
302         */
303         return pid;
304
305 }
306
307 //SIGINT and SIGTERM signal handler
308 void quit(int sig) {
309         //let the process continue if it's stopped
310         kill(pid,SIGCONT);
311         printf("Exiting...\n");
312         exit(0);
313 }
314
315
316 #ifdef FREEBSD
317 //get jiffies count from /proc filesystem
318 int getjiffies(int pid)
319 {
320    kvm_t *my_kernel = NULL;
321    struct kinfo_proc *process_data = NULL;
322    int processes;
323    int my_jiffies = -1;
324
325    my_kernel = kvm_open(0, 0, 0, O_RDONLY, "kvm_open");
326    if (! my_kernel)
327    {
328       printf("Error opening kernel vm. You should be running as root.\n");
329       return -1;
330    }
331
332    process_data = kvm_getprocs(my_kernel, KERN_PROC_PID, pid, &processes);
333    if ( (process_data) && (processes >= 1) )
334        my_jiffies = process_data->ki_runtime;
335    
336    kvm_close(my_kernel);
337    if (my_jiffies >= 0)
338      my_jiffies /= 1000;
339    return my_jiffies;
340 }
341
342 #endif
343
344 #ifdef LINUX
345 int getjiffies(int pid) {
346         static char stat[20];
347         static char buffer[1024];
348         char *p;
349         sprintf(stat,"/proc/%d/stat",pid);
350         FILE *f=fopen(stat,"r");
351         if (f==NULL) return -1;
352         p = fgets(buffer,sizeof(buffer),f);
353         fclose(f);
354         // char *p=buffer;
355         if (p)
356         {
357           p=memchr(p+1,')',sizeof(buffer)-(p-buffer));
358           int sp=12;
359           while (sp--)
360                 p=memchr(p+1,' ',sizeof(buffer)-(p-buffer));
361           //user mode jiffies
362           int utime=atoi(p+1);
363           p=memchr(p+1,' ',sizeof(buffer)-(p-buffer));
364           //kernel mode jiffies
365           int ktime=atoi(p+1);
366           return utime+ktime;
367         }
368         // could not read info
369         return -1;
370 }
371 #endif
372
373
374 //process instant photo
375 struct process_screenshot {
376         struct timespec when;   //timestamp
377         int jiffies;    //jiffies count of the process
378         int cputime;    //microseconds of work from previous screenshot to current
379 };
380
381 //extracted process statistics
382 struct cpu_usage {
383         float pcpu;
384         float workingrate;
385 };
386
387 //this function is an autonomous dynamic system
388 //it works with static variables (state variables of the system), that keep memory of recent past
389 //its aim is to estimate the cpu usage of the process
390 //to work properly it should be called in a fixed periodic way
391 //perhaps i will put it in a separate thread...
392 int compute_cpu_usage(int pid,int last_working_quantum,struct cpu_usage *pusage) {
393         #define MEM_ORDER 10
394         //circular buffer containing last MEM_ORDER process screenshots
395         static struct process_screenshot ps[MEM_ORDER];
396         //the last screenshot recorded in the buffer
397         static int front=-1;
398         //the oldest screenshot recorded in the buffer
399         static int tail=0;
400
401         if (pusage==NULL) {
402                 //reinit static variables
403                 front=-1;
404                 tail=0;
405                 return 0;
406         }
407
408         //let's advance front index and save the screenshot
409         front=(front+1)%MEM_ORDER;
410         int j=getjiffies(pid);
411         if (j>=0) ps[front].jiffies=j;
412         else return -1; //error: pid does not exist
413
414         #ifdef __APPLE__
415         // OS X does not have clock_gettime, use clock_get_time
416         clock_serv_t cclock;
417         mach_timespec_t mts;
418         host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &cclock);
419         clock_get_time(cclock, &mts);
420         mach_port_deallocate(mach_task_self(), cclock);
421         ps[front].when.tv_sec = mts.tv_sec;
422         ps[front].when.tv_nsec = mts.tv_nsec;
423
424         #else
425         // Linux and BSD can use real time
426         clock_gettime(CLOCK_REALTIME,&(ps[front].when));
427         ps[front].cputime=last_working_quantum;
428         #endif
429         //buffer actual size is: (front-tail+MEM_ORDER)%MEM_ORDER+1
430         int size=(front-tail+MEM_ORDER)%MEM_ORDER+1;
431
432         if (size==1) {
433                 //not enough samples taken (it's the first one!), return -1
434                 pusage->pcpu=-1;
435                 pusage->workingrate=1;
436                 return 0;
437         }
438         else {
439                 //now we can calculate cpu usage, interval dt and dtwork are expressed in microseconds
440                 long dt=timediff(&(ps[front].when),&(ps[tail].when));
441                 long dtwork=0;
442                 int i=(tail+1)%MEM_ORDER;
443                 int max=(front+1)%MEM_ORDER;
444                 do {
445                         dtwork+=ps[i].cputime;
446                         i=(i+1)%MEM_ORDER;
447                 } while (i!=max);
448                 int used=ps[front].jiffies-ps[tail].jiffies;
449                 float usage=(used*1000000.0/HZ)/dtwork;
450                 pusage->workingrate=1.0*dtwork/dt;
451                 pusage->pcpu=usage*pusage->workingrate;
452                 if (size==MEM_ORDER)
453                         tail=(tail+1)%MEM_ORDER;
454                 return 0;
455         }
456         #undef MEM_ORDER
457 }
458
459 void print_caption() {
460         printf("\n%%CPU\twork quantum\tsleep quantum\tactive rate\n");
461 }
462
463
464 void increase_priority()
465 {
466         //find the best available nice value
467         int old_priority = getpriority(PRIO_PROCESS, 0);
468         int priority = old_priority;
469         while ( (setpriority(PRIO_PROCESS, 0, priority-1) == 0) &&
470                 (priority > BEST_PRIORITY) )
471         {
472                 priority--;
473         }
474         if (priority != old_priority) {
475                 if (verbose) printf("Priority changed to %d\n", priority);
476         }
477         else {
478                 if (verbose) printf("Warning: Cannot change priority. Run as root or renice for best results.\n");
479         }
480
481
482 }
483
484
485
486 void print_usage(FILE *stream,int exit_code) {
487         fprintf(stream, "CPUlimit version %1.1f\n", VERSION);
488         fprintf(stream, "Usage: %s TARGET [OPTIONS...] [-- PROGRAM]\n",program_name);
489         fprintf(stream, "   TARGET must be exactly one of these:\n");
490         fprintf(stream, "      -p, --pid=N        pid of the process\n");
491         fprintf(stream, "      -e, --exe=FILE     name of the executable program file\n");
492         fprintf(stream, "                         The -e option only works when\n");
493         fprintf(stream, "                         cpulimit is run with admin rights.\n");
494         fprintf(stream, "      -P, --path=PATH    absolute path name of the\n");
495         fprintf(stream, "                         executable program file\n");
496         fprintf(stream, "   OPTIONS\n");
497         fprintf(stream, "      -b  --background   run in background\n");
498         fprintf(stream, "      -c  --cpu=N        override the detection of CPUs on the machine.\n");
499         fprintf(stream, "      -l, --limit=N      percentage of cpu allowed from 1 up.\n");
500         fprintf(stream, "                         Usually 1 - %d00, but can be higher\n", NCPU);
501         fprintf(stream, "                         on multi-core CPUs (mandatory)\n");
502         fprintf(stream, "      -k, --kill         kill processes going over their limit\n");
503         fprintf(stream, "                         instead of just throttling them.\n");
504         fprintf(stream, "      -r, --restore      Restore processes after they have\n");
505         fprintf(stream, "                         been killed. Works with the -k flag.\n");
506
507         fprintf(stream, "      -v, --verbose      show control statistics\n");
508         fprintf(stream, "      -z, --lazy         exit if there is no suitable target process,\n");
509         fprintf(stream, "                         or if it dies\n");
510         fprintf(stream, "          --             This is the final CPUlimit option. All following\n");
511         fprintf(stream, "                         options are for another program we will launch.\n");
512         fprintf(stream, "      -h, --help         display this help and exit\n");
513         exit(exit_code);
514 }
515
516
517
518 // Get the number of CPU cores on this machine.
519 int get_ncpu()
520 {
521         int ncpu = 1;
522 #ifdef _SC_NPROCESSORS_ONLN
523         ncpu = sysconf(_SC_NPROCESSORS_ONLN);
524 #endif
525         return ncpu;
526 }
527
528
529
530
531 int main(int argc, char **argv) {
532
533         //get program name
534         // char *p=(char*)memrchr(argv[0],(unsigned int)'/',strlen(argv[0]));
535         // program_name = p==NULL?argv[0]:(p+1);
536         program_name = argv[0];
537         int run_in_background = FALSE;
538         //parse arguments
539         int next_option;
540         /* A string listing valid short options letters. */
541         const char* short_options="p:e:P:l:c:bkrvzh";
542         /* An array describing valid long options. */
543         const struct option long_options[] = {
544                 { "pid", required_argument, NULL, 'p' },
545                 { "exe", required_argument, NULL, 'e' },
546                 { "path", required_argument, NULL, 'P' },
547                 { "limit", required_argument, NULL, 'l' },
548                 { "background", no_argument, NULL, 'b' },
549                 { "verbose", no_argument, NULL, 'v' },
550                 { "lazy", no_argument, NULL, 'z' },
551                 { "help", no_argument, NULL, 'h' },
552                 { "cpu", required_argument, NULL, 'c'},
553                 { NULL, 0, NULL, 0 }
554         };
555         //argument variables
556         const char *exe=NULL;
557         const char *path=NULL;
558         int perclimit=0;
559         int pid_ok = FALSE;
560         int process_ok = FALSE;
561         int limit_ok = FALSE;
562         int last_known_argument = 0;
563         int kill_process = FALSE;   // kill process instead of stopping it
564         int restore_process = FALSE;  // restore killed process
565         // struct rlimit maxlimit;
566
567         NCPU = get_ncpu();
568
569         opterr = 0;      // avoid unwanted error messages for unknown parameters
570         do {
571                 next_option = getopt_long (argc, argv, short_options,long_options, NULL);
572                 switch(next_option) {
573                         case 'b':
574                                 run_in_background = TRUE;
575                                 last_known_argument++;
576                                 break;
577                         case 'p':
578                                 pid=atoi(optarg);
579                                 if (pid)   // valid PID
580                                 {
581                                   pid_ok = TRUE;
582                                   lazy = TRUE;
583                                 }
584                                 last_known_argument += 2;
585                                 break;
586                         case 'e':
587                                 exe=optarg;
588                                 process_ok = TRUE;
589                                 last_known_argument += 2;
590                                 break;
591                         case 'P':
592                                 path=optarg;
593                                 process_ok = TRUE;
594                                 last_known_argument += 2;
595                                 break;
596                         case 'l':
597                                 perclimit=atoi(optarg);
598                                 limit_ok = TRUE;
599                                 last_known_argument += 2;
600                                 break;
601                         case 'c':
602                                 NCPU = atoi(optarg);
603                                 last_known_argument += 2;
604                                 break;
605                         case 'k':
606                                 kill_process = TRUE;
607                                 last_known_argument++;
608                                 break;
609                         case 'r':
610                                 restore_process = TRUE;
611                                 last_known_argument++;
612                                 break;
613
614                         case 'v':
615                                 verbose = TRUE;
616                                 last_known_argument++;
617                                 break;
618                         case 'z':
619                                 lazy = TRUE;
620                                 last_known_argument++;
621                                 break;
622                         case 'h':
623                                 print_usage (stdout, 1);
624                                 last_known_argument++;
625                                 break;
626                         case 'o':
627                                 last_known_argument++;
628                                 next_option = -1;
629                                 break;
630                         case '?':
631                                 print_usage (stderr, 1);
632                                 last_known_argument++;
633                                 break;
634                         case -1:
635                                 break;
636                         // default:
637                         //      abort();
638                 }
639         } while(next_option != -1);
640
641
642         // try to launch a program passed on the command line
643         // But only if we do not already have a PID to watch
644         if ( (last_known_argument + 1 < argc) && (pid_ok == FALSE) )
645         {
646            last_known_argument++;
647            // if we stopped on "--" jump to the next parameter
648            if ( (last_known_argument + 1 < argc) && (! strcmp(argv[last_known_argument], "--") ) )
649                last_known_argument++;
650            pid_t forked_pid;
651            // try to launch remaining arguments
652            if (verbose)
653            {
654                int index = last_known_argument;
655                printf("Launching %s", argv[index]);
656                for (index = last_known_argument + 1; index < argc; index++)
657                     printf(" %s", argv[index]);
658                printf(" with limit %d\n", perclimit);
659            }
660            forked_pid = fork();
661            if (forked_pid == -1)  // error
662            {
663                printf("Failed to launch specified process.\n");
664                exit(1);
665            }
666            else if (forked_pid == 0)   // target child
667            {
668               execvp(argv[last_known_argument],
669                      &(argv[last_known_argument]) );
670               exit(2);
671            }
672            else     // parent who will now fork the throttler
673            {
674               pid_t limit_pid;
675               // if we are planning to kill a process, give it
676               // a running head start to avoid death at start-up
677               if (kill_process)
678                  sleep(5);
679      
680               limit_pid = fork();
681               if (limit_pid == 0)   // child
682               {
683                  pid = forked_pid;    // the first child
684                  lazy = TRUE;
685                  pid_ok = TRUE;
686                  if (verbose)
687                    printf("Throttling process %d\n", (int) pid);
688               }
689               else    // parent
690                 exit(0);
691            }
692
693            /*
694            else if (forked_pid == 0)   // child
695            {
696                lazy = TRUE;
697                pid_ok = TRUE;
698                pid = getppid();
699                if (verbose)
700                   printf("Throttling process %d\n", (int) pid);
701            }
702            else // parent
703            {
704                execvp(argv[last_known_argument], 
705                       &(argv[last_known_argument]));
706                
707                // we should never return  
708                exit(2);
709            }
710            */
711            
712         }      // end of launching child process
713
714         if (!process_ok && !pid_ok) {
715                 fprintf(stderr,"Error: You must specify a target process\n");
716                 print_usage (stderr, 1);
717                 exit(1);
718         }
719         if ((exe!=NULL && path!=NULL) || (pid_ok && (exe!=NULL || path!=NULL))) {
720                 fprintf(stderr,"Error: You must specify exactly one target process\n");
721                 print_usage (stderr, 1);
722                 exit(1);
723         }
724         if (!limit_ok) {
725                 fprintf(stderr,"Error: You must specify a cpu limit\n");
726                 print_usage (stderr, 1);
727                 exit(1);
728         }
729         float limit=perclimit/100.0;
730         if ( (limit <= 0.00) || (limit > NCPU) )
731         {
732                 fprintf(stderr,"Error: limit must be in the range of 1 to %d00\n", NCPU);
733                 print_usage (stderr, 1);
734                 exit(1);
735         }
736
737         // check to see if we should fork
738         if (run_in_background)
739         {
740              pid_t process_id;
741              process_id = fork();
742              if (! process_id)
743                 exit(0);
744              else
745              {
746                 setsid();
747                 process_id = fork();
748                 if (process_id)
749                   exit(0);
750              }
751         }
752
753         //parameters are all ok!
754         signal(SIGINT,quit);
755         signal(SIGTERM,quit);
756
757         my_pid = getpid();
758         if (verbose)
759            printf("%d CPUs detected.\n", NCPU);
760
761         increase_priority();
762 /*
763 Instead of all this big block of code to detect and change
764 priority settings, let us just use the increase_priority()
765 function. It is a little more simple and takes a more
766 gradual approach, rather than "all or nothing".
767 -- Jesse
768
769         if (setpriority(PRIO_PROCESS, my_pid,-20)!=0) {
770         //if that failed, check if we have a limit 
771         // by how much we can raise the priority
772 #ifdef RLIMIT_NICE 
773 //check if non-root can even make changes 
774 // (ifdef because it's only available in linux >= 2.6.13)
775                 nice_lim=getpriority(PRIO_PROCESS, my_pid);
776                 getrlimit(RLIMIT_NICE, &maxlimit);
777
778 //if we can do better then current
779                 if( (20 - (signed)maxlimit.rlim_cur) < nice_lim &&  
780                     setpriority(PRIO_PROCESS, my_pid,
781                     20 - (signed)maxlimit.rlim_cur)==0 //and it actually works
782                   ) {
783
784                         //if we can do better, but not by much, warn about it
785                         if( (nice_lim - (20 - (signed)maxlimit.rlim_cur)) < 9) 
786                         {
787                         printf("Warning, can only increase priority by %d.\n",                                nice_lim - (20 - (signed)maxlimit.rlim_cur));
788                         }
789                         //our new limit
790                         nice_lim = 20 - (signed)maxlimit.rlim_cur; 
791
792                 } else 
793 // otherwise don't try to change priority. 
794 // The below will also run if it's not possible 
795 // for non-root to change priority
796 #endif
797                 {
798                         printf("Warning: cannot renice.\nTo work better you should run this program as root, or adjust RLIMIT_NICE.\nFor example in /etc/security/limits.conf add a line with: * - nice -10\n\n");
799                         nice_lim=INT_MAX;
800                 }
801         } else {
802                 nice_lim=-20;
803         }
804 */
805
806
807         //time quantum in microseconds. it's splitted in a working period and a sleeping one
808         int period=100000;
809         struct timespec twork,tsleep;   //working and sleeping intervals
810         memset(&twork,0,sizeof(struct timespec));
811         memset(&tsleep,0,sizeof(struct timespec));
812
813 wait_for_process:
814
815         //look for the target process..or wait for it
816         if (exe != NULL)
817                 pid=getpidof(exe);
818         else if (path != NULL)
819                 pid=getpidof(path);
820         else 
821                 waitforpid(pid);
822
823         
824         //process detected...let's play
825
826         //init compute_cpu_usage internal stuff
827         compute_cpu_usage(0,0,NULL);
828         //main loop counter
829         int i=0;
830
831         struct timespec startwork,endwork;
832         long workingtime=0;             //last working time in microseconds
833
834         if (verbose) print_caption();
835
836         float pcpu_avg=0;
837
838         //here we should already have high priority, for time precision
839         while(1) {
840
841                 //estimate how much the controlled process is using the cpu in its working interval
842                 struct cpu_usage cu;
843                 if (compute_cpu_usage(pid,workingtime,&cu)==-1) {
844                         fprintf(stderr,"Process %d dead!\n",pid);
845                         if (lazy) exit(2);
846                         //wait until our process appears
847                         goto wait_for_process;          
848                 }
849
850                 //cpu actual usage of process (range 0-1)
851                 float pcpu=cu.pcpu;
852                 //rate at which we are keeping active the process (range 0-1)
853                 float workingrate=cu.workingrate;
854
855                 //adjust work and sleep time slices
856                 if (pcpu>0) {
857                         twork.tv_nsec=min(period*limit*1000/pcpu*workingrate,period*1000);
858                 }
859                 else if (pcpu==0) {
860                         twork.tv_nsec=period*1000;
861                 }
862                 else if (pcpu==-1) {
863                         //not yet a valid idea of cpu usage
864                         pcpu=limit;
865                         workingrate=limit;
866                         twork.tv_nsec=min(period*limit*1000,period*1000);
867                 }
868                 tsleep.tv_nsec=period*1000-twork.tv_nsec;
869
870                 //update average usage
871                 pcpu_avg=(pcpu_avg*i+pcpu)/(i+1);
872
873                 if (verbose && i%10==0 && i>0) {
874                         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);
875                         if (i%200 == 0)
876                            print_caption();
877                 }
878
879                 // if (limit<1 && limit>0) {
880                 // printf("Comparing %f to %f\n", pcpu, limit);
881                 if (pcpu < limit)
882                 {
883                         // printf("Continue\n");
884                         //resume process
885                         if (kill(pid,SIGCONT)!=0) {
886                                 fprintf(stderr,"Process %d dead!\n",pid);
887                                 if (lazy) exit(2);
888                                 //wait until our process appears
889                                 goto wait_for_process;
890                         }
891                 }
892
893                 #ifdef __APPLE_
894                 // OS X does not have clock_gettime, use clock_get_time
895                 clock_serv_t cclock;
896                 mach_timespec_t mts;
897                 host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &cclock);
898                 clock_get_time(cclock, &mts);
899                 mach_port_deallocate(mach_task_self(), cclock);
900                 startwork.tv_sec = mts.tv_sec;
901                 startwork.tv_nsec = mts.tv_nsec;
902
903                 #else
904                 clock_gettime(CLOCK_REALTIME,&startwork);
905                 #endif
906
907                 nanosleep(&twork,NULL);         //now process is working
908                 #ifdef __APPLE__
909                 // OS X does not have clock_gettime, use clock_get_time
910                 // clock_serv_t cclock;
911                 // mach_timespec_t mts;
912                 host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &cclock);
913                 clock_get_time(cclock, &mts);
914                 mach_port_deallocate(mach_task_self(), cclock);
915                 endwork.tv_sec = mts.tv_sec;
916                 endwork.tv_nsec = mts.tv_nsec;
917
918                 #else
919                 clock_gettime(CLOCK_REALTIME,&endwork);
920                 #endif
921                 workingtime=timediff(&endwork,&startwork);
922
923                 // if (limit<1) {
924                 // printf("Checking %f vs %f\n", pcpu, limit);
925                 if (pcpu > limit)
926                 {
927                      // When over our limit we may run into
928                      // situations where we want to kill
929                      // the offending process, then restart it
930                      if (kill_process)
931                      {
932                          kill(pid, SIGKILL);
933                          fprintf(stderr, "Process %d killed.\n", pid);
934                          if ( (lazy) && (! restore_process) ) 
935                               exit(2);
936                          // restart killed process
937                          if (restore_process)
938                          {
939                              pid_t new_process;
940                              new_process = fork();
941                              if (new_process == -1)
942                              {
943                               fprintf(stderr, "Failed to restore killed process.\n");
944                              }
945                              else if (new_process == 0)
946                              {
947                                 // child which becomes new process
948                                 if (verbose)
949                                    printf("Relaunching %s\n",
950                                           argv[last_known_argument]);
951                                 execvp(argv[last_known_argument],
952                                        &(argv[last_known_argument]) ); 
953                              }
954                              else // parent
955                              {
956                                 // we need to track new process
957                                 pid = new_process;
958                                 // avoid killing child process
959                                 sleep(5);
960                              }
961                          }
962                      }
963                      // do not kll process, just throttle it
964                      else
965                      {
966
967                         // printf("Stop\n");
968                         //stop process, it has worked enough
969                         if (kill(pid,SIGSTOP)!=0) {
970                                 fprintf(stderr,"Process %d dead!\n", pid);
971                                 if (lazy) exit(2);
972                                 //wait until our process appears
973                                 goto wait_for_process;
974                         }
975                         nanosleep(&tsleep,NULL);        //now process is sleeping
976                       }   // end of throttle process
977                 }         // end of process using too much CPU
978                 i++;
979         }
980
981    return 0;
982 }