On Mon, 24 Jun 2019 13:02:52 +0200 Benjamin Baier <program...@netzbasis.de> wrote:
> Hi, > > this is wip for a new sysctl that implements gpu throttling. > Only implemented for inteldrm right now, and tested on a single amd64 > laptop. Helps to keep the GPU/CPU cooler and save some energy. > > Most of the diff is for sensors to verify if the sysctl works, and will > be removed once i'm confident enought. > > Some notes from my x220 with integrated intel graphics (HD3000): > - min gpu freq: 650 MHz > - max gpu freq: 1300 MHz > Setting hw.gpuperf to anything > 10 (max. 700 MHz) will eventually run > into thermal throttling (GPU temp 96 deg C). > Setting hw.gpuperf=0 (650MHz) will run Youtube video and browser games > together fine, and reduce GPU/CPU temp from 96 deg C to about 80 - 86 deg C. > > thoughts? tests? > > Greetings Ben Thanks, for the feedback. Updated diff below. Seems to work without regressions so far on at least HD3000 (Sandy Bridge), HD4400 (Haswell), HD510 (Skylake), HD405 (Atom x7). My findings of reduced temps where also replicated. === This implements a new sysctl hw.gpuperf. This will throttle down your graphic card for better thermal and energy management. Unlike hw.setperf which sets a fixed CPU clock, hw.gpuperf will limit the max. clock the GPU is allowed to reach. So it will still downclock while idle even at hw.gpuperf=100. Patch Version 2 Patch apply directions have changed Includes man page change Header cleanup Patch Version 1 Throttle down to base freq on haswell & broadwell Remove sensors, use debug printf Need: OpenBSD-current source code Only implemented for intel graphic (atm.) To apply: cd /usr/src && patch < gpuperf.diff Rebuild and install a new kernel: KK=`sysctl -n kern.osversion | cut -d# -f1` cd /usr/src/sys/arch/`machine`/compile/$KK make obj make config make make install Rebuild and install a new sysctl: cp /usr/src/sys/sys/sysctl.h /usr/include/sys/ cd /usr/src/sbin/sysctl make obj make make install Test various sysctl hw.gpuperf settings (0, 10, ..., 100) Send output of: dmesg | grep -e gpuperf -e inteldrm -e cpu0 and test results/feedback to program...@netzbasis.de Wed Jun 26 12:16:25 CEST 2019 /home/cvsgit/hellfish/src Index: lib/libc/sys/sysctl.2 =================================================================== RCS file: /cvs/src/lib/libc/sys/sysctl.2,v retrieving revision 1.27 diff -u -p -r1.27 sysctl.2 --- lib/libc/sys/sysctl.2 9 May 2019 15:05:47 -0000 1.27 +++ lib/libc/sys/sysctl.2 26 Jun 2019 10:09:56 -0000 @@ -282,6 +282,7 @@ privileges may change the value. .It Dv HW_DISKCOUNT Ta "integer" Ta "no" .It Dv HW_DISKNAMES Ta "string" Ta "no" .It Dv HW_DISKSTATS Ta "struct" Ta "no" +.It Dv HW_GPUPERF Ta "integer" Ta "yes" .It Dv HW_MACHINE Ta "string" Ta "no" .It Dv HW_MODEL Ta "string" Ta "no" .It Dv HW_NCPU Ta "integer" Ta "no" @@ -324,6 +325,10 @@ A comma-separated list of disk names. An array of .Vt struct diskstats structures containing disk statistics. +.It Dv HW_GPUPERF Pq Va hw.gpuperf +Maximum GPU performance +.Pq percentage . +Only for supported hardware. .It Dv HW_MACHINE Pq Va hw.machine The machine class. .It Dv HW_MODEL Pq Va hw.model Index: sys/conf/files =================================================================== RCS file: /cvs/src/sys/conf/files,v retrieving revision 1.671 diff -u -p -r1.671 files --- sys/conf/files 4 May 2019 11:34:47 -0000 1.671 +++ sys/conf/files 25 Jun 2019 20:21:29 -0000 @@ -710,6 +710,7 @@ file kern/subr_autoconf.c file kern/subr_disk.c file kern/subr_evcount.c file kern/subr_extent.c +file kern/subr_gpuperf.c inteldrm file kern/subr_hibernate.c hibernate file kern/subr_kubsan.c kubsan file kern/subr_log.c Index: sys/dev/pci/drm/i915/i915_drv.c =================================================================== RCS file: /cvs/src/sys/dev/pci/drm/i915/i915_drv.c,v retrieving revision 1.118 diff -u -p -r1.118 i915_drv.c --- sys/dev/pci/drm/i915/i915_drv.c 8 May 2019 15:55:56 -0000 1.118 +++ sys/dev/pci/drm/i915/i915_drv.c 25 Jun 2019 20:21:29 -0000 @@ -46,6 +46,10 @@ #include <drm/drm_atomic_helper.h> #include <drm/i915_drm.h> +#ifdef __OpenBSD__ +#include <sys/gpuperf.h> +#endif /* __OpenBSD__ */ + #include "i915_drv.h" #include "i915_trace.h" #include "i915_pmu.h" @@ -3668,12 +3672,54 @@ inteldrm_attachhook(struct device *self) config_found_sm(self, &aa, wsemuldisplaydevprint, wsemuldisplaydevsubmatch); + +#ifdef __OpenBSD__ + gpuperf_register(dev_priv->sc_dev.dv_xname, + inteldrm_set_gpuperf, dev_priv); +#endif /* __OpenBSD__ */ + return; fail: inteldrm_fatal_error = 1; inteldrm_forcedetach(dev_priv); } + +#ifdef __OpenBSD__ +#define GPUPERF_DEBUG +#ifdef GPUPERF_DEBUG +#define PPRINTF(x...) do { printf(x); } while(0) +#else +#define PPRINTF(x...) +#endif /* GPUPERF_DEBUG */ +int +inteldrm_set_gpuperf(int level, void *arg) +{ + struct inteldrm_softc *dev_priv = arg; + struct intel_rps *rps = &dev_priv->gt_pm.rps; + u_int32_t min = rps->min_freq; + u_int32_t max = rps->max_freq; + + if (max <= min) + return (-1); + + PPRINTF("inteldrm: min %u, max %u, min_s %u, max_s %u, b %u, act %d MHz\n", + min, max, rps->min_freq_softlimit, rps->max_freq_softlimit, + rps->boost_freq, intel_gpu_freq(dev_priv, rps->cur_freq)); + + rps->max_freq_softlimit = (u8)((((max - min) * level) / 100) + min); + rps->boost_freq = rps->max_freq_softlimit; + + if (rps->min_freq_softlimit > min) { + PPRINTF("inteldrm: override min_s (%u > %u). haswell or broadwell\n", + rps->min_freq_softlimit, min); + rps->min_freq_softlimit = min; + } + + /* returning gpu freq, before new performance setting takes effect */ + return (intel_gpu_freq(dev_priv, rps->cur_freq)); +} +#endif /* __OpenBSD__ */ int inteldrm_detach(struct device *self, int flags) Index: sys/dev/pci/drm/i915/i915_drv.h =================================================================== RCS file: /cvs/src/sys/dev/pci/drm/i915/i915_drv.h,v retrieving revision 1.82 diff -u -p -r1.82 i915_drv.h --- sys/dev/pci/drm/i915/i915_drv.h 4 May 2019 11:34:47 -0000 1.82 +++ sys/dev/pci/drm/i915/i915_drv.h 26 Jun 2019 09:42:42 -0000 @@ -4014,3 +4014,8 @@ static inline int intel_hws_csb_write_in } #endif + +/* gpuperf callback */ +#ifdef __OpenBSD__ +int inteldrm_set_gpuperf(int level, void *arg); +#endif /* __OpenBSD__ */ Index: sys/kern/kern_sysctl.c =================================================================== RCS file: /cvs/src/sys/kern/kern_sysctl.c,v retrieving revision 1.360 diff -u -p -r1.360 kern_sysctl.c --- sys/kern/kern_sysctl.c 16 Jun 2019 00:56:53 -0000 1.360 +++ sys/kern/kern_sysctl.c 25 Jun 2019 20:21:29 -0000 @@ -103,6 +103,9 @@ #include <ddb/db_var.h> #endif +#ifndef SMALL_KERNEL +#include <sys/gpuperf.h> +#endif /* !SMALL_KERNEL */ #ifdef SYSVMSG #include <sys/msg.h> #endif @@ -749,6 +752,8 @@ hw_sysctl(int *name, u_int namelen, void return (sysctl_hwsetperf(oldp, oldlenp, newp, newlen)); case HW_PERFPOLICY: return (sysctl_hwperfpolicy(oldp, oldlenp, newp, newlen)); + case HW_GPUPERF: + return (sysctl_hwgpuperf(oldp, oldlenp, newp, newlen)); #endif /* !SMALL_KERNEL */ case HW_VENDOR: if (hw_vendor) Index: sys/kern/subr_gpuperf.c =================================================================== RCS file: sys/kern/subr_gpuperf.c diff -N sys/kern/subr_gpuperf.c --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ sys/kern/subr_gpuperf.c 26 Jun 2019 09:48:03 -0000 @@ -0,0 +1,91 @@ +/* $OpenBSD$ */ + +/* + * Copyright (c) 2019 Benjamin Baier <b...@netzbasis.de> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <sys/gpuperf.h> +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/sysctl.h> + +#define GPUPERF_DEBUG +#ifdef GPUPERF_DEBUG +#define DPRINTF(x...) do { printf(x); } while(0) +#else +#define DPRINTF(x...) +#endif /* GPUPERF_DEBUG */ + +struct gpuperf_node { + char name[16]; /* gpu driver name */ + int (*callback)(int, void *); /* must understand 0 - 100 as % */ + void *arg; /* arg passthrough */ +}; + +struct gpuperf_node gpuperf_registered_nodes[GPUPERF_MAX_NODES]; + +int gpuperf = 100; +int gpuperf_gpun = 0; + +int +gpuperf_register(const char *name, int (*callback)(int, void *), void *arg) +{ + if (gpuperf_gpun >= GPUPERF_MAX_NODES) + return (-1); + + strlcpy(gpuperf_registered_nodes[gpuperf_gpun].name, name, + sizeof(gpuperf_registered_nodes[gpuperf_gpun].name)); + gpuperf_registered_nodes[gpuperf_gpun].callback = callback; + gpuperf_registered_nodes[gpuperf_gpun].arg = arg; + + /* + * Drivers may take a while to register, even after /etc/sysctl.conf + * was processed. So immediately call back. + */ + (void) callback(gpuperf, arg); + + gpuperf_gpun += 1; + DPRINTF("gpuperf: %s registered (total nodes %d)\n", + name, gpuperf_gpun); + + return (0); +} + +int +sysctl_hwgpuperf(void *oldp, size_t *oldlenp, void *newp, size_t newlen) +{ + int i, err, newperf, dstatus; + + newperf = gpuperf; + err = sysctl_int(oldp, oldlenp, newp, newlen, &newperf); + if (err) + return err; + if (newperf > 100) + newperf = 100; + if (newperf < 0) + newperf = 0; + gpuperf = newperf; + + for (i=0; i < gpuperf_gpun; i++) { + dstatus = gpuperf_registered_nodes[i].callback(gpuperf, + gpuperf_registered_nodes[i].arg); + + DPRINTF("gpuperf: requesting level %d from %s (dstatus %d)\n", + gpuperf, gpuperf_registered_nodes[i].name, dstatus); + + } + + return (0); +} Index: sys/sys/gpuperf.h =================================================================== RCS file: sys/sys/gpuperf.h diff -N sys/sys/gpuperf.h --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ sys/sys/gpuperf.h 26 Jun 2019 09:53:51 -0000 @@ -0,0 +1,29 @@ +/* $OpenBSD$ */ + +/* + * Copyright (c) 2019 Benjamin Baier <b...@netzbasis.de> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _SYS_GPUPERF_H_ +#define _SYS_GPUPERF_H_ + +#include <sys/types.h> + +#define GPUPERF_MAX_NODES 4 + +int sysctl_hwgpuperf(void *, size_t *, void *, size_t); +int gpuperf_register(const char *, int (*)(int, void *), void *); + +#endif /* _SYS_GPUPERF_H_ */ Index: sys/sys/sysctl.h =================================================================== RCS file: /cvs/src/sys/sys/sysctl.h,v retrieving revision 1.189 diff -u -p -r1.189 sysctl.h --- sys/sys/sysctl.h 21 Jun 2019 09:39:48 -0000 1.189 +++ sys/sys/sysctl.h 25 Jun 2019 20:21:29 -0000 @@ -892,7 +892,8 @@ struct kinfo_file { #define HW_PERFPOLICY 23 /* set performance policy */ #define HW_SMT 24 /* int: enable SMT/HT/CMT */ #define HW_NCPUONLINE 25 /* int: number of cpus being used */ -#define HW_MAXID 26 /* number of valid hw ids */ +#define HW_GPUPERF 26 /* set max GPU performance % */ +#define HW_MAXID 27 /* number of valid hw ids */ #define CTL_HW_NAMES { \ { 0, 0 }, \ @@ -921,6 +922,7 @@ struct kinfo_file { { "perfpolicy", CTLTYPE_STRING }, \ { "smt", CTLTYPE_INT }, \ { "ncpuonline", CTLTYPE_INT }, \ + { "gpuperf", CTLTYPE_INT }, \ } /*