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