Saturday, October 29, 2022

obsdfreqd fails to get temperature and exits on Toshiba NB250 + fix suggestions

Hi,

I was trying to get obsdfreqd to work (on 7.2), but it doesn't:

obsdfreqd> doas obsdfreqd -v -T 70
mode;Temperature;maximum_frequency;current_frequency;cpu
usage;inertia;new frequency
obsdfreqd: sysctl to get temperature: No such file or directory
1;

I had apmd running with -L, and obsdfreqd seems to work without
temperature limits (though my CPU was getting awfully hot...).

I grabbed the source code and checked what it was doing:

mib[0] = CTL_HW;
mib[1] = HW_SENSORS;
mib[2] = 0;
mib[3] = SENSOR_TEMP;
mib[4] = 0;

if (sysctl(mib, 5, &sensor, &len, NULL, 0) == -1)
err(1, "sysctl to get temperature");

Bingo, so something's wrong there. I know I can read the temperature
with sysctl(1), so what's wrong?

According to the man page, mib[2] is the device name/number, but is 0
really the CPU device? I wrote a test program to dump the sensors, and
sure enough, on my machine, it is device 3... (test program and output
at the end; maybe OpenBSD already had this program, but I invoke the
"learning opportunity" card)

There might be another issue, though it's hard to check, and I don't
know exactly how OpenBSD works on most machines. I have another HP
laptop, which, OK, it's running Linux, but it reports no less than 10
different temperature readings, and they are all slightly different
(though within a few degrees of each other). I might check how many
temperature sensors OpenBSD will actually read on that machine, but I
need to find the time. The point is, grabbing the first temperature
sensor on the first device that has one might not actually be THE
temperature of the CPU whose frequency we're controlling.

I'm not sure what the fix here would be; if it were up to me, I'd add a
flag like "-S hw.sensors.cpu0.temp0" to tell it exactly which sensor I
want, then have the obsdfreqd code:
a) get a list of all sensordev devices (3-level mib loop)
b) find the one whose xname is 'cpu0'
c) parse 'temp0' and extract the '0'
d) run sysctl with a 5-level mib
{ CTL_HW, HW_SENSORS, sensordev.num, SENSOR_TEMP, atoi(tempidx) }

I could write that logic if everyone's on board. Actually, the logic to
parse those sysctl(1) style strings is already in sysctl's source code,
it's more a question of adding a parameter or conf file or something to
obsdfreqd to actually tell it what temperature sensor to look at.

Test program:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <err.h>

#include <sys/time.h>
#include <sys/types.h>
#include <sys/sensors.h>
#include <sys/sysctl.h>

#include <assert.h>

const char* sensor_type_names[] = {
"SENSOR_TEMP",
"SENSOR_FANRPM",
"SENSOR_VOLTS_DC",
"SENSOR_VOLTS_AC",
"SENSOR_OHMS",
"SENSOR_WATTS",
"SENSOR_AMPS",
"SENSOR_WATTHOUR",
"SENSOR_AMPHOUR",
"SENSOR_INDICATOR",
"SENSOR_INTEGER",
"SENSOR_PERCENT",
"SENSOR_LUX",
"SENSOR_DRIVE",
"SENSOR_TIMEDELTA",
"SENSOR_HUMIDITY",
"SENSOR_FREQ",
"SENSOR_ANGLE",
"SENSOR_DISTANCE",
"SENSOR_PRESSURE",
"SENSOR_ACCEL",
"SENSOR_VELOCITY",
"SENSOR_ENERGY",
};

