CfT: powerd++

Kamikaze

Warrior of Sunlight
Teammitglied
Ich habe mal einen Ersatz für powerd geschrieben: https://github.com/lonkamikaze/powerdxx

Bevor ich einen Port dafür mache hätte ich gerne noch etwas Feedback gesammelt.

Warum das ganze zitiere ich einfach mal aus dem Readme:
README.md schrieb:
Pitfalls of powerd?

At the time powerd++ was first created (February 2016), powerd exhibited some unhealthy behaviours on multi-core machines.

In order to make sure that single core loads do not suffer from the use of powerd it was designed to use the sum load of all cores as the current load rating. A side effect of this is that it causes powerd to never clock down on systems with even moderate numbers of cores. E.g. on a quad-core system with hyper threading a background load of 12.5% per core suffices to score a 100% load rating.

The more cores are added, the worse it gets. Even on a dual core machine (with HT) having a browser and an e-mail client open, suffices to keep the load rating above 100% for most of the time, even without user activity. Thus powerd never does its job of saving energy, by reducing the clock frequency.

Advantages of powerd++

The powerd++ implementation addresses this issue and more:

  • powerd++ groups cores with a common clock frequency together and handles each group's load and target frequency separately. I.e. the moment FreeBSD starts offering individual clock settings on the CPU, core or thread level, powerd++ already supports it.
  • powerd++ takes the highest load within a group of cores to rate the load. This approach responds well to single core loads as well as evenly distributed loads.
  • powerd++ sets the clock frequency according to a load target, i.e. it jumps right to the clock rate it will stay in if the load does not change.
  • powerd++ supports taking the average load over more than two samples, this makes it more robust against small load spikes, but sacrifices less responsiveness than just increasing the polling interval would. Because only the oldest and the newest sample are required for calculating the average, this approach does not even cause additional runtime cost!
  • powerd++ parses command line arguments as floating point numbers, allowing expressive commands like powerd++ --batt 1.2ghz.
 
Sehr schön, danke, dass du das mal angehst.

Gerade habe ich ihn ausprobiert. Sieht erst mal ganz gut aus:
http://paste2.org/ec3bKngc

Am Anfang lief nix, dann ein, dann zwei HD Filme. Dabei ist der Load laut powerd++ bei ca. 20% geblieben und die CPU bei 1200 MHz. Ein "cat /dev/random > /dev/null" hat es dann auf 100% / 2901 MHz hochgesetzt. Als ich dann aber alles beendet habe, war angeblich der Load laut powerd++ bei 50%>80%, top(1) zeigte allerdings so um die 80% Idle an.
 
Am Anfang lief nix, dann ein, dann zwei HD Filme. Dabei ist der Load laut powerd++ bei ca. 20% geblieben und die CPU bei 1200 MHz. Ein "cat /dev/random > /dev/null" hat es dann auf 100% / 2901 MHz hochgesetzt. Als ich dann aber alles beendet habe, war angeblich der Load laut powerd++ bei 50%>80%, top(1) zeigte allerdings so um die 80% Idle an.
80% Load auf einem einzelnen Kern entsprechen halt nur 20% insgesamt. powerd++ richtet sich immer nach dem Kern mit dem höchsten Load damit Single-Thread Loads nicht benachteiligt werden. Mit top -P bekommst Du wahrscheinlich eine bessere Übereinstimmung.
 
Inzwischen kamen noch ein paar Änderungen hinzu. Rotluchs hat mir im IRC ein sehr kompetentes code Review gemacht, von dem ich eine Menge lernen konnte.

Beim Beenden setzt powerd++ jetzt den Takt auf das Maximum. Das ist wohl nicht immer optimal aber zumindest mal ein Default mit dem man sich arrangieren kann.
 
Ich habe powerd++ eben für einige Zeit mitlaufen lassen. Es funktioniert einwandfrei. Was sehr positiv auffällt ist, dass er deutlich weniger nervös als der normale powerd ist. Werden dort die 4 Kernel (8 HT-Threads) des Core i7 6700k schon beim kleinsten Hauch von Last mit vollen 4001MHz getaktet, bleibt das System bei powerd++ weitgehend auf 800MHz. Damit ist es auch merklich auch ruhiger, da die Drehzahl des CPU-Lüfters u.a. an die Taktfrequenz gebunden zu sein scheint. Der Workload war etwas SSH, Chromium mit mehreren Tabs und eine Windows 10 VM in Bhyve.
 

