// SPDX-License-Identifier: GPL-2.0-only
/*
* ( C ) 2004 - 2009 Dominik Brodowski < linux @ dominikbrodowski . de >
* ( C ) 2011 Thomas Renninger < trenn @ novell . com > Novell Inc .
*/
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include "helpers/sysfs.h"
unsigned int sysfs_read_file(const char *path, char *buf, size_t buflen)
{
int fd;
ssize_t numread;
fd = open(path, O_RDONLY);
if (fd == -1 )
return 0 ;
numread = read(fd, buf, buflen - 1 );
if (numread < 1 ) {
close(fd);
return 0 ;
}
buf[numread] = '\0' ;
close(fd);
return (unsigned int ) numread;
}
/*
* Detect whether a CPU is online
*
* Returns :
* 1 - > if CPU is online
* 0 - > if CPU is offline
* negative errno values in error case
*/
int sysfs_is_cpu_online(unsigned int cpu)
{
char path[SYSFS_PATH_MAX];
int fd;
ssize_t numread;
unsigned long long value;
char linebuf[MAX_LINE_LEN];
char *endp;
struct stat statbuf;
snprintf(path, sizeof (path), PATH_TO_CPU "cpu%u" , cpu);
if (stat(path, &statbuf) != 0 )
return 0 ;
/*
* kernel without CONFIG_HOTPLUG_CPU
* - > cpuX directory exists , but not cpuX / online file
*/
snprintf(path, sizeof (path), PATH_TO_CPU "cpu%u/online" , cpu);
if (stat(path, &statbuf) != 0 )
return 1 ;
fd = open(path, O_RDONLY);
if (fd == -1 )
return -errno;
numread = read(fd, linebuf, MAX_LINE_LEN - 1 );
if (numread < 1 ) {
close(fd);
return -EIO;
}
linebuf[numread] = '\0' ;
close(fd);
value = strtoull(linebuf, &endp, 0 );
if (value > 1 )
return -EINVAL;
return value;
}
/* CPUidle idlestate specific /sys/devices/system/cpu/cpuX/cpuidle/ access */
/* CPUidle idlestate specific /sys/devices/system/cpu/cpuX/cpuidle/ access */
/*
* helper function to check whether a file under " . . / cpuX / cpuidle / stateX / " dir
* exists .
* For example the functionality to disable c - states was introduced in later
* kernel versions , this function can be used to explicitly check for this
* feature .
*
* returns 1 if the file exists , 0 otherwise .
*/
unsigned int sysfs_idlestate_file_exists(unsigned int cpu,
unsigned int idlestate,
const char *fname)
{
char path[SYSFS_PATH_MAX];
struct stat statbuf;
snprintf(path, sizeof (path), PATH_TO_CPU "cpu%u/cpuidle/state%u/%s" ,
cpu, idlestate, fname);
if (stat(path, &statbuf) != 0 )
return 0 ;
return 1 ;
}
/*
* helper function to read file from / sys into given buffer
* fname is a relative path under " cpuX / cpuidle / stateX / " dir
* cstates starting with 0 , C0 is not counted as cstate .
* This means if you want C1 info , pass 0 as idlestate param
*/
unsigned int sysfs_idlestate_read_file(unsigned int cpu, unsigned int idlestate,
const char *fname, char *buf, size_t buflen)
{
char path[SYSFS_PATH_MAX];
int fd;
ssize_t numread;
snprintf(path, sizeof (path), PATH_TO_CPU "cpu%u/cpuidle/state%u/%s" ,
cpu, idlestate, fname);
fd = open(path, O_RDONLY);
if (fd == -1 )
return 0 ;
numread = read(fd, buf, buflen - 1 );
if (numread < 1 ) {
close(fd);
return 0 ;
}
buf[numread] = '\0' ;
close(fd);
return (unsigned int ) numread;
}
/*
* helper function to write a new value to a / sys file
* fname is a relative path under " . . / cpuX / cpuidle / cstateY / " dir
*
* Returns the number of bytes written or 0 on error
*/
static
unsigned int sysfs_idlestate_write_file(unsigned int cpu,
unsigned int idlestate,
const char *fname,
const char *value, size_t len)
{
char path[SYSFS_PATH_MAX];
int fd;
ssize_t numwrite;
snprintf(path, sizeof (path), PATH_TO_CPU "cpu%u/cpuidle/state%u/%s" ,
cpu, idlestate, fname);
fd = open(path, O_WRONLY);
if (fd == -1 )
return 0 ;
numwrite = write(fd, value, len);
if (numwrite < 1 ) {
close(fd);
return 0 ;
}
close(fd);
return (unsigned int ) numwrite;
}
/* read access to files which contain one numeric value */
enum idlestate_value {
IDLESTATE_USAGE,
IDLESTATE_POWER,
IDLESTATE_LATENCY,
IDLESTATE_TIME,
IDLESTATE_DISABLE,
MAX_IDLESTATE_VALUE_FILES
};
static const char *idlestate_value_files[MAX_IDLESTATE_VALUE_FILES] = {
[IDLESTATE_USAGE] = "usage" ,
[IDLESTATE_POWER] = "power" ,
[IDLESTATE_LATENCY] = "latency" ,
[IDLESTATE_TIME] = "time" ,
[IDLESTATE_DISABLE] = "disable" ,
};
static unsigned long long sysfs_idlestate_get_one_value(unsigned int cpu,
unsigned int idlestate,
enum idlestate_value which)
{
unsigned long long value;
unsigned int len;
char linebuf[MAX_LINE_LEN];
char *endp;
if (which >= MAX_IDLESTATE_VALUE_FILES)
return 0 ;
len = sysfs_idlestate_read_file(cpu, idlestate,
idlestate_value_files[which],
linebuf, sizeof (linebuf));
if (len == 0 )
return 0 ;
value = strtoull(linebuf, &endp, 0 );
if (endp == linebuf || errno == ERANGE)
return 0 ;
return value;
}
/* read access to files which contain one string */
enum idlestate_string {
IDLESTATE_DESC,
IDLESTATE_NAME,
MAX_IDLESTATE_STRING_FILES
};
static const char *idlestate_string_files[MAX_IDLESTATE_STRING_FILES] = {
[IDLESTATE_DESC] = "desc" ,
[IDLESTATE_NAME] = "name" ,
};
static char *sysfs_idlestate_get_one_string(unsigned int cpu,
unsigned int idlestate,
enum idlestate_string which)
{
char linebuf[MAX_LINE_LEN];
char *result;
unsigned int len;
if (which >= MAX_IDLESTATE_STRING_FILES)
return NULL;
len = sysfs_idlestate_read_file(cpu, idlestate,
idlestate_string_files[which],
linebuf, sizeof (linebuf));
if (len == 0 )
return NULL;
result = strdup(linebuf);
if (result == NULL)
return NULL;
if (result[strlen(result) - 1 ] == '\n' )
result[strlen(result) - 1 ] = '\0' ;
return result;
}
/*
* Returns :
* 1 if disabled
* 0 if enabled
* - 1 if idlestate is not available
* - 2 if disabling is not supported by the kernel
*/
int sysfs_is_idlestate_disabled(unsigned int cpu,
unsigned int idlestate)
{
if (sysfs_get_idlestate_count(cpu) <= idlestate)
return -1 ;
if (!sysfs_idlestate_file_exists(cpu, idlestate,
idlestate_value_files[IDLESTATE_DISABLE]))
return -2 ;
return sysfs_idlestate_get_one_value(cpu, idlestate, IDLESTATE_DISABLE);
}
/*
* Pass 1 as last argument to disable or 0 to enable the state
* Returns :
* 0 on success
* negative values on error , for example :
* - 1 if idlestate is not available
* - 2 if disabling is not supported by the kernel
* - 3 No write access to disable / enable C - states
*/
int sysfs_idlestate_disable(unsigned int cpu,
unsigned int idlestate,
unsigned int disable)
{
char value[SYSFS_PATH_MAX];
int bytes_written;
if (sysfs_get_idlestate_count(cpu) <= idlestate)
return -1 ;
if (!sysfs_idlestate_file_exists(cpu, idlestate,
idlestate_value_files[IDLESTATE_DISABLE]))
return -2 ;
snprintf(value, SYSFS_PATH_MAX, "%u" , disable);
bytes_written = sysfs_idlestate_write_file(cpu, idlestate, "disable" ,
value, sizeof (disable));
if (bytes_written)
return 0 ;
return -3 ;
}
unsigned long sysfs_get_idlestate_latency(unsigned int cpu,
unsigned int idlestate)
{
return sysfs_idlestate_get_one_value(cpu, idlestate, IDLESTATE_LATENCY);
}
unsigned long sysfs_get_idlestate_usage(unsigned int cpu,
unsigned int idlestate)
{
return sysfs_idlestate_get_one_value(cpu, idlestate, IDLESTATE_USAGE);
}
unsigned long long sysfs_get_idlestate_time(unsigned int cpu,
unsigned int idlestate)
{
return sysfs_idlestate_get_one_value(cpu, idlestate, IDLESTATE_TIME);
}
char *sysfs_get_idlestate_name(unsigned int cpu, unsigned int idlestate)
{
return sysfs_idlestate_get_one_string(cpu, idlestate, IDLESTATE_NAME);
}
char *sysfs_get_idlestate_desc(unsigned int cpu, unsigned int idlestate)
{
return sysfs_idlestate_get_one_string(cpu, idlestate, IDLESTATE_DESC);
}
/*
* Returns number of supported C - states of CPU core cpu
* Negativ in error case
* Zero if cpuidle does not export any C - states
*/
unsigned int sysfs_get_idlestate_count(unsigned int cpu)
{
char file[SYSFS_PATH_MAX];
struct stat statbuf;
int idlestates = 1 ;
snprintf(file, SYSFS_PATH_MAX, PATH_TO_CPU "cpuidle" );
if (stat(file, &statbuf) != 0 || !S_ISDIR(statbuf.st_mode))
return 0 ;
snprintf(file, SYSFS_PATH_MAX, PATH_TO_CPU "cpu%u/cpuidle/state0" , cpu);
if (stat(file, &statbuf) != 0 || !S_ISDIR(statbuf.st_mode))
return 0 ;
while (stat(file, &statbuf) == 0 && S_ISDIR(statbuf.st_mode)) {
snprintf(file, SYSFS_PATH_MAX, PATH_TO_CPU
"cpu%u/cpuidle/state%d" , cpu, idlestates);
idlestates++;
}
idlestates--;
return idlestates;
}
/* CPUidle general /sys/devices/system/cpu/cpuidle/ sysfs access ********/
/*
* helper function to read file from / sys into given buffer
* fname is a relative path under " cpu / cpuidle / " dir
*/
static unsigned int sysfs_cpuidle_read_file(const char *fname, char *buf,
size_t buflen)
{
char path[SYSFS_PATH_MAX];
snprintf(path, sizeof (path), PATH_TO_CPU "cpuidle/%s" , fname);
return sysfs_read_file(path, buf, buflen);
}
/* read access to files which contain one string */
enum cpuidle_string {
CPUIDLE_GOVERNOR,
CPUIDLE_GOVERNOR_RO,
CPUIDLE_DRIVER,
MAX_CPUIDLE_STRING_FILES
};
static const char *cpuidle_string_files[MAX_CPUIDLE_STRING_FILES] = {
[CPUIDLE_GOVERNOR] = "current_governor" ,
[CPUIDLE_GOVERNOR_RO] = "current_governor_ro" ,
[CPUIDLE_DRIVER] = "current_driver" ,
};
static char *sysfs_cpuidle_get_one_string(enum cpuidle_string which)
{
char linebuf[MAX_LINE_LEN];
char *result;
unsigned int len;
if (which >= MAX_CPUIDLE_STRING_FILES)
return NULL;
len = sysfs_cpuidle_read_file(cpuidle_string_files[which],
linebuf, sizeof (linebuf));
if (len == 0 )
return NULL;
result = strdup(linebuf);
if (result == NULL)
return NULL;
if (result[strlen(result) - 1 ] == '\n' )
result[strlen(result) - 1 ] = '\0' ;
return result;
}
char *sysfs_get_cpuidle_governor(void )
{
char *tmp = sysfs_cpuidle_get_one_string(CPUIDLE_GOVERNOR_RO);
if (!tmp)
return sysfs_cpuidle_get_one_string(CPUIDLE_GOVERNOR);
else
return tmp;
}
char *sysfs_get_cpuidle_driver(void )
{
return sysfs_cpuidle_get_one_string(CPUIDLE_DRIVER);
}
/* CPUidle idlestate specific /sys/devices/system/cpu/cpuX/cpuidle/ access */
/*
* Get sched_mc or sched_smt settings
* Pass " mc " or " smt " as argument
*
* Returns negative value on failure
*/
int sysfs_get_sched(const char *smt_mc)
{
return -ENODEV;
}
/*
* Get sched_mc or sched_smt settings
* Pass " mc " or " smt " as argument
*
* Returns negative value on failure
*/
int sysfs_set_sched(const char *smt_mc, int val)
{
return -ENODEV;
}
Messung V0.5 in Prozent C=96 H=100 G=97
¤ Dauer der Verarbeitung: 0.13 Sekunden
(vorverarbeitet am 2026-10-11)
¤
*© Formatika GbR, Deutschland