3 * cpulimit - a cpu limiter for Linux
5 * Copyright (C) 2005-2008, by: Angelo Marletta <marlonx80@hotmail.com>
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21 **********************************************************************
23 * This is a simple program to limit the cpu usage of a process
24 * If you modify this code, send me a copy please
28 * Get the latest version at: http://cpulimit.sourceforge.net
31 * - reorganization of the code, splitted in more source files
32 * - control function process_monitor() optimized by eliminating an unnecessary loop
33 * - experimental support for multiple control of children processes and threads
34 * children detection algorithm seems heavy because of the amount of code,
35 * but it's designed to be scalable when there are a lot of children processes
36 * - cpu count detection, i.e. if you have 4 cpu, it is possible to limit up to 400%
37 * - in order to avoid deadlock, cpulimit prevents to limit itself
38 * - option --path eliminated, use --exe instead both for absolute path and file name
39 * - deleted almost every setpriority(), just set it once at startup
40 * - minor enhancements and bugfixes
52 #include <sys/types.h>
54 #include <sys/resource.h>
61 #include "procutils.h"
65 #define MIN(a,b) (a<b?a:b)
66 #define MAX(a,b) (a>b?a:b)
67 #define print_caption() printf("\n%%CPU\twork quantum\tsleep quantum\tactive rate\n")
68 //control time slot in microseconds
69 //each slot is splitted in a working slice and a sleeping slice
70 #define CONTROL_SLOT 100000
72 #define MAX_PRIORITY -10
75 struct process_family pf;
78 //name of this program (maybe cpulimit...)
81 /* CONFIGURATION VARIABLES */
85 //lazy mode (exits if there is no process)
88 //how many cpu do we have?
94 fd = fopen("/proc/stat", "r");
96 return 0; //are we running Linux??
97 while (fgets(line,sizeof(line),fd)!=NULL) {
98 if (strncmp(line, "cpu", 3) != 0) break;
102 return cpu_count - 1;
105 //return t1-t2 in microseconds (no overflow checks, so better watch out!)
106 inline unsigned long timediff(const struct timespec *t1,const struct timespec *t2)
108 return (t1->tv_sec - t2->tv_sec) * 1000000 + (t1->tv_nsec/1000 - t2->tv_nsec/1000);
111 //returns t1-t2 in microseconds
112 inline unsigned long long tv_diff(struct timeval *t1, struct timeval *t2)
114 return ((unsigned long long)(t1->tv_sec - t2->tv_sec)) * 1000000ULL + t1->tv_usec - t2->tv_usec;
117 //SIGINT and SIGTERM signal handler
120 //let all the processes continue if stopped
121 struct list_node *node = NULL;
122 for (node=pf.members.first; node!= NULL; node=node->next) {
123 struct process *p = (struct process*)(node->data);
124 process_close(p->history);
125 kill(p->pid, SIGCONT);
127 //free all the memory
128 cleanup_process_family(&pf);
132 void print_usage(FILE *stream, int exit_code)
134 fprintf(stream, "Usage: %s TARGET [OPTIONS...]\n",program_name);
135 fprintf(stream, " TARGET must be exactly one of these:\n");
136 fprintf(stream, " -p, --pid=N pid of the process (implies -z)\n");
137 fprintf(stream, " -e, --exe=FILE name of the executable program file or absolute path name\n");
138 fprintf(stream, " OPTIONS\n");
139 fprintf(stream, " -l, --limit=N percentage of cpu allowed from 0 to 100 (required)\n");
140 fprintf(stream, " -v, --verbose show control statistics\n");
141 fprintf(stream, " -z, --lazy exit if there is no suitable target process, or if it dies\n");
142 fprintf(stream, " -h, --help display this help and exit\n");
146 void limit_process(int pid, float limit)
148 //slice of the slot in which the process is allowed to run
149 struct timespec twork;
150 //slice of the slot in which the process is stopped
151 struct timespec tsleep;
152 //when the last twork has started
153 struct timespec startwork;
154 //when the last twork has finished
155 struct timespec endwork;
157 memset(&twork, 0, sizeof(struct timespec));
158 memset(&tsleep, 0, sizeof(struct timespec));
159 memset(&startwork, 0, sizeof(struct timespec));
160 memset(&endwork, 0, sizeof(struct timespec));
161 //last working time in microseconds
162 unsigned long workingtime = 0;
166 create_process_family(&pf, pid);
167 struct list_node *node;
169 if (verbose) printf("Members in the family owned by %d: %d\n", pf.father, pf.members.count);
173 if (i%100==0 && verbose) print_caption();
176 //update the process family (checks only for new members)
177 int newborn = check_new_members(&pf);
179 printf("%d new children processes detected (", newborn);
181 node = pf.members.last;
182 for (j=0; j<newborn; j++) {
183 printf("%d", ((struct process*)(node->data))->pid);
184 if (j<newborn-1) printf(" ");
185 node = node->previous;
191 //total cpu actual usage (range 0-1)
192 //1 means that the processes are using 100% cpu
194 //rate at which we are keeping active the processes (range 0-1)
195 //1 means that the process are using all the twork slice
196 float workingrate = 0;
198 //estimate how much the controlled processes are using the cpu in the working interval
199 for (node=pf.members.first; node!=NULL; node=node->next) {
200 struct process *proc = (struct process*)(node->data);
201 if (process_monitor(proc->history, workingtime, &(proc->history->usage))==-1) {
202 //process is dead, remove it from family
203 remove_process_from_family(&pf, proc->pid);
204 fprintf(stderr,"Process %d dead!\n", proc->pid);
206 pcpu += proc->history->usage.pcpu;
207 workingrate += proc->history->usage.workingrate;
210 workingrate /= pf.members.count;
212 //TODO: make workingtime customized for each process, now it's equal for all
214 //adjust work and sleep time slices
216 twork.tv_nsec = MIN(CONTROL_SLOT*limit*1000/pcpu*workingrate,CONTROL_SLOT*1000);
219 twork.tv_nsec = CONTROL_SLOT*1000;
222 //not yet a valid idea of cpu usage
225 twork.tv_nsec = MIN(CONTROL_SLOT*limit*1000,CONTROL_SLOT*1000);
227 tsleep.tv_nsec = CONTROL_SLOT*1000-twork.tv_nsec;
229 if (verbose && i%10==0 && i>0) {
230 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);
234 for (node=pf.members.first; node!=NULL; node=node->next) {
235 struct process *proc = (struct process*)(node->data);
236 if (kill(proc->pid,SIGCONT)!=0) {
237 //process is dead, remove it from family
238 fprintf(stderr,"Process %d dead!\n", proc->pid);
239 remove_process_from_family(&pf, proc->pid);
243 //now processes are free to run (same working slice for all)
244 clock_gettime(CLOCK_REALTIME,&startwork);
245 nanosleep(&twork,NULL);
246 clock_gettime(CLOCK_REALTIME,&endwork);
247 workingtime = timediff(&endwork,&startwork);
249 //stop processes, they have worked enough
251 for (node=pf.members.first; node!=NULL; node=node->next) {
252 struct process *proc = (struct process*)(node->data);
253 if (kill(proc->pid,SIGSTOP)!=0) {
254 //process is dead, remove it from family
255 fprintf(stderr,"Process %d dead!\n", proc->pid);
256 remove_process_from_family(&pf, proc->pid);
259 //now the process is forced to sleep
260 nanosleep(&tsleep,NULL);
263 cleanup_process_family(&pf);
266 int main(int argc, char **argv) {
269 char *p=(char*)memrchr(argv[0],(unsigned int)'/',strlen(argv[0]));
270 program_name = p==NULL?argv[0]:(p+1);
271 cpulimit_pid = getpid();
274 const char *exe = NULL;
283 int option_index = 0;
284 //A string listing valid short options letters
285 const char* short_options = "p:e:l:vzh";
286 //An array describing valid long options
287 const struct option long_options[] = {
288 { "pid", required_argument, NULL, 'p' },
289 { "exe", required_argument, NULL, 'e' },
290 { "limit", required_argument, NULL, 'l' },
291 { "verbose", no_argument, &verbose, 'v' },
292 { "lazy", no_argument, &lazy, 'z' },
293 { "help", no_argument, NULL, 'h' },
298 next_option = getopt_long(argc, argv, short_options,long_options, &option_index);
299 switch(next_option) {
302 //todo: verify pid is valid
311 perclimit = atoi(optarg);
321 print_usage(stdout, 1);
324 print_usage(stderr, 1);
331 } while(next_option != -1);
338 fprintf(stderr,"Error: You must specify a target process, by name or by PID\n");
339 print_usage(stderr, 1);
342 if (pid_ok && exe!=NULL) {
343 fprintf(stderr, "Error: You must specify exactly one process, by name or by PID\n");
344 print_usage(stderr, 1);
348 fprintf(stderr,"Error: You must specify a cpu limit percentage\n");
349 print_usage(stderr, 1);
352 float limit = perclimit/100.0;
353 int cpu_count = get_cpu_count();
354 if (limit<0 || limit >cpu_count) {
355 fprintf(stderr,"Error: limit must be in the range 0-%d00\n", cpu_count);
356 print_usage(stderr, 1);
359 //parameters are all ok!
360 signal(SIGINT, quit);
361 signal(SIGTERM, quit);
363 //try to renice with the best value
364 int old_priority = getpriority(PRIO_PROCESS, 0);
365 int priority = old_priority;
366 while (setpriority(PRIO_PROCESS, 0, priority-1) == 0 && priority>MAX_PRIORITY) {
369 if (priority != old_priority) {
370 printf("Priority changed to %d\n", priority);
373 printf("Cannot change priority\n");
377 //look for the target process..or wait for it
381 ret = look_for_process_by_pid(pid);
383 printf("No process found\n");
386 printf("Process found but you aren't allowed to control it\n");
390 //search by file or path name
391 ret = look_for_process_by_name(exe);
393 printf("No process found\n");
396 printf("Process found but you aren't allowed to control it\n");
403 if (ret == cpulimit_pid) {
404 printf("Process %d is cpulimit itself! Aborting to avoid deadlock\n", ret);
407 printf("Process %d found\n", pid);
409 limit_process(pid, limit);
412 printf("Giving up...\n");