Radek Chalupa   konzultace a školení programování, vývoj software na zakázku

Jak na Linuxu v programu v jazyce C sledovat aktuální frekvenci procesoru

27.7.2020

Aktuální frekvenci jednotlivých procesorů/jader zjistíme načtením souboru /sys/devices/system/cpu/cpu*/cpufreq/scaling_cur_freq, kde * je číslo toho kterého procesoru/jádra v kilohertzech. Můžeme tedy za * postupně dosazovat čísla od nuly a po testu zda takový soubor existuje, jej načíst a hodnotu převést na číslo a podle potřeby nějak formátově vypsat (nejlépe v MHz nebo GHz)

Následující zdrojový kód můžeme po přeložení využít jako výstup na nějaký panel (tint2, xfce4-panel, ...), kde nastavíme jeho spuštění třeba každou sekundu. Jako parametry můžeme zadat nadpis (label) jako parametr -l a pokud chceme výpis v MHz, zadáme parametr jednotky jako -um. Výchozí jednotkou jsou GHz.

#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <sys/stat.h>
#include <unistd.h>
#include <string.h>
#include <limits.h>
#include <getopt.h>

#define MAX_LABEL_LENGTH 15
#define MAX_CPU_COUNT 16

long _frequency[MAX_CPU_COUNT];
unsigned int _cpu_found = 0;
int _units = 6; // Ghz

int is_regular_file(const char* file_path)
{
	struct stat ss;
	if (stat(file_path, &ss) != 0)
		return 0;
	else
		return (ss.st_mode & S_IFMT) == S_IFREG;
}

long get_value_from_file(const char* file_path)
{
	FILE* pfile = fopen(file_path, "r");
	if (NULL == pfile)
		return -1;
	char buffer[255];
	long lret;
	if (fgets(buffer, sizeof(buffer), pfile))
	{
		lret = strtol(buffer, NULL, 10);
		if (0 == lret)
		{
			lret = -1;
		}
		else if (LONG_MAX == lret || LONG_MIN == lret)
		{
			lret = -1;
		}
	}
	else
	{
		lret = -1;
	}
	fclose(pfile);
	return lret;
}

int main(int argc, char** argv)
{
	char label[MAX_LABEL_LENGTH+1];
	int opt;
	strcpy(label, "cpu: ");
	if (argc > 1)
	{
		while ((opt = getopt(argc, argv, "l:u:")) != -1)
		{
			switch (opt)
			{
			case 'l':
				if (strlen(optarg) <= MAX_LABEL_LENGTH)
				{
					if (0 == strcmp(optarg, "0"))
						*label = 0;
					else
						strcpy(label, optarg);
				}
				break;
			case 'u':
				if (*optarg == 'm' || *optarg == 'M')
					_units = 3;
				break;
			}
		}
	}
	char file_path[255];
	for (;;)
	{
		sprintf(file_path,
			"/sys/devices/system/cpu/cpu%u/cpufreq/scaling_cur_freq",
			_cpu_found);
		if (is_regular_file(file_path))
		{
			_frequency[_cpu_found] = get_value_from_file(file_path);
			_cpu_found++;
		}
		else
			break;
	}
	printf("%s", label);
	for (size_t i = 0; i < _cpu_found; i++)
	{
		if (6 ==_units)
			printf("%.2f ", (float)_frequency[i]/1000000);
		else
			printf("%ld ", _frequency[i]/1000);
	}
	if (6 ==_units)
		printf("(GHz)");
	else
		printf("(MHz)");
	return EXIT_SUCCESS;
}

Zdrojový kód přeložíme překladačem GCC:

gcc -O3 show-cpu-freq.c -o show-cpu-freq

Zdojový kód na github: https://github.com/radekchalupa/cpu-tools/blob/master/show-cpu-freq.c