www.fabiankeil.de/blog-surrogat/2007/05/20/gkibm-acpi-nach-freebsd-portiert.html

GKIBM-ACPI nach FreeBSD portiert

[Screenshot: Grafischer System-Monitor GKrellm2 mit hervorgehobenen GKIBM-ACPI-Plugins.] GKIBM-ACPI ist eine Sammlung von GKrellm2-Plugins zum Auslesen verschiedener ThinkPad-Sensoren, der Autor ist Collin Richard Mulliner.

GKIBM-ACPI 0.1.1 ist für Linux geschrieben, die Sensoren werden von ibm-acpi ermittelt und von den Plugins über das procfs-Pseudo-Dateisystem gelesen.

FreeBSDs Gegenstück zu ibm-acpi ist acpi_ibm(4), procfs kann zwar vom Nutzer aktiviert werden, soweit möglich wird jedoch sysctl(3) zum Auslesen von Kernel-Werten bevorzugt.

Um die Plugins unter FreeBSD nutzen zu können musste ich zwei Lese-Funktionen ersetzen: read_fan() zum Auslesen der Lüfter-Umdrehungen und read_data() für die verschiedenen Temperatur-Sensoren.

Dank FreeBSDs Dokumentation gab es bei der Portierung keine nennenswerten Probleme, an dieser Stelle daher nur eine kommentierte Gegenüberstellung der Linux- und FreeBSD-Version von read_data().

/proc vs. sysctl(3)

procfs rockt, das read_data()-Original aus dem GKIBM-ACPI-Code muss die Sensor-Werte als Zeichenkette lesen und vor der Verarbeitung erst in numerische Werte zurück konvertieren:

char *read_data(int i)
{
	FILE *f;
	int d[8]; 
	char *buffer;


	buffer = malloc(sizeof(char)*512);
	if ((f = fopen("/proc/acpi/ibm/thermal", "r")) == NULL) {
		sprintf(buffer, "ibm-acpi?");
		return(buffer);
	}
	fgets(buffer, 512, f);
	sscanf(buffer, "temperatures: %d %d %d %d %d %d %d %d", &d[0], &d[1], &d[2], &d[3], &d[4], &d[5], &d[6], &d[7]);
	switch (i) {
	case 0:
		snprintf(buffer, 512, "CPU %dC", d[i]);
		break;
	case 1:
		snprintf(buffer, 512, "PCI %dC", d[i]);
		break;
	case 2:
		snprintf(buffer, 512, "HDD %dC", d[i]);
		break;
	case 3:
		snprintf(buffer, 512, "GPU %dC", d[i]);
		break;
	case 4:
		if (d[i] < 0) snprintf(buffer, 512, "BAT n/a");
		else snprintf(buffer, 512, "BAT %dC", d[i]);
		break;
	}
	fclose(f);
 
	//printf("buffer=%s\n", buffer);
 
	return(buffer);
}

FreeBSDs sysctl(3) liefert gleich numerische Werte, das Zeichenketten-Gefrickel fällt folglich weg:

static char info[20];
const static char *sensors[] = {"CPU", "PCI", "HDD", "GPU", "BAT", "UBAT", "BAT2", "UBAT2"}; 
#define NUMBER_OF_SENSORS sizeof(sensors) / sizeof(char*)

