commit 6914d302fb3800c4704594ea7402e6f69845dc06
parent bd21de03ccb49344d258b1e0d6c63ee79e0b5956
Author: Jesus Galan Lopez (yiyus) <yiyu.jgl@gmail.com>
Date: Wed, 30 Jun 2010 23:07:31 +0200
new plimit (inside sched), separated cpuload
Diffstat:
8 files changed, 69 insertions(+), 465 deletions(-)
diff --git a/src/9vx/Makefrag b/src/9vx/Makefrag
@@ -32,7 +32,6 @@ all: 9vx/9vx
PLAN9_OBJS = \
$(addprefix 9vx/, \
bootcode.o \
- plimit-$(OS).o \
conf.o \
devaudio.o \
devaudio-$(PLAN9AUDIO).o \
@@ -45,6 +44,7 @@ PLAN9_OBJS = \
fossil.o \
kprocdev.o \
label.o \
+ load.o \
main.o \
mmu.o \
sched.o \
diff --git a/src/9vx/a/portfns.h b/src/9vx/a/portfns.h
@@ -410,3 +410,5 @@ void uartecho(char*, int);
void vx32sysr1(void);
void vxnewproc(Proc*);
void mmusize(int);
+void plimitproc(void*);
+void ploadproc(void*);
diff --git a/src/9vx/load.c b/src/9vx/load.c
@@ -0,0 +1,37 @@
+#include "u.h"
+#include <sys/times.h>
+#include "lib.h"
+#include "mem.h"
+#include "dat.h"
+
+/*
+ * CPU load
+ */
+void
+ploadproc(void *v)
+{
+ double load;
+ vlong hz;
+ struct tms t;
+ clock_t now, last;
+ clock_t used, lastused;
+
+ hz = sysconf(_SC_CLK_TCK);
+ last = 0;
+ lastused = 0;
+ load = 0;
+
+ for(;;){
+ usleep(1000000);
+ now = times(&t);
+ used = t.tms_utime + t.tms_stime;
+ load = (double)(used - lastused) / (now - last);
+ machp[0]->load = load * 100 * hz;
+/*
+iprint("XXX Load: %d%%\n", (int)(load * 100));
+*/
+ lastused = used;
+ last = now;
+ }
+}
+
diff --git a/src/9vx/main.c b/src/9vx/main.c
@@ -47,6 +47,7 @@ extern Dev audiodevtab;
int doabort = 1; // for now
int abortonfault;
+int nocpuload;
char* argv0;
char* conffile = "9vx";
char* defaultroot = "local!#Z/usr/local/9vx";
@@ -112,6 +113,9 @@ main(int argc, char **argv)
case 'K':
tracekdev++;
break;
+ case 'L':
+ nocpuload++;
+ break;
case 'M':
tracemmu++;
break;
@@ -213,13 +217,6 @@ main(int argc, char **argv)
#endif
/*
- * After fork to deal with the correct pid.
- * The cpu limiter will run in a new process.
- */
- if(cpulimit != 0)
- plimit(getpid(), cpulimit);
-
- /*
* Have to do this after fork; on OS X child does
* not inherit sigaltstack.
*/
@@ -243,6 +240,10 @@ main(int argc, char **argv)
makekprocdev(&fsdevtab);
makekprocdev(&drawdevtab);
makekprocdev(&audiodevtab);
+ if(nocpuload == 0)
+ kproc("pload", &ploadproc, nil);
+ if(cpulimit > 0 && cpulimit < 100)
+ kproc("plimit", &plimitproc, &cpulimit);
}
bootinit();
pageinit();
diff --git a/src/9vx/plimit-bsd.c b/src/9vx/plimit-bsd.c
@@ -1,144 +0,0 @@
-/*
- * plimit-bsd.c - Process limiting support for BSD systems.
- *
- * Copyright (c) 2008 by Devon H. O'Dell <devon.odell@gmail.com>
- *
- * This software is released under a 2-clause BSD license.
- */
-
-#include <sys/types.h>
-#include <sys/proc.h>
-#include <sys/resource.h>
-#include <sys/resourcevar.h>
-#include <sys/sysctl.h>
-#include <sys/time.h>
-#include <sys/timespec.h>
-#include <sys/user.h>
-
-#include <fcntl.h>
-#include <kvm.h>
-#include <signal.h>
-#include <string.h>
-#include <unistd.h>
-
-#include "u.h"
-
-#define timediff(x, y) \
- (((x)->tv_sec - (y)->tv_sec) * 1000000 + \
- ((x)->tv_usec - (y)->tv_usec))
-
-void
-plimit(pid_t pid, int percent)
-{
- pid_t p;
- double lim;
-
- lim = (double)percent; // XXX: / 100 ?
-
- p = rfork(RFPROC|RFNOWAIT|RFCFDG);
-
- if (p == 0) {
- struct timespec sleep_slice;
- struct timespec work_slice;
- struct timeval last_sample;
- struct timeval last_start;
- struct timeval last_end;
- struct clockinfo ci;
- double last_usage;
- int last_pstart;
- int mibctl[2];
- size_t len;
- double rat;
- double cpu;
- int c;
-
- mibctl[0] = CTL_KERN;
- mibctl[1] = KERN_CLOCKRATE;
- len = sizeof(ci);
- sysctl(mibctl, 2, &ci, &len, NULL, 0);
-
- rat = cpu = -1;
- last_usage = 0.0;
- c = last_pstart = -1;
-
- memset(&sleep_slice, 0, sizeof(struct timespec));
- memset(&work_slice, 0, sizeof(struct timespec));
- memset(&last_sample, 0, sizeof(struct timeval));
- memset(&last_start, 0, sizeof(struct timeval));
- memset(&last_end, 0, sizeof(struct timeval));
-
- while (1) {
- struct kinfo_proc *kp;
- struct timeval now;
- struct proc kp_p;
- kvm_t *kd;
- long dt;
- uint64_t mt;
- int t;
-
- kd = kvm_open(NULL, NULL, NULL, O_RDONLY, NULL);
- if (!kd) {
- return;
- }
-
- kp = kvm_getprocs(kd, KERN_PROC_PID, pid, &t);
- if (!kp) {
- return;
- }
-
- if (kvm_read(kd, (ulong)kp->ki_paddr, &kp_p, sizeof (struct proc)) == -1) {
- return;
- }
-
- mt = kp_p.p_rux.rux_tu + kp_p.p_crux.rux_tu;
-
- kvm_close(kd);
-
- gettimeofday(&now, NULL);
- if (last_pstart < 0) {
- last_sample = now;
- last_pstart = mt;
-
- kill(pid, SIGSTOP);
- continue;
- }
-
- dt = timediff(&now, &last_sample);
-
- if (last_usage == 0.0) {
- last_usage = ((mt - last_pstart) / (dt * ci.hz / 1000000.0));
- } else {
- last_usage = 0.96 * last_usage + 0.96 * ((mt - last_pstart) / (dt * ci.hz / 1000000.0));
- }
-
- last_sample = now;
- last_pstart = mt;
-
- if (cpu < 0) {
- cpu = lim;
- rat = lim;
- work_slice.tv_nsec = 100000000 * lim;
- } else {
- rat = MIN(rat / cpu * lim, 1);
- work_slice.tv_nsec = 100000000 * rat;
- }
-
- sleep_slice.tv_nsec = 100000000 - work_slice.tv_nsec;
-
- kill(pid, SIGCONT);
-
- gettimeofday(&last_start, NULL);
- nanosleep(&work_slice, NULL);
- gettimeofday(&last_end, NULL);
-
- if (sleep_slice.tv_nsec > 0) {
- kill(pid, SIGSTOP);
- nanosleep(&sleep_slice, NULL);
- }
- }
- } else {
- return;
- }
-
- return;
-}
diff --git a/src/9vx/plimit-darwin.c b/src/9vx/plimit-darwin.c
@@ -1,153 +0,0 @@
-/*
- * plimit-bsd.c - Process limiting support for Darwin.
- *
- * Copyright (c) 2008 by Devon H. O'Dell <devon.odell@gmail.com>
- *
- * This software is released under a 2-clause BSD license.
- */
-
-#warning "Darwin has no rfork; we'll have to figure out how to do this."
-
-#if 0
-#include <sys/types.h>
-#include <sys/proc.h>
-#include <sys/resource.h>
-#include <sys/resourcevar.h>
-#include <sys/sysctl.h>
-#include <sys/time.h>
-#include <sys/timespec.h>
-#include <sys/user.h>
-
-#include <fcntl.h>
-#include <kvm.h>
-#include <signal.h>
-#include <string.h>
-#include <unistd.h>
-
-#include "u.h"
-
-
-#define timediff(x, y) \
- (((x)->tv_sec - (y)->tv_sec) * 1000000 + \
- ((x)->tv_usec - (y)->tv_usec))
-#endif
-
-void
-plimit(pid_t pid, int percent)
-{
-
-fprintf(fileno(stderr), "there is no darwin support in plimit");
-/*
- pid_t p;
- double lim;
-
- lim = (double)percent; // XXX: / 100 ?
-
- p = rfork(RFPROC|RFNOWAIT|RFCFDG);
-
- if (p == 0) {
- struct timespec sleep_slice;
- struct timespec work_slice;
- struct timeval last_sample;
- struct timeval last_start;
- struct timeval last_end;
- struct clockinfo ci;
- double last_usage;
- int last_pstart;
- int mibctl[2];
- size_t len;
- double rat;
- double cpu;
- int c;
-
- mibctl[0] = CTL_KERN;
- mibctl[1] = KERN_CLOCKRATE;
- len = sizeof(ci);
- sysctl(mibctl, 2, &ci, &len, NULL, 0);
-
- rat = cpu = -1;
- last_usage = 0.0;
- c = last_pstart = -1;
-
- memset(&sleep_slice, 0, sizeof(struct timespec));
- memset(&work_slice, 0, sizeof(struct timespec));
- memset(&last_sample, 0, sizeof(struct timeval));
- memset(&last_start, 0, sizeof(struct timeval));
- memset(&last_end, 0, sizeof(struct timeval));
-
- while (1) {
- struct kinfo_proc *kp;
- struct timeval now;
- struct proc kp_p;
- kvm_t *kd;
- long dt;
- uint64_t mt;
- int t;
-
- kd = kvm_open(NULL, NULL, NULL, O_RDONLY, NULL);
- if (!kd) {
- return;
- }
-
- kp = kvm_getprocs(kd, KERN_PROC_PID, pid, &t);
- if (!kp) {
- return;
- }
-
- if (kvm_read(kd, (ulong)kp->ki_paddr, &kp_p, sizeof (struct proc)) == -1) {
- return;
- }
-
- mt = kp_p.p_rux.rux_tu + kp_p.p_crux.rux_tu;
-
- kvm_close(kd);
-
- gettimeofday(&now, NULL);
- if (last_pstart < 0) {
- last_sample = now;
- last_pstart = mt;
-
- kill(pid, SIGSTOP);
- continue;
- }
-
- dt = timediff(&now, &last_sample);
-
- if (last_usage == 0.0) {
- last_usage = ((mt - last_pstart) / (dt * ci.hz / 1000000.0));
- } else {
- last_usage = 0.96 * last_usage + 0.96 * ((mt - last_pstart) / (dt * ci.hz / 1000000.0));
- }
-
- last_sample = now;
- last_pstart = mt;
-
- if (cpu < 0) {
- cpu = lim;
- rat = lim;
- work_slice.tv_nsec = 100000000 * lim;
- } else {
- rat = MIN(rat / cpu * lim, 1);
- work_slice.tv_nsec = 100000000 * rat;
- }
-
- sleep_slice.tv_nsec = 100000000 - work_slice.tv_nsec;
-
- kill(pid, SIGCONT);
-
- gettimeofday(&last_start, NULL);
- nanosleep(&work_slice, NULL);
- gettimeofday(&last_end, NULL);
-
- if (sleep_slice.tv_nsec > 0) {
- kill(pid, SIGSTOP);
- nanosleep(&sleep_slice, NULL);
- }
- }
- } else {
- return;
- }
-*/
-
- return;
-}
diff --git a/src/9vx/plimit-linux.c b/src/9vx/plimit-linux.c
@@ -1,160 +0,0 @@
-/*
- * plimit-linux.c - Process limiting support for Linux systems.
- *
- * Copyright (c) 2008 by Devon H. O'Dell <devon.odell@gmail.com>
- * Copyright (c) 2010 by Devon H. O'Dell <devon.odell@gmail.com>
- *
- * This software is released under a 2-clause BSD license.
- */
-
-#include <sys/types.h>
-#include <sys/ioctl.h>
-#include <sys/param.h>
-#include <sys/mman.h>
-
-#include <fcntl.h>
-#include <limits.h>
-#include <sched.h>
-#include <signal.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include "u.h"
-
-#define timediff(x, y) \
- (((x)->tv_sec - (y)->tv_sec) * 1000000 + \
- ((x)->tv_usec - (y)->tv_usec))
-
-int pid;
-
-void
-limit(int percent) {
- struct timespec sleep_slice;
- struct timespec work_slice;
- struct timeval last_sample;
- struct timeval last_start;
- struct timeval last_end;
- double last_usage;
- int last_pstart;
- double lim;
- double rat;
- double cpu;
- char buf[1024];
- char stat[MAXPATHLEN];
- long hz;
- int c;
-
- hz = sysconf(_SC_CLK_TCK);
-
- lim = (double)percent / 100;
- rat = cpu = -1;
- last_usage = 0.0;
- c = last_pstart = -1;
-
- snprintf(stat, MAXPATHLEN, "/proc/%d/stat", pid);
-
- memset(&sleep_slice, 0, sizeof(struct timespec));
- memset(&work_slice, 0, sizeof(struct timespec));
- memset(&last_sample, 0, sizeof(struct timeval));
- memset(&last_start, 0, sizeof(struct timeval));
- memset(&last_end, 0, sizeof(struct timeval));
-
- while (1) {
- struct timeval now;
- int seen_paren;
- char *tmp;
- long uj;
- long sj;
- long dt;
- int n;
- int r;
- long t;
-
- t = open(stat, O_RDONLY);
- if (t < 0)
- exit(1);
- tmp = buf;
- while ((n = read(t, tmp, 1024)) != 0)
- tmp += n;
- close(t);
-
- seen_paren = n = 0;
- while (buf[n] != ' ' && seen_paren == 0) {
- if (buf[n] == ')')
- seen_paren = 1;
- n++;
- }
-
- r = 0;
- while (r < 13)
- if (buf[n++] == ' ')
- r++;
-
- uj = strtol(&buf[n], &tmp, 10);
- sj = strtol(tmp, NULL, 10);
-
- t = (uj + sj) * hz;
-
- gettimeofday(&now, NULL);
- if (last_pstart < 0) {
- last_sample = now;
- last_pstart = t;
-
- kill(pid, SIGSTOP);
- continue;
- }
-
- dt = timediff(&now, &last_sample);
-
- if (last_usage == 0.0)
- last_usage = ((t - last_pstart) / (dt * hz / 1000000.0));
- else
- last_usage = 0.96 * last_usage + 0.96 * ((t - last_pstart) / (dt * hz / 1000000.0));
-
- last_sample = now;
- last_pstart = t;
-
- if (cpu < 0) {
- cpu = lim;
- rat = cpu;
- work_slice.tv_nsec = 100000000 * lim;
- } else {
- rat = MIN(rat / cpu * lim, 1);
- work_slice.tv_nsec = 100000000 * rat;
- }
-
- sleep_slice.tv_nsec = 100000000 - work_slice.tv_nsec;
-
- kill(pid, SIGCONT);
-
- gettimeofday(&last_start, NULL);
- nanosleep(&work_slice, NULL);
- gettimeofday(&last_end, NULL);
-
- if (sleep_slice.tv_nsec > 0) {
- kill(pid, SIGSTOP);
- nanosleep(&sleep_slice, NULL);
- }
- }
-}
-
-void
-quit(int sig){
- kill(pid, SIGCONT);
- exit(0);
-}
-
-void
-plimit(pid_t p, int lim)
-{
- if(fork() > 0)
- return;
-
- signal(SIGINT, quit);
- signal(SIGTERM, quit);
-
- pid = p;
- limit(lim);
-}
diff --git a/src/9vx/sched.c b/src/9vx/sched.c
@@ -162,6 +162,27 @@ runproc(void)
}
/*
+ * Limit CPU usage going to sleep while holding the run lock
+ */
+void
+plimitproc(void *v)
+{
+ int lim;
+ uint sleeping, working;
+
+ lim = *((int*)v);
+ sleeping = 100000 * (100 - lim) / 100;
+ working = 100000 * lim / 100;
+
+ for(;;){
+ usleep(working);
+ plock(&run);
+ usleep(sleeping);
+ punlock(&run);
+ }
+}
+
+/*
* Host OS process sleep and wakeup.
*/
static pthread_mutex_t initmutex = PTHREAD_MUTEX_INITIALIZER;