zoukankan      html  css  js  c++  java
  • cpulimit备用源文件

    cpulimit备用源文件

    一、目录结构

    cpulimit-1.1
    ├── cpulimit.c
    └── Makefile

    二、文件内容

    文件格式均为unix格式

    1、cpulimit.c

    /**
     * Copyright (c) 2005, by:      Angelo Marletta <marlonx80@hotmail.com>
     *
     * This file may be used subject to the terms and conditions of the
     * GNU Library General Public License Version 2, or any later version
     * at your option, as published by the Free Software Foundation.
     * This program is distributed in the hope that it will be useful,
     * but WITHOUT ANY WARRANTY; without even the implied warranty of
     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     * GNU Library General Public License for more details.
     *
     **********************************************************************
     *
     * Simple program to limit the cpu usage of a process
     * If you modify this code, send me a copy please
     *
     * Author:  Angelo Marletta
     * Date:    26/06/2005
     * Version: 1.1
     * Last version at: http://marlon80.interfree.it/cpulimit/index.html
     *
     * Changelog:
     *  - Fixed a segmentation fault if controlled process exited in particular circumstances
     *  - Better CPU usage estimate
     *  - Fixed a <0 %CPU usage reporting in rare cases
     *  - Replaced MAX_PATH_SIZE with PATH_MAX already defined in <limits.h>
     *  - Command line arguments now available
     *  - Now is possible to specify target process by pid
     */
    
    
    #include <getopt.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <time.h>
    #include <sys/time.h>
    #include <unistd.h>
    #include <sys/types.h>
    #include <signal.h>
    #include <sys/resource.h>
    #include <string.h>
    #include <dirent.h>
    #include <errno.h>
    #include <string.h>
    
    //kernel time resolution (inverse of one jiffy interval) in Hertz
    //i don't know how to detect it, then define to the default (not very clean!)
    #define HZ 100
    
    //some useful macro
    #define min(a,b) (a<b?a:b)
    #define max(a,b) (a>b?a:b)
    
    //pid of the controlled process
    int pid=0;
    //executable file name
    char *program_name;
    //verbose mode
    int verbose=0;
    //lazy mode
    int lazy=0;
    
    //reverse byte search
    void *memrchr(const void *s, int c, size_t n);
    
    //return ta-tb in microseconds (no overflow checks!)
    inline long timediff(const struct timespec *ta,const struct timespec *tb) {
        unsigned long us = (ta->tv_sec-tb->tv_sec)*1000000 + (ta->tv_nsec/1000 - tb->tv_nsec/1000);
        return us;
    }
    
    int waitforpid(int pid) {
    	//switch to low priority
    	if (setpriority(PRIO_PROCESS,getpid(),19)!=0) {
    		printf("Warning: cannot renice
    ");
    	}
    
    	int i=0;
    
    	while(1) {
    
    		DIR *dip;
    		struct dirent *dit;
    
    		//open a directory stream to /proc directory
    		if ((dip = opendir("/proc")) == NULL) {
    			perror("opendir");
    			return -1;
    		}
    
    		//read in from /proc and seek for process dirs
    		while ((dit = readdir(dip)) != NULL) {
    			//get pid
    			if (pid==atoi(dit->d_name)) {
    				//pid detected
    				if (kill(pid,SIGSTOP)==0 &&  kill(pid,SIGCONT)==0) {
    					//process is ok!
    					goto done;
    				}
    				else {
    					fprintf(stderr,"Error: Process %d detected, but you don't have permission to control it
    ",pid);
    				}
    			}
    		}
    
    		//close the dir stream and check for errors
    		if (closedir(dip) == -1) {
    			perror("closedir");
    			return -1;
    		}
    
    		//no suitable target found
    		if (i++==0) {
    			if (lazy) {
    				fprintf(stderr,"No process found
    ");
    				exit(2);
    			}
    			else {
    				printf("Warning: no target process found. Waiting for it...
    ");
    			}
    		}
    
    		//sleep for a while
    		sleep(2);
    	}
    
    done:
    	printf("Process %d detected
    ",pid);
    	//now set high priority, if possible
    	if (setpriority(PRIO_PROCESS,getpid(),-20)!=0) {
    		printf("Warning: cannot renice.
    To work better you should run this program as root.
    ");
    	}
    	return 0;
    
    }
    
    //this function periodically scans process list and looks for executable path names
    //it should be executed in a low priority context, since precise timing does not matter
    //if a process is found then its pid is returned
    //process: the name of the wanted process, can be an absolute path name to the executable file
    //         or simply its name
    //return: pid of the found process
    int getpidof(const char *process) {
    
    	//set low priority
    	if (setpriority(PRIO_PROCESS,getpid(),19)!=0) {
    		printf("Warning: cannot renice
    ");
    	}
    
    	char exelink[20];
    	char exepath[PATH_MAX+1];
    	int pid=0;
    	int i=0;
    
    	while(1) {
    
    		DIR *dip;
    		struct dirent *dit;
    
    		//open a directory stream to /proc directory
    		if ((dip = opendir("/proc")) == NULL) {
    			perror("opendir");
    			return -1;
    		}
    
    		//read in from /proc and seek for process dirs
    		while ((dit = readdir(dip)) != NULL) {
    			//get pid
    			pid=atoi(dit->d_name);
    			if (pid>0) {
    				sprintf(exelink,"/proc/%d/exe",pid);
    				int size=readlink(exelink,exepath,sizeof(exepath));
    				if (size>0) {
    					int found=0;
    					if (process[0]=='/' && strncmp(exepath,process,size)==0 && size==strlen(process)) {
    						//process starts with / then it's an absolute path
    						found=1;
    					}
    					else {
    						//process is the name of the executable file
    						if (strncmp(exepath+size-strlen(process),process,strlen(process))==0) {
    							found=1;
    						}
    					}
    					if (found==1) {
    						if (kill(pid,SIGSTOP)==0 &&  kill(pid,SIGCONT)==0) {
    							//process is ok!
    							goto done;
    						}
    						else {
    							fprintf(stderr,"Error: Process %d detected, but you don't have permission to control it
    ",pid);
    						}
    					}
    				}
    			}
    		}
    
    		//close the dir stream and check for errors
    		if (closedir(dip) == -1) {
    			perror("closedir");
    			return -1;
    		}
    
    		//no suitable target found
    		if (i++==0) {
    			if (lazy) {
    				fprintf(stderr,"No process found
    ");
    				exit(2);
    			}
    			else {
    				printf("Warning: no target process found. Waiting for it...
    ");
    			}
    		}
    
    		//sleep for a while
    		sleep(2);
    	}
    
    done:
    	printf("Process %d detected
    ",pid);
    	//now set high priority, if possible
    	if (setpriority(PRIO_PROCESS,getpid(),-20)!=0) {
    		printf("Warning: cannot renice.
    To work better you should run this program as root.
    ");
    	}
    	return pid;
    
    }
    
    //SIGINT and SIGTERM signal handler
    void quit(int sig) {
    	//let the process continue if it's stopped
    	kill(pid,SIGCONT);
    	printf("Exiting...
    ");
    	exit(0);
    }
    
    //get jiffies count from /proc filesystem
    int getjiffies(int pid) {
    	static char stat[20];
    	static char buffer[1024];
    	sprintf(stat,"/proc/%d/stat",pid);
    	FILE *f=fopen(stat,"r");
    	if (f==NULL) return -1;
    	fgets(buffer,sizeof(buffer),f);
    	fclose(f);
    	char *p=buffer;
    	p=memchr(p+1,')',sizeof(buffer)-(p-buffer));
    	int sp=12;
    	while (sp--)
    		p=memchr(p+1,' ',sizeof(buffer)-(p-buffer));
    	//user mode jiffies
    	int utime=atoi(p+1);
    	p=memchr(p+1,' ',sizeof(buffer)-(p-buffer));
    	//kernel mode jiffies
    	int ktime=atoi(p+1);
    	return utime+ktime;
    }
    
    //process instant photo
    struct process_screenshot {
    	struct timespec when;	//timestamp
    	int jiffies;	//jiffies count of the process
    	int cputime;	//microseconds of work from previous screenshot to current
    };
    
    //extracted process statistics
    struct cpu_usage {
    	float pcpu;
    	float workingrate;
    };
    
    //this function is an autonomous dynamic system
    //it works with static variables (state variables of the system), that keep memory of recent past
    //its aim is to estimate the cpu usage of the process
    //to work properly it should be called in a fixed periodic way
    //perhaps i will put it in a separate thread...
    int compute_cpu_usage(int pid,int last_working_quantum,struct cpu_usage *pusage) {
    	#define MEM_ORDER 10
    	//circular buffer containing last MEM_ORDER process screenshots
    	static struct process_screenshot ps[MEM_ORDER];
    	//the last screenshot recorded in the buffer
    	static int front=-1;
    	//the oldest screenshot recorded in the buffer
    	static int tail=0;
    
    	if (pusage==NULL) {
    		//reinit static variables
    		front=-1;
    		tail=0;
    		return 0;
    	}
    
    	//let's advance front index and save the screenshot
    	front=(front+1)%MEM_ORDER;
    	int j=getjiffies(pid);
    	if (j>=0) ps[front].jiffies=j;
    	else return -1;	//error: pid does not exist
    	clock_gettime(CLOCK_REALTIME,&(ps[front].when));
    	ps[front].cputime=last_working_quantum;
    
    	//buffer actual size is: (front-tail+MEM_ORDER)%MEM_ORDER+1
    	int size=(front-tail+MEM_ORDER)%MEM_ORDER+1;
    
    	if (size==1) {
    		//not enough samples taken (it's the first one!), return -1
    		pusage->pcpu=-1;
    		pusage->workingrate=1;
    		return 0;
    	}
    	else {
    		//now we can calculate cpu usage, interval dt and dtwork are expressed in microseconds
    		long dt=timediff(&(ps[front].when),&(ps[tail].when));
    		long dtwork=0;
    		int i=(tail+1)%MEM_ORDER;
    		int max=(front+1)%MEM_ORDER;
    		do {
    			dtwork+=ps[i].cputime;
    			i=(i+1)%MEM_ORDER;
    		} while (i!=max);
    		int used=ps[front].jiffies-ps[tail].jiffies;
    		float usage=(used*1000000.0/HZ)/dtwork;
    		pusage->workingrate=1.0*dtwork/dt;
    		pusage->pcpu=usage*pusage->workingrate;
    		if (size==MEM_ORDER)
    			tail=(tail+1)%MEM_ORDER;
    		return 0;
    	}
    	#undef MEM_ORDER
    }
    
    void print_caption() {
    	printf("
    %%CPU	work quantum	sleep quantum	active rate
    ");
    }
    
    void print_usage(FILE *stream,int exit_code) {
    	fprintf(stream, "Usage: %s TARGET [OPTIONS...]
    ",program_name);
    	fprintf(stream, "   TARGET must be exactly one of these:
    ");
    	fprintf(stream, "      -p, --pid=N        pid of the process
    ");
    	fprintf(stream, "      -e, --exe=FILE     name of the executable program file
    ");
    	fprintf(stream, "      -P, --path=PATH    absolute path name of the executable program file
    ");
    	fprintf(stream, "   OPTIONS
    ");
    	fprintf(stream, "      -l, --limit=N      percentage of cpu allowed from 0 to 100 (mandatory)
    ");
    	fprintf(stream, "      -v, --verbose      show control statistics
    ");
    	fprintf(stream, "      -z, --lazy         exit if there is no suitable target process, or if it dies
    ");
    	fprintf(stream, "      -h, --help         display this help and exit
    ");
    	exit(exit_code);
    }
    
    int main(int argc, char **argv) {
    
    	//get program name
    	char *p=(char*)memrchr(argv[0],(unsigned int)'/',strlen(argv[0]));
    	program_name = p==NULL?argv[0]:(p+1);
    	//parse arguments
    	int next_option;
    	/* A string listing valid short options letters. */
    	const char* short_options="p:e:P:l:vzh";
    	/* An array describing valid long options. */
    	const struct option long_options[] = {
    		{ "pid", 0, NULL, 'p' },
    		{ "exe", 1, NULL, 'e' },
    		{ "path", 0, NULL, 'P' },
    		{ "limit", 0, NULL, 'l' },
    		{ "verbose", 0, NULL, 'v' },
    		{ "lazy", 0, NULL, 'z' },
    		{ "help", 0, NULL, 'h' },
    		{ NULL, 0, NULL, 0 }
    	};
    	//argument variables
    	const char *exe=NULL;
    	const char *path=NULL;
    	int perclimit=0;
    	int pid_ok=0;
    	int process_ok=0;
    	int limit_ok=0;
    
    	do {
    		next_option = getopt_long (argc, argv, short_options,long_options, NULL);
    		switch(next_option) {
    			case 'p':
    				pid=atoi(optarg);
    				pid_ok=1;
    				break;
    			case 'e':
    				exe=optarg;
    				process_ok=1;
    				break;
    			case 'P':
    				path=optarg;
    				process_ok=1;
    				break;
    			case 'l':
    				perclimit=atoi(optarg);
    				limit_ok=1;
    				break;
    			case 'v':
    				verbose=1;
    				break;
    			case 'z':
    				lazy=1;
    				break;
    			case 'h':
    				print_usage (stdout, 1);
    				break;
    			case '?':
    				print_usage (stderr, 1);
    				break;
    			case -1:
    				break;
    			default:
    				abort();
    		}
    	} while(next_option != -1);
    
    	if (!process_ok && !pid_ok) {
    		fprintf(stderr,"Error: You must specify a target process
    ");
    		print_usage (stderr, 1);
    		exit(1);
    	}
    	if ((exe!=NULL && path!=NULL) || (pid_ok && (exe!=NULL || path!=NULL))) {
    		fprintf(stderr,"Error: You must specify exactly one target process
    ");
    		print_usage (stderr, 1);
    		exit(1);
    	}
    	if (!limit_ok) {
    		fprintf(stderr,"Error: You must specify a cpu limit
    ");
    		print_usage (stderr, 1);
    		exit(1);
    	}
    	float limit=perclimit/100.0;
    	if (limit<0 || limit >1) {
    		fprintf(stderr,"Error: limit must be in the range 0-100
    ");
    		print_usage (stderr, 1);
    		exit(1);
    	}
    	//parameters are all ok!
    	signal(SIGINT,quit);
    	signal(SIGTERM,quit);
    
    	//time quantum in microseconds. it's splitted in a working period and a sleeping one
    	int period=100000;
    	struct timespec twork,tsleep;   //working and sleeping intervals
    	memset(&twork,0,sizeof(struct timespec));
    	memset(&tsleep,0,sizeof(struct timespec));
    
    wait_for_process:
    
    	//look for the target process..or wait for it
    	if (exe!=NULL)
    		pid=getpidof(exe);
    	else if (path!=NULL)
    		pid=getpidof(path);
    	else {
    		waitforpid(pid);
    	}
    	//process detected...let's play
    
    	//init compute_cpu_usage internal stuff
    	compute_cpu_usage(0,0,NULL);
    	//main loop counter
    	int i=0;
    
    	struct timespec startwork,endwork;
    	long workingtime=0;		//last working time in microseconds
    
    	if (verbose) print_caption();
    
    	float pcpu_avg=0;
    
    	//here we should already have high priority, for time precision
    	while(1) {
    
    		//estimate how much the controlled process is using the cpu in its working interval
    		struct cpu_usage cu;
    		if (compute_cpu_usage(pid,workingtime,&cu)==-1) {
    			fprintf(stderr,"Process %d dead!
    ",pid);
    			if (lazy) exit(2);
    			//wait until our process appears
    			goto wait_for_process;		
    		}
    
    		//cpu actual usage of process (range 0-1)
    		float pcpu=cu.pcpu;
    		//rate at which we are keeping active the process (range 0-1)
    		float workingrate=cu.workingrate;
    
    		//adjust work and sleep time slices
    		if (pcpu>0) {
    			twork.tv_nsec=min(period*limit*1000/pcpu*workingrate,period*1000);
    		}
    		else if (pcpu==0) {
    			twork.tv_nsec=period*1000;
    		}
    		else if (pcpu==-1) {
    			//not yet a valid idea of cpu usage
    			pcpu=limit;
    			workingrate=limit;
    			twork.tv_nsec=min(period*limit*1000,period*1000);
    		}
    		tsleep.tv_nsec=period*1000-twork.tv_nsec;
    
    		//update average usage
    		pcpu_avg=(pcpu_avg*i+pcpu)/(i+1);
    
    		if (verbose && i%10==0 && i>0) {
    			printf("%0.2f%%	%6ld us	%6ld us	%0.2f%%
    ",pcpu*100,twork.tv_nsec/1000,tsleep.tv_nsec/1000,workingrate*100);
    		}
    
    		if (limit<1 && limit>0) {
    			//resume process
    			if (kill(pid,SIGCONT)!=0) {
    				fprintf(stderr,"Process %d dead!
    ",pid);
    				if (lazy) exit(2);
    				//wait until our process appears
    				goto wait_for_process;
    			}
    		}
    
    		clock_gettime(CLOCK_REALTIME,&startwork);
    		nanosleep(&twork,NULL);		//now process is working	
    		clock_gettime(CLOCK_REALTIME,&endwork);
    		workingtime=timediff(&endwork,&startwork);
    
    		if (limit<1) {
    			//stop process, it has worked enough
    			if (kill(pid,SIGSTOP)!=0) {
    				fprintf(stderr,"Process %d dead!
    ",pid);
    				if (lazy) exit(2);
    				//wait until our process appears
    				goto wait_for_process;
    			}
    			nanosleep(&tsleep,NULL);	//now process is sleeping
    		}
    		i++;
    	}
    
    }
    

      

    2、Makefile

    all::	cpulimit
    
    cpulimit:	cpulimit.c
    	gcc -o cpulimit cpulimit.c -lrt -Wall -O2
    
    clean:
    	rm -f *~ cpulimit
    

      

    三、编译安装

    cd cpulimit-1.1
    make
    cp cpulimit /usr/bin/cpulimit
    chmod 777 /usr/bin/cpulimit
    
    cpulimit --help
    

      

  • 相关阅读:
    2018.9.22 Bubble Cup 11-Finals(Online Mirror,Div.2)
    2018.9.21 Codeforces Round #511(Div.2)
    2018.9.20 Educational Codeforces Round 51
    解题:USACO12OPEN Bookshelf
    解题:CF983B pyramid
    1214. 许可证密钥格式
    1212. 最大连续1的个数
    1270. 勒索信
    1250. 第三大的数
    1218. 补数
  • 原文地址:https://www.cnblogs.com/andy9468/p/15357524.html
Copyright © 2011-2022 走看看