Development Using powerapi
(Optional) Source Code Download
Source code download: https://gitee.com/openeuler/powerapi
Some interfaces in the source code are experimental and have not been released. RELEASE_MODE in the code indicates whether the interfaces are officially released.
For details about released APIs, see the API document in the source code repository.
Installation
Run the following command to install the powerapi-devel software package and use the provided interfaces for development:
yum install powerapi-devel
Basic Procedure
To use query interfaces, you only need to register with powerapi. To use setting interfaces, you need to register with powerapi and request control. Based on service scenarios, the service processes are as follows: Discrete perception service scenario: log callback setting -> registration -> query interface calling -> deregistration Configuration service scenario: log callback setting -> registration -> Control request -> Configuration interface calling -> Control release -> deregistration
powerapi APIs
General APIs
Setting the Log Callback Function
Definition:
PWR_API int PWR_SetLogCallback(void(LogCallback)(int level, const char *fmt, va_list vl))
Description:
Sets the callback logs. After the logs are set, the powerapi library prints the LogCallBack function to the logs. If they are not set, the LogCallBack function is printed to the terminal by default. This API can be called before registration.
Parameters:
Parameter | Type | Description |
---|---|---|
LogCallBack | void(*) | Log callback function pointer |
Returns:
Type | Description |
---|---|
int | 0: Succeeded. 4: Failed. The callback function pointer is empty. |
Setting Server Information
Definition:
PWR_API int PWR_SetServerInfo(const char* socketPath)
Description:
Sets the address of the Unix domain socket communication server.
Parameters:
Parameter | Type | Description |
---|---|---|
socketPath | const char* | Path of the server. |
Returns:
Type | Description |
---|---|
int | 0: Succeeded. 4: Failed. The callback function pointer is empty. |
Note:
The default path of the server socket file is /etc/sysconfig/pwrapis/pwrserver.sock. If you change the default path in the pwrapis configuration file, ensure that the directory permission is 755 and the file permission is 722.
After the path is changed, use this interface to specify the new path of the socket before registration. Otherwise, the connection fails.
Registration
Definition:
PWR_API int PWR_Register(void)
Description:
Registers with the powerapi service.
Parameters: None
Returns:
Type | Description |
---|---|
int | 0: Succeeded. 1: Failed to initialize the socket client. |
Deregistration
Definition:
PWR_API int PWR_UnRegister(void)
Description:
Deregisters with the powerapi service.
Parameters: None
Returns:
Type | Description |
---|---|
int | 0: Succeeded. |
Requesting Energy Efficiency Control
Definition:
PWR_API int PWR_RequestControlAuth(void)
Description:
Requests control of the system energy efficiency. After an upper-layer application takes over energy efficiency control, the system does not automatically adjust energy efficiency anymore.
Parameters: None
Returns:
Type | Description |
---|---|
int | 0: Succeeded. Other value: Failed. See the error codes for details. |
Releasing Energy Efficiency Control
Definition:
PWR_API int PWR_ReleaseControlAuth(void)
Description:
Releases control of the system energy efficiency.
Parameters: None
Returns:
Type | Description |
---|---|
int | 0: Succeeded. Other value: Failed. See the error codes for details. |
CPU
Obtaining CPU Information
Definition:
PWR_API int PWR_CPU_GetInfo(PWR_CPU_Info *cpuInfo)
Description:
Obtains CPU information, including basic CPU information and NUMA information.
Parameters:
Parameter | Type | Description |
---|---|---|
cpuinfo | PWR_CPU_Info* | CPU information. |
Returns:
Type | Description |
---|---|
int | 0: Succeeded. Other value: Failed. See the error codes for details. |
Obtaining the CPU Frequency Ability
Definition:
PWR_API int PWR_CPU_GetFreqAbility(PWR_CPU_FreqAbility *freqAbi, uint32_t bufferSize)
Description:
Queries the information about the available CPU frequency domain, governor, and currently used CPU frequency driver.
Parameters:
Parameter | Type | Description |
---|---|---|
freqAbi | PWR_CPU_FreqAbility* | CPU frequency ability information |
bufferSize | uint32_t | Size of the freqAbi memory block. Recommended size: sizeof(PWR_CPU_FreqAbility) + CPU core count x (sizeof(int) + 5) If the size is too small, only the frequency domain data that can be contained is returned. |
Returns:
Type | Description |
---|---|
int | 0: Succeeded. Other value: Failed. See the error codes for details. |
Obtaining the CPU Frequency Governor
Definition:
PWR_API int PWR_CPU_GetFreqGovernor(char gov[], uint32_t size)
Description:
Obtains the CPU frequency governor in use. By default, the governor of the first frequency domain is obtained.
Parameters:
Parameter | Type | Description |
---|---|---|
gov | char[] | Governor name. The value can contain a maximum of 31 characters. |
size | uint32_t | Size of the gov array. The value must be greater than or equal to PWR_MAX_ELEMENT_NAME_LEN(32). |
Returns:
Type | Description |
---|---|
int | 0: Succeeded. Other value: Failed. See the error codes for details. |
Setting the CPU Frequency Governor
Definition:
PWR_API int PWR_CPU_SetFreqGovernor(const char gov[])
Description:
Sets the CPU frequency governor in use. (The governor will be set for all frequency domains).
Parameters:
Parameter | Type | Description |
---|---|---|
gov | char[] | Governor name. The value can contain a maximum of 31 characters. Examples: conservative ondemand userspace powersave performance schedutil seep |
Returns:
Type | Description |
---|---|
int | 0: Succeeded. Other value: Failed. See the error codes for details. |
Obtaining All Attributes of the CPU Frequency Governor
Definition:
PWR_API int PWR_CPU_GetFreqGovAttrs(PWR_CPU_FreqGovAttrs *govAttrs)
Description:
Obtains all attributes of the CPU frequency governor in use.
Parameters:
Parameter | Type | Description |
---|---|---|
govAttrs | PWR_CPU_FreqGovAttrs* | Attributes of the frequency governor. |
Returns:
Type | Description |
---|---|
int | 0: Succeeded. Other value: Failed. See the error codes for details. |
Obtaining an Attribute of the CPU Frequency Governor
Definition:
PWR_API int PWR_CPU_GetFreqGovAttr(PWR_CPU_FreqGovAttr *govAttr)
Description:
Obtains the attribute of the current CPU frequency in use. The attribute corresponding to the governor used by the first frequency domain (policy0) is obtained.
Parameters:
Parameter | Type | Description |
---|---|---|
govAttrs | PWR_CPU_FreqGovAttrs* | Attributes of the frequency governor. |
Returns:
Type | Description |
---|---|
int | 0: Succeeded. Other value: Failed. See the error codes for details. |
Setting an Attribute of the CPU Frequency Governor
Definition:
PWR_API int PWR_CPU_SetFreqGovAttr(const PWR_CPU_FreqGovAttr *govAttr)
Description:
Sets the attribute of the current CPU frequency in use. The attribute corresponding to the governor used by the first frequency domain (policy0) is set.
Parameters:
Parameter | Type | Description |
---|---|---|
govAttrs | PWR_CPU_FreqGovAttrs* | Attribute of the frequency governor. You need to specify the name and value of the attribute to be set. |
Returns:
Type | Description |
---|---|
int | 0: Succeeded. Other value: Failed. See the error codes for details. |
Note:
Different governor support different attributes. The attributes supported by the governor are stored in /sys/devices/system/cpu/cpufreq/{gov}/, where {gov} indicates the name of the current governor.
Obtaining the CPU Frequency Range
Definition:
PWR_API int PWR_CPU_GetFreqRange(PWR_CPU_FreqRange *freqRange)
Description:
Obtains the CPU frequency range. By default, the frequency range of the first frequency domain is obtained.
Parameters:
Parameter | Type | Description |
---|---|---|
freqRange | PWR_CPU_FreqRange* | Frequency range to obtain. |
Returns:
Type | Description |
---|---|
int | 0: Succeeded. Other value: Failed. See the error codes for details. |
Setting the CPU Frequency Range
Definition:
PWR_API int PWR_CPU_SetFreqRange(const PWR_CPU_FreqRange *freqRange)
Description:
Sets the CPU frequency range. The frequency range will be set for all frequency domains.
Parameters:
Parameter | Type | Description |
---|---|---|
freqRange | PWR_CPU_FreqRange* | Frequency range to set. |
Returns:
Type | Description |
---|---|
int | 0: Succeeded. Other value: Failed. See the error codes for details. |
Obtaining the Current CPU Frequency
Definition:
PWR_API int PWR_CPU_GetFreq(PWR_CPU_CurFreq curFreq[], uint32_t *num, int spec)
Description:
Obtains the current frequency of the frequency domain.
Parameters:
Parameter | Type | Description |
---|---|---|
curFreq | PWR_CPU_CurFreq[] | Frequency information of the current frequency domain of the policy to be queried. When spec is set to 1, policyId of the corresponding member needs to be set. The current frequency of the frequency domain will be output. |
num | uint32_t * | Length of the curFreq array, indicating the number of policies to be queried. The output is the length of the valid data returned by the system (the smaller value between the actual number of policies and the input num). |
spec | int | Whether to obtain the information about one or more specific frequency domains. 0: No. 1: Yes. In this case, you need to set the policyId corresponding to the specific frequency domain in the curFreq member, for example, 32 or 64. |
Returns:
Type | Description |
---|---|
int | 0: Succeeded. Other value: Failed. See the error codes for details. |
Setting the Current CPU Frequency
Definition:
PWR_API int PWR_CPU_SetFreq(const PWR_CPU_CurFreq curFreq[], uint32_t num)
Description:
Sets the frequency of the frequency domain, which can be set only when the CPU frequency governor is set to userspace.
Parameters:
Parameter | Type | Description |
---|---|---|
curFreq | PWR_CPU_CurFreq[] | Frequency domain to be set and its frequency list. |
num | uint32_t | Length of the curFreq array, indicating the number of policies to be set. |
Returns:
Type | Description |
---|---|
int | 0: Succeeded. Other value: Failed. See the error codes for details. |
Obtaining the CPU Idle Ability and Status Information
Definition:
PWR_API int PWR_CPU_GetIdleInfo(PWR_CPU_IdleInfo *idleInfo)
Description:
Obtains the CPU idle ability and status information.
Parameters:
Parameter | Type | Description |
---|---|---|
idleInfo | PWR_CPU_IdleInfo* | CPU idle ability and status information. |
Returns:
Type | Description |
---|---|
int | 0: Succeeded. Other value: Failed. See the error codes for details. |
Obtaining the CPU Idle Governor
Definition:
PWR_API int PWR_CPU_GetIdleGovernor(char idleGov[], uint32_t size)
Description:
Obtains the CPU idle mode.
Parameters:
Parameter | Type | Description |
---|---|---|
idleGov | char[] | Governor name. |
size | uint32_t | Size of the idleGov buffer. The minimum value is PWR_MAX_ELEMENT_NAME_LEN(32). |
Returns:
Type | Description |
---|---|
int | 0: Succeeded. Other value: Failed. See the error codes for details. |
Setting the CPU Idle Governor
Definition:
PWR_API int PWR_CPU_SetIdleGovernor(const char idleGov[])
Description:
Sets the CPU idle mode.
Parameters:
Parameter | Type | Description |
---|---|---|
idleGov | char[] | Governor name, for example: ladder menu teo haltpoll |
Returns:
Type | Description |
---|---|
int | 0: Succeeded. Other value: Failed. See the error codes for details. |
Obtaining the CPU and DMA Latency
Definition:
PWR_API int PWR_CPU_DmaGetLatency(int *latency)
Description:
Obtains the acceptable latency of the CPU and DMA.
Parameters:
Parameter | Type | Description |
---|---|---|
latency | int* | Latency (us). |
Returns:
Type | Description |
---|---|
int | 0: Succeeded. Other value: Failed. See the error codes for details. |
Setting the CPU and DMA Latency
Definition:
PWR_API int PWR_CPU_DmaSetLatency(int latency)
Description:
Sets the acceptable latency of the CPU and DMA.
Parameters:
Parameter | Type | Description |
---|---|---|
latency | int* | Latency (us). Value range: [0, 2000000000] |
Returns:
Type | Description |
---|---|
int | 0: Succeeded. Other value: Failed. See the error codes for details. |
Note:
The CPU requires different wake-up time in different C-states. The wake-up latency increases as the C-states get deeper. Therefore, the system checks the CPU and DMA latency before entering a C-state. If the latency in the C-state is longer than the CPU and DMA latency, the CPU does not enter the C-state.
Reference Wake-up Latency of Each C-state (us)
C-state | Latency |
---|---|
C0 POLL | 0 |
C1 | 2 |
C1E | 10 |
C3 | 40 |
C6 | 133 |
C7S | 166 |
C8 | 300 |
C9 | 600 |
C10 | 2600 |
Usage
Save the following code as powerapi_test.c.
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <string.h>
#include <stdlib.h>
#include <pwrapic/powerapi.h>
#define MAIN_LOOP_INTERVAL 5
#define TEST_FREQ 2400
#define TEST_CORE_NUM 128
#define AVG_LEN_PER_CORE 5
#define TEST_CPU_DMA_LATENCY 2000
#define TASK_INTERVAL 1000
#define TASK_RUN_TIME 10
#define TEST_FREQ_RANGE_MIN 500
#define TEST_FREQ_RANGE_MAX 2500
static int g_run = 1;
static void PrintResult(char *function, int ret)
{
int length = 24;
printf("[TEST ] ");
printf("%-*s", length, function);
printf(":");
if (ret == PWR_SUCCESS) {
printf("SUCCESS ret: %d\n", ret);
} else {
printf("ERROR ret: %d\n", ret);
}
}
enum {
DEBUG = 0,
INFO,
WARNING,
ERROR
};
static const char *GetLevelName(int level)
{
static char debug[] = "DEBUG";
static char info[] = "INFO";
static char warning[] = "WARNING";
static char error[] = "ERROR";
switch (level) {
case DEBUG:
return debug;
case INFO:
return info;
case WARNING:
return warning;
case ERROR:
return error;
default:
return info;
}
}
void LogCallback(int level, const char *fmt, va_list vl)
{
char logLine[4096] = {0};
char message[4000] = {0};
int length = 5;
if (vsnprintf(message, sizeof(message) - 1, fmt, vl) < 0) {
return;
}
printf("[");
printf("%-*s", length, GetLevelName(level));
printf("] %s\n", message);
}
static void SignalHandler(int none)
{
g_run = 0;
}
static void SetupSignal(void)
{
// regist signal handler
(void)signal(SIGINT, SignalHandler);
(void)signal(SIGUSR1, SignalHandler);
(void)signal(SIGUSR2, SignalHandler);
(void)signal(SIGTERM, SignalHandler);
(void)signal(SIGKILL, SignalHandler);
}
/************************** COMMON ************************/
static void TEST_PWR_SetLogCallback(void)
{
int ret = -1;
ret = PWR_SetLogCallback(LogCallback);
PrintResult("PWR_SetLogCallback", ret);
}
static void TEST_PWR_SetServerInfo(void)
{
int ret = -1;
char str[] = "/etc/sysconfig/pwrapis/pwrserver.sock";
ret = PWR_SetServerInfo(str);
PrintResult("PWR_SetServerInfo", ret);
}
static void TEST_PWR_Register(void)
{
while (PWR_Register() != PWR_SUCCESS) {
sleep(MAIN_LOOP_INTERVAL);
PrintResult("PWR_Register", PWR_ERR_COMMON);
continue;
}
PrintResult("PWR_Register", PWR_SUCCESS);
}
static void TEST_PWR_RequestControlAuth(void)
{
int ret = -1;
ret = PWR_RequestControlAuth();
PrintResult("PWR_RequestControlAuth", ret);
}
/************************** COMMON END************************/
/***************************** CPU ***************************/
static void TEST_PWR_CPU_GetInfo(void)
{
int ret = -1;
PWR_CPU_Info *info = (PWR_CPU_Info *)malloc(sizeof(PWR_CPU_Info));
if (!info) {
return;
}
bzero(info, sizeof(PWR_CPU_Info));
ret = PWR_CPU_GetInfo(info);
PrintResult("PWR_CPU_GetInfo", ret);
printf(" arch: %s\n coreNum: %d\n maxFreq: %f\n minFreq: %f\n "
"modelName: %s\n numaNum: %d\n threadsPerCore: %d\n", info->arch,
info->coreNum, info->maxFreq, info->minFreq, info->modelName, info->numaNum,
info->threadsPerCore);
for (int i = 0; i < info->numaNum; i++) {
printf(" numa node[%d] cpuList: %s\n", info->numa[i].nodeNo, info->numa[i].cpuList);
}
free(info);
}
static void TEST_PWR_CPU_GetFreq(void)
{
int ret = -1;
int num = 0;
int spec = 0;
int i = 0;
/**
* Test 1: spec = 0, get all policy freq.
* Set the num to the number of CPU cores
* (it is possible that one kernel corresponds to one policy)
*/
num = TEST_CORE_NUM;
spec = 0;
PWR_CPU_CurFreq cpuCurFreq1[num];
bzero(cpuCurFreq1, num * sizeof(PWR_CPU_CurFreq));
ret = PWR_CPU_GetFreq(cpuCurFreq1, &num, spec);
PrintResult("1 PWR_CPU_GetFreq", ret);
for (i = 0; i < num; i++) {
printf(" policy[%d]: %lf\n", cpuCurFreq1[i].policyId, cpuCurFreq1[i].curFreq);
}
/**
* Test 2: spec = 0 num = 2. get the previous 2 policies freq
*/
ret = -1;
// 2: previous 2 policies
num = 2;
spec = 0;
PWR_CPU_CurFreq cpuCurFreq2[num];
bzero(cpuCurFreq2, num * sizeof(PWR_CPU_CurFreq));
ret = PWR_CPU_GetFreq(cpuCurFreq2, &num, spec);
PrintResult("2 PWR_CPU_GetFreq", ret);
for (i = 0; i < num; i++) {
printf(" policy[%d]: %lf\n", cpuCurFreq2[i].policyId, cpuCurFreq2[i].curFreq);
}
/**
* Test 3: spec = 1, get the two target policy freq
*/
ret = -1;
// 2: previous 2 policies
num = 2;
spec = 1;
PWR_CPU_CurFreq cpuCurFreq3[num];
bzero(cpuCurFreq3, num * sizeof(PWR_CPU_CurFreq));
cpuCurFreq3[0].policyId = 0;
// 32 : the Id of the second policy.
cpuCurFreq3[1].policyId = 32;
ret = PWR_CPU_GetFreq(cpuCurFreq3, &num, spec);
PrintResult("3 PWR_CPU_GetFreq", ret);
for (i = 0; i < num; i++) {
printf(" policy[%d]: %lf\n", cpuCurFreq3[i].policyId, cpuCurFreq3[i].curFreq);
}
}
static void TEST_PWR_CPU_SetFreq(void)
{
int ret = -1;
int num = 1;
PWR_CPU_CurFreq cpuCurFreq[num];
bzero(cpuCurFreq, num * sizeof(PWR_CPU_CurFreq));
cpuCurFreq[0].policyId = 0;
cpuCurFreq[0].curFreq = TEST_FREQ;
ret = PWR_CPU_SetFreq(cpuCurFreq, num);
PrintResult("PWR_CPU_SetFreq", ret);
int spec = 1;
bzero(cpuCurFreq, num * sizeof(PWR_CPU_CurFreq));
cpuCurFreq[0].policyId = 0;
ret = PWR_CPU_GetFreq(cpuCurFreq, &num, spec);
printf(" current policy[%d]: %lf\n", cpuCurFreq[0].policyId, cpuCurFreq[0].curFreq);
}
/*************************** CPU END *************************/
int main(int argc, const char *args[])
{
/********** Common **********/
TEST_PWR_SetServerInfo();
TEST_PWR_SetLogCallback();
TEST_PWR_Register();
TEST_PWR_RequestControlAuth();
/************ CPU ***********/
TEST_PWR_CPU_GetInfo();
TEST_PWR_CPU_GetFreq();
TEST_PWR_CPU_SetFreq();
PWR_ReleaseControlAuth();
PWR_UnRegister();
return 0;
}
Run gcc
to compile the program.
gcc powerapi_test.c -o powerapi_test -lpwrapi
Run the program to view the result.
./powerapi_test