Compare commits
No commits in common. "main" and "main" have entirely different histories.
|
@ -1,2 +0,0 @@
|
|||
obsdfreqd
|
||||
*.orig
|
4
Makefile
4
Makefile
|
@ -3,7 +3,8 @@ LDFLAGS = -lm
|
|||
|
||||
CFLAGS += -pedantic -Wall -Wextra -Wmissing-prototypes \
|
||||
-Wunused-function -Wshadow -Wstrict-overflow -fno-strict-aliasing \
|
||||
-Wunused-variable -Wstrict-prototypes -Wwrite-strings -O2
|
||||
-Wunused-variable -Wstrict-prototypes -Wwrite-strings \
|
||||
-Os
|
||||
|
||||
obsdfreqd: main.c
|
||||
${CC} ${CFLAGS} ${LDFLAGS} main.c -o $@
|
||||
|
@ -15,4 +16,5 @@ clean:
|
|||
|
||||
install: obsdfreqd
|
||||
install -o root -g wheel -m 555 obsdfreqd ${PREFIX}/sbin/obsdfreqd
|
||||
install -o root -g wheel -m 555 obsdfreqd.rc ${DESTDIR}/etc/rc.d/obsdfreqd
|
||||
install -o root -g wheel -m 444 obsdfreqd.1 ${PREFIX}/man/man1/obsdfreqd.1
|
||||
|
|
35
README.md
35
README.md
|
@ -1,20 +1,15 @@
|
|||
# Project moved
|
||||
|
||||
Due to technical issues with tildegit.org, the project moved to sourcehut.
|
||||
|
||||
- New upstream URL: https://git.sr.ht/~solene/obsdfreqd
|
||||
|
||||
# obsdfreqd
|
||||
|
||||
Userland CPU frequency scheduling for OpenBSD >= 7.1
|
||||
|
||||
# TLDR
|
||||
|
||||
- `pkg_add obsdfreqd`
|
||||
- clone this repository
|
||||
- as root `make install`
|
||||
- as root `rcctl enable obsdfreqd` and `rcctl stop apmd ; rcctl disable apmd`
|
||||
- as root `rcctl start obsdfreqd`
|
||||
- apmd can be kept but not with flag `-A`
|
||||
- if any tuning is needed, it may be `-T` for temperature limit
|
||||
- most interesting flag for end users is `-T`
|
||||
|
||||
# Compilation
|
||||
|
||||
|
@ -24,25 +19,10 @@ As easy as `make`
|
|||
|
||||
Run `obsdfreqd` as root, quit with `Ctrl+C`.
|
||||
|
||||
# Source installation
|
||||
# Installation
|
||||
|
||||
`make install` as root, enable the service using `rcctl enable obsdfreqd`.
|
||||
|
||||
Create `/etc/rc.d/obsdfreqd` with this content and make it executable:
|
||||
|
||||
```
|
||||
#!/bin/ksh
|
||||
|
||||
daemon="/usr/local/sbin/obsdfreqd"
|
||||
|
||||
. /etc/rc.d/rc.subr
|
||||
|
||||
pexp="${daemon}.*"
|
||||
rc_reload=NO
|
||||
rc_bg=YES
|
||||
|
||||
rc_cmd $1
|
||||
```
|
||||
`make install` as root, enable the service using `rcctl enable
|
||||
obsdfreqd`.
|
||||
|
||||
Start the service with `rcctl start obsdfreqd`.
|
||||
|
||||
|
@ -58,11 +38,10 @@ Parameters are applied when both plugged on the wall or on battery, parameters c
|
|||
- `-i inertia` sets the number of cycles after which the frequency will decay, 0 is the default
|
||||
- `-m maxfrequency` sets the maximum frequency the CPU can reach in percent, 100% is default
|
||||
- `-l minfrequency` sets the minimum frequency the CPU must be lowered to, 0% is default
|
||||
- `-r threshold` sets the CPU usage in % that will trigger the frequency increase, defaults to 80% of a single core.
|
||||
- `-r threshold` sets the CPU usage in % that will trigger the frequency increase, 30% is the default
|
||||
- `-s stepfrequency` sets the percent of frequency added every cycle when increasing, 10% is default
|
||||
- `-t timefreq` sets the milliseconds between each poll, 300 is the default
|
||||
- `-T maxtemperature` sets the temperature threshold under which the maximum frequency will be temporary lowered until the CPU cools down
|
||||
- `-S sensor` specify a sensor (using its sysctl path) to use with `-T`
|
||||
|
||||
**Example**:
|
||||
|
||||
|
|
361
main.c
361
main.c
|
@ -11,28 +11,6 @@
|
|||
#include <signal.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <sys/errno.h>
|
||||
#include <assert.h>
|
||||
#include <syslog.h>
|
||||
|
||||
/* I have to redefined this because obsdfreqd is compiled with
|
||||
-Wall and I don't know of a compiler agnostic way to disable
|
||||
warnings, and I don't want to assume `cc' is clang forever */
|
||||
struct ctlnameconst {
|
||||
const char* ctl_name; /* struct ctlname has this nonconst */
|
||||
int ctl_type;
|
||||
};
|
||||
#if __STDC_VERSION__ >= 201112L
|
||||
/* be polite to maintainers and give them a better compile error */
|
||||
# include <stddef.h> /* offsetof */
|
||||
static_assert(sizeof(struct ctlnameconst) == sizeof(struct ctlname),
|
||||
"struct ctlname changed, update ctlnameconst");
|
||||
static_assert(offsetof(struct ctlnameconst, ctl_name) == offsetof(struct ctlname, ctl_name),
|
||||
"struct ctlname changed, update ctlnameconst");
|
||||
static_assert(offsetof(struct ctlnameconst, ctl_type) == offsetof(struct ctlname, ctl_type),
|
||||
"struct ctlname changed, update ctlnameconst");
|
||||
#endif
|
||||
|
||||
int hard_min_freq, batt_min, wall_min;
|
||||
int hard_max_freq, batt_max, wall_max;
|
||||
|
@ -45,114 +23,28 @@ int temp_max, batt_tmax, wall_tmax;
|
|||
int verbose = 0;
|
||||
int max;
|
||||
|
||||
/* sysctl path to the temperature sensor we're tracking */
|
||||
int temperature_mib[5];
|
||||
/* if false(0), get_temp() will error out */
|
||||
int temperature_sensor_found;
|
||||
|
||||
void try_to_find_default_temperature_sensor(void);
|
||||
int get_temp(void);
|
||||
int get_cpu_online(void);
|
||||
void set_policy(const char*);
|
||||
void quit_gracefully(int signum);
|
||||
void usage(void);
|
||||
void switch_wall(void);
|
||||
void switch_batt(void);
|
||||
void assign_values_from_param(char*, int*, int*);
|
||||
void parse_sensor_path(char*);
|
||||
|
||||
/* heuristics to find a good temperature sensor */
|
||||
void try_to_find_default_temperature_sensor(void) {
|
||||
/* pick the first temperature sensor, but...
|
||||
bonify devices named `cpuN'
|
||||
TODO and we should probably blacklist devices like:
|
||||
- GPU temperature sensors
|
||||
- battery temperature sensors
|
||||
- UPS temperature sensors
|
||||
...just in case the CPU thermometer is not cpu0, or,
|
||||
for some bizzare reason, there is no CPU thermometer.
|
||||
|
||||
There may be other strange cases, like OpenBSD running
|
||||
on a Raspberry PI where I can connect an external
|
||||
temperature sensor and sensor_install that; but I have
|
||||
a feeling external thermometers would be at the very end */
|
||||
int dev = 0;
|
||||
|
||||
temperature_mib[0] = CTL_HW;
|
||||
temperature_mib[1] = HW_SENSORS;
|
||||
for(dev = 0; ; ++dev) {
|
||||
struct sensordev sensordev;
|
||||
size_t sensordevlen = sizeof(struct sensordev);
|
||||
memset(&sensordev, 0, sizeof(struct sensordev));
|
||||
temperature_mib[2] = dev;
|
||||
if(-1 == sysctl(
|
||||
temperature_mib, 3,
|
||||
&sensordev, &sensordevlen,
|
||||
NULL, 0)
|
||||
) {
|
||||
/* end of array */
|
||||
break;
|
||||
}
|
||||
|
||||
/* does it have temperature sensors? */
|
||||
if(sensordev.maxnumt[SENSOR_TEMP] <= 0) {
|
||||
/* no */
|
||||
continue;
|
||||
}
|
||||
|
||||
/* potentially use this */
|
||||
if(!temperature_sensor_found) {
|
||||
temperature_sensor_found = 1;
|
||||
temperature_mib[2] = sensordev.num;
|
||||
temperature_mib[3] = SENSOR_TEMP;
|
||||
temperature_mib[4] = 0;
|
||||
}
|
||||
|
||||
/* is it called cpuSOMETHING? */
|
||||
if(strncmp(sensordev.xname, "cpu", 3) == 0) {
|
||||
/* definitely use this! */
|
||||
temperature_sensor_found = 1;
|
||||
temperature_mib[2] = sensordev.num;
|
||||
temperature_mib[3] = SENSOR_TEMP;
|
||||
temperature_mib[4] = 0;
|
||||
/* stop here, this is our best candidate */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(verbose) {
|
||||
if(!temperature_sensor_found) {
|
||||
fprintf(stderr, "Could not find any temperature sensors.\n");
|
||||
} else {
|
||||
/* we need to get the device name again in order to print it */
|
||||
struct sensordev sensordev;
|
||||
size_t sensordevlen = sizeof(struct sensordev);
|
||||
memset(&sensordev, 0, sizeof(struct sensordev));
|
||||
if(0 == sysctl(temperature_mib, 3, &sensordev, &sensordevlen, NULL, 0)) {
|
||||
fprintf(stderr,
|
||||
"Using hw.sensors.%s.temp%d as the temperature sensor\n",
|
||||
sensordev.xname,
|
||||
temperature_mib[4]);
|
||||
} else {
|
||||
/* panic? */
|
||||
err(1, "Failed to read sensordev a second time?");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int get_temp() {
|
||||
struct sensor sensor;
|
||||
int mib[5];
|
||||
int value = 0;
|
||||
size_t len = sizeof(sensor);
|
||||
|
||||
if (!temperature_sensor_found) {
|
||||
errno = ENOENT;
|
||||
err(1, "no temperature sensor");
|
||||
}
|
||||
mib[0] = CTL_HW;
|
||||
mib[1] = HW_SENSORS;
|
||||
mib[2] = 0;
|
||||
mib[3] = SENSOR_TEMP;
|
||||
mib[4] = 0;
|
||||
|
||||
if (sysctl(temperature_mib, 5, &sensor, &len, NULL, 0) == -1)
|
||||
err(1, "failed to read temperature");
|
||||
if (sysctl(mib, 5, &sensor, &len, NULL, 0) == -1)
|
||||
err(1, "sysctl to get temperature");
|
||||
|
||||
// convert from uK to C
|
||||
value = (sensor.value - 273150000) / 1000 / 1000;
|
||||
|
@ -160,21 +52,6 @@ int get_temp() {
|
|||
return(value);
|
||||
}
|
||||
|
||||
/* get the number of online CPUs */
|
||||
int get_cpu_online(void) {
|
||||
int mib_cpu[2] = { CTL_HW, HW_NCPUONLINE };
|
||||
int ncpu = 1;
|
||||
size_t len_ncpu = sizeof(len_ncpu);
|
||||
|
||||
if (sysctl(mib_cpu, 2, &ncpu, &len_ncpu, NULL, 0) == -1)
|
||||
err(1, "sysctl");
|
||||
|
||||
if (ncpu <= 0)
|
||||
err(1, "cpuonline detection");
|
||||
|
||||
return(ncpu);
|
||||
}
|
||||
|
||||
/* define the policy to auto or manual */
|
||||
void set_policy(const char* policy) {
|
||||
int mib[2] = { CTL_HW, HW_PERFPOLICY };
|
||||
|
@ -185,39 +62,13 @@ void set_policy(const char* policy) {
|
|||
|
||||
/* restore policy auto upon exit */
|
||||
void quit_gracefully(int signum) {
|
||||
char message[48];
|
||||
|
||||
strncpy(message, "Caught signal ", 14);
|
||||
|
||||
switch(signum) {
|
||||
case SIGINT:
|
||||
strncat(message, "SIGINT", 6);
|
||||
break;
|
||||
case SIGTERM:
|
||||
strncat(message, "SIGTERM", 7);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
strncat(message, ", set auto policy\n", 18);
|
||||
|
||||
if (isatty(STDERR_FILENO)) {
|
||||
write(STDERR_FILENO, message, strlen(message));
|
||||
} else {
|
||||
struct syslog_data data = SYSLOG_DATA_INIT;
|
||||
syslog_r(LOG_DAEMON|LOG_INFO, &data, "%s", message);
|
||||
}
|
||||
|
||||
printf("Caught signal %d, set auto policy\n", signum);
|
||||
set_policy("auto");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
void usage(void) {
|
||||
fprintf(stderr,
|
||||
"obsdfreqd [-hv] [-d downstepfrequency] [-i inertia] [-m maxfrequency]\n"
|
||||
" [-l minfrequency] [-r threshold] [-s stepfrequency]\n"
|
||||
" [-t timefreq] [-T maxtemperature [-S sensorpath]]\n");
|
||||
printf("obsdfreqd [-h] [-v] [-i cycles] [-l min_freq] [-m max_freq] [-d percent_down_freq_step] [-r threshold] [-s percent_freq_step] [-t milliseconds]\n");
|
||||
}
|
||||
|
||||
/* switch to wall profile */
|
||||
|
@ -247,15 +98,9 @@ void switch_batt() {
|
|||
/* assign values to variable if comma separated
|
||||
* if not, assign value to two variables
|
||||
*/
|
||||
void assign_values_from_param(char* parameterk, int* charging, int* battery) {
|
||||
char *parameter = strdup(parameterk);
|
||||
void assign_values_from_param(char* parameter, int* charging, int* battery) {
|
||||
int count = 0;
|
||||
char *token = NULL;
|
||||
|
||||
if(parameter == NULL)
|
||||
err(1, "malloc failed");
|
||||
|
||||
token = strtok(parameter, ",");
|
||||
char *token = strtok(parameter, ",");
|
||||
|
||||
while (token != NULL) {
|
||||
if(count == 0)
|
||||
|
@ -275,157 +120,8 @@ void assign_values_from_param(char* parameterk, int* charging, int* battery) {
|
|||
|
||||
if(count == 1)
|
||||
*battery = *charging;
|
||||
|
||||
free(parameter);
|
||||
}
|
||||
|
||||
/* parse optarg for a sensor path, sysctl style;
|
||||
* expecting hw.sensors.*.temp*;
|
||||
* sets temperature_mid and temperature_sensor_found
|
||||
* IFF it's a valid path, else sets errno to something
|
||||
* relevant.
|
||||
*/
|
||||
void parse_sensor_path(char* pathk) {
|
||||
const struct ctlnameconst ctlnames[] = CTL_NAMES;
|
||||
const struct ctlnameconst ctlhwnames[] = CTL_HW_NAMES;
|
||||
const size_t prefix_len =
|
||||
/*hw*/strlen(ctlnames[CTL_HW].ctl_name) +
|
||||
/*.*/1 +
|
||||
/*sensors*/strlen(ctlhwnames[HW_SENSORS].ctl_name) +
|
||||
/*.*/1;
|
||||
char* path = NULL;
|
||||
char* prefix = NULL;
|
||||
/* these are pointers into optarg */
|
||||
char* sensordevname = NULL, *sensortype = NULL, *sensornumts = NULL;
|
||||
int sensornumt = -1;
|
||||
const size_t tempslen = strlen(sensor_type_s[SENSOR_TEMP]);
|
||||
const char* errstr = NULL;
|
||||
int dev = 0;
|
||||
|
||||
path = strdup(pathk);
|
||||
if(path == NULL)
|
||||
err(1, "malloc failed");
|
||||
|
||||
prefix = malloc(prefix_len + 1);
|
||||
if(prefix == NULL)
|
||||
err(1, "malloc failed");
|
||||
|
||||
memset(prefix, 0, prefix_len + 1);
|
||||
strcpy(prefix, ctlnames[CTL_HW].ctl_name);
|
||||
strcat(prefix, ".");
|
||||
strcat(prefix, ctlhwnames[HW_SENSORS].ctl_name);
|
||||
strcat(prefix, ".");
|
||||
|
||||
/* we only allow hw.sensors...; everything else is irrelevant */
|
||||
if(strncmp(path, prefix, prefix_len) != 0) {
|
||||
if(verbose)
|
||||
fprintf(stderr,
|
||||
"Valid temperature sensors start with %s\n"
|
||||
"Run `sysctl -a' to find sensors",
|
||||
prefix);
|
||||
errno = EINVAL;
|
||||
goto badprefix;
|
||||
}
|
||||
|
||||
|
||||
/* parse sensordevname and tail */
|
||||
sensordevname = path + prefix_len;
|
||||
sensortype = strchr(sensordevname, '.');
|
||||
if(!sensortype) {
|
||||
if(verbose)
|
||||
fprintf(stderr,
|
||||
"Valid sensor names are of the form hw.sensors.device.temp42\n"
|
||||
"for example hw.sensors.cpu0.temp0\n");
|
||||
errno = EINVAL;
|
||||
goto badprefix;
|
||||
}
|
||||
*sensortype++ = '\0'; /* save sensordevname, we need to find it later */
|
||||
|
||||
/* assert tail strats with "temp" */
|
||||
if(strncmp(sensortype, sensor_type_s[SENSOR_TEMP], tempslen) != 0) {
|
||||
if(verbose)
|
||||
fprintf(stderr,
|
||||
"%s does not look like a temperature sensor\n",
|
||||
path);
|
||||
errno = EINVAL;
|
||||
goto badprefix;
|
||||
}
|
||||
|
||||
/* convert remaining string to number = numt */
|
||||
sensornumts = sensortype + tempslen;
|
||||
sensornumt = strtonum(sensornumts, 0, INT_MAX, &errstr);
|
||||
if(errstr != NULL) {
|
||||
if(verbose)
|
||||
fprintf(stderr,
|
||||
"%s does not look like a temperature sensor\n",
|
||||
pathk);
|
||||
errno = EINVAL;
|
||||
goto badprefix;
|
||||
}
|
||||
|
||||
/* the string format looks good, now let's see if we can actually
|
||||
find the sensor */
|
||||
temperature_mib[0] = CTL_HW;
|
||||
temperature_mib[1] = HW_SENSORS;
|
||||
/* this is a NULL terminated array of sensordev's */
|
||||
for(dev = 0; ; ++dev) {
|
||||
struct sensordev sensordev;
|
||||
size_t sensordevlen = sizeof(struct sensordev);
|
||||
|
||||
memset(&sensordev, 0, sizeof(struct sensordev));
|
||||
temperature_mib[2] = dev;
|
||||
if(-1 == sysctl(
|
||||
temperature_mib, 3,
|
||||
&sensordev, &sensordevlen,
|
||||
NULL, 0)
|
||||
) {
|
||||
/* probably end of array; sysctl sets errno to ENOENT */
|
||||
/* the man page doesn't say what other errno's it could
|
||||
set, so let's assume it *is* ENOENT */
|
||||
if(verbose)
|
||||
/* using warn to print errno in case it wasn't ENOENT */
|
||||
warn("No such sensor device: %s\n", sensordevname);
|
||||
goto badprefix;
|
||||
}
|
||||
|
||||
assert(sensordevlen == sizeof(struct sensordev));
|
||||
|
||||
if(strcmp(sensordevname, sensordev.xname) == 0) {
|
||||
/* found it; before we yield success, check if it has
|
||||
a temperature sensor */
|
||||
if(sensornumt >= sensordev.maxnumt[SENSOR_TEMP]) {
|
||||
/* no dice */
|
||||
if(verbose)
|
||||
fprintf(stderr,
|
||||
"temp%d is out of range, max is temp%d\n",
|
||||
sensornumt,
|
||||
sensordev.maxnumt[SENSOR_TEMP]);
|
||||
errno = ENOENT;
|
||||
goto badprefix;
|
||||
}
|
||||
temperature_mib[2] = sensordev.num;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* okay, we have it; finish populating mib and claim we're done */
|
||||
temperature_mib[3] = SENSOR_TEMP;
|
||||
temperature_mib[4] = sensornumt;
|
||||
temperature_sensor_found = 1;
|
||||
|
||||
if(verbose) {
|
||||
fprintf(stderr,
|
||||
"Using hw.sensors.%s.temp%d as the temperature sensor\n",
|
||||
sensordevname,
|
||||
sensornumt);
|
||||
}
|
||||
|
||||
badprefix:
|
||||
free(prefix);
|
||||
free(path);
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
|
||||
int opt;
|
||||
|
@ -441,17 +137,11 @@ int main(int argc, char *argv[]) {
|
|||
int cpu_usage_percent = 0, cpu_usage;
|
||||
float temp;
|
||||
size_t len, len_cpu;
|
||||
int ncpu;
|
||||
|
||||
ncpu = get_cpu_online();
|
||||
|
||||
// battery defaults
|
||||
hard_min_freq = batt_min= 0;
|
||||
hard_max_freq = batt_max= 100;
|
||||
|
||||
// threshold defaults to 80% usage of one CPU
|
||||
threshold = batt_threshold= floor(100/ncpu*0.8);
|
||||
|
||||
threshold = batt_threshold= 30;
|
||||
down_step = batt_down_step= 100;
|
||||
inertia = batt_inertia= 5;
|
||||
step = batt_step= 100;
|
||||
|
@ -472,7 +162,7 @@ int main(int argc, char *argv[]) {
|
|||
err(1, "unveil failed");
|
||||
unveil(NULL, NULL);
|
||||
|
||||
while((opt = getopt(argc, argv, "d:hi:l:m:r:s:S:t:T:v")) != -1) {
|
||||
while((opt = getopt(argc, argv, "d:hi:l:m:r:s:t:T:v")) != -1) {
|
||||
switch(opt) {
|
||||
case 'd':
|
||||
assign_values_from_param(optarg, &wall_down_step, &batt_down_step);
|
||||
|
@ -486,14 +176,12 @@ int main(int argc, char *argv[]) {
|
|||
break;
|
||||
case 'l':
|
||||
assign_values_from_param(optarg, &wall_min, &batt_min);
|
||||
if(wall_min > 100 || wall_min < 0 ||
|
||||
batt_min > 100 || batt_min < 0)
|
||||
if(hard_min_freq > 100 || hard_min_freq < 0)
|
||||
err(1, "minimum frequency must be between 0 and 100");
|
||||
break;
|
||||
case 'm':
|
||||
assign_values_from_param(optarg, &wall_max, &batt_max);
|
||||
if(wall_max > 100 || wall_max < 0 ||
|
||||
batt_max > 100 || batt_max < 0)
|
||||
if(hard_max_freq > 100 || hard_max_freq < 0)
|
||||
err(1, "maximum frequency must be between 0 and 100");
|
||||
break;
|
||||
case 'v':
|
||||
|
@ -509,11 +197,6 @@ int main(int argc, char *argv[]) {
|
|||
if(step > 100 || step <= 0)
|
||||
err(1, "step must be positive and up to 100");
|
||||
break;
|
||||
case 'S':
|
||||
parse_sensor_path(optarg);
|
||||
if(!temperature_sensor_found)
|
||||
err(1, "invalid temperature sensor");
|
||||
break;
|
||||
case 't':
|
||||
assign_values_from_param(optarg, &wall_timefreq, &batt_timefreq);
|
||||
if(wall_timefreq <= 0 || batt_timefreq <= 0)
|
||||
|
@ -550,18 +233,6 @@ int main(int argc, char *argv[]) {
|
|||
}
|
||||
}
|
||||
|
||||
/* initialize default temp sensor if we need to */
|
||||
if(temp_max > 0 && !temperature_sensor_found) {
|
||||
try_to_find_default_temperature_sensor();
|
||||
}
|
||||
|
||||
/* warn if -S was specified, but not -T */
|
||||
if(temp_max <= 0 && temperature_sensor_found) {
|
||||
errno = EINVAL;
|
||||
warn("you have specified a temperature sensor without setting\ntemperature limits with -T");
|
||||
errno = 0;
|
||||
}
|
||||
|
||||
/* avoid weird reading for first delta */
|
||||
if (sysctl(mib_load, 2, &cpu_previous, &len_cpu, NULL, 0) == -1)
|
||||
err(1, "sysctl");
|
||||
|
|
70
obsdfreqd.1
70
obsdfreqd.1
|
@ -6,18 +6,18 @@
|
|||
.Nd manage the CPU frequency on OpenBSD from userland
|
||||
.Sh SYNOPSIS
|
||||
.Nm
|
||||
.Op Fl hv
|
||||
.Op Fl v
|
||||
.Op Fl h
|
||||
.Op Fl d Ar downstepfrequency
|
||||
.Op Fl i Ar inertia
|
||||
.Op Fl m Ar maxfrequency
|
||||
.Op Fl l Ar minfrequency
|
||||
.Op Fl r Ar threshold
|
||||
.Op Fl s Ar stepfrequency
|
||||
.Op Fl t Ar timefrequency
|
||||
.Oo Fl T Ar maxtemperature
|
||||
.Op Fl S Ar sensorpath
|
||||
.Oc
|
||||
.Op Fl t Ar timefreq
|
||||
.Op Fl T Ar maxtemperature
|
||||
.Sh DESCRIPTION
|
||||
.Pp
|
||||
.Nm
|
||||
is a program to play with the CPU frequency scheduler by providing
|
||||
many variables involved in the process.
|
||||
|
@ -25,54 +25,51 @@ many variables involved in the process.
|
|||
will switch the frequency policy to manual to manage the frequency itself
|
||||
and will restore the policy to auto upon exit.
|
||||
.Sh OPTIONS
|
||||
Arguments can be comma separated to provide different values for when on
|
||||
battery, if so, the first value is used when power plug is connected and second
|
||||
value when on battery.
|
||||
.Bl -tag -width Ds
|
||||
.It Fl v
|
||||
Arguments can be comma separated to provide different values for when on battery,
|
||||
if so, the first value is used when power plug is connected and second value
|
||||
when on battery.
|
||||
.Bl -tag -width
|
||||
.It Op Fl v
|
||||
Enable verbose output in CSV format.
|
||||
.It Fl h
|
||||
.It Op Fl h
|
||||
Display usage
|
||||
.It Fl d Ar downstepfrequency
|
||||
.It Op Fl d Ar downstepfrequency
|
||||
Defines the frequency decrease step in percent.
|
||||
.It Fl i Ar inertia
|
||||
Defines the number of cycles under the CPU threshold before decreasing
|
||||
frequency.
|
||||
.It Fl m Ar maxfrequency
|
||||
.It Op Fl i Ar inertia
|
||||
Defines the number of cycles under the CPU threshold before decreasing frequency.
|
||||
.It Op Fl m Ar maxfrequency
|
||||
Defines the maximum frequency in percent the CPU can be increased to.
|
||||
.It Fl l Ar minfrequency
|
||||
.It Op Fl l Ar minfrequency
|
||||
Defines the minimum frequency in percent the CPU can be reduced to.
|
||||
.It Fl r Ar threshold
|
||||
.It Op Fl r Ar threshold
|
||||
Defines the CPU usage in percent above which the frequency is increased.
|
||||
The default is to use a value that match the usage of 80% of a single core.
|
||||
Example: for a 4 CPU system, the threshold will be 100/4*0.8 = 20%
|
||||
.It Fl s Ar stepfrequency
|
||||
.It Op Fl s Ar stepfrequency
|
||||
Defines the frequency increase step in percent.
|
||||
.It Fl t Ar timefrequency
|
||||
.It Op Fl t Ar timefreq
|
||||
Defines the time in milliseconds between each cycle.
|
||||
.It Fl T Ar maxtemperature
|
||||
.It Op Fl T Ar maxtemperature
|
||||
Defines the maximum temperature in Celcius
|
||||
.Nm
|
||||
will allow before lowering the maximum frequency until the temperature
|
||||
will allow before lowering the maximum frequency until it the temperature
|
||||
cooled down.
|
||||
.It Fl S Ar sensorpath
|
||||
In conjunction with
|
||||
.Sy -T,
|
||||
.No allows you to specify which sensor to use for temperature readings. If unspecified,
|
||||
.Nm
|
||||
will try to guess which temperature sensor to use (usually hw.sensors.cpu0.temp0).
|
||||
.El
|
||||
.Ed
|
||||
.Sh EXIT STATUS
|
||||
.Ex
|
||||
.Pp
|
||||
In case of a fatal error,
|
||||
.Nm
|
||||
will exit on a status code 1.
|
||||
In normal operations,
|
||||
.Nm
|
||||
will exit on a status code 0.
|
||||
.Sh EXAMPLES
|
||||
Temperature throttling at 50°C
|
||||
This is a balanced power profile.
|
||||
.Bd -literal -offset indent
|
||||
obsdfreqd -T 50
|
||||
obsdfreqd -t 150 -r 30 -d 10 -i 2
|
||||
.Ed
|
||||
.Pp
|
||||
Temperature throttling at 50°C using sensor hw.sensors.acpithinkpad0.temp0
|
||||
Use different values for when on battery to save power.
|
||||
.Bd -literal -offset indent
|
||||
obsdfreqd -T 50 -S hw.sensors.acpithinkpad0.temp0
|
||||
obsdfreqd -m 100,60 -r 25,40 -t 90,300 -d 10,100 -i 10,0
|
||||
.Ed
|
||||
.Sh DIAGNOSTICS
|
||||
.Nm
|
||||
|
@ -82,6 +79,7 @@ has a verbose mode to get realtime information about frequency.
|
|||
.Sh LICENSE
|
||||
See the LICENSE file for the terms of redistribution.
|
||||
.Sh BUGS
|
||||
.Pp
|
||||
When set to run a startup, if you also start the
|
||||
.Xr apmd 8
|
||||
service, make sure to start it with
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
#!/bin/ksh
|
||||
|
||||
daemon="/usr/local/sbin/obsdfreqd"
|
||||
|
||||
. /etc/rc.d/rc.subr
|
||||
|
||||
pexp="${daemon}.*"
|
||||
rc_reload=NO
|
||||
rc_bg=YES
|
||||
|
||||
rc_cmd $1
|
Reference in New Issue