aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorbhackerozzo <bhackerozzo@3b445381-d045-0410-9223-e17ecdb95f4b>2008-08-28 00:32:21 +0000
committerbhackerozzo <bhackerozzo@3b445381-d045-0410-9223-e17ecdb95f4b>2008-08-28 00:32:21 +0000
commit20cad7b4efc241a438c7134cc2bfff5f9a8db2f6 (patch)
tree15ae3cfccb5fb88353916dff377cd1cd5ca82911
parent0343c0946a0d4dba4bf161fd992ee6abb49fa955 (diff)
downloadcpulimit-20cad7b4efc241a438c7134cc2bfff5f9a8db2f6.tar.gz
simplified and lightweight control algorithm
-rw-r--r--Makefile6
-rw-r--r--cpulimit.c65
-rw-r--r--process.c82
-rw-r--r--process.h40
-rw-r--r--ptest.c31
5 files changed, 105 insertions, 119 deletions
diff --git a/Makefile b/Makefile
index 261a76a..7bd54ec 100644
--- a/Makefile
+++ b/Makefile
@@ -8,9 +8,6 @@ all:: $(TARGETS)
cpulimit: cpulimit.c $(LIBS)
$(CC) -o cpulimit cpulimit.c $(LIBS) -lrt $(CFLAGS)
-ptest: ptest.c process.o procutils.o list.o
- $(CC) -o ptest ptest.c process.o procutils.o list.o -lrt $(CFLAGS)
-
process.o: process.c process.h
$(CC) -c process.c $(CFLAGS)
@@ -20,6 +17,9 @@ 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)
diff --git a/cpulimit.c b/cpulimit.c
index c64a069..6127f5f 100644
--- a/cpulimit.c
+++ b/cpulimit.c
@@ -146,7 +146,7 @@ void print_usage(FILE *stream, int exit_code)
exit(exit_code);
}
-void limit_process(int pid, float limit)
+void limit_process(int pid, double limit)
{
//slice of the slot in which the process is allowed to run
struct timespec twork;
@@ -171,9 +171,13 @@ void limit_process(int pid, float limit)
if (verbose) printf("Members in the family owned by %d: %d\n", pf.father, pf.members.count);
+ //rate at which we are keeping active the processes (range 0-1)
+ //1 means that the process are using all the twork slice
+ double workingrate = -1;
+
while(1) {
- if (i%100==0 && verbose) print_caption();
+ if (i%200==0 && verbose) print_caption();
if (i%10==0) {
//update the process family (checks only for new members)
@@ -193,45 +197,46 @@ void limit_process(int pid, float limit)
//total cpu actual usage (range 0-1)
//1 means that the processes are using 100% cpu
- float pcpu = 0;
- //rate at which we are keeping active the processes (range 0-1)
- //1 means that the process are using all the twork slice
- float workingrate = 0;
-
+ double pcpu = -1;
+ //number of processes in the family
+ int pcount = 0;
+
//estimate how much the controlled processes are using the cpu in the working interval
for (node=pf.members.first; node!=NULL; node=node->next) {
struct process *proc = (struct process*)(node->data);
- if (process_monitor(proc->history, workingtime, &(proc->history->usage))==-1) {
+ if (process_monitor(proc->history)==-1) {
//process is dead, remove it from family
fprintf(stderr,"Process %d dead!\n", proc->pid);
remove_process_from_family(&pf, proc->pid);
continue;
}
- pcpu += proc->history->usage.pcpu;
- workingrate += proc->history->usage.workingrate;
+//printf("pid %d limit %f pcpu %f wrate %f\n", proc->pid, limit, proc->history->usage.pcpu, proc->history->usage.workingrate);
+ if (proc->history->cpu_usage<0) {
+ continue;
+ }
+ if (pcpu<0) pcpu = 0;
+ pcpu += proc->history->cpu_usage;
+ pcount++;
}
- //average value
- workingrate /= pf.members.count;
-
- //TODO: make workingtime customized for each process, now it's equal for all
//adjust work and sleep time slices
- if (pcpu>0) {
- twork.tv_nsec = MIN(TIME_SLOT*limit*1000/pcpu*workingrate,TIME_SLOT*1000);
- }
- else if (pcpu==0) {
- twork.tv_nsec = TIME_SLOT*1000;
- }
- else if (pcpu==-1) {
- //not yet a valid idea of cpu usage
+ if (pcpu < 0) {
+ //it's the 1st cycle, initialize workingrate
pcpu = limit;
workingrate = limit;
- twork.tv_nsec = MIN(TIME_SLOT*limit*1000,TIME_SLOT*1000);
+ twork.tv_nsec = TIME_SLOT*limit*1000;
+ }
+ else {
+ //adjust workingrate
+ workingrate = MIN(workingrate / pcpu * limit, 1);
+ twork.tv_nsec = TIME_SLOT*1000*workingrate;
}
tsleep.tv_nsec = TIME_SLOT*1000-twork.tv_nsec;
+//printf("%lf %lf\n", workingrate, pcpu);
+
if (verbose && i%10==0 && i>0) {
- 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);
+ printf("%0.2lf%%\t%6ld us\t%6ld us\t%0.2lf%%\n",pcpu*100,twork.tv_nsec/1000,tsleep.tv_nsec/1000,workingrate*100);
}
//resume processes
@@ -251,8 +256,7 @@ void limit_process(int pid, float limit)
workingtime = timediff(&endwork,&startwork);
if (tsleep.tv_nsec>0) {
- //stop only if the process is active
- //stop processes, they have worked enough
+ //stop only if tsleep>0, instead it's useless
for (node=pf.members.first; node!=NULL; node=node->next) {
struct process *proc = (struct process*)(node->data);
if (kill(proc->pid,SIGSTOP)!=0) {
@@ -270,7 +274,6 @@ void limit_process(int pid, float limit)
}
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);
@@ -347,12 +350,12 @@ int main(int argc, char **argv) {
}
if (!process_ok) {
- fprintf(stderr,"Error: You must specify a target process, by name or by PID\n");
+ fprintf(stderr,"Error: You must specify a target process, either by name or by PID\n");
print_usage(stderr, 1);
exit(1);
}
if (pid_ok && exe!=NULL) {
- fprintf(stderr, "Error: You must specify exactly one process, by name or by PID\n");
+ fprintf(stderr, "Error: You must specify exactly one process, either by name or by PID\n");
print_usage(stderr, 1);
exit(1);
}
@@ -361,7 +364,7 @@ int main(int argc, char **argv) {
print_usage(stderr, 1);
exit(1);
}
- float limit = perclimit/100.0;
+ double limit = perclimit/100.0;
int cpu_count = get_cpu_count();
if (limit<0 || limit >cpu_count) {
fprintf(stderr,"Error: limit must be in the range 0-%d00\n", cpu_count);
@@ -382,7 +385,7 @@ int main(int argc, char **argv) {
printf("Priority changed to %d\n", priority);
}
else {
- printf("Cannot change priority\n");
+ printf("Warning: Cannot change priority. Run as root for best results.\n");
}
while(1) {
diff --git a/process.c b/process.c
index e044fdc..4131ce4 100644
--- a/process.c
+++ b/process.c
@@ -25,20 +25,17 @@
int process_init(struct process_history *proc, int pid)
{
- proc->pid = pid;
- //init circular queue
- proc->front_index = -1;
- proc->tail_index = 0;
- proc->actual_history_size = 0;
- memset(proc->history, 0, sizeof(proc->history));
- proc->total_workingtime = 0;
//test /proc file descriptor for reading
- sprintf(proc->stat_file, "/proc/%d/stat", proc->pid);
+ sprintf(proc->stat_file, "/proc/%d/stat", pid);
FILE *fd = fopen(proc->stat_file, "r");
+ if (fd == NULL) return 1;
fclose(fd);
- proc->usage.pcpu = 0;
- proc->usage.workingrate = 0;
- return (fd == NULL);
+ //init properties
+ proc->pid = pid;
+ proc->cpu_usage = 0;
+ memset(&(proc->last_sample), 0, sizeof(struct timespec));
+ proc->last_jiffies = -1;
+ return 0;
}
//return t1-t2 in microseconds (no overflow checks, so better watch out!)
@@ -65,46 +62,43 @@ static int get_jiffies(struct process_history *proc) {
return utime+ktime;
}
-int process_monitor(struct process_history *proc, int last_working_quantum, struct cpu_usage *usage)
-{
- //increment front index
- proc->front_index = (proc->front_index+1) % HISTORY_SIZE;
-
- //actual history size is: (front-tail+HISTORY_SIZE)%HISTORY_SIZE+1
- proc->actual_history_size = (proc->front_index - proc->tail_index + HISTORY_SIZE) % HISTORY_SIZE + 1;
-
- //actual front and tail of the queue
- struct process_screenshot *front = &(proc->history[proc->front_index]);
- struct process_screenshot *tail = &(proc->history[proc->tail_index]);
+#define ALFA 0.08
- //take a shot and save in front
+int process_monitor(struct process_history *proc)
+{
int j = get_jiffies(proc);
if (j<0) return -1; //error retrieving jiffies count (maybe the process is dead)
- front->jiffies = j;
- clock_gettime(CLOCK_REALTIME, &(front->when));
- front->cputime = last_working_quantum;
-
- if (proc->actual_history_size==1) {
- //not enough elements taken (it's the first one!), return 0
- usage->pcpu = -1;
- usage->workingrate = 1;
+ struct timespec now;
+ clock_gettime(CLOCK_REALTIME, &now);
+ if (proc->last_jiffies==-1) {
+ //store current time
+ proc->last_sample = now;
+ //store current jiffies
+ proc->last_jiffies = j;
+ //it's the first sample, cannot figure out the cpu usage
+ proc->cpu_usage = -1;
return 0;
}
+ //time from previous sample (in ns)
+ long dt = timediff(&now, &(proc->last_sample));
+ //how many jiffies in dt?
+ double max_jiffies = dt * HZ / 1000000.0;
+ double sample = (j - proc->last_jiffies) / max_jiffies;
+ if (proc->cpu_usage == -1) {
+ //initialization
+ proc->cpu_usage = sample;
+ }
else {
- //queue has enough elements
- //now we can calculate cpu usage, interval dt and dtwork are expressed in microseconds
- long dt = timediff(&(front->when), &(tail->when));
- //the total time between tail and front in which the process was allowed to run
- proc->total_workingtime += front->cputime - tail->cputime;
- int used_jiffies = front->jiffies - tail->jiffies;
- float usage_ratio = (used_jiffies*1000000.0/HZ) / proc->total_workingtime;
- usage->workingrate = 1.0 * proc->total_workingtime / dt;
- usage->pcpu = usage_ratio * usage->workingrate;
- //increment tail index if the queue is full
- if (proc->actual_history_size==HISTORY_SIZE)
- proc->tail_index = (proc->tail_index+1) % HISTORY_SIZE;
- return 0;
+ //adaptative adjustment
+ proc->cpu_usage = (1-ALFA) * proc->cpu_usage + ALFA * sample;
}
+
+ //store current time
+ proc->last_sample = now;
+ //store current jiffies
+ proc->last_jiffies = j;
+
+ return 0;
}
int process_close(struct process_history *proc)
diff --git a/process.h b/process.h
index 16cbf8f..5a73cc2 100644
--- a/process.h
+++ b/process.h
@@ -32,26 +32,8 @@
#include <sys/time.h>
#include <unistd.h>
-//kernel time resolution (inverse of one jiffy interval) in Hertz
+//kernel time resolution timer interrupt frequency in Hertz
#define HZ sysconf(_SC_CLK_TCK)
-//size of the history circular queue
-#define HISTORY_SIZE 10
-
-//extracted process statistics
-struct cpu_usage {
- float pcpu;
- float workingrate;
-};
-
-//process instant photo
-struct process_screenshot {
- //timestamp
- struct timespec when;
- //total jiffies used by the process
- int jiffies;
- //cpu time used since previous screenshot expressed in microseconds
- int cputime;
-};
//process descriptor
struct process_history {
@@ -61,23 +43,17 @@ struct process_history {
char stat_file[20];
//read buffer for /proc filesystem
char buffer[1024];
- //recent history of the process (fixed circular queue)
- struct process_screenshot history[HISTORY_SIZE];
- //the index of the last screenshot made to the process
- int front_index;
- //the index of the oldest screenshot made to the process
- int tail_index;
- //how many screenshots we have in the queue (max HISTORY_SIZE)
- int actual_history_size;
- //total cputime saved in the history
- long total_workingtime;
- //current usage
- struct cpu_usage usage;
+ //timestamp when last_j and cpu_usage was calculated
+ struct timespec last_sample;
+ //total number of jiffies used by the process at time last_sample
+ int last_jiffies;
+ //cpu usage estimation (value in range 0-1)
+ double cpu_usage;
};
int process_init(struct process_history *proc, int pid);
-int process_monitor(struct process_history *proc, int last_working_quantum, struct cpu_usage *usage);
+int process_monitor(struct process_history *proc);
int process_close(struct process_history *proc);
diff --git a/ptest.c b/ptest.c
index ca30b1a..64b124d 100644
--- a/ptest.c
+++ b/ptest.c
@@ -3,15 +3,18 @@
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
-#include "procutils.h"
+#include <sys/time.h>
+#include <stdlib.h>
+#include <unistd.h>
-#define N 10
+#define N 8
//simple program to test cpulimit
int main()
{
printf("Parent: PID %d\n", getpid());
getchar();
+ sleep(1);
int i;
int children[N];
for (i=0;i<N;i++) {
@@ -22,14 +25,24 @@ int main()
printf("Child %d created\n", pid);
}
else if (pid==0) {
+ while(1);
//child code
- struct timeval t;
- gettimeofday(&t, NULL);
- srandom(t.tv_usec + getpid());
- int time = random() % 2000000;
-// printf("Child %d wait %d\n", getpid(), time);
- usleep(time);
- printf("Child %d terminated\n", getpid());
+// 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 {
Un proyecto texto-plano.xyz