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