Seite wählen

NETWAYS Blog

P-States selbst schalten? CPU-Performancemanagement unter Linux

Was sind nochmal P-States?

TLDR: P-States sind Performance-States. Wer sich mit der offiziellen Linux-Kernel Dokumentation auseinandersetzt, findet zusammengefasst das moderne Prozessoren in verschiedenen Abständen Frequenz- und Spannungskonfigurationen vornehmen, die auch ‚Operating Performance Points‘ oder auch P-States genannt werden (obwohl man hier korrekterweise eigentlich nach CPU-Architektur & Generation unterscheiden müsste), um Leistung und Stromverbrauch zu bestimmen. Im Linux Kernel findet man hierzu das CPUFreq-Subsystem das aus drei Layern besteht: Dem Kern, Scaling-Governorn und Scaling-Treibern. Während Scaling-Governer Algorithmen zur Abschätzung künftiger Leistung da sind, kommunizieren Scaling-Treiber mit der Hardware.

Vorab: Überprüfe bitte, dass Tuned & TLP nicht stören (sollten diese extra installiert worden sein). Unter Linux befindet sich das CPUFreq Verzeichnis unter /sys/devices/system/cpu und für cpu0 unter /sys/devices/system/cpu/cpu0/cpufreq/

Einfach mal ein cat auf die oben gelisteten Dateien werfen und schauen was das eigene Gerät so bietet. Zum Beispiel könnte man sich die scaling_available_governors (das braucht man für später) anschauen. Noch cooler, durch die „Everything is a file“-Philosophie bei Unix ist es jetzt direkt möglich die scaling_min_freq zu überschreiben und sofort hochzutakten! Wichtig ist nur zu wissen, dass die Werte in KHz angegeben werden.

  • Beispiel: Bei mir sind in jenem scaling_min_freq 800000 KHz eingetragen was also 0.8 GHz entspräche.
  • Ich ändere mal den Wert in 2.7 GHz um nicht unter 2.7 GHz zu takten, danach lasse mir im Anschluss das Ergebnis zur Prüfung anzeigen (nur zu Demozwecken):

Als Root:

 echo 2700000 > /sys/devices/system/cpu/cpu0/cpufreq/scaling_min_freq && cat /proc/cpuinfo | grep MHz

Warum manuell schalten oft besser sein kann:

Die meisten Geräte laufen meiner Erfahrung nach unter einem powersave statt einem performance-Profil was manche Desktop-Erweiterungen anzeigen.

  • Das kann natürlich beim sofortigen Browseröffnen mit mehreren Tabs (plus mehreren Extensions), oder Snaps oft zum Ruckeln führen da es auch für gute Governor Profile sehr schwer ist alles mit einzubeziehen.
  • Selbiges betrifft oft auch Wifi & Bluetooth-Chipsätze, die mit individuelleren Performance-Tweaks sowie dem Abschalten des Anderen (fast immer teilen sich beide den Chip) auf einmal wesentlich besser oder stromsparender laufen.
  • Wenn Du auf längeren Reisen unterwegs bist drehst Du einfach die Frequenz auf ein Minimum runter (ohne irgendeine Chance auf höhere Frequenzen) um auf höhere Batterielaufzeiten zu kommen.
  • Nicht jedes Gerät unterstützt CPU Governor wie ondemand oder conservative wobei ersteres aggressiver, schneller und genauer arbeitet und letzterer entspannter, langsamer und ungenauer. Willst du wirklich nur powersave ausgesetzt bleiben?

Du scheinst zu wissen worauf ich nun hinaus will, es ist gut zu wissen wie man selbst schaltet, und das am besten sicher, ohne dauernd das Root-Passwort einzugeben müssen und mit Hotkey? Hier mein Ansatz:

Der Plan:

  • Teil 1: Du installierst Dir die entsprechenden Distributions-Kernel-Module.
  • Teil 2: Du legst Dir als Root-Benutzer unter /usr/local/bin 6 Dateien an. Somit teilst Du deine CPU Leistung in sinnvolle Profile ein (ein Beispiel folgt), während der eigentliche Nutzer in diese Skripte nicht schreiben darf.
  • Teil 3: Du gibst jenem Benutzer die Möglichkeit diese Skripte ohne Passwortabfrage auszuführen.
  • Teil 4: Du legst dir 6 Hotkeys an: 4 für die Skripte sowie 2 für powersave und performance.

