Raketenwilli: Wer kann das bitte mit testen?

Das Skript läuft nur auf Linux-Servern - und ich würde gerne mal wissen auf wie vielen - oder wenigen 😟

  • Läuft.
  • Läuft nicht.
  • Mangels öffentlicher URL nicht zeigbar: Auf einem Rechner mit AMD-CPU läuft es sehr wohl...

Bevor gefragt wird: Das Skript ändert nichts am System, es gibt nur - wenn die Voraussetzungen erfüllt sind - die möglichen Arbeitsfrequenzen und deren Nutzungszeit (je nach Auswahl menschen- und maschinenlesbar) aus.

<?php

class cpustat {

	protected $governor;
	protected $minfreq;
	protected $curfreq;
	protected $maxfreq;
	protected $timestates;
	protected $calcstates;
	protected $sysruntime;
	protected $cpuTimefactor = 100;
	protected $hmFactor      = 1000000;
	protected $hmString      = 'GHz';

	function __construct() {
		$this -> read_from_system();
	}
	
	function read_from_system() {
		$this -> governor   = trim( file_get_contents( '/sys/devices/system/cpu/cpu0/cpufreq/scaling_governor' ) );
		$this -> minfreq    = trim( file_get_contents( '/sys/devices/system/cpu/cpu0/cpufreq/scaling_min_freq' ) );
		$this -> curfreq    = trim( file_get_contents( '/sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq' ) );
		$this -> maxfreq    = trim( file_get_contents( '/sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq' ) );
		$this -> timestates = file_get_contents( '/sys/devices/system/cpu/cpu0/cpufreq/stats/time_in_state' );
		$this -> calcstates = $this -> calcTimestates();
	}

	function human_readble ( $z ) {
			$z = $z / $this -> hmFactor;
			return sprintf("%0.3f %s", $z, $this -> hmString );
	}

	private function getValue ( $v, $hm ) {
		if ( $hm ) {
			return $this -> human_readble( $v );
		} else {
			return $v;
		}		
	}
	
    function calcTimestates()  {
		$lines = explode ( "\n", $this -> timestates );
		$sum = 0;
		$arr = [];
		foreach ( $lines as $line ) {
			$line = trim( $line );
			if ( $line ) {
				list( $f, $t ) = explode ( ' ', $line );
				$t = floor( $t / $this->cpuTimefactor );
				if ( $t != 0 ) {
					$sum += $t;
					$f = $this -> human_readble( $f);
					$arr[$f]['t_abs'] = $t;
					$arr[$f]['t_hum'] = Seconds2Human( $t );
				}
			}
		}
		$this -> sysruntime = $sum;
				
		foreach ( array_keys( $arr )  as $f ) {
			$arr[$f]['t_rel'] = round( $arr[$f]['t_abs'] / $sum , 3 ) ;
			$arr[$f]['t_100'] = round( $arr[$f]['t_abs'] / $sum * 100 , 1 ) . '%';
		}
		return $arr;
	}	

	function getMinFreq( $hm=false ) {
		 return $this -> getValue ( $this -> minfreq, $hm );
	}
	
	function getCurFreq( $hm=false ) {
		 return $this -> getValue ( $this -> curfreq, $hm );
	}
	
	function getMaxFreq( $hm=false ) {
		 return $this -> getValue ( $this -> maxfreq, $hm );
	}
	
	function getSysRunTime( $hm=false ) {
		if ( $hm ) {
			return Seconds2Human( $this -> sysruntime );
		} else {
			$this -> sysruntime;		
		}
	}
	
	function getCalcstates () {
		return  $this -> calcstates;
	}
	
	function getGovernor () {
		return  $this -> governor;
	}	
	
}


function Seconds2Human( $s, $daystring="d" ) {
	$s = (int) $s;
	# Days
	if ( $s > 86400 ) {
		$d = floor( $s / 86400 );
		$s = $s - $d * 86400;
	} else {
		$d = 0;
	}
	
	# Houres
	if ( $s > 3600 ) {
		$h = floor( $s / 3600 );
		$s = $s - $h * 3600;
	} else {
		$h = 0;
	}
	
	# Minutes
	if ( $s > 60 ) {
		$m = floor( $s / 60 );
		$s = $s - $m * 60;
	} else {
		$m = 0;
	}	
	
	return sprintf( '%d%s %02d:%02d:%02d', $d, $daystring, $h, $m, $s );
}

