Another one is:but I think it doesn't use as much electrical power as the fft one.Compile with something like:
Code:
stress-ng --matrix 0 -t 0Its a C program I wrote. Very badly written, but efficient in that it uses as few resources as possible so that it doesn't itself affect the readings. I used to have a shell script but found the minimum clock speeds were not happening because of the load caused by running the script!How and where did you get that log? does it create a log file with this, and where is it located?
Code:
/* * Raspberry Pi 5 System Monitor * * This code is lightweight to avoid triggering the frequency scaling governor. * * It would be preferable to use the mailbox directly. However compared to the shell * script this C version does one less call to vcgencmd (collects CPU and CORE in one go), * removes the script overheads, and improves the presentation. * Worst case execution time per sample (700MHz Pi1) 87ms. * * USAGE: pistat [delay [count]] * Delay and count behave as vmstat see "man vmstat" for info. * * LIMITS (without simple code change): * MEMORY >= 256MB && MEMORY <= 128GB * CPU >= 100MHz && CPU < 10GHz * CORE >= 100MHz && CORE < 1GHz * VOLTS < 10.0 * TEMP >= 10C && TEMP < 100 * * fft consumes more power * // stress-ng --matrix 0 -t 0 * stress-ng --cpu 0 --cpu-method fft * * benchmark * sysbench --test=cpu --cpu-max-prime=20000 --num-threads=4 run * sysbench cpu --threads=4 --time=60 run * * 22/04/2022 record min and max temperatures * 06/11/2022 sample time origin * 21/11/2022 corrected cpu/core rounding * 12/01/2024 use /sys/class/thermal instead of vcgencmd for temps * 11/01/2025 removed NULL bytes from output * 28/01/2025 Summary is only printed when count terminates * 28/01/2025 Acore removed from display leaving only Vcore and Wcore */ // check outputs from vsgencmd etc#define DEBUG 1#define _GNU_SOURCE 1#include <stdio.h>#include <stdlib.h>#include <stdbool.h>#include <inttypes.h>#include <unistd.h>#include <fcntl.h>#include <string.h>#include <time.h>#include <signal.h>#include <errno.h>#define chr(c) (char)((c) | 48)#define scan(p,r,c) ({ do --r; while( *p++ != c && r ); p[-1] == c; })#define result(st) fgets(in, IOSIZE, fp); s = in + st#define collect(com,st) fp = popen("vcgencmd " #com, "r"); result(st)#define inline __inline__ __attribute__((always_inline))#define error(s) { write(2, s "\n", sizeof(s)); _exit(1); }#define repeat for(;;)#define elif else iftypedef uint16_t u16;typedef uint32_t u32;typedef double real;#define IOSIZE 1024static inline char *utoa( char *p, u32 n ){ do *--p = chr(n % 10); while( n /= 10 ); return p;}/* * Get the Pi description including the memory size * For example: Raspberry Pi 4 Model B Rev 1.4 8GB */static char *model( char * const in, char * const buf ){ const int fd = open("/proc/device-tree/model", O_RDONLY); if( fd < 0 ) return in; char *tail, *p = in + read(fd, in, IOSIZE) - 1; close(fd); /* * Get the Pi's memory size. * Also properly validate vcgencmd (no checks are done for the periodic update). */ errno = 0; FILE *fp = popen("vcgencmd get_config total_mem", "r"); if( fp == NULL || errno ) error("cannot run vcgencmd"); fgets(buf, IOSIZE, fp); pclose(fp);#if DEBUG if( memcmp(buf, "total_mem=", 10) ) error("total_mem field missing");#endif u32 mem = (u32)strtoul(buf + 10, &tail, 10); if( *tail != '\n' || mem < 256 || mem > 128*1024 || errno ) error("total_mem field invalid"); char *e = buf + 8; if( mem < 1024 ) *e = 'M'; else { mem /= 1024; *e = 'G'; } e[1] = 'B'; e = utoa(e, mem); *p++ = ' '; p = mempcpy(p, e, (size_t)((buf + 10) - e));#if 0 // no separate GPU mem in Pi5 fp = popen("vcgencmd get_mem gpu", "r"); fgets(buf, IOSIZE, fp); pclose(fp); e = buf + 4; while( *e != 'M' ) ++e; return mempcpy(mempcpy(mempcpy(p, " (GPU ", 6), buf + 4, (size_t)(e - (buf + 3))), "B)\n", 3);#else *p++ = '\n'; return p;#endif} // Stats so far (time spent at each CPU frequency)static char *time_in_state( char *p, char *buf ){ const int fd = open("/sys/devices/system/cpu/cpufreq/policy0/stats/time_in_state", O_RDONLY); if( fd < 0 ) return p; const ssize_t file_len = read(fd, buf, IOSIZE); close(fd); bool align = false; ssize_t rem = file_len; for( char *t = buf, *ptr = buf; rem > 0 && scan(ptr, rem, '\n'); t = ptr ) { if( t[6] != ' ' ) { align = true; break; } } rem = file_len; for( char *ptr = buf; rem > 0 && scan(ptr, rem, '\n'); buf = ptr ) { size_t len = 7; if( buf[6] == ' ' ) { if( align )*p++ = ' '; len = 6; } // discard last three zero's giving MHz to match values below p = mempcpy(mempcpy(p, buf, len - 3), buf + len, (size_t)(ptr - buf) - len); } return p;} // round CPU speedsstatic inline size_tinc( char ** const p, size_t len ){ char *q = *p; u32 n = 0; do n = n * 10 + (*q++ & 15); while( --len ); const u32 r = n % 10; if( r < 5 ) n -= r; else n += 10 - r; *p = utoa(q, n); return (size_t)(q - *p);}static real min_vcore = 100.0, max_vcore = 0.0, min_wcore = 100.0, max_wcore = 0.0, min_temp = 100.0, max_temp = 0.0;static long double sum_vcore = 0.0, sum_wcore = 0.0, sum_temp = 0.0;static u32 delay = 1, sample_count = 0;static long doubleroll( const long double ave, real sample ){ if( sample_count == 0 ) return sample; return ave + sample;}static voidsummary( void ){ if( max_vcore > 0.0 ) { printf("\nSummary min ave max (over %.2Lf minutes)\n" "Vcore %6.3f%7.3Lf%6.3f\n" "Wcore %6.3f%7.3Lf%6.3f\n" "Temp %6.0f%7.2Lf%6.0f\n", ((long double)sample_count * (long double)delay) / 60.0L, min_vcore, sum_vcore / sample_count, max_vcore, min_wcore, sum_wcore / sample_count, max_wcore, min_temp, sum_temp / sample_count, max_temp); }}intmain( int argc, const char *argv[] ){ char buf[IOSIZE+8], in[IOSIZE]; char *s, *p; u32 count = 1; size_t len; FILE *fp; time_t t; if( argc > 1 ) { char *tail; delay = (u32)strtoul(argv[1], &tail, 10); if( tail == argv[1] ) error("invalid delay"); if( argc > 2 ) { count = (u32)strtoul(argv[2], &tail, 10); if( tail == argv[2] )error("invalid count"); } else count = UINT32_MAX; } // headers write(1, in, (size_t)(time_in_state(model(in, buf), buf) - in)); fp = popen("uptime", "r"); memcpy(buf, "Uptime:\n", 8); fgets(buf + 8, IOSIZE, fp); write(1, buf, strlen(buf)); pclose(fp); fp = popen("free -h", "r"); fgets(buf, IOSIZE, fp); memcpy(buf, "Free -h:", 8); write(1, buf, strlen(buf)); fgets(buf, IOSIZE, fp); write(1, buf, strlen(buf)); fgets(buf, IOSIZE, fp); write(1, buf, strlen(buf)); pclose(fp); const int fan = open("/sys/class/thermal/cooling_device0/cur_state", O_RDONLY); if( fan < 0 ) write(1, "Fan disabled.\n", 14); else { close(fan); write(1, "Fan enabled.\n", 13); } // const int temp = open("/sys/class/thermal/thermal_zone0/temp", O_RDONLY); const int temp = open("/sys/devices/virtual/thermal/thermal_zone0/temp", O_RDONLY); if( temp < 0 ) { write(1, "/sys/class/thermal ... failure\n", 32); exit(EXIT_FAILURE); } buf[5] = buf[2] = ':'; for( u32 i = 0; i < count; ++i ) { ++sample_count; memset(p = buf + 8, ' ', 64); // CPU MHz "frequency(48)=2100000000" collect(measure_clock arm core, 13); // 14 for Pi4 13 for Pi5 len = 3 + (s[9] != '\n'); if( s[len] != '0' ) len = inc(&s, len); memcpy((p += 8) - len, s, len); // CORE MHz "frequency(1)=200000000" result(13); pclose(fp); len = 3 + (s[9] != '\n'); if( s[len] != '0' ) len = inc(&s, len); memcpy((p += 7) - len, s, len); // cpu VOLTAGE and CURRENT "VDD_CORE_A current(7)=1.58061000A" fp = popen("vcgencmd pmic_read_adc", "r"); for( int i = 0; i < 8; ++i ) fgets(in, IOSIZE, fp); const real acore = strtod(in + 24, NULL);#if DEBUG if( memcmp(in, " VDD_CORE_A", 12) ) error("VDD_CORE_A field missing");#endif for( int i = 0; i < 12; ++i ) fgets(in, IOSIZE, fp);#if DEBUG if( memcmp(in, " VDD_CORE_V", 12) ) error("VDD_CORE_V field missing");#endif const real vcore = strtod(in + 22, NULL); const real wcore = vcore * acore; buf[25 + sprintf(buf + 25, "%6.3f%8.3f", vcore, wcore)] = ' '; pclose(fp); if( vcore > max_vcore ) max_vcore = vcore; if( vcore < min_vcore ) min_vcore = vcore; sum_vcore = roll(sum_vcore, vcore); if( wcore > max_wcore ) max_wcore = wcore; if( wcore < min_wcore ) min_wcore = wcore; sum_wcore = roll(sum_wcore, wcore); // TEMPERATURE "12345\n" read(temp, in, 3); lseek(temp, 0, SEEK_SET); u32 cur_temp = (in[0] - 48U) * 10U + in[1] - 48U; if( in[2] > '4' ) ++cur_temp; p = buf + 44; p[0] = chr(cur_temp / 10); p[1] = chr(cur_temp % 10); const real ct = (real)cur_temp; if( ct > max_temp ) max_temp = ct; if( ct < min_temp ) min_temp = ct; sum_temp = roll(sum_temp, ct); // HEALTH "throttled=0x0\n" p = buf + 51; collect(get_throttled, 10); if( s[3] == '\n' ) p = mempcpy(p, "OK", 2); pclose(fp); // TIME time(&t); struct tm const * const now = localtime(&t); buf[0] = chr(now->tm_hour / 10); buf[1] = chr(now->tm_hour % 10); buf[3] = chr(now->tm_min / 10); buf[4] = chr(now->tm_min % 10); buf[6] = chr(now->tm_sec / 10); buf[7] = chr(now->tm_sec % 10); // Print record *p++ = '\n'; if( (i & 15) == 0 ) write(1, "Time CPU Core Vcore Wcore Temp Health\n", 55); write(1, buf, (size_t)(p - buf)); if( i + 1 < count ) sleep(delay); } if( count > 1 ) summary();}Code:
gcc pistat.c -Os -s -mcmodel=tiny -o pistatStatistics: Posted by jahboater — Tue Jul 01, 2025 2:17 pm