cpulimit working in linux - vx32 - Local 9vx git repository for patches.
       
 (DIR) Log
 (DIR) Files
 (DIR) Refs
       ---
 (DIR) commit 788314fcd19a0728b05839a35c5b9fd6e9c57f8d
 (DIR) parent 742d6606c16b27283c5942e3df326a57571783e9
 (HTM) 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(-)
       ---
 (DIR) 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 \
 (DIR) 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);
       +}
 (DIR) 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.
                 */
 (DIR) 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);