Teil 1

  • Packte installieren:

Fedora:

sudo dnf install kernel-tools

Ubuntu:

sudo apt install linux-tools-5.8.0-63-generic #(Ubuntu will an dieser Stelle die genaue Kernelversion zum Packet wissen, und macht dir einen Vorschlag)

Testen ob es funktioniert, nun solltet du einen Frequenzwechsel der Kerne zurückbekommen:

sudo cpupower frequency-set -g powersave
sudo cpupower frequency-set -g performance

Teil 2

  • Ab jetzt bitte unter Root arbeiten: Hier erstellst und legst Du in einem Benutzerverzeichnis für Skripte 6 zusätzliche Performanz-Profile an (low, medium, high, max, powersave & performance) und machst diese im Anschluss ausführbar.
  • In folgendem Codeabschnitt ersetzt du min und max je pro Profil also 8x: Angenommen deine CPU hätte 4,2 GHZ Maximum, eine sinnvolle Einteilung in 1 GHz Abständen könnte so aussehen. (min=Minimum ist und max=Maximum):
cd /usr/local/bin && touch cpu{low,mid,high,max,performance,powersave}.sh;
echo $'#!/bin/bash\ncpupower frequency-set --min 800000 --max 1500000' > /usr/local/bin/cpulow.sh;
echo $'#!/bin/bash\ncpupower frequency-set --min 1500000 --max 2500000' > /usr/local/bin/cpumid.sh;
echo $'#!/bin/bash\ncpupower frequency-set --min 2600000 --max 3500000' > /usr/local/bin/cpuhigh.sh;
echo $'#!/bin/bash\ncpupower frequency-set --min 3600000 --max 4200000' > /usr/local/bin/cpumax.sh;
echo $'#!/bin/bash\ncpupower frequency-set -g performance' > /usr/local/bin/cpuperformance.sh;
echo $'#!/bin/bash\ncpupower frequency-set -g powersave' > /usr/local/bin/cpupowersave.sh;
cd /usr/local/bin && chmod +x cpu{low,mid,high,max,performance,powersave}.sh

Teil 3

  • Rechte setzen via: visudo
  • Hier ersetzt Du folgendes: Dein_Benutzername=Deinen Benutzernamen

#Eigene CPU-Frequenz Profile für Benutzer: Dein_Benutzername

 Dein_Benutzername ALL=(root) NOPASSWD: /usr/local/bin/cpulow.sh, /usr/local/bin/cpumid.sh, /usr/local/bin/cpuhigh.sh, /usr/local/bin/cpumax.sh, /usr/local/bin/cpuperformance.sh, /usr/local/bin/cpupowersave.sh

Teil 4

Hotkeys legen ist je nach Desktop-Umgebung anders, die Logik dahinter aber gleich: Immer gibt es irgendwo ein Feld oder eine Konfigurationsdatei in die man reinschreibt: Zum Beispiel unter XFCE4  via Keyboard->Application Shortcuts. Ich lege mir hier meine 6 Skripte auf die Windows/Super-Tasten {1-6}.

Super+1 = sudo -u root /usr/local/bin/cpulow.sh
Super+2 = sudo -u root /usr/local/bin/cpumid.sh
Super+3 = sudo -u root /usr/local/bin/cpuhigh.sh
Super+4 = sudo -u root /usr/local/bin/cpumax.sh
Super+5 = sudo -u root /usr/local/bin/cpuperformance.sh
Super+6 = sudo -u root /usr/local/bin/cpupowersave.sh

Lust auf mehr? Meine Ausbilder bei Professional Services bringen mir später in der Ausbildung noch mehr zu Thema Performance-Tuning bei und können Dir helfen das letzte bisschen Leistung aus Deiner Open Source Infrastruktur herauszuholen.

Stresstest für InfluxDB

Nach einer frischen Installation von InfluxDB, egal ob auf einem dedizierten System oder nicht, frägt man sich vielleicht wie leistungsfähig das Graphing Setup nun wirklich ist oder wie viel es denn eigentlich verträgt?

Diese Fragen lassen sich mit influx-stress beantworten. Das in Golang geschriebene Helferchen ist über GitHub erhältlich und feuert beliebig viele einstellbare Metriken an InfluxDB. Dabei spielt es keine Rolle ob es lokal oder remote von einem anderen System aus aufgerufen wird.