Anhänge

  • log.txt
    568,8 KB · Aufrufe: 455
@Yamagi
Du kannst es ähnlich nervös wie powerd machen, wenn Du die Anzahl Samples verringerst (-s2) und den Polling Interval halbierst (-p.25s).

Ich gehe davon aus das Du dann trotzdem noch bessere Ergebnisse als mit powerd hast. Der Regelalgorithmus von powerd++ ist zwar IMHO schöner als der von powerd, aber der echte Vorteil liegt darin wie der Load berechnet wird.

Du warst übrigens im hiadaptive Modus unterwegs. Wenn die Stromquele (hw.acpi.acline) unknown (2) oder nicht lesbar ist, gehe ich davon aus nicht auf einem Notebook zu laufen.
 
Wow, was ein Unterschied zu powerd, vielen Dank. Jetzt wird meine CPU mit allen Kernen auf 80% idle sogar mal runtergetaktet! :)
 
Wenn man nur einen stupiden Fileserver hat, hätte dein powerd da auch Vorteile?

Und dann noch:
Hat zwar nur leichten Bezug dazu... aber in Intel CPUs ab Skylake gibt es ja die Möglichkeit, dass die CPU selbst ihre Taktung / PowerManagement übernimmt. Das OS sagt nur: "Ich will diesen Modus". Gibt es da eigentlich auch schon Unterstützung in FreeBSD?
 
Wenn man nur einen stupiden Fileserver hat, hätte dein powerd da auch Vorteile?
Wenn Du mehr als einen Kern hast (oder HT) dann hat es Vorteile.

Und dann noch:
Hat zwar nur leichten Bezug dazu... aber in Intel CPUs ab Skylake gibt es ja die Möglichkeit, dass die CPU selbst ihre Taktung / PowerManagement übernimmt. Das OS sagt nur: "Ich will diesen Modus". Gibt es da eigentlich auch schon Unterstützung in FreeBSD?
Meinst Du den Turbo-Modus? Dann taktet die CPU automatisch nach thermischen Gesichtspunkten. Das heißt immer alles was geht. Genau das Gegenteil von Energie sparen also.
 
Gut, dann probiere ich das mal die Tage auf meinem Fileserver aus. Ist ein i3-4130T. Ein Port wäre super :)

Und ne, ich meine nicht den Turbo-Modus ich meine das was bei Windows 10 / Intel den Namen Speed Shift hat und unter Linux Hardware P-State. Dort wird im Endeffekt vom Kernel nur ein Flag der CPU gesetzt und die verwaltet sich dann selbst je nach Last. Der Kernel / Das Userland muss da gar nichts mehr machen.
 
So habe powerd++ jetzt mal auf meinem NAS getestet. Hier die Ergebnisse:

Versuch 1
  • - Kein powerd beim boot aktiv
  • - Nach 10min. im Leerlauf 35W

Versuch 2
  • - powerd beim booten aktiv
  • - Nach 10min. im Leerlauf 35W

Versuch 3
  • - powerd beim booten aktiv mit folgenden Einstellungen:
  • - performance_cx_lowest="C2"
  • - economy_cx_lowest="C2"
  • - Nach 10min. im Leerlauf 32W

Versuch 4
  • - powerd++ beim booten aktiv
  • - Nach 10min. im Leerlauf 35W

Hier noch ein ein paar Zeilen Output:
Code:
powerd++: cannot read hw.acpi.acline
powerd++: cannot access sysctl: dev.cpu.1.freq
powerd++: cannot access sysctl: dev.cpu.2.freq
powerd++: cannot access sysctl: dev.cpu.3.freq
Terminal Output
        verbose:               yes
        foreground:            yes
Load Sampling
        cp_time samples:       5
        polling interval:      500 ms
        load average over:     2000 ms
CPU Cores
        CPU cores:             4
        user frequency limits: [0 MHz, 1000000 MHz]
Core Groups
        0: [0, 3]
Core Frequency Limits
        0: [1200, 2401]
Load Targets
        battery power target:  63% load
        online power target:   38% load
        unknown power target:  38% load
