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 }, \
 }
 
 /*


Reply via email to