Skip to content

Commit

Permalink
expose the state of thermal zones as kstats.
Browse files Browse the repository at this point in the history
this makes it a bit more obvious how much head room you have for
things like cpu performance scaling.

the information provided at the moment is more useful for developers
working on cpu scaling, but it should improve as i get my head
around more of these things.

patrick@ and kettenis@ like the idea.
  • Loading branch information
dlg committed Nov 23, 2023
1 parent 9fa027f commit dfd7428
Showing 1 changed file with 155 additions and 9 deletions.
164 changes: 155 additions & 9 deletions sys/dev/ofw/ofw_thermal.c
@@ -1,4 +1,4 @@
/* $OpenBSD: ofw_thermal.c,v 1.7 2020/12/31 11:11:22 kettenis Exp $ */
/* $OpenBSD: ofw_thermal.c,v 1.8 2023/11/23 00:47:13 dlg Exp $ */
/*
* Copyright (c) 2019 Mark Kettenis
*
Expand All @@ -15,12 +15,16 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/

#include "kstat.h"

#include <sys/types.h>
#include <sys/systm.h>
#include <sys/malloc.h>
#include <sys/stdint.h>
#include <sys/task.h>
#include <sys/timeout.h>
#include <sys/sched.h>
#include <sys/kstat.h>

#include <machine/bus.h>

Expand All @@ -36,6 +40,7 @@ LIST_HEAD(, cooling_device) cooling_devices =
struct taskq *tztq;

struct trippoint {
int tp_node;
int32_t tp_temperature;
uint32_t tp_hysteresis;
int tp_type;
Expand All @@ -48,6 +53,14 @@ struct trippoint {
#define THERMAL_HOT 3
#define THERMAL_CRITICAL 4

static const char *trip_types[] = {
[THERMAL_NONE] = "none",
[THERMAL_ACTIVE] = "active",
[THERMAL_PASSIVE] = "passive",
[THERMAL_HOT] = "hot",
[THERMAL_CRITICAL] = "critical",
};

struct cmap {
uint32_t *cm_cdev;
uint32_t *cm_cdevend;
Expand Down Expand Up @@ -82,8 +95,16 @@ struct thermal_zone {
LIST_HEAD(, cdev) tz_cdevs;

int32_t tz_temperature;

struct rwlock tz_lock;
struct kstat *tz_kstat;
};

#if NKSTAT > 0
static void thermal_zone_kstat_attach(struct thermal_zone *);
static void thermal_zone_kstat_update(struct thermal_zone *);
#endif /* NKSTAT > 0 */

LIST_HEAD(, thermal_zone) thermal_zones =
LIST_HEAD_INITIALIZER(thermal_zones);

Expand Down Expand Up @@ -324,13 +345,33 @@ thermal_zone_poll(void *arg)

out:
tz->tz_temperature = temp;
#if NKSTAT > 0
thermal_zone_kstat_update(tz);
#endif
if (tz->tz_tp && tz->tz_tp->tp_type == THERMAL_PASSIVE)
polling_delay = tz->tz_polling_delay_passive;
else
polling_delay = tz->tz_polling_delay;
timeout_add_msec(&tz->tz_poll_to, polling_delay);
}

static int
thermal_zone_triptype(const char *prop)
{
size_t i;

for (i = 0; i < nitems(trip_types); i++) {
const char *name = trip_types[i];
if (name == NULL)
continue;

if (strcmp(name, prop) == 0)
return (i);
}

return (THERMAL_NONE);
}

void
thermal_zone_init(int node)
{
Expand All @@ -351,6 +392,7 @@ thermal_zone_init(int node)

tz = malloc(sizeof(struct thermal_zone), M_DEVBUF, M_ZERO | M_WAITOK);
tz->tz_node = node;
rw_init(&tz->tz_lock, "tzlk");

OF_getprop(node, "name", &tz->tz_name, sizeof(tz->tz_name));
tz->tz_name[sizeof(tz->tz_name) - 1] = 0;
Expand Down Expand Up @@ -394,17 +436,11 @@ thermal_zone_init(int node)
break;
}
tp = &tz->tz_trips[i];
tp->tp_node = node;
tp->tp_temperature = temp;
tp->tp_hysteresis = OF_getpropint(node, "hysteresis", 0);
OF_getprop(node, "type", type, sizeof(type));
if (strcmp(type, "active") == 0)
tp->tp_type = THERMAL_ACTIVE;
else if (strcmp(type, "passive") == 0)
tp->tp_type = THERMAL_PASSIVE;
else if (strcmp(type, "hot") == 0)
tp->tp_type = THERMAL_HOT;
else if (strcmp(type, "critical") == 0)
tp->tp_type = THERMAL_CRITICAL;
tp->tp_type = thermal_zone_triptype(type);
tp->tp_phandle = OF_getpropint(node, "phandle", 0);
tp++;
}
Expand Down Expand Up @@ -465,6 +501,10 @@ thermal_zone_init(int node)
if (tz->tz_polling_delay > 0)
timeout_add_msec(&tz->tz_poll_to, tz->tz_polling_delay);
LIST_INSERT_HEAD(&thermal_zones, tz, tz_list);