power: unknown, load:   2%, cpu0.freq: 2401 -> 1200 MHz
power: unknown, load:   1%, cpu0.freq: 1200
power: unknown, load:   1%, cpu0.freq: 1200
power: unknown, load:   0%, cpu0.freq: 1200
power: unknown, load:   0%, cpu0.freq: 1200
power: unknown, load:   0%, cpu0.freq: 1200
power: unknown, load:   0%, cpu0.freq: 1200
power: unknown, load:   1%, cpu0.freq: 1200
power: unknown, load:   1%, cpu0.freq: 1200
power: unknown, load:   0%, cpu0.freq: 1200
power: unknown, load:   1%, cpu0.freq: 1200
power: unknown, load:   0%, cpu0.freq: 1200
power: unknown, load:   0%, cpu0.freq: 1200
power: unknown, load:   1%, cpu0.freq: 1200
power: unknown, load:   0%, cpu0.freq: 1200
power: unknown, load:   1%, cpu0.freq: 1200
power: unknown, load:   1%, cpu0.freq: 1200
power: unknown, load:   1%, cpu0.freq: 1200
power: unknown, load:   1%, cpu0.freq: 1200
power: unknown, load:   1%, cpu0.freq: 1200
power: unknown, load:   1%, cpu0.freq: 1200
power: unknown, load:   1%, cpu0.freq: 1200
power: unknown, load:   1%, cpu0.freq: 1200
power: unknown, load:   1%, cpu0.freq: 1200
power: unknown, load:   0%, cpu0.freq: 1200
power: unknown, load:   1%, cpu0.freq: 1200
power: unknown, load:   1%, cpu0.freq: 1200
power: unknown, load:   1%, cpu0.freq: 1200
power: unknown, load:   1%, cpu0.freq: 1200
power: unknown, load:   1%, cpu0.freq: 1200
power: unknown, load:   0%, cpu0.freq: 1200
power: unknown, load:   0%, cpu0.freq: 1200
power: unknown, load:   1%, cpu0.freq: 1200
power: unknown, load:   0%, cpu0.freq: 1200
power: unknown, load:   1%, cpu0.freq: 1200
power: unknown, load:   1%, cpu0.freq: 1200
power: unknown, load:   0%, cpu0.freq: 1200
power: unknown, load:  10%, cpu0.freq: 1200
power: unknown, load:  14%, cpu0.freq: 1200
power: unknown, load:  14%, cpu0.freq: 1200
power: unknown, load:  14%, cpu0.freq: 1200
power: unknown, load:  14%, cpu0.freq: 1200
power: unknown, load:   0%, cpu0.freq: 1200
power: unknown, load:   0%, cpu0.freq: 1200
power: unknown, load:   0%, cpu0.freq: 1200
power: unknown, load:   0%, cpu0.freq: 1200
power: unknown, load:   0%, cpu0.freq: 1200
power: unknown, load:   1%, cpu0.freq: 1200
power: unknown, load:   1%, cpu0.freq: 1200
power: unknown, load:   1%, cpu0.freq: 1200
power: unknown, load:   1%, cpu0.freq: 1200

Allgemein zum NAS:
Code:
sysctl dev.cpu.0.freq_levels
dev.cpu.0.freq_levels: 2401/11500 2400/10000 2300/9250 2200/8500 2100/7750 2000/7000 1900/6250 1800/5500 1700/4750 1600/4000 1500/3250 1400/2500 1300/1750 1200/1000

sysctl dev.cpu.0.cx_lowest
dev.cpu.0.cx_lowest: C1

sysctl dev.cpu.0.cx_supported
dev.cpu.0.cx_supported: C1/1/1 C2/2/41

sysctl hw.model
hw.model: Intel(R) Atom(TM) CPU  C2550  @ 2.40GHz

Gruss
 
Also bringen beim Atom die P-States wohl nichts. Das ist relativ enttäuschend. Aber power_profile und powerd schließen sich nicht gegenseitig aus.
 
Schoener Daemon bzw. geiler Hack!

Was mir besonders gut gefaellt, ist der kreative
Umgang mit dem "Waffenarsenal" von C++, um
einen klassischen Daemon zu implementieren.

Danke fuer das Programm... :)
 
Auf meinem alten Thinkpad T61 mit C2D verrichtet er auch gute Dienste. Keine negativen Auffälligkeiten.
 
Auf meinem alten Thinkpad T61 mit C2D verrichtet er auch gute Dienste. Keine negativen Auffälligkeiten.
Danke!
Schoener Daemon bzw. geiler Hack!

Was mir besonders gut gefaellt, ist der kreative
Umgang mit dem "Waffenarsenal" von C++, um
einen klassischen Daemon zu implementieren.