int main(int argc, char* argv[])
{
int mib[5];
size_t len = 0;
struct sensordev *sensordevs = NULL;
size_t sensorlen = sizeof(struct sensor);
memset(mib, 0, sizeof(mib));
mib[0] = CTL_HW;
mib[1] = HW_SENSORS;
for(int dev = 0; ; ++dev) {
mib[2] = dev;
if(-1 == sysctl(mib, 3, NULL, &len, NULL, 0)) {
warn("Failed to get sensor count for dev %d, end of
array, exiting", dev);
break;
} // sysctl get num sensordevs
assert((len % sizeof(struct sensordev)) == 0);
size_t nsensordevs = len / sizeof(struct sensordev);
printf("Device %d, %zd sensordevs\n", dev, nsensordevs);
sensordevs = malloc(len);
memset(sensordevs, 0, len);
if(-1 == sysctl(mib, 3, sensordevs, &len, NULL, 0)) {
warn("Failed to retrieve sensors for device %d", dev);
continue;
} // sysctl get sensordevs

for(int sd = 0; sd < nsensordevs; ++sd) {
char xname[17];
memset(xname, 0, sizeof(xname));
strncpy(xname, sensordevs[sd].xname, 16);
printf(
"num: %d\n"
"xname: %s\n"
"sensors_count: %d\n",
sensordevs[sd].num,
xname,
sensordevs[sd].sensors_count);
for(int st = 0; st < SENSOR_MAX_TYPES; ++st) {
if(sensordevs[sd].maxnumt[st] == 0) continue;
for(int s = 0; s < sensordevs[sd].maxnumt[st]; ++s) {
struct sensor sensor;
memset(&sensor, 0, sizeof(struct sensor));
mib[2] = sensordevs[sd].num;
mib[3] = st;
mib[4] = s;
if(-1 == sysctl(mib, 5, &sensor, &sensorlen, NULL, 0)) {
warn("Failed to get sensors of type %d for
sd %d for dev %d", st, sd, dev);
continue;
}
char desc[33];
memset(desc, 0, sizeof(desc));
strncpy(desc, sensor.desc, 32);
printf("\n");
printf(
"\tName: %s\n"
"\tValue: %llx\n"
"\tType: %d (%s)\n"
"\tnumt: %d\n",
desc,
sensor.value,
sensor.type, sensor_type_names[sensor.type],
sensor.numt);
} // for each sensor
} // for each sensor type
} // for each sensordev
free(sensordevs);
} // for each dev
return 0;
}

Compile with `cc -o sensors -g -O0 sensors.c` or whatever you usually do.

Output on my Toshiba NB250-101 running OpenBSD 7.2:

Device 0, 1 sensordevs
num: 0
xname: acpiac0
sensors_count: 1

Name: power supply
Value: 1
Type: 9 (SENSOR_INDICATOR)
numt: 0
Device 1, 1 sensordevs
num: 1
xname: acpibat0
sensors_count: 9

Name: voltage
Value: a4cb80
Type: 2 (SENSOR_VOLTS_DC)
numt: 0

Name: current voltage
Value: bf40f0
Type: 2 (SENSOR_VOLTS_DC)
numt: 1

Name: rate
Value: 3e7fc18
Type: 6 (SENSOR_AMPS)
numt: 0

Name: last full capacity
Value: 423d08
Type: 8 (SENSOR_AMPHOUR)
numt: 0

Name: warning capacity
Value: 68fb0
Type: 8 (SENSOR_AMPHOUR)
numt: 1

Name: low capacity
Value: 1f7e8
Type: 8 (SENSOR_AMPHOUR)
numt: 2

Name: remaining capacity
Value: 423d08
Type: 8 (SENSOR_AMPHOUR)
numt: 3

Name: design capacity
Value: 432380
Type: 8 (SENSOR_AMPHOUR)
numt: 4

Name: battery full
Value: 80
Type: 10 (SENSOR_INTEGER)
numt: 0
Device 2, 1 sensordevs
num: 2
xname: acpibtn0
sensors_count: 1

Name: lid open
Value: 1
Type: 9 (SENSOR_INDICATOR)
numt: 0
Device 3, 1 sensordevs
num: 3
xname: cpu0
sensors_count: 1

Name:
Value: 14093df0
Type: 0 (SENSOR_TEMP)
numt: 0
Device 4, 1 sensordevs
num: 4
xname: softraid0
sensors_count: 0

Strangely enough, the temperature sensor on this laptop seems to
be nameless. Huh.

Best regards,
Vlad Meşco



P.S., I really was not sure what the best way to get in touch with the
developer was, so I posted here. I hope it reaches them <3

No comments:

Post a Comment