up cpulimit 0.3.2

This commit is contained in:
SirPdboy 2022-10-12 12:57:37 +08:00 committed by GitHub
parent 6fd4d1c241
commit 91276a6f01
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 158 additions and 139 deletions

View File

@ -1,9 +1,8 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=cpulimit
PKG_VERSION:=0.2
PKG_RELEASE:=1
#PKG_REV:=cabeb9947ccddd9a6e6ba14503e2a33063ac1b21
PKG_VERSION:=0.3.2
PKG_RELEASE:=$(AUTORELEASE)
#PKG_SOURCE_PROTO:=git
#PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.bz2
@ -16,8 +15,8 @@ include $(INCLUDE_DIR)/package.mk
define Package/cpulimit
SECTION:=utils
CATEGORY:=Utilities
TITLE:=cpulimit
URL:=https://github.com/opsengine/cpulimit.git
TITLE:=CPU usage limiter
URL:=https://github.com/denji/cpulimit
endef
define Build/Prepare

View File

@ -1,9 +1,10 @@
BINDIR ?= $(PREFIX)/bin
BIN_TARGET = cpulimit
CC ?= gcc
CFLAGS ?= -O2 -Wall -g -D_GNU_SOURCE
CC ?= gcc
CFLAGS ?= -Os -Wall -g -D_GNU_SOURCE
HELP2MAN := $(shell which help2man)
LIBS = list.o process_iterator.o process_group.o
MANDIR ?= $(PREFIX)/share/man/man1
MAN_NAME := "CPU Utilization Limiter"
MAN_SEC := 1
MAN_SRC := $(shell git remote get-url origin)
@ -20,14 +21,21 @@ endif
all:: $(TARGETS) $(LIBS)
static:
$(MAKE) all CFLAGS="$(CFLAGS) --static"
static: $(TARGETS) $(LIBS)
$(MAKE) all CFLAGS="$(CFLAGS) --static" CC="musl-gcc"
touch static
strip: $(BIN_TARGET)
$(STRIP) $<
touch strip
install: $(TARGETS)
$(SUDO) install $^ $(BINDIR)
$(SUDO) install -D $(BIN_TARGET) $(BINDIR)/$(BIN_TARGET)
$(SUDO) install -D $(MAN_TARGET) $(MANDIR)/$(MAN_TARGET)
touch install
static_install: static strip install
touch static_install
$(BIN_TARGET): cpulimit.c $(LIBS)
$(CC) -o cpulimit cpulimit.c $(LIBS) $(CFLAGS)
@ -45,5 +53,5 @@ process_group.o: process_group.c process_group.h process_iterator.o list.o
$(CC) -c process_group.c $(CFLAGS)
clean:
rm -f *~ *.o $(TARGETS)
rm -f *~ *.o static strip install static_install $(TARGETS)

View File