Danke fuer das Programm... :)
Was heißt hier Hack?! Das ist aller feinstes Software Engineering!

Nee Ernsthaft. Ich wollte halt kein OO-Programm für so eine Kleinigkeit schreiben. Aber exceptions sind praktisch und RAII funktioniert halt nicht nur für Speicher sondern auch für Dateien, Locks etc. Da bietet es sich an alles was wieder aufgeräumt werden muss in einen Constructor/Destructor Container (aka. Klasse) zu packen. Denn ohne RAII sind Exceptions die Hölle.
 
Hallo Kamikaze,

erst einmal vielen Dank für deine Arbeit!!!

Hier mal ein kurzer Test auf meinen Laptop:

Code:
user@machine : /usr/ports/sysutils/powerdxx # /usr/local/sbin/powerd++ -v -f
powerd++: cannot access sysctl: dev.cpu.0.freq
powerd++: (ENOFREQ) at least the first CPU core must support frequency updates

user@machine : /usr/ports/sysutils/powerdxx # sysctl hw.model hw.machine hw.ncpu
hw.model: AMD A10-5750M APU with Radeon(tm) HD Graphics
hw.machine: amd64
hw.ncpu: 4

user@machine : /usr/ports/sysutils/powerdxx # sysctl dev.cpu
dev.cpu.3.cx_usage: 100.00% 0.00% last 3675us
dev.cpu.3.cx_lowest: C1
dev.cpu.3.cx_supported: C1/1/0 C2/2/100
dev.cpu.3.%parent: acpi0
dev.cpu.3.%pnpinfo: _HID=none _UID=0
dev.cpu.3.%location: handle=\_PR_.C003
dev.cpu.3.%driver: cpu
dev.cpu.3.%desc: ACPI CPU
dev.cpu.2.cx_usage: 100.00% 0.00% last 5985us
dev.cpu.2.cx_lowest: C1
dev.cpu.2.cx_supported: C1/1/0 C2/2/100
dev.cpu.2.%parent: acpi0
dev.cpu.2.%pnpinfo: _HID=none _UID=0
dev.cpu.2.%location: handle=\_PR_.C002
dev.cpu.2.%driver: cpu
dev.cpu.2.%desc: ACPI CPU
dev.cpu.1.cx_usage: 100.00% 0.00% last 1538us
dev.cpu.1.cx_lowest: C1
dev.cpu.1.cx_supported: C1/1/0 C2/2/100
dev.cpu.1.%parent: acpi0
dev.cpu.1.%pnpinfo: _HID=none _UID=0
dev.cpu.1.%location: handle=\_PR_.C001
dev.cpu.1.%driver: cpu
dev.cpu.1.%desc: ACPI CPU
dev.cpu.0.cx_usage: 100.00% 0.00% last 299us
dev.cpu.0.cx_lowest: C1
dev.cpu.0.cx_supported: C1/1/0 C2/2/100
dev.cpu.0.%parent: acpi0
dev.cpu.0.%pnpinfo: _HID=none _UID=0
dev.cpu.0.%location: handle=\_PR_.C000
dev.cpu.0.%driver: cpu
dev.cpu.0.%desc: ACPI CPU
dev.cpu.%parent:

Ich muss mal schauen, ob ich im BIOS einen Schalter für APM finde...

Nachtrag: Habe jetzt erst in deiner "bunten" Beschreibung gelesen, dass AMD64-System noch gar nicht unterstützt werden. Dann ist das ein zu erwartendes Ergebnis ... ;-)
 
Nachtrag: Habe jetzt erst in deiner "bunten" Beschreibung gelesen, dass AMD64-System noch gar nicht unterstützt werden. Dann ist das ein zu erwartendes Ergebnis ... ;-)
Ich erinnere mich nicht so etwas jemals geschrieben zu haben. Du hast wahrscheinlich das cpufreq Kernel Modul nicht geladen.

Das sollte ich wohl besser mal mit in das rc-Skript einbauen.
 
Das cpufreq Modul ist Teil des GENERIC Kernels unter amd64 und i386.

Ein
Code:
kldload -n cpufreq
schadet zwar nicht, aber es gibt valide Gründe aus denen es fehlschlagen kann z.B. wenn powerd++ mit bereits erhöhtem Securelevel gestartet wird.
 
Zurück
Oben