#if NKSTAT > 0
thermal_zone_kstat_attach(tz);
#endif
}

void
Expand All @@ -480,3 +520,109 @@ thermal_init(void)
for (node = OF_child(node); node != 0; node = OF_peer(node))
thermal_zone_init(node);
}

#if NKSTAT > 0

static const char *
thermal_zone_tripname(int type)
{
if (type >= nitems(trip_types))
return (NULL);

return (trip_types[type]);
}

struct thermal_zone_kstats {
struct kstat_kv tzk_name; /* istr could be short */
struct kstat_kv tzk_temp;
struct kstat_kv tzk_tp;
struct kstat_kv tzk_tp_type;
struct kstat_kv tzk_cooling;
};

static void
thermal_zone_kstat_update(struct thermal_zone *tz)
{
struct kstat *ks = tz->tz_kstat;
struct thermal_zone_kstats *tzk;

if (ks == NULL)
return;

tzk = ks->ks_data;

rw_enter_write(&tz->tz_lock);
if (tz->tz_temperature == THERMAL_SENSOR_MAX)
tzk->tzk_temp.kv_type = KSTAT_KV_T_NULL;
else {
tzk->tzk_temp.kv_type = KSTAT_KV_T_TEMP;
kstat_kv_temp(&tzk->tzk_temp) = 273150000 +
1000 * tz->tz_temperature;
}

if (tz->tz_tp == NULL) {
kstat_kv_u32(&tzk->tzk_tp) = 0;
strlcpy(kstat_kv_istr(&tzk->tzk_tp_type), "none",
sizeof(kstat_kv_istr(&tzk->tzk_tp_type)));
} else {
int triptype = tz->tz_tp->tp_type;
const char *tripname = thermal_zone_tripname(triptype);

kstat_kv_u32(&tzk->tzk_tp) = tz->tz_tp->tp_node;

if (tripname == NULL) {
snprintf(kstat_kv_istr(&tzk->tzk_tp_type),
sizeof(kstat_kv_istr(&tzk->tzk_tp_type)),
"%u", triptype);
} else {
strlcpy(kstat_kv_istr(&tzk->tzk_tp_type), tripname,
sizeof(kstat_kv_istr(&tzk->tzk_tp_type)));
}
}

kstat_kv_bool(&tzk->tzk_cooling) = (tz->tz_cm != NULL);

getnanouptime(&ks->ks_updated);
rw_exit_write(&tz->tz_lock);
}

static void
thermal_zone_kstat_attach(struct thermal_zone *tz)
{
struct kstat *ks;
struct thermal_zone_kstats *tzk;
static unsigned int unit = 0;

ks = kstat_create("dt", 0, "thermal-zone", unit++, KSTAT_T_KV, 0);
if (ks == NULL) {
printf("unable to create thermal-zone kstats for %s",
tz->tz_name);
return;
}

tzk = malloc(sizeof(*tzk), M_DEVBUF, M_WAITOK|M_ZERO);

kstat_kv_init(&tzk->tzk_name, "name", KSTAT_KV_T_ISTR);
strlcpy(kstat_kv_istr(&tzk->tzk_name), tz->tz_name,
sizeof(kstat_kv_istr(&tzk->tzk_name)));
kstat_kv_init(&tzk->tzk_temp, "temperature", KSTAT_KV_T_NULL);

/* XXX dt node is not be the most useful info here. */
kstat_kv_init(&tzk->tzk_tp, "trip-point-node", KSTAT_KV_T_UINT32);
kstat_kv_init(&tzk->tzk_tp_type, "trip-type", KSTAT_KV_T_ISTR);
strlcpy(kstat_kv_istr(&tzk->tzk_tp_type), "unknown",
sizeof(kstat_kv_istr(&tzk->tzk_tp_type)));

kstat_kv_init(&tzk->tzk_cooling, "active-cooling", KSTAT_KV_T_BOOL);
kstat_kv_bool(&tzk->tzk_cooling) = 0;

ks->ks_softc = tz;
ks->ks_data = tzk;
ks->ks_datalen = sizeof(*tzk);
ks->ks_read = kstat_read_nop;
kstat_set_rlock(ks, &tz->tz_lock);

tz->tz_kstat = ks;
kstat_install(ks);
}
#endif /* NKSTAT > 0 */

0 comments on commit dfd7428

Please sign in to comment.