@ -23,7 +23,7 @@
* This is a simple program to limit the cpu usage of a process
* If you modify this code, send me a copy please
*
* Get the latest version at: http://github.com/opsengine/cpulimit
* Get the latest version at: http://github.com/denji/cpulimit
*
*/
@ -38,8 +38,11 @@
#include <string.h>
#include <sys/stat.h>
#include <sys/time.h>
/* This breaks under musl and isn't necessary under glibc
#ifndef __sun__
#include <sys/sysctl.h>
#endif
*/
#include <sys/resource.h>
#include <sys/types.h>
#include <sys/wait.h>
@ -67,14 +70,9 @@
#define MAX(a,b) (((a)>(b))?(a):(b))
#endif
//control time slot in microseconds
//each slot is splitted in a working slice and a sleeping slice
//TODO: make it adaptive, based on the actual system load
#define TIME_SLOT 100000
#define MAX_PRIORITY -10
#define VERSION "0.3"
#define VERSION "0.3.2"
/* GLOBAL VARIABLES */
@ -121,6 +119,7 @@ static void print_usage(FILE *stream, int exit_code) {
fprintf(stream, "Usage: %s [OPTIONS...] TARGET\n", program_name);
fprintf(stream, " OPTIONS\n");
fprintf(stream, " -l, --limit=N percentage of cpu allowed from 0 to %d (required)\n", 100*NCPU);
fprintf(stream, " -c, --chunk-size=N enforce CPU limit in N microsecond chunks\n");
fprintf(stream, " -v, --verbose show control statistics\n");
fprintf(stream, " -V, --version show program version number\n");
fprintf(stream, " -z, --lazy exit if there is no target process, or if it dies\n");
@ -193,7 +192,7 @@ int get_pid_max() {
#endif
}
void limit_process(pid_t pid, double limit, int include_children, float minimum_cpu_usage) {
void limit_process(pid_t pid, double limit, int include_children, float minimum_cpu_usage, int chunk_size) {
//slice of the slot in which the process is allowed to run
struct timespec twork;
//slice of the slot in which the process is stopped
@ -258,13 +257,13 @@ void limit_process(pid_t pid, double limit, int include_children, float minimum_
//it's the 1st cycle, initialize workingrate
pcpu = limit;
workingrate = limit;
twork.tv_nsec = TIME_SLOT * limit * 1000;
twork.tv_nsec = chunk_size * limit * 1000;
} else {
//adjust workingrate
workingrate = MIN(workingrate / pcpu * limit, 1);
twork.tv_nsec = TIME_SLOT * 1000 * workingrate;
twork.tv_nsec = chunk_size * 1000 * workingrate;
}
tsleep.tv_nsec = TIME_SLOT * 1000 - twork.tv_nsec;
tsleep.tv_nsec = chunk_size * 1000 - twork.tv_nsec;
if (verbose) {
if (c%200==0) {
@ -339,6 +338,7 @@ int main(int argc, char **argv) {
pid_t pid = 0;
float minimum_cpu_usage=0;
int include_children = 0;
int chunk_size = 100000;
//get program name
#ifdef __sun__
@ -356,14 +356,15 @@ int main(int argc, char **argv) {
int next_option;
int option_index = 0;
//A string listing valid short options letters
const char *short_options = "+p:e:l:vVzim:h";
const char *short_options = "+p:e:l:c:vVzim:h";
//An array describing valid long options
const struct option long_options[] = {
{ "pid", required_argument, NULL, 'p' },
{ "exe", required_argument, NULL, 'e' },
{ "limit", required_argument, NULL, 'l' },
{ "chunk-size", required_argument, NULL, 'c' },
{ "verbose", no_argument, NULL, 'v' },
{ "version", no_argument, NULL, 'V' },
{ "version", no_argument, NULL, 'V' },
{ "lazy", no_argument, NULL, 'z' },
{ "include-children", no_argument, NULL, 'i' },
{ "minimum-limited-cpu", no_argument, NULL, 'm' },
@ -386,12 +387,15 @@ int main(int argc, char **argv) {
perclimit = atoi(optarg);
limit_ok = 1;
break;
case 'c':
chunk_size = atoi(optarg);
break;
case 'v':
verbose = 1;
break;
case 'V':
print_version(stdout, 0);
break;
case 'V':
print_version(stdout, 0);
break;
case 'z':
lazy = 1;
break;
@ -435,6 +439,12 @@ int main(int argc, char **argv) {
exit(1);
}
if (0 > chunk_size || chunk_size > 1000000) {
fprintf(stderr,"Error: chunk size must be in the range 0-1000000\n");
print_usage(stderr, 1);
exit(1);
}
int command_mode = optind < argc;
if (exe_ok + pid_ok + command_mode == 0) {
fprintf(stderr,"Error: You must specify one target process, either by name, pid, or command line\n");
@ -513,7 +523,7 @@ int main(int argc, char **argv) {
if (verbose) {
printf("Limiting process %d\n",child);
}
limit_process(child, limit, include_children, minimum_cpu_usage);
limit_process(child, limit, include_children, minimum_cpu_usage, chunk_size);
exit(0);
}
}
@ -548,7 +558,7 @@ int main(int argc, char **argv) {
}
printf("Process %d found\n", pid);
//control
limit_process(pid, limit, include_children, minimum_cpu_usage);
limit_process(pid, limit, include_children, minimum_cpu_usage, chunk_size);
}
if (lazy) {
break;

View File

@ -32,7 +32,7 @@
#include <assert.h>
#ifdef __sun__
#include <libgen.h>
#include <libgen.h>
#endif
#include "process_iterator.h"

View File

@ -23,9 +23,10 @@
#include <stdlib.h>
#include <string.h>
#ifdef __sun__
#include <procfs.h>
#include <procfs.h>
#elif !defined __APPLE__
#include <sys/procfs.h>
#include <unistd.h>
#include <sys/procfs.h>
#endif
#include <time.h>
#include "process_iterator.h"
@ -46,7 +47,7 @@
#elif defined __sun__
#include "process_iterator_solaris.c"
#include "process_iterator_solaris.c"
#else

View File

@ -4,7 +4,7 @@
* Copyright (C) 2016 by Jim Mason <jmason at ibinx dot com>
*
* Adapted from process_iterator_linux.c
* Copyright (C) 2005-2012, by: Angelo Marletta <angelo dot marletta at gmail dot com>
* Copyright (C) 2005-2012, by: Angelo Marletta <angelo dot marletta at gmail dot com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@ -22,97 +22,114 @@
*/
int init_process_iterator(struct process_iterator *it, struct process_filter *filter) {
// open a directory stream to /proc directory
if (!(it->dip = opendir("/proc"))) {
perror("opendir");
return -1;
}
it->filter = filter;
return 0;
// open a directory stream to /proc directory
if (!(it->dip = opendir("/proc"))) {
perror("opendir");
return -1;
}
it->filter = filter;
return 0;
}
static int read_process_info(pid_t pid, struct process *p) {
psinfo_t psinfo;
char statfile[32];
psinfo_t psinfo;
char statfile[32];
p->pid = pid;
sprintf(statfile, "/proc/%ld/psinfo", (long)pid);
FILE *fd = fopen(statfile, "r");
if (!fd) return -1;
if (!fread(&psinfo, sizeof(psinfo), 1, fd)) {
fclose(fd);
return -1;
}
fclose(fd);
p->pid = pid;
sprintf(statfile, "/proc/%ld/psinfo", (long)pid);
FILE *fd = fopen(statfile, "r");
if (!fd) {
return -1;
}
if (!fread(&psinfo, sizeof(psinfo), 1, fd)) {
fclose(fd);
return -1;
}
fclose(fd);
p->ppid = psinfo.pr_ppid;
p->cputime = psinfo.pr_time.tv_sec * 1.0e03 + psinfo.pr_time.tv_nsec / 1.0e06;
p->starttime = psinfo.pr_start.tv_sec * 1.0e03 + psinfo.pr_start.tv_nsec / 1.0e06;
strcpy(p->command, psinfo.pr_psargs);
p->ppid = psinfo.pr_ppid;
p->cputime = psinfo.pr_time.tv_sec * 1.0e03 + psinfo.pr_time.tv_nsec / 1.0e06;
p->starttime = psinfo.pr_start.tv_sec * 1.0e03 + psinfo.pr_start.tv_nsec / 1.0e06;
strcpy(p->command, psinfo.pr_psargs);
return 0;
/**
* per proc(4):
*
* If the process is a zombie, pr_nlwp, pr_nzomb, and
* pr_lwp.pr_lwpid are zero and the other fields of pr_lwp
* are undefined
*
* In this case, we'll return -1 to the caller
*/
return psinfo.pr_nlwp?0:-1;
}
static pid_t getppid_of(pid_t pid) {
psinfo_t psinfo;
char statfile[32];
psinfo_t psinfo;
char statfile[32];
sprintf(statfile, "/proc/%ld/psinfo", (long)pid);
FILE *fd = fopen(statfile, "r");
if (!fd) return -1;
if (!fread(&psinfo, sizeof(psinfo), 1, fd)) {
fclose(fd);
return -1;
}
fclose(fd);
sprintf(statfile, "/proc/%ld/psinfo", (long)pid);
FILE *fd = fopen(statfile, "r");
if (!fd) {
return -1;
}
if (!fread(&psinfo, sizeof(psinfo), 1, fd)) {
fclose(fd);
return -1;
}
fclose(fd);
return psinfo.pr_ppid;
return psinfo.pr_ppid;
}
static int is_child_of(pid_t child_pid, pid_t parent_pid) {
int ppid = child_pid;
while(ppid > 1 && ppid != parent_pid)
ppid = getppid_of(ppid);
return ppid == parent_pid;
int ppid = child_pid;
while (ppid > 1 && ppid != parent_pid) {
ppid = getppid_of(ppid);
}
return ppid == parent_pid;
}
int get_next_process(struct process_iterator *it, struct process *p) {
if (!it->dip) {
// end of processes
return -1;
}
if (!it->dip) {
// end of processes
return -1;
}
if (it->filter->pid != 0 && !it->filter->include_children) {
int ret = read_process_info(it->filter->pid, p);
closedir(it->dip);
it->dip = NULL;
return ret;
}
if (it->filter->pid != 0 && !it->filter->include_children) {
int ret = read_process_info(it->filter->pid, p);
closedir(it->dip);
it->dip = NULL;
return ret;
}
// read in from /proc and seek for process dirs
struct dirent *dit;
while ((dit = readdir(it->dip))) {
p->pid = atoi(dit->d_name);
if (it->filter->pid != 0 && it->filter->pid != p->pid && !is_child_of(p->pid, it->filter->pid)) continue;
read_process_info(p->pid, p);
break;
}
// read in from /proc and seek for process dirs
struct dirent *dit;
while ((dit = readdir(it->dip))) {
p->pid = atoi(dit->d_name);
if (it->filter->pid != 0 && it->filter->pid != p->pid && !is_child_of(p->pid, it->filter->pid)) {
continue;
}
if (!read_process_info(p->pid, p)) {
break;
}
}
if (!dit) {
// end of processes
closedir(it->dip);
it->dip = NULL;
return -1;
}
if (!dit) {
// end of processes
closedir(it->dip);
it->dip = NULL;
return -1;
}
return 0;
return 0;
}
int close_process_iterator(struct process_iterator *it) {
if (it->dip && closedir(it->dip) == -1) {
perror("closedir");
return 1;
}
it->dip = NULL;
return 0;
if (it->dip && closedir(it->dip) == -1) {
perror("closedir");
return 1;
}
it->dip = NULL;
return 0;
}

View File

@ -5,42 +5,11 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=luci-app-cpulimit
PKG_VERSION=1.0
PKG_RELEASE:=2
LUCI_TITLE:=cpulimit configuration module
LUCI_DEPENDS:=+cpulimit
include $(INCLUDE_DIR)/package.mk
define Package/$(PKG_NAME)
SECTION:=luci
CATEGORY:=LuCI
SUBMENU:=3. Applications
DEPENDS:=+cpulimit
TITLE:=LuCI support for cpulimit
PKGARCH:=all
endef
include $(TOPDIR)/feeds/luci/luci.mk
define Build/Compile
endef
define Package/$(PKG_NAME)/postinst
#!/bin/sh
rm -f /tmp/luci-indexcache /tmp/luci-modulecache
endef
define Package/$(PKG_NAME)/conffiles
/etc/config/cpulimit
endef
define Package/$(PKG_NAME)/install
$(INSTALL_DIR) $(1)/etc/init.d $(1)/etc/config $(1)/usr/lib/lua/luci
$(CP) ./luasrc/* $(1)/usr/lib/lua/luci
$(INSTALL_CONF) ./root/etc/config/cpulimit $(1)/etc/config
$(INSTALL_BIN) ./root/etc/init.d/cpulimit $(1)/etc/init.d
$(INSTALL_DIR) $(1)/usr/bin
$(INSTALL_BIN) ./root/usr/bin/cpulimit.sh $(1)/usr/bin
$(INSTALL_DIR) $(1)/usr/lib/lua/luci/i18n
po2lmo ./po/zh-cn/cpulimit.po $(1)/usr/lib/lua/luci/i18n/cpulimit.zh-cn.lmo
endef
$(eval $(call BuildPackage,$(PKG_NAME)))
# call BuildPackage - OpenWrt buildroot signature

View File

@ -18,7 +18,7 @@ end
limit = s:option(Value, "limit", translate("limit"))
limit.optional = false
limit.rmempty = false
limit.default="50"
limit.default="30"
limit:value("100","100%")
limit:value("90","90%")
limit:value("80","80%")

View File

@ -0,0 +1,13 @@
#!/bin/sh
uci -q batch <<-EOF >/dev/null
delete ucitrack.@cpulimit[-1]
add ucitrack cpulimit
set ucitrack.@cpulimit[-1].init=cpulimit
commit ucitrack
EOF
/etc/init.d/cpulimit enable
rm -f /tmp/luci-indexcache
exit 0

View File

@ -20,6 +20,8 @@ killall -9 cpulimit
# do
# killall cpulimit>/dev/null 2>&1
# done
# pgrep -f cpulimit | xargs kill -9 >/dev/null 2>&1
}
case "$1" in