There has been some interest here and there,
an I have been running it for about 1.5 years.
With crappy laptop cooling, failing CPU fans
and the summer approaching fast i think i'll
share the newest iteration.

Greetings Ben

===

This will throttle down your intel graphic card for 
better thermal management.
It is bound to CPU performance settings via
hw.setperf sysctl.

Main Test Machine
    cpu0: Intel(R) Core(TM) i5-2520M CPU @ 2.50GHz, 2492.32 MHz, 06-2a-07
    inteldrm0 at pci0 dev 2 function 0 "Intel HD Graphics 3000" rev 0x09
    CPU 800MHz to 2500MHz
    GPU 650MHz to 1300MHz
Secondary Test Machine
    cpu0: Intel(R) Core(TM) i3-9100 CPU @ 3.60GHz, 3593.36 MHz, 06-9e-0b
    inteldrm0 at pci0 dev 2 function 0 "Intel UHD Graphics 630" rev 0x00

CPU autothrottle -> GPU autothrottle (i.e 650MHz - 1300MHz)
CPU perf = 100 -> GPU throttle to max. frequency (i.e. 1300MHz)
CPU perf < 100 -> GPU throttle to base frequency (i.e. 650MHz)

Patch Version 8
    Adapt for new DRM code (OpenBSD 6.7-current)
Patch Version 7
    Header shuffling
    Cleanup
Patch Version 6
    Don't include in SMALL_KERNEL
    Copyright update
    Disable DEBUG output
    Patch apply directions have changed
Patch Version 5
    Cleanup
Patch Version 4
    Switch from percentage to performance groups (LOW, HIGH, AUTO)
    Cleanup
Patch Version 3
    No longer implements a own sysctl
    Patch apply directions have changed
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
Patch Version 0
    Initial POC
    Using sensors framework only for debug
    Only implemented for intel graphic
To apply:
    cd /usr/src/sys && 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
Feedback and questions: program...@netzbasis.de

Index: conf/files
===================================================================
RCS file: /var/cvs/src/sys/conf/files,v
retrieving revision 1.690
diff -u -p -r1.690 files
--- conf/files  6 Jul 2020 04:09:46 -0000       1.690
+++ conf/files  18 Jul 2020 19:43:06 -0000
@@ -717,6 +717,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               !small_kernel
 file kern/subr_hibernate.c             hibernate
 file kern/subr_kubsan.c                        kubsan
 file kern/subr_log.c