Installation

Nachdem das Repository heruntergeladen wurde, wird das Ganze mit „go build“ kompiliert:

# git clone https://github.com/influxdata/influx-stress.git
# cd influx-stress/cmd/influx-stress/
# go build -o /usr/local/bin/influx-stress

Vorbereitungen

Das Tool unterstützt derzeit nur die Authentifizierung für v1, allerdings kann man auf diese bei Bedarf auch komplett verzichten. Mit InfluxDB OSS 2.x kann dafür die „InfluxDB 1.x compatibility API“ benutzt werden. Außerdem empfiehlt es sich für die Tests ein eigenes Bucket anzulegen um es später in einem Rutsch wieder zu löschen oder um gleich eine passende Retention Policy zu definieren.

# influx bucket create -n stress
# influx bucket list
# influx v1 auth create --username stress --password ****** --write-bucket f596604f968324ff
# influx v1 dbrp create --bucket-id f596604f968324ff --db stress --rp infinite

Let’s go!

Sind die Vorbereitungen gemacht, kann es losgehen. Mit „-f“ läuft die Abgabe der Metriken so schnell wie möglich (fast as possible). Ich würde empfehlen zumindest noch mit „-r“ (runtime) die Laufzeit einzuschränken, andernfalls würde es endlos laufen. Durch Eingabe von „–host“ definiert man den Remotehost (Standard: „http://localhost:8086“).

# /usr/local/bin/influx-stress insert -f -r 1m --user stress --passs ****** --db stress

Eine beispielhafte Serie (für Icinga) könnte so aussehen: (Standard: „ctr,some=tag n=0i“)

# /usr/local/bin/influx-stress insert -r 1m ping4,hostname=agent.example.com,service=ping4,metric=rta crit=0.200000,min=0,unit="seconds",value=0.200000,warn=0.100000 --user stress --passs ****** --db stress

Nach erfolgtem Lauf bekommt man sowohl den Durchsatz (Throughput) als auch die geschriebenen Punkte (Points Written) angezeigt. Außerdem werden die Standardeinstellungen für die nicht definierten Parameter ausgegeben, die sich natürlich aber auch noch abändern lassen.

Using batch size of 10000 line(s)
Spreading writes across 100000 series
Output is unthrottled
Using 20 concurrent writer(s)
Running until ~18446744073709551615 points sent or until ~1m0s has elapsed
Write Throughput: 212335
Points Written: 13100000

Wer mehr zum Thema InfluxDB erfahren möchte, dem kann ich neben unseren üblichen Dienstleistungen auch unser InfluxDB & Grafana Training wärmstens ans Herz legen.

Markus Waldmüller
Markus Waldmüller
Head of Strategic Projects

Markus war bereits mehrere Jahre als Sysadmin in Neumarkt i.d.OPf. und Regensburg tätig. Nach Technikerschule und Selbständigkeit ist er nun Anfang 2013 bei NETWAYS als Senior Manager Services gelandet. Seit September 2023 kümmert er sich bei der NETWAYS Gruppe um strategische Projekte. Wenn er nicht gerade die Welt bereist, ist der sportbegeisterte Neumarkter mit an Sicherheit grenzender Wahrscheinlichkeit auf dem Mountainbike oder am Baggersee zu finden.

Festplattenbenchmark mit bonnie++

Vor einigen Wochen haben Killian und Ich eine Serverwartung durchgeführt. Dabei haben wir nach der Aktualisierung einen sehr simplen Festplatten-Benchmark mittels dd durchgeführt. Im Nachhinein interessierte es mich, welche Performancewerte denn mein Arbeitslaptop bringen würde. Da ich genauere und ausführlichere Performancewerte haben wollte, suchte ich nach Benchmarktools. Nach einiger Recherche im Internet fand ich das Tool bonnie++, welches sich perfekt für einen Festplattenbenchmark eignet.
bonnie++ ist in den meisten Repositories verfügbar oder kann auf der Homepage heruntergeladen werden. Mit „aptget install bonnie++installiert man bonnie++ auf einem Debian/Ubuntu basierten System. Nun kann man schon mit den Tests starten!

Um  aussagekräftige Werte zu bekommen, muss man den Filecache so gering wie möglich halten. Man erreicht dies indem man Datasets schreibt, welche größer als der zu Verfügung stehende RAM ist (bonnie++ nimmt als Defaultwert  2 x RAM). Als Folge muss man also mindestens 2 x RAM freien Festplattenspeicher haben!

Wenn man bonnie++ ohne Parameter startet wird das Tool ausgeführt und liefert ein leicht unübersichtliches Ergebnis:

user@user-notebook:~$ bonnie++
Writing a byte at a time...done
Writing intelligently...done
Rewriting...done
Reading a byte at a time...done
Reading intelligently...done
start 'em...done...done...done...done...done...
Create files in sequential order...done.
Stat files in sequential order...done.
Delete files in sequential order...done.
Create files in random order...done.
Stat files in random order...done.
Delete files in random order...done.
Version 1.97 ------Sequential Output------ --Sequential Input- --Random-
Concurrency 1 -Per Chr- --Block-- -Rewrite- -Per Chr- --Block-- --Seeks--
Machine Size K/sec %CP K/sec %CP K/sec %CP K/sec %CP K/sec %CP /sec %CP
user-notebook 15664M 658 99 290591 40 180714 21 1909 99 498792 39 8705 159
Latency 38628us 193ms 269ms 22258us 14790us 5094us
Version 1.97 ------Sequential Create------ --------Random Create--------
user-notebook -Create-- --Read--- -Delete-- -Create-- --Read--- -Delete--
 files /sec %CP /sec %CP /sec %CP /sec %CP /sec %CP /sec %CP
 16 +++++ +++ +++++ +++ +++++ +++ +++++ +++ +++++ +++ +++++ +++
Latency 589us 1486us 935us 814us 71us 452us
1.97,1.97,nb-user-notebook,1,1524129932,15664M,,658,99,290591,40,180714,21,1909,99,498792,39,8705,159,16,,,,,+++++,+++,+++++,+++,+++++,+++,+++++,+++,+++++,+++,+++++,+++,38628us,193ms,269ms,22258us,14790us,5094us,589us,1486us,935us,814us,71us,452us

Falls man über eine GUI verfügt, kann man sich den Output auch in eine HTML-Datei speichern und diese über einen Webbrowser öffnen. Dies geht mit folgendem Befehl:

bonnie++ | tail -n 1 | bon_csv2html > $(date +"%Y.%m.%d.%S.%N")_bonnie.html

Die nun erstellte HTML-Datei listet alle Werte strukturiert auf und kann zugleich als Vergleichswert für spätere Tests verwendet werden.

Es ist auch möglich bonnie++ mit individuellen Einstellungen zu starten, im Folgendem die wichtigsten Parameter:

  • -r: Größe des Arbeitsspeichers in Megabyte und somit auch die Größe des zu erstellenden Datasets
  • -n: Anzahl der Dateien die zu einem Dataset zusammengesetzt werden
  • -x n: Der Test wird „n-mal“ ausgeführt
  • -s: Definiert die Größe des Datasets in Megabyte
  • -b: Schaltet „write buffering“ aus und führt einen „Sync“ am Ende jeder bonnie++-Operation durch

(Alle Parameter mit ausführlicher Beschreibung findet man im Manual)
Man sollte bonnie++ mehrmals am Tag ausführen, denn nur so können Anomalien abgefangen werden und man erhält einen aussagekräftigen Durchschnittswert.
Quellen: UbuntuWiki, OCH-Group, JamesCoyle

NETWAYS Web Services: Nextcloud 13 now up and running!


A lot of Nextcloud users have waited for the new Nextcloud 13 version to be available. Now our NWS team has implemented it for all Nextcloud apps on our platform.
Nextcloud 13 will bring you the following enhanced functions to your cloud:

  • Video and Text chat
  • End-to-end Encryption
  • Refined User Interface
  • Improved Performance
  • Improved File Sync and Share

Nextcloud users will now profit from a new app called Nextcloud Talk which provides an Open Source platform for audio, video and text communication in real-time as well as in asynchronous mode. Push notifications will help you to never miss a message! Absolute privacy is guaranteed by implementation of end-to-end encrypted calls that are 100% secure peer-to-peer.
Another big innovation is the End-to-End Encryption of content which can now be controlled by the users themselves. In the current Tech Preview release in version 13 it is now possible to encrypt single folders chosen by the users via their Nextcloud client. This prohibits the server side from accessing and seeing the folder or file content. The preview is available in mobile clients for Android and iOS as well as in desktop clients for Windows, Mac and Linux. Nextcloud will continue to enhance its encryption functionality over the next months.

Performance is also an important subject when it comes to the daily use of a certain software. The Nextcloud team has done a lot to make your work and collaboration faster and more comfortable by decreasing for example page load times as well as improving Server-Side-Encryption and external storage performance. For more information on performance enhancements please have a look at Nextcloud’s own blog article

For more detailed information on the new Nextcloud release you should visit the Nextcloud website or start your own Nextcloud instance on our NWS platform. Please remember that we offer a 30 day free trial period for every app!

Avoiding Common Pitfalls with Apply Rules

When building apply rules for your Icinga 2 configuration there are a few common pitfalls you should avoid:
1. Using apply when you’re really just creating a single object
Rule-based configs are great at simplifying your config. However, there are times when you really just want to create a single object. One common anti-pattern I’ve come across is this:

apply Service "ntp" {
  ...
  assign where host.name == "ntp1.example.org"
}

Now, obviously this will work as intended, however there are two significant problems: Writing a filter rule for a single host is unnecessarily complicated and additionaly there is a significant performance penalty because this rule has to be evaluated for all of your hosts.
A much simpler way to achieve this is to just use a simple object declaration:

object Service "ntp" {
  host_name = "ntp1.example.org"
  ...
}

2. Using too many assign where rules
Apply rules are intended to be used to make your config more general by putting your hosts into certain classes („all ntp servers“, „all database servers“, etc.) and then assigning services and notifications to each member of a certain class. However, for some reason people sometimes do this instead:

apply Service "web" {
  ...
  assign where host.name == "web1.example.org"
  assign where host.name == "web2.example.org"
  assign where host.name == "web3.example.org"
  ...
  assign where host.name == "web73.example.org"
}

The obvious problem here is that this is a maintenance nightmare – and as we’ve already learned „assign where“ rules aren’t exactly free in terms of performance.
Unlike in our first example the solution isn’t to unroll this filter by creating an „object“ definition for each of the hosts. Instead you should use some of the great filtering capabilities that come with Icinga 2. Here’s a short list of just some of the filters that are available:
1. CIDR matching (using the cidr_match function)
2. Regular expressions (using the regex function)
3. Wildcard matches (using the match function)
4. and last but not least: custom variables
In this particular example I’m going to use wildcard matching and custom variables:

object Host "web1.example.org" { }
object Host "web2.example.org" { }
object Host "web3.example.org" { vars.no_web_check = false }
apply Service "web" {
  ...
  assign where match("web*.example.org", host.name)
  ignore where host.vars.no_web_check
}

This assumes that all of your „web“ hosts should have a „web“ service by default. Using „ignore where“ we can make sure that certain hosts don’t get the service.
3. Reusing „assign where“ filters
This is pretty much the opposite problem compared to our previous example. Instead of using the same filter expression dozens of times in the same apply rule this is about unnecessarily repeating the filter in multiple apply rules:

apply Service "mysql" {
  ...
  // All db hosts except those in the dev subnet
  assign where match("db*.example.org", host.name) && !cidr_match("172.16.23.0/24", host.address)
}
apply Service "postgresql" {
  ...
  // All db hosts except those in the dev subnet
  assign where match("db*.example.org", host.name) && !cidr_match("172.16.23.0/24", host.address)
}
apply Service "mssql" {
  ...
  // All db hosts except those in the dev subnet
  assign where match("db*.example.org", host.name) && !cidr_match("172.16.23.0/24", host.address)
}

Code reuse is a best common practice when it comes to writing software. This also applies to Icinga 2 and makes your config much more maintainable and pleasant to work with.
Here’s how you can re-use your filter expression in multiple apply rules:

globals.is_prod_database_host = function(host) {
  // All db hosts except those in the dev subnet
  return match("db*.example.org", host.name) && !cidr_match("172.16.23.0/24", host.address)
}
apply Service "mysql" {
  ...
  assign where is_prod_database_host(host)
}
apply Service "postgresql" {
  ...
  assign where is_prod_database_host(host)
}
apply Service "mssql" {
  ...
  assign where is_prod_database_host(host)
}

By using descriptive function names you also gain the advantage of making your code… er, config more readable.