char *read_data(int i)
{
        int thermal[NUMBER_OF_SENSORS];
        size_t thermal_size = sizeof(thermal);

        if (NUMBER_OF_SENSORS - 1 < i)
        {
                return "Unsupported sensor";
        }

        if (sysctlbyname("dev.acpi_ibm.0.thermal", thermal, &thermal_size, NULL, 0))
        {
                return "acpi_ibm.ko loaded?";
        }
        else
        {
                /*
                 * Quoting acpi_ibm(4):
                 *
                 *  dev.acpi_ibm.0.thermal
                 *
                 *   (read-only) Shows the readings of up to eight different tempera-
                 *   ture sensors.  Most ThinkPads include six or more temperature
                 *   sensors but only expose the CPU temperature through
                 *   acpi_thermal(4).  Some ThinkPads have the below sensor layout
                 *   which might vary depending on the specific model:
                 *
                 *   1.   CPU
                 *   2.   Mini PCI Module
                 *   3.   HDD
                 *   4.   GPU
                 *   5.   Built-in battery
                 *   6.   UltraBay battery
                 *   7.   Built-in battery
                 *   8.   UltraBay battery
                 */
                const int temperature = thermal[i];
                const char *sensor = sensors[i];

                if (0 <= temperature)
                {
                        snprintf(info, sizeof(info), "%s %dC", sensor, temperature);
                }
                else
                {
                        snprintf(info, sizeof(info), "%s n/a", sensor);
                }

        }

        return info;
}

Ebenfalls gespart habe ich mir die dynamische Speicher-Allozierung: der Nutzer wird zwanzig Bytes pro Temperatur-Sensor wohl für die gesamte Laufzeit entbehren können und da read_data() mehrmals pro Sekunde aufgerufen wird muss eh der ganze Speicher verfügbar bleiben.

Garantie gibt es keine

Beide read_data()-Versionen erwarten ein bestimmtes Sensor-Layout; laut FreeBSD-Manpage wird es nicht garantiert, sondern ist Laptop-abhängig. Auf meinem Laptop deckt sich das Sensor-Layout allerdings, soweit ich das beurteilen kann, sowohl mit dem in acpi_ibm(4) beschriebenen als auch mit dem von der Linux-Version erwarteten – scheint also tatsächlich weit verbreitet zu sein.

Solange lediglich ein paar Sensoren fehlen, die vorhandenen aber an erwarteter Position bleiben, sollten die zugehörigen Plugins korrekt n/a anzeigen, ansonsten hat der Nutzer halt Pech gehabt und kann sich bei IBM bedanken.

Zum Testen ohne GKrellm habe ich GKIBM-ACPI ein kleines Test-Programm spendiert. Hier meldet es:

./test
Does this look reasonable?
CPU 50C, PCI 50C, HDD 38C, GPU 53C, BAT 37C, UBAT n/a, BAT2 33C, UBAT2 n/a, 3774 RPM

Für die beiden UltraBay-Akku-Sensoren bringt GKIBM-ACPI keine Plugins mit, da ich keinen UltraBay-Akku besitze, habe ich auch keine Motivation das zu ändern.

Für den zweiten Sensor im Standard-Akku gibt es ebenfalls kein Plugin. Mein GKrellm-Fenster wäre prinzipiell breit genug um die Werte für beide Sensoren in einem Plugin aufzunehmen, ich habe aber auch schon Screenshots gesehen, bei denen es eng werden würde. Für ein weiteres Plugin für den zweiten Sensor im Standard-Akku ist mir der Platz zu schade sowie der Sensor zu unwichtig.

[Screenshot-Ausschnitt: Von fchart geplottetes Linien-Diagram der CPU-Frequenz, und die Frequenz-Anzeige in GKfreq.] Mittlerweile bin ich außerdem auf das GKrellm-Plugin FChart gestoßen, mit dem man GKIBM-ACPI (und viele andere Plugins) über eigene Skripten komplett ersetzen kann – als Bonus gibt es optional Linien-Diagramme dazu. Der Screenshot demonstriert das für das GKfreq-Plugin, auf dem auch GKIBM-ACPI basiert.

Abwarten

Mit dem Einsenden des FreeBSD-Ports werde ich noch etwas warten: wegen der Xorg-7.2-Integration sind die Ports momentan sowieso eingefroren, zudem würde ich es vorziehen, wenn die FreeBSD-Unterstützung in die offizielle GKIBM-ACPI-Version aufgenommen würde, der Port also ohne die Patches auskäme.