Index: dev/pci/drm/i915/i915_drv.c
===================================================================
RCS file: /var/cvs/src/sys/dev/pci/drm/i915/i915_drv.c,v
retrieving revision 1.132
diff -u -p -r1.132 i915_drv.c
--- dev/pci/drm/i915/i915_drv.c 28 Jun 2020 02:29:19 -0000      1.132
+++ dev/pci/drm/i915/i915_drv.c 18 Jul 2020 19:46:36 -0000
@@ -2605,12 +2605,70 @@ 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__
+#ifdef GPUPERF_DEBUG
+#define GPRINTF(x...) do { printf(x); } while(0)
+#else
+#define GPRINTF(x...)
+#endif /* GPUPERF_DEBUG */
+
+int
+inteldrm_set_gpuperf(gpuperf_level level, void *arg)
+{
+       struct inteldrm_softc *dev_priv = arg;
+       struct intel_rps *rps = &dev_priv->gt.rps;
+       u_int32_t min = rps->min_freq;
+       u_int32_t max = rps->max_freq;
+
+       GPRINTF("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));
+
+       /*
+        * On haswell & broadwell min_freq_softlimit is higher than min_freq
+        * by default. Allow those devices to clock down further by ignoring
+        * this special case.
+        */
+       switch (level) {
+       case GPU_AUTO:
+               rps->max_freq_softlimit = max;
+               rps->boost_freq = max;
+               rps->min_freq_softlimit = min;
+               break;
+       case GPU_LOW:
+               rps->max_freq_softlimit = min;
+               rps->boost_freq = min;
+               rps->min_freq_softlimit = min;
+               break;
+       case GPU_HIGH:
+               rps->max_freq_softlimit = max;
+               rps->boost_freq = max;
+               rps->min_freq_softlimit = max;
+               break;
+       default:
+               return 1;
+       }
+
+       GPRINTF("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));
+
+       return 0;
+}
+#endif /* __OpenBSD__ */
 
 int
 inteldrm_detach(struct device *self, int flags)
Index: dev/pci/drm/i915/i915_drv.h
===================================================================
RCS file: /var/cvs/src/sys/dev/pci/drm/i915/i915_drv.h,v
retrieving revision 1.92
diff -u -p -r1.92 i915_drv.h
--- dev/pci/drm/i915/i915_drv.h 29 Jun 2020 04:13:30 -0000      1.92
+++ dev/pci/drm/i915/i915_drv.h 18 Jul 2020 19:43:06 -0000
@@ -2000,3 +2000,8 @@ i915_coherent_map_type(struct drm_i915_p
 }
 
 #endif
+
+#ifdef __OpenBSD__
+#include <sys/gpuperf.h>
+int inteldrm_set_gpuperf(gpuperf_level level, void *arg);
+#endif /* __OpenBSD__ */
Index: kern/sched_bsd.c
===================================================================
RCS file: /var/cvs/src/sys/kern/sched_bsd.c,v
retrieving revision 1.63
diff -u -p -r1.63 sched_bsd.c
--- kern/sched_bsd.c    30 May 2020 14:42:59 -0000      1.63
+++ kern/sched_bsd.c    18 Jul 2020 19:43:06 -0000
@@ -540,6 +540,7 @@ int perfpolicy = PERFPOL_MANUAL;
 /*
  * The code below handles CPU throttling.
  */
+#include <sys/gpuperf.h>
 #include <sys/sysctl.h>
 
 void setperf_auto(void *);
@@ -630,6 +631,11 @@ sysctl_hwsetperf(void *oldp, size_t *old
        perflevel = newperf;
        cpu_setperf(perflevel);
 
+       if (perflevel == 100)
+               gpuperf_set(GPU_HIGH);
+       else
+               gpuperf_set(GPU_LOW);
+
        return 0;
 }
 
@@ -674,9 +680,11 @@ sysctl_hwperfpolicy(void *oldp, size_t *
 
        if (perfpolicy == PERFPOL_AUTO) {
                timeout_add_msec(&setperf_to, 200);
+               gpuperf_set(GPU_AUTO);
        } else if (perfpolicy == PERFPOL_HIGH) {
                perflevel = 100;
                cpu_setperf(perflevel);
+               gpuperf_set(GPU_HIGH);
        }
        return 0;
 }
Index: kern/subr_gpuperf.c
===================================================================
RCS file: kern/subr_gpuperf.c
diff -N kern/subr_gpuperf.c
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ kern/subr_gpuperf.c 18 Jul 2020 19:43:06 -0000
@@ -0,0 +1,79 @@
+/*     $OpenBSD$       */
+
+/*
+ * Copyright (c) 2019, 2020 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/malloc.h>
+
+#ifdef GPUPERF_DEBUG
+#define DPRINTF(x...) do { printf(x); } while(0)
+#else
+#define DPRINTF(x...)
+#endif /* GPUPERF_DEBUG */
+
+struct gpuperf_dev {
+       char name[16];                          /* device name */
+       void *arg;                              /* arg passthrough */
+       int (*callback)(gpuperf_level, void *);
+       LIST_ENTRY(gpuperf_dev) next;
+};
+
+LIST_HEAD(, gpuperf_dev) gpuperf_list =
+       LIST_HEAD_INITIALIZER(gpuperf_list);
+
+int
+gpuperf_register(const char *name, int (*callback)(gpuperf_level, void *),
+    void *arg)
+{
+       struct gpuperf_dev *dev;
+       int status = 0;
+
+       if ((dev = malloc(sizeof(*dev), M_DEVBUF, M_NOWAIT)) == NULL)
+               return -1;
+
+       strlcpy(dev->name, name, sizeof(dev->name));
+       dev->callback = callback;
+       dev->arg = arg;
+
+       LIST_INSERT_HEAD(&gpuperf_list, dev, next);
+       status = dev->callback(GPU_AUTO, dev->arg);
+
+       DPRINTF("gpuperf: %s registered, status %d\n", dev->name, status);
+
+       return status;
+}
+
+int
+gpuperf_set(gpuperf_level level)
+{
+       struct gpuperf_dev *dev;
+       int status = 0;
+
+       if ((level < GPU_AUTO) || (level > GPU_HIGH))
+               return -1;
+
+       LIST_FOREACH(dev, &gpuperf_list, next) {
+               status += dev->callback(level, dev->arg);
+
+               DPRINTF("gpuperf: requesting %d from %s, status %d\n",
+                   level, dev->name, status);
+       }
+
+       return status;
+}
Index: sys/gpuperf.h
===================================================================
RCS file: sys/gpuperf.h
diff -N sys/gpuperf.h
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ sys/gpuperf.h       18 Jul 2020 19:43:06 -0000
@@ -0,0 +1,31 @@
+/*     $OpenBSD$       */
+
+/*
+ * Copyright (c) 2019, 2020 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_
+
+typedef enum {
+       GPU_AUTO,
+       GPU_LOW,
+       GPU_HIGH
+} gpuperf_level;
+
+int gpuperf_set(gpuperf_level);
+int gpuperf_register(const char *, int (*)(gpuperf_level, void *), void *);
+
+#endif /* _SYS_GPUPERF_H_ */


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?

Reply via email to