diff options
author | bhackerozzo <bhackerozzo@3b445381-d045-0410-9223-e17ecdb95f4b> | 2008-08-29 21:45:04 +0000 |
---|---|---|
committer | bhackerozzo <bhackerozzo@3b445381-d045-0410-9223-e17ecdb95f4b> | 2008-08-29 21:45:04 +0000 |
commit | 794f9410a52b21e8bcedeecedc7f8737daee5418 (patch) | |
tree | d6a8a5f585110b64167fe4f38d1de248a657c3b3 | |
parent | 83bce718d6f49760463e973759ab575f8573f297 (diff) | |
download | cpulimit-794f9410a52b21e8bcedeecedc7f8737daee5418.tar.gz |
experimental support for OS X
-rw-r--r-- | Makefile | 13 | ||||
-rw-r--r-- | cpulimit.c | 57 | ||||
-rw-r--r-- | process.c | 15 | ||||
-rw-r--r-- | process.h | 6 | ||||
-rw-r--r-- | procutils.c | 106 | ||||
-rw-r--r-- | procutils.h | 25 | ||||
-rw-r--r-- | tools/jiffy.c | 69 | ||||
-rw-r--r-- | tools/loop.c | 3 | ||||
-rw-r--r-- | tools/ptest.c | 59 |
9 files changed, 300 insertions, 53 deletions
@@ -1,13 +1,17 @@ CC?=gcc CFLAGS?=-Wall -O2 -CFLAGS+=-D_GNU_SOURCE -TARGETS=cpulimit ptest +TARGETS=cpulimit LIBS=process.o procutils.o list.o +OSXFLAGS=-framework Carbon + +ifeq ($(OS), APPLE) +CFLAGS+=-framework Carbon +endif all:: $(TARGETS) cpulimit: cpulimit.c $(LIBS) - $(CC) -o cpulimit cpulimit.c $(LIBS) -lrt $(CFLAGS) + $(CC) -o cpulimit cpulimit.c $(LIBS) $(CFLAGS) process.o: process.c process.h $(CC) -c process.c $(CFLAGS) @@ -18,9 +22,6 @@ procutils.o: procutils.c procutils.h list.o: list.c list.h $(CC) -c list.c $(CFLAGS) -ptest: ptest.c - $(CC) -o ptest ptest.c -lrt $(CFLAGS) - clean: rm -f *~ *.o $(TARGETS) @@ -46,24 +46,29 @@ #include <fcntl.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> +#include <sys/stat.h> +#include <sys/time.h> +#include <sys/types.h> +#include <sys/sysctl.h> +#include <sys/resource.h> #include "process.h" #include "procutils.h" #include "list.h" //some useful macro +#ifndef MIN #define MIN(a,b) (a<b?a:b) +#endif +#ifndef MAX #define MAX(a,b) (a>b?a:b) -#define print_caption() printf("\n%%CPU\twork quantum\tsleep quantum\tactive rate\n") +#endif //control time slot in microseconds //each slot is splitted in a working slice and a sleeping slice @@ -76,7 +81,7 @@ //the "family" struct process_family pf; //pid of cpulimit -int cpulimit_pid; +pid_t cpulimit_pid; //name of this program (maybe cpulimit...) char *program_name; @@ -87,11 +92,28 @@ int verbose = 0; //lazy mode (exits if there is no process) int lazy = 0; +void *memrchr(const void *s, int c, size_t n) +{ + const unsigned char *start=s,*end=s; + + end+=n-1; + + while(end>=start) { + if(*end==c) + return (void *)end; + else + end--; + } + + return NULL; +} + //how many cpu do we have? int get_cpu_count() { - FILE *fd; int cpu_count = 0; +#ifdef __GNUC__ + FILE *fd; char line[100]; fd = fopen("/proc/stat", "r"); if (fd < 0) @@ -102,6 +124,11 @@ int get_cpu_count() } fclose(fd); return cpu_count - 1; +#elif defined __APPLE__ +//TODO: test sysconf(_SC_NPROCESSORS_ONLN), sysconf(_SC_NPROCESSORS_CONF) + if (sysctlbyname("hw.ncpu",&cpu_count,sizeof(int),NULL,0)) return 1; + return cpu_count; +#endif } //return t1-t2 in microseconds (no overflow checks, so better watch out!) @@ -146,7 +173,7 @@ void print_usage(FILE *stream, int exit_code) exit(exit_code); } -void limit_process(int pid, double limit) +void limit_process(pid_t pid, double limit) { //slice of the slot in which the process is allowed to run struct timespec twork; @@ -177,7 +204,8 @@ void limit_process(int pid, double limit) while(1) { - if (i%200==0 && verbose) print_caption(); + if (i%200==0 && verbose) + printf("\n%%CPU\twork quantum\tsleep quantum\tactive rate\n"); if (i%10==0) { //update the process family (checks only for new members) @@ -327,7 +355,7 @@ int main(int argc, char **argv) { int exe_ok = 0; int pid_ok = 0; int limit_ok = 0; - int pid = 0; + pid_t pid = 0; //parse arguments int next_option; @@ -447,11 +475,11 @@ int main(int argc, char **argv) { cmd_args[i] = NULL; if (verbose) { - printf("Running command: %s ", cmd); + printf("Running command: '%s", cmd); for (i=0; i<argc-optind-1; i++) { - printf("%s ", cmd_args[i]); + printf(" %s", cmd_args[i]); } - printf("\n"); + printf("'\n"); } int child = fork(); @@ -469,7 +497,8 @@ int main(int argc, char **argv) { else { //child code int ret = execvp(cmd, cmd_args); - //if we are here there was a fatal ERROR! + //if we are here there was an error, show it + perror("Error"); exit(ret); } return 0; @@ -477,7 +506,7 @@ int main(int argc, char **argv) { while(!lazy) { //look for the target process..or wait for it - int ret = 0; + pid_t ret = 0; if (pid_ok) { //search by pid ret = look_for_process_by_pid(pid); @@ -23,13 +23,19 @@ #include "process.h" +#ifdef __APPLE__ +#include <Carbon/Carbon.h> +#endif + int process_init(struct process_history *proc, int pid) { +#ifdef __GNUC__ //test /proc file descriptor for reading sprintf(proc->stat_file, "/proc/%d/stat", pid); FILE *fd = fopen(proc->stat_file, "r"); if (fd == NULL) return 1; fclose(fd); +#endif //init properties proc->pid = pid; proc->cpu_usage = 0; @@ -45,6 +51,7 @@ static inline unsigned long timediff(const struct timeval *t1,const struct timev } static int get_jiffies(struct process_history *proc) { +#ifdef __GNUC__ FILE *f = fopen(proc->stat_file, "r"); if (f==NULL) return -1; fgets(proc->buffer, sizeof(proc->buffer),f); @@ -60,8 +67,16 @@ static int get_jiffies(struct process_history *proc) { //kernel mode jiffies int ktime = atoi(p+1); return utime+ktime; +#elif defined __APPLE__ + ProcessSerialNumber psn; + ProcessInfoRec info; + if (GetProcessForPID(proc->pid, &psn)) return -1; + if (GetProcessInformation(&psn, &info)) return -1; + return info.processActiveTime; +#endif } +//parameter in range 0-1 #define ALFA 0.08 int process_monitor(struct process_history *proc) @@ -38,11 +38,13 @@ //process descriptor struct process_history { //the PID of the process - int pid; + pid_t pid; +#ifdef __GNUC__ //name of /proc/PID/stat file char stat_file[20]; //read buffer for /proc filesystem char buffer[1024]; +#endif //timestamp when last_j and cpu_usage was calculated struct timeval last_sample; //total number of jiffies used by the process at time last_sample @@ -51,7 +53,7 @@ struct process_history { double cpu_usage; }; -int process_init(struct process_history *proc, int pid); +int process_init(struct process_history *proc, pid_t pid); int process_monitor(struct process_history *proc); diff --git a/procutils.c b/procutils.c index 989c555..e7d4d89 100644 --- a/procutils.c +++ b/procutils.c @@ -25,8 +25,9 @@ /* PROCESS STATISTICS FUNCTIONS */ // returns pid of the parent process -static int getppid_of(int pid) +static pid_t getppid_of(pid_t pid) { +#ifdef __GNUC__ char file[20]; char buffer[1024]; sprintf(file, "/proc/%d/stat", pid); @@ -40,13 +41,25 @@ static int getppid_of(int pid) while (sp--) p = memchr(p+1,' ',sizeof(buffer) - (p-buffer)); //pid of the parent process - int ppid = atoi(p+1); + pid_t ppid = atoi(p+1); return ppid; +#elif defined __APPLE__ + ProcessSerialNumber psn_child; + ProcessInfoRec info_child; + pid_t ppid; + memset(&info_child, 0, sizeof(ProcessInfoRec)); + info_child.processInfoLength = sizeof(ProcessInfoRec); + if (GetProcessForPID(pid, &psn_child)) return -1; + if (GetProcessInformation(&psn_child, &info_child)) return -1; + if (GetProcessPID (&(info_child.processLauncher), &ppid)) return -1; + return ppid; +#endif } // returns the start time of a process (used with pid to identify a process) -static int get_starttime(int pid) +static int get_starttime(pid_t pid) { +#ifdef __GNUC__ char file[20]; char buffer[1024]; sprintf(file, "/proc/%d/stat", pid); @@ -62,11 +75,21 @@ static int get_starttime(int pid) //start time of the process int time = atoi(p+1); return time; +#elif defined __APPLE__ + ProcessSerialNumber psn; + ProcessInfoRec info; + memset(&info, 0, sizeof(ProcessInfoRec)); + info.processInfoLength = sizeof(ProcessInfoRec); + if (GetProcessForPID(pid, &psn)) return -1; + if (GetProcessInformation(&psn, &info)) return -1; + return info.processLaunchDate; +#endif } // detects whether a process is a kernel thread or not -static int is_kernel_thread(int pid) +static int is_kernel_thread(pid_t pid) { +#ifdef __GNUC__ static char statfile[20]; static char buffer[64]; int ret; @@ -77,10 +100,14 @@ static int is_kernel_thread(int pid) ret = strncmp(buffer,"0 0 0",3)==0; fclose(fd); return ret; +#elif defined __APPLE__ + return 0; +#endif } // returns 1 if pid is a user process, 0 otherwise -static int process_exists(int pid) { +static int process_exists(pid_t pid) { +#ifdef __GNUC__ static char statfile[20]; static char buffer[64]; int ret; @@ -91,6 +118,10 @@ static int process_exists(int pid) { ret = strncmp(buffer,"0 0 0",3)!=0; fclose(fd); return ret; +#elif defined __APPLE__ + ProcessSerialNumber psn; + return !GetProcessForPID(pid, &psn); +#endif } /* PID HASH FUNCTIONS */ @@ -112,7 +143,6 @@ static int hash_process(struct process_family *f, struct process *p) //list already exists struct process *tmp = (struct process*)locate_elem(*l, p); if (tmp != NULL) { - //TODO: should free() something? tmp? p? //update process info memcpy(tmp, p, sizeof(struct process)); free(p); @@ -129,7 +159,7 @@ static int hash_process(struct process_family *f, struct process *p) return ret; } -static void unhash_process(struct process_family *f, int pid) { +static void unhash_process(struct process_family *f, pid_t pid) { //remove process from hashtable struct list **l = &(f->hashtable[pid_hashfn(pid)]); if (*l == NULL) @@ -140,41 +170,42 @@ static void unhash_process(struct process_family *f, int pid) { f->count--; } -static struct process *seek_process(struct process_family *f, int pid) +static struct process *seek_process(struct process_family *f, pid_t pid) { struct list **l = &(f->hashtable[pid_hashfn(pid)]); return (*l != NULL) ? (struct process*)locate_elem(*l, &pid) : NULL; } /* -static int is_member(struct process_family *f, int pid) { +static int is_member(struct process_family *f, pid_t pid) { struct process *p = seek_process(f, pid); return (p!=NULL && p->member); } - -static int exists(struct process_family *f, int pid) { - struct process *p = seek_process(f, pid); - return p!=NULL; -} */ /* PROCESS ITERATOR STUFF */ // creates an object that browse all running processes static int init_process_iterator(struct process_iterator *i) { +#ifdef __GNUC__ //open a directory stream to /proc directory if ((i->dip = opendir("/proc")) == NULL) { perror("opendir"); return -1; } +#elif defined __APPLE__ + i->psn.highLongOfPSN = kNoProcess; + i->psn.lowLongOfPSN = kNoProcess; +#endif return 0; } // reads the next user process from /process // automatic closing if the end of the list is reached static int read_next_process(struct process_iterator *i) { + pid_t pid = 0; +#ifdef __GNUC__ //read in from /proc and seek for process dirs - int pid = 0; while ((i->dit = readdir(i->dip)) != NULL) { pid = atoi(i->dit->d_name); if (pid<=0 || is_kernel_thread(pid)) @@ -186,6 +217,13 @@ static int read_next_process(struct process_iterator *i) { //no more processes, release resources closedir(i->dip); } +#elif defined __APPLE__ + ProcessInfoRec info; + memset(&info, 0, sizeof(ProcessInfoRec)); + info.processInfoLength = sizeof(ProcessInfoRec); + if (GetNextProcess(&i->psn)) return 0; + GetProcessPID(&(i->psn), &pid); +#endif return pid; } @@ -193,7 +231,7 @@ static int read_next_process(struct process_iterator *i) { // searches for all the processes derived from father and stores them // in the process family struct -int create_process_family(struct process_family *f, int father) +int create_process_family(struct process_family *f, pid_t father) { //process list initialization (4 bytes key) init_list(&(f->members), 4); @@ -283,7 +321,7 @@ int update_process_family(struct process_family *f) } // removes a process from the family by its pid -void remove_process_from_family(struct process_family *f, int pid) +void remove_process_from_family(struct process_family *f, pid_t pid) { struct list_node *node = locate_node(&(f->members), &pid); if (node != NULL) { @@ -324,7 +362,7 @@ void cleanup_process_family(struct process_family *f) // return: pid of the found process, if it is found // 0, if it's not found // negative pid, if it is found but it's not possible to control it -int look_for_process_by_pid(int pid) +int look_for_process_by_pid(pid_t pid) { if (process_exists(pid)) return (kill(pid,SIGCONT)==0) ? pid : -pid; @@ -337,34 +375,48 @@ int look_for_process_by_pid(int pid) // return: pid of the found process, if it is found // 0, if it's not found // negative pid, if it is found but it's not possible to control it -int look_for_process_by_name(const char *process) +int look_for_process_by_name(const char *process_name) { //the name of /proc/pid/exe symbolic link pointing to the executable file char exelink[20]; //the name of the executable file - char exepath[PATH_MAX+1]; - //whether the variable process is the absolute path or not - int is_absolute_path = process[0] == '/'; + char *exepath = malloc((PATH_MAX+1) * sizeof(char)); + //whether the variable process_name is the absolute path or not + int is_absolute_path = process_name[0] == '/'; //flag indicating if the a process with given name was found int found = 0; //process iterator struct process_iterator iter; init_process_iterator(&iter); - int pid = 0; + pid_t pid = 0; +#ifdef __APPLE__ + ProcessSerialNumber psn; + ProcessInfoRec info; + memset(&info, 0, sizeof(ProcessInfoRec)); + info_child.processInfoLength = sizeof(ProcessInfoRec); + info.processName = (char*)malloc(64*sizeof(char)); +#endif while ((pid = read_next_process(&iter))) { +#ifdef __GNUC__ //read the executable link sprintf(exelink,"/proc/%d/exe",pid); int size = readlink(exelink, exepath, sizeof(exepath)); +#elif defined __APPLE__ + //get the executable file name + if (GetProcessForPID(pid, &psn)) return -1; + if (GetProcessInformation(&psn, &info)) return -1; + int size = strlen(info.processName); +#endif if (size>0) { found = 0; - if (is_absolute_path && strncmp(exepath, process, size)==0 && size==strlen(process)) { + if (is_absolute_path && strncmp(exepath, process_name, size)==0 && size==strlen(process_name)) { //process found found = 1; } else { //process found - if (strncmp(exepath + size - strlen(process), process, strlen(process))==0) { + if (strncmp(exepath + size - strlen(process_name), process_name, strlen(process_name))==0) { found = 1; } } @@ -381,6 +433,10 @@ int look_for_process_by_name(const char *process) } } } + free(exepath); +#ifdef __APPLE__ + free(info.processName); +#endif if (found == 1) { //ok, the process was found return pid; diff --git a/procutils.h b/procutils.h index 8a1deb2..d0d2f3e 100644 --- a/procutils.h +++ b/procutils.h @@ -30,16 +30,25 @@ #include <sys/types.h> #include <dirent.h> #include <string.h> +#include <limits.h> #include "list.h" #include "process.h" +#ifdef __APPLE__ +#include <Carbon/Carbon.h> +#endif + +#ifndef PATH_MAX +#define PATH_MAX 4096 +#endif + #define PIDHASH_SZ 1024 #define pid_hashfn(x) ((((x) >> 8) ^ (x)) & (PIDHASH_SZ - 1)) // a hierarchy of processes struct process_family { //the (god)father of the process family - int father; + pid_t father; //process list (father process is the first element) //elements are struct process struct list members; @@ -53,7 +62,7 @@ struct process_family { // process descriptor struct process { //pid of the process - int pid; + pid_t pid; //start time int starttime; //is member of the family? @@ -63,13 +72,17 @@ struct process { // object to enumerate running processes struct process_iterator { +#ifdef __GNUC__ DIR *dip; - struct dirent *dit; + struct dirent *dit; +#elif defined __APPLE__ + ProcessSerialNumber psn; +#endif }; // searches for all the processes derived from father and stores them // in the process family struct -int create_process_family(struct process_family *f, int father); +int create_process_family(struct process_family *f, pid_t father); // checks if there are new processes born in the specified family // if any they are added to the members list @@ -77,7 +90,7 @@ int create_process_family(struct process_family *f, int father); int update_process_family(struct process_family *f); // removes a process from the family by its pid -void remove_process_from_family(struct process_family *f, int pid); +void remove_process_from_family(struct process_family *f, pid_t pid); // free the heap memory used by a process family void cleanup_process_family(struct process_family *f); @@ -88,6 +101,6 @@ int look_for_process_by_name(const char *process); // searches a process given its pid // returns the pid, or 0 if it's not found -int look_for_process_by_pid(int pid); +int look_for_process_by_pid(pid_t pid); #endif diff --git a/tools/jiffy.c b/tools/jiffy.c new file mode 100644 index 0000000..298f300 --- /dev/null +++ b/tools/jiffy.c @@ -0,0 +1,69 @@ +#include <stdio.h> +#include <stdlib.h> +#include <sys/time.h> +#include <string.h> +#include <unistd.h> + +#ifdef __APPLE__ +#include <Carbon/Carbon.h> +#endif + +static int get_jiffies(pid_t pid) { +#ifdef __GNUC__ + char buffer[1024]; + char stat_file[32]; + sprintf(stat_file, "/proc/%d/stat", pid); + FILE *f = fopen(stat_file, "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; +#elif defined __APPLE__ + ProcessSerialNumber psn; + ProcessInfoRec info; + if (GetProcessForPID(pid, &psn)) return -1; + if (GetProcessInformation(&psn, &info)) return -1; + return info.processActiveTime; +#endif +} + +struct timeval timeval_diff(struct timeval *tv1, struct timeval *tv2) +{ + struct timeval diff; + diff.tv_sec = tv2->tv_sec - tv1->tv_sec; + diff.tv_usec = tv2->tv_usec - tv1->tv_usec; + if (diff.tv_usec < 0) { + diff.tv_sec--; + diff.tv_usec += 1000000; + } + return diff; +} + +int main() { + struct timeval start, now, diff; + int i,j; + int pid = getpid(); + gettimeofday(&start, NULL); + printf("time j HZ jiffy time\n"); + while(1) { + for(i=0;i<100000;i++) + for(j=0;j<10000;j++); + int j = get_jiffies(pid); + if (j<0) exit(-1); + gettimeofday(&now, NULL); + diff = timeval_diff(&start, &now); + double d = diff.tv_sec + diff.tv_usec * 1e-6; + printf("%lf %d %lf %lf ms\n", d, j, j/d, 1000*d/j); + } + exit(0); +} diff --git a/tools/loop.c b/tools/loop.c new file mode 100644 index 0000000..c9280d2 --- /dev/null +++ b/tools/loop.c @@ -0,0 +1,3 @@ +int main() { + while(1); +} diff --git a/tools/ptest.c b/tools/ptest.c new file mode 100644 index 0000000..ee85a2a --- /dev/null +++ b/tools/ptest.c @@ -0,0 +1,59 @@ +#include <stdio.h> +#include <sys/types.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/wait.h> +#include <sys/time.h> +#include <stdlib.h> +#include <unistd.h> + +#define N 8 + +//simple program to test cpulimit +int main() +{ + printf("Parent: PID %d\n", getpid()); + getchar(); + sleep(1); + while(1); + int i; + int children[N]; + for (i=0;i<N;i++) { + int pid = fork(); + if (pid>0) { + //parent code + children[i] = pid; + printf("Child %d created\n", pid); + } + else if (pid==0) { + while(1); + //child code +// while(1) { + //random generator initialization + struct timeval t; + gettimeofday(&t, NULL); + srandom(t.tv_sec + t.tv_usec + getpid()); + int loop = random() % 1000000; + printf("start\n"); + int i,j; + for (i=0;i<1000;i++) + for (j=0;j<loop;j++); + printf("stop\n"); + int time = random() % 10000000; + // printf("Child %d wait %d\n", getpid(), time); + usleep(time); + printf("Child %d terminated\n", getpid()); +// } + exit(0); + } + else { + fprintf(stderr, "fork() failed!\n"); + } + } + for (i=0;i<N;i++) { + int status; + waitpid(children[i], &status, 0); + } + sleep(1); + return 0; +} |