header ( 'Content-Type: text/plain; charset=utf-8' );
error_reporting( E_ALL );
ini_set('display_errors', 1);

if (! is_file( '/sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq' ) ) {
	echo "Leider wird Ihr System nicht unterstützt. Ende.";
	exit;
}

$cpustat = new cpustat();
echo 'Governor:              ' . $cpustat-> getGovernor(     ) . PHP_EOL;
echo 'Geringste Frequenz:    ' . $cpustat-> getMinFreq( true ) . PHP_EOL;
echo 'Geringste Frequenz:    ' . $cpustat-> getMinFreq( true ) . PHP_EOL;
echo 'Gegenwärtige Frequenz: ' . $cpustat-> getCurFreq( true ) . PHP_EOL;
echo 'Maximale Frequenz:     ' . $cpustat-> getMaxFreq( true ) . PHP_EOL;
echo 'System läuft seit:     ' . $cpustat-> getSysRunTime( true ) . PHP_EOL . PHP_EOL;
echo 'Zeitliche Frequenznutzung:';
print_r( $cpustat-> getCalcstates() ) ;
echo PHP_EOL;

akzeptierte Antworten

  1. Leider wird Ihr System nicht unterstützt. Ende.

    if (! is_file( '/sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq' ) ) {

    wird es wohl sein. Win10 WSL2 Debian.

    1. Hi there,

      Leider wird Ihr System nicht unterstützt. Ende.

      if (! is_file( '/sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq' ) ) {

      wird es wohl sein. Win10 WSL2 Debian.

      ich nehme einmal an, deswegen hat der Raketenfuzzy auch geschrieben: "Das Skript läuft nur auf Linux-Servern"...

      1. Hi there,

        Leider wird Ihr System nicht unterstützt. Ende.

        if (! is_file( '/sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq' ) ) {

        wird es wohl sein. Win10 WSL2 Debian.

        ich nehme einmal an, deswegen hat der Raketenfuzzy auch geschrieben: "Das Skript läuft nur auf Linux-Servern"...

        Eine Virtualisierung ist eine Virtualisierung. Wie oft kommt aktuell noch wirklich direkt Blech zum Einsatz?

        1. Hallo Mitleser,

          es gibt aber einen Unterschied zwischen einem virtualisierten Linux und einem Windows-basierenden Hilfskonstrukt (um es mal wertschätzend und höflich zu formulieren 😉)

          Offenbar ist Windows Subsystem for Linux ≠ Linux

          Das lässt nun zwei Deutungen zu:

          • Das Hilfskonstrukt ist nicht kompatibel genug
          • Die Raketenidee /sys/devices/system/cpu ist nicht kompatibel genug

          Weswegen ja auch diese Umfrage initiiert wurde, denke ich mal.

          Rolf

          --
          sumpsi - posui - obstruxi
        2. Hi there,

          ich nehme einmal an, deswegen hat der Raketenfuzzy auch geschrieben: "Das Skript läuft nur auf Linux-Servern"...

          Eine Virtualisierung ist eine Virtualisierung. Wie oft kommt aktuell noch wirklich direkt Blech zum Einsatz?

          Ja, im Produktivitätseinsatz vermutlich nicht oft. Anyway, ich hab mir im Detail nicht angesehen, was das Skript macht oder wie tief es in die Hardware schaut...

    2. Das Skript läuft zumindest nicht mit in jeder „Virtualisierungsumgebung“, scheinbar auch nicht in jeder

      In manchen werden eben die Prozessordaten nicht nach nach /sys/sonstwas geschrieben, da erhalte ich übrigens auch so manche andere Daten nicht...

  2. Das Skript läuft nur auf Linux-Servern - und ich würde gerne mal wissen auf wie vielen - oder wenigen 😟

    also ich weiß ja nicht was Du unter "läuft" verstehst, auf einem Mint-Rechner, der aus welchem Grund auch immer einen Apachen startet (mit anderen Worten, den man auch als Webserver verwenden könnte) kommt Folgendes zum Vorschein:

    <br /> <b>Warning</b>: file_get_contents(/sys/devices/system/cpu/cpu0/cpufreq/stats/time_in_state): failed to open stream: No such file or directory in <b>/var/www/html/test.php</b> on line <b>25</b><br />

    Governor: powersave

    Geringste Frequenz: 1.600 GHz

    Geringste Frequenz: 1.600 GHz

    Gegenw�rtige Frequenz: 1.600 GHz

    Maximale Frequenz: 2.400 GHz

    System l�uft seit: 0d 00:00:00

    Zeitliche Frequenznutzung:Array ( )

    Was jetzt kein Wunder ist, weil unter "/sys/devices/system/cpu"" kein "cpu0" zu finden ist. Der Rechner ist ein eher lahmer Celeron-Doppelkerner. Ich hab noch irgendwo einen AMD-Webserver mit Ubuntu20irgendwas stehen, ich werd's dort auch noch probieren...

    1. Hallo klawischnigg,

      Was jetzt kein Wunder ist, weil unter "/sys/devices/system/cpu" kein "cpu0" zu finden ist.

      Was jetzt durchaus ein Wunder ist, denn

      if (! is_file( '/sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq' ) ) {
      	echo "Leider wird Ihr System nicht unterstützt. Ende.";
      	exit;
      }
      

      sollte in dem Fall dafür sorgen, dass das Programm gar nicht erst in die cpustat Klasse einsteigt (abgesehen vom Fun Fact, dass dein Pfefferminzbonbon ohne cpu0 nichts hätte, um das Script auszuführen 😉).

      Ich kenne den devices-Zweig von Linux nicht, aber im Sinne von "everything is a file" dürften sich dort Systeminfos finden, die wie Dateien in Ordnern präsentiert werden. Und wenn eine is_file Abfrage auf ein Dings im cpu0 Ordner zutrifft, müsstet Du den auch finden können. Es sei denn, ein schnöder ls zeigt sowas - weil's nicht wirklich eine Datei ist - nicht an.

      Rolf

      --
      sumpsi - posui - obstruxi
      1. Hi there,

        sollte in dem Fall dafür sorgen, dass das Programm gar nicht erst in die cpustat Klasse einsteigt (abgesehen vom Fun Fact, dass dein Pfefferminzbonbon ohne cpu0 nichts hätte, um das Script auszuführen 😉).

        Du hast ja sowas von recht, ich hab mich nur verschaut...😉

      2. Es sei denn, ein schnöder ls zeigt sowas - weil's nicht wirklich eine Datei ist - nicht an.

        Tut es. Es ist ein Dateisystem namens "sysfs". Was allenfalls verwirrend ist sind die Größenangaben.

        mount sagt:

        sysfs on /sys type sysfs (rw,nosuid,nodev,noexec,relatime)
        
    2. Was jetzt kein Wunder ist, weil unter "/sys/devices/system/cpu"" kein "cpu0" zu finden ist.

      Hm. Kann ich bitte mal die Ausgaben von

      uname -a
      

      und

      ls /sys/devices/system/cpu
      

      sehen?

      1. Was jetzt kein Wunder ist, weil unter "/sys/devices/system/cpu"" kein "cpu0" zu finden ist.

        Hm. Kann ich bitte mal die Ausgaben von

        uname -a
        

        Linux vpc 5.4.0-107-generic #121-Ubuntu SMP Thu Mar 24 16:04:27 UTC 2022 x86_64 x86_64 x86_64 GNU/Linux

        und

        ls /sys/devices/system/cpu
        

        sehen?

        cpu0 cpufreq hotplug isolated microcode offline possible present uevent cpu1 cpuidle intel_pstate kernel_max modalias online power smt vulnerabilities

        hope it helps...;)

    3. Frage: Hast Du nur den Unterordner /cpu0/ rausgeschraubt?

      1. Frage: Hast Du nur den Unterordner /cpu0/ rausgeschraubt?

        nein, ich hab mich nur verschaut, ich "/sys/devices/cpu" mit "/sys/devices/system/cpu" verwechselt...

        anyway, die Ressource resp. Datei "/sys/devices/system/cpu/cpu0/cpufreq/stats/time_in_state" ist trotzdem nicht da. Ich schick Dir einen Sshot von dem Directory mit:

        1. Hm. cpuinfo_cur_freq gibt es bei Dir auch nicht…

  3. Hi there,

    Das Skript läuft nur auf Linux-Servern - und ich würde gerne mal wissen auf wie vielen - oder wenigen 😟

    also, ich habs jetzt auf einem "echten" Webserver getestet (also das ist ein relativ alter AMD-Einkerner, auf dem läuft nix anderes als Apache und Co., ich verwend den ab zu zum Entwickeln und Ausprobieren, denn wenn es auf dieser Krücke zufriendenstellend läuft, dann geht es überall😉)

    Das Ergebnis:

    Das System ist:

    Linux flagship22 5.4.0-92-generic #103-Ubuntu SMP Fri Nov 26 16:13:00 UTC 2021 x86_64 x86_64 x86_64 GNU/Linux

    1. ein relativ alter AMD-Einkerner

      Das scheint viel mehr vom Kernel und geladenen Modulen abhängig zu sein - die z.B. bei Virtualisierungen halt modprobe nicht fehlerfrei überstehen und rausgeworfen werden.

      Irgendwie ist es Dir gelungen, den Quelltext in einer anderes Kodierung als utf-8 zu übertragen. Auch das der MC bei Dir so merkwürdig aufscheint hängt damit zusammen...

      1. ein relativ alter AMD-Einkerner

        Das scheint viel mehr vom Kernel und geladenen Modulen abhängig zu sein - die z.B. bei Virtualisierungen halt modprobe nicht fehlerfrei überstehen und rausgeworfen werden.

        Ja, alles was hardware-nahe ist oder mit dem System zu tun hat ist mit Sprachen wie PHP oä. nicht wirklich gut abzufragen...

        1. Ja, alles was hardware-nahe ist oder mit dem System zu tun hat ist mit Sprachen wie PHP oä. nicht wirklich gut abzufragen...

          Naja. Linux-Programme wie cpufreq-info fragen auch nur den Kram unter /sys ab. Aber offenbar haben die Entwickler Zugang zu Informationen, was welcher Kernel und welches Modul so treibt.

      2. Hi there,

        Irgendwie ist es Dir gelungen, den Quelltext in einer anderes Kodierung als utf-8 zu übertragen.

        Ich hätte das in meinem Editor (Ultra-Edit von IDM) als utf-8 speichern müssen, dann wäre die Anzeige richtig gewesen.

        Auch das der MC bei Dir so merkwürdig aufscheint hängt damit zusammen...

        Das glaub ich nicht. Ich seh' jetzt nicht, was Dein Skript, das ich auf den Servern gespeichert habe, mit der Darstellung des MC in meinem Putty zu tun haben soll. Besonders nicht, da ja die Umlaute richtig dargestellt werden, nur manche Sonderzeichen werden falsch dargestellt. Ich hab irgendwann damit herumgespielt, und dann hab ich es nach 10 Minuten bleiben lassen, meine Zeit ist mir für diesen Blödsinn echt zu schade...😉

  4. Dank Eurer Unterstützung und ein paar Fundstellen im Netz habe ich eine neue Version zusammengekratzt.

    Das Problem, dass virtuelle Maschinen und etliche andere Umgebungen die Daten aus /sys gar nicht erst bekommen ist auch nicht behebbar, sondern mindestens teilweise die Absicht der Erschaffer dieser Umgebungen. Immerhin kann man in etliche der Dateien unter sys auch direkt schreiben.

    <?php
    
    class cpufreq {
    
    	protected $governor;
    	protected $minfreq;
    	protected $curfreq;
    	protected $maxfreq;
    	protected $calcstates;
    	protected $sysruntime;
    	protected $cpuTimefactor = 100;
    	protected $hmFactor      = 1000000;
    	protected $hmString      = 'GHz';
    	protected $path;
    	
    	function __construct() {
    		if ( is_dir( '/sys/devices/system/cpu/cpu0/cpufreq/' ) ) {
    			$this -> path = '/sys/devices/system/cpu/cpu0/cpufreq/';
    		} elseif ( is_dir( '/sys/devices/system/cpu/cpufreq/' ) ) {
    			$this -> path = '/sys/devices/system/cpu/cpufreq/';
    		}
    		$this -> read_from_system();
    	}
    	
    	function read_from_system() {
    		
    		if ( is_file( $this -> path . 'scaling_governor' ) )  {
    			$this -> governor   = trim( file_get_contents( $this -> path . 'scaling_governor' ) );
    			$this -> minfreq    = trim( file_get_contents( $this -> path . 'scaling_min_freq' ) );
    			$this -> curfreq    = trim( file_get_contents( $this -> path . 'scaling_cur_freq' ) );
    			$this -> maxfreq    = trim( file_get_contents( $this -> path . 'scaling_max_freq' ) );
    		} elseif( is_file( $this -> path . 'cpuinfo_min_freq' ) ) {
    			$this -> governor = false;
    			$this -> minfreq    = trim( file_get_contents( $this -> path . 'cpuinfo_min_freq' ) );
    			$this -> maxfreq    = trim( file_get_contents( $this -> path . 'cpuinfo_max_freq' ) );
    			if ( is_file( $this -> path . 'cpuinfo_curr_freq' ) ) {
    				$this -> curfreq = trim( file_get_contents( $this -> path . 'cpuinfo_cur_freq' ) );
    			} elseif ( $this -> maxfreq == $this -> minfreq ) {
    				$this -> curfreq = 	$this -> minfreq;
    			} else {
    				$this -> curfreq = 0;
    			}
    		} else {
    			http_response_code( 507 );
    			echo 'Leider wird Ihr System nicht unterstützt. Ende.';
    			trigger_error( 'System wird vom Skript nicht unterstützt.', E_USER_NOTICE );
    			$this -> governor = false;
    			$this -> minfreq  = 0;
    			$this -> curfreq  = 0;
    			$this -> maxfreq  = trim( file_get_contents( $this -> path . 'cpuinfo_max_freq' ) );				
    		}
    		
    		if ( is_file( $this -> path . 'stats/time_in_state' ) ) {
    			$this -> calcstates = $this -> calcTimestates();
    		} else {
    			$this -> calcstates = false;
    		}
    	}
    
    	function human_readble ( $z ) {
    			$z = $z / $this -> hmFactor;
    			return sprintf('%0.3f %s', $z, $this -> hmString );
    	}
    
    	private function getFreq ( $v, $hm ) {
    		if ( $hm ) {
    			return $this -> human_readble( $v );
    		} else {
    			return $v;
    		}		
    	}
    	
        function calcTimestates()  {
    		$lines = file_get_contents( $this -> path . 'stats/time_in_state' );
    		$lines = explode ( "\n", $lines );
    		$sum = 0;
    		$arr = [];
    		foreach ( $lines as $line ) {
    			$line = trim( $line );
    			if ( $line ) {
    				list( $f, $t ) = explode ( ' ', $line );
    				$t = floor( $t / $this->cpuTimefactor );
    				if ( $t != 0 ) {
    					$sum += $t;
    					$f = $this -> human_readble( $f);
    					$arr[$f]['t_abs'] = $t;
    					$arr[$f]['t_hum'] = Seconds2Human( $t );
    				}
    			}
    		}
    		$this -> sysruntime = $sum;
    				
    		foreach ( array_keys( $arr )  as $f ) {
    			$arr[$f]['t_rel'] = round( $arr[$f]['t_abs'] / $sum , 3 ) ;
    			$arr[$f]['t_100'] = sprintf( '%2.1f%%', round( $arr[$f]['t_abs'] / $sum * 100 , 1 ) );
    		}
    		return $arr;
    	}	
    
    	function getMinFreq( $hm = false ) {
    		 return $this -> getFreq ( $this -> minfreq, $hm );
    	}
    	
    	function getCurFreq( $hm = false ) {
    		 return $this -> getFreq ( $this -> curfreq, $hm );
    	}
    	
    	function getMaxFreq( $hm = false ) {
    		 return $this -> getFreq ( $this -> maxfreq, $hm );
    	}
    	
    	function getSysRunTime( $hm = false ) {
    		if ( $hm ) {
    			return Seconds2Human( $this -> sysruntime );
    		} else {
    			$this -> sysruntime;		
    		}
    	}
    	
    	function getCalcstates () {
    		return  $this -> calcstates;
    	}
    	
    	function getGovernor () {
    		return  $this -> governor;
    	}	
    	
    }
    
    function Seconds2Human( $s, $daystring = 'd' ) {
    	$s = (int) $s;
    	# Days
    	if ( $s > 86400 ) {
    		$d = floor( $s / 86400 );
    		$s = $s - $d * 86400;
    	} else {
    		$d = 0;
    	}
    	
    	# Houres
    	if ( $s > 3600 ) {
    		$h = floor( $s / 3600 );
    		$s = $s - $h * 3600;
    	} else {
    		$h = 0;
    	}
    	
    	# Minutes
    	if ( $s > 60 ) {
    		$m = floor( $s / 60 );
    		$s = $s - $m * 60;
    	} else {
    		$m = 0;
    	}	
    	
    	return sprintf( '%d%s %02d:%02d:%02d', $d, $daystring, $h, $m, $s );
    }
    
    header ( 'Content-Type: text/plain; charset=utf-8' );
    error_reporting( E_ALL );
    ini_set( 'display_errors', 1 );
    
    $cpustat = new cpufreq();
    echo 'Governor:              ' . $cpustat-> getGovernor(     ) . PHP_EOL;
    echo 'Geringste Frequenz:    ' . $cpustat-> getMinFreq( true ) . PHP_EOL;
    echo 'Gegenwärtige Frequenz: ' . $cpustat-> getCurFreq( true ) . PHP_EOL;
    echo 'Maximale Frequenz:     ' . $cpustat-> getMaxFreq( true ) . PHP_EOL;
    echo 'System läuft seit:     ' . $cpustat-> getSysRunTime( true ) . PHP_EOL . PHP_EOL;
    
    /*
    if ( $a = $cpustat-> getCalcstates() ) {
    	echo PHP_EOL . 'Zeitliche Frequenznutzung:'. PHP_EOL;
    	print_r( $cpustat-> getCalcstates() ) ;
    }
    # */ 
    
    #/*
    if ( $a = $cpustat-> getCalcstates() ) {
    	
    	echo PHP_EOL . 'Zeitliche Frequenznutzung:' . PHP_EOL;
    	foreach ( array_keys( $a ) as $freq ) {
    		echo $freq . ':  ' . sprintf( "%5s", $a[$freq]['t_100'] ) . "\n";
    	}
    }
    # */
    
    echo PHP_EOL;
    

    Output:

    Governor:              conservative
    Geringste Frequenz:    0.600 GHz
    Gegenwärtige Frequenz: 0.600 GHz
    Maximale Frequenz:     1.500 GHz
    System läuft seit:     1d 20:19:26
    
    
    Zeitliche Frequenznutzung:
    0.600 GHz:  99.4%
    0.700 GHz:   0.2%
    0.800 GHz:   0.1%
    0.900 GHz:   0.1%
    1.000 GHz:   0.0%
    1.100 GHz:   0.0%
    1.200 GHz:   0.1%
    1.300 GHz:   0.0%
    1.400 GHz:   0.0%
    1.500 GHz:   0.0%
    

    Ich schreib das gleich noch mal in Python…

    1. Fortschritt (Ansicht):

      Quelltext:

      Oder, mit umgebrochen notiertem Shell-„Einzeiler” regelmäßig starten:

      while true; do
          out=`php cpufreq.php`;
          clear;
          cat <<< $out;
          sleep 1;
      done
      
    2. Gesagt:

      Ich schreib das gleich noch mal in Python…

      Getan. Beide funktionieren jetzt auch auf dem Webserver und in der Shell.

      PHP:

      Python:

      Das bei der Python-Version (auf einem Raspberry Pi) die CPU-Frequenz stets (sowohl als cgi unter Apache als auch in der Shell ausgeführt) auf das Maximum ansteigt (bei der PHP-Version unter gleichen Bedingungen indes nicht) scheint normal zu sein und liegt wohl am Start des Python-Interpreters.

      Ein häufigeres (aller 1/10 Sekunden) paralleles Auslesen der Datei in der Shell zeigt bei einem den Anstieg und den Abfall der Frequenz an wenn man das Python-Skript startet.