vx32

Local 9vx git repository for patches.
git clone git://r-36.net/vx32
Log | Files | Refs

commit 788314fcd19a0728b05839a35c5b9fd6e9c57f8d
parent 742d6606c16b27283c5942e3df326a57571783e9
Author: Jesus Galan Lopez (yiyus) <yiyu.jgl@gmail.com>
Date:   Sat, 26 Jun 2010 10:55:34 +0200

cpulimit working in linux

Diffstat:
src/9vx/Makefrag | 1+
src/9vx/cpulimit-linux.c | 160+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/9vx/main.c | 7+++++++
src/9vx/unix.h | 1+
4 files changed, 169 insertions(+), 0 deletions(-)

diff --git a/src/9vx/Makefrag b/src/9vx/Makefrag @@ -32,6 +32,7 @@ all: 9vx/9vx PLAN9_OBJS = \ $(addprefix 9vx/, \ bootcode.o \ + cpulimit-$(OS).o \ conf.o \ devaudio.o \ devaudio-$(PLAN9AUDIO).o \ diff --git a/src/9vx/cpulimit-linux.c b/src/9vx/cpulimit-linux.c @@ -0,0 +1,160 @@ +/* + * 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/main.c b/src/9vx/main.c @@ -212,6 +212,13 @@ 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. */ diff --git a/src/9vx/unix.h b/src/9vx/unix.h @@ -63,3 +63,4 @@ typedef long long int64; #define USED(x) ((void)(x)) +void plimit(pid_t, int);