使用powerapi进行开发
下载源码(可选)
源码下载:https://gitee.com/openeuler/powerapi
源码中部分接口还处于实验阶段,并未发布,代码中使用 RELEASE_MODE 对接口是否正式发布进行了隔离。
当前已发布接口参考源码库中的 API 文档。
安装软件包
使用以下命令安装 powerapi-devel 软件包,使用提供的接口进行开发。
yum install powerapi-devel
基本流程
查询类接口调用只需要注册,设置类接口调用前除了注册还需要请求控制权。按业务场景分,业务流程如下:
离散型感知类业务场景:设置日志回调 -> 注册 -> 查询接口调用 -> 注销
配置类业务场景:设置日志回调 -> 注册 -> 请求控制权 -> 配置接口调用 -> 释放控制权 -> 注销
powerapi接口
通用接口
设置日志回调函数
接口定义:PWR_API int PWR_SetLogCallback(void(LogCallback)(int level, const char *fmt, va_list vl))
接口描述:设置日志打印回调,设置后,powerapi库将回调LogCallBack函数打印日志。如不设置,默认打印到控制台。该接口可在注册前调用。
参数描述:
参数 | 类型 | 描述 |
---|---|---|
LogCallBack | void(*) | 日志打印回调函数指针 |
返回值:
类型 | 描述 |
---|---|
int | 返回码 0:成功 4:失败,回调函数指针为空 |
设置服务端信息
接口定义:PWR_API int PWR_SetServerInfo(const char* socketPath)
接口描述:该接口用于设置unix domain socket通信服务端地址信息。
参数描述:
参数 | 类型 | 描述 |
---|---|---|
socketPath | const char* | 服务端地址路径信息 |
返回值:
类型 | 描述 |
---|---|
int | 返回码 0:成功 4:失败,回调函数指针为空 |
注:
服务端sock文件默认路径为/etc/sysconfig/pwrapis/pwrserver.sock,若在pwrapis配置文件修改默认路径,则需要保证目录权限为755,而文件权限为722。
修改路径后需要在注册前通过该接口来告知so修改后的路径,否则连接将失败。
注册
接口定义:PWR_API int PWR_Register(void)
接口描述:用于注册到powerapi service。
参数描述:无参数
返回值:
类型 | 描述 |
---|---|
int | 返回码 0:成功 1:失败,初始化sock客户端失败 |
注销
接口定义:PWR_API int PWR_UnRegister(void)
接口描述:用于从服务端注销。
参数描述:无参数
返回值:
类型 | 描述 |
---|---|
int | 返回码 0:注销成功 |
请求接管能效控制权
接口定义:PWR_API int PWR_RequestControlAuth(void)
接口描述:该接口用于请求对系统能效控制权进行接管。上层应用接管后,系统不会自动进行能效调控,否则会自动进行能效调控。
参数描述:无参数
返回值:
类型 | 描述 |
---|---|
int | 返回码 0:成功 其他值:失败,参见错误码 |
放弃能效控制权
接口定义:PWR_API int PWR_ReleaseControlAuth(void)
接口描述:该接口用于释放对系统能效的控制权。
参数描述:无参数
返回值:
类型 | 描述 |
---|---|
int | 返回码 0:成功 其他值:失败,参见错误码 |
CPU
获取CPU信息
接口定义:PWR_API int PWR_CPU_GetInfo(PWR_CPU_Info *cpuInfo)
接口描述:获取CPU信息,包含CPU基础信息,NUMA信息。
参数描述:
参数 | 类型 | 描述 |
---|---|---|
cpuinfo | PWR_CPU_Info* | CPU信息 |
返回值:
类型 | 描述 |
---|---|
int | 返回码 0:成功 其他值:失败,参见错误码 |
获取CPU Frequency能力
接口定义:PWR_API int PWR_CPU_GetFreqAbility(PWR_CPU_FreqAbility *freqAbi, uint32_t bufferSize)
参数描述:查询可用的CPUFreq调频域信息,可用governor和当前使用的CPUFreq驱动。
参数 | 类型 | 描述 |
---|---|---|
freqAbi | PWR_CPU_FreqAbility* | CPUFreq能力信息 |
bufferSize | uint32_t | freqAbi内存块大小。 该内存块建议大小: sizeof(PWR_CPU_FreqAbility)+CPU核心数*(sizeof(int)+5) 内存块太小,则只返回能容纳的调频域数据。 |
返回值:
类型 | 描述 |
---|---|
int | 返回码 0:成功 其他值:失败,参见错误码 |
获取CPU Frequency governor
接口定义:PWR_API int PWR_CPU_GetFreqGovernor(char gov[], uint32_t size)
接口描述:获取系统当前使用的CPUFreq调频器(默认获取第一个调频域的governor)。
参数描述:
参数 | 类型 | 描述 |
---|---|---|
gov | char[] | governor的名称,最大长度31。 |
size | uint32_t | 给定gov数组空间大小,需大于等于PWR_MAX_ELEMENT_NAME_LEN(32)。 |
返回值:
类型 | 描述 |
---|---|
int | 返回码 0:成功 其他值:失败,参见错误码 |
设置CPU Frequency governor
接口定义:PWR_API int PWR_CPU_SetFreqGovernor(const char gov[])
接口描述:设置系统当前使用的CPUFreq调频器(设置时将所有调频域设置为输入的governor)。
参数描述:
参数 | 类型 | 描述 |
---|---|---|
gov | char[] | governor的名称,最大长度31。 取值如: conservative ondemand userspace powersave performance schedutil seep |
返回值:
类型 | 描述 |
---|---|
int | 返回码 0:成功 其他值:失败,参见错误码 |
获取CPU Frequency governor所有属性值
接口定义:PWR_API int PWR_CPU_GetFreqGovAttrs(PWR_CPU_FreqGovAttrs *govAttrs)
接口描述:获取当前所使用的CPUFreq调频器的所有属性信息。
参数描述:
参数 | 类型 | 描述 |
---|---|---|
govAttrs | PWR_CPU_FreqGovAttrs* | 调频器属性信息 |
返回值:
类型 | 描述 |
---|---|
int | 返回码 0:成功 其他值:失败,参见错误码 |
获取CPU Frequency governor属性
接口定义:PWR_API int PWR_CPU_GetFreqGovAttr(PWR_CPU_FreqGovAttr *govAttr)
接口描述:获取当前使用的CPUFreq属性(系统将获取第一个调频域(policy0)当前使用的governor对应的属性)。
参数描述:
参数 | 类型 | 描述 |
---|---|---|
govAttrs | PWR_CPU_FreqGovAttrs* | 调频器属性信息 |
返回值:
类型 | 描述 |
---|---|
int | 返回码 0:成功 其他值:失败,参见错误码 |
设置CPU Frequency governor属性
接口定义:PWR_API int PWR_CPU_SetFreqGovAttr(const PWR_CPU_FreqGovAttr *govAttr)
接口描述:设置当前使用的CPUFreq属性(系统将设置第一个调频域(policy0)当前使用的governor对应的属性)。
参数描述:
参数 | 类型 | 描述 |
---|---|---|
govAttrs | PWR_CPU_FreqGovAttrs* | 调频器属性信息。 需指定要设置的attr名称及其value。 |
返回值:
类型 | 描述 |
---|---|
int | 返回码 0:成功 其他值:失败,参见错误码 |
注:
不同的governor所支持的属性有所差异,governor所支持的属性一般在以下路径:/sys/devices/system/cpu/cpufreq/{gov}/,其中{gov}为当前使用的调频器名称。
获取CPU工作频率范围
接口定义:PWR_API int PWR_CPU_GetFreqRange(PWR_CPU_FreqRange *freqRange)
接口描述:获取CPU工作频率范围(默认获取第一个调频域的工作频率范围)。
参数描述:
参数 | 类型 | 描述 |
---|---|---|
freqRange | PWR_CPU_FreqRange* | 所获取的工作频率范围 |
返回值:
类型 | 描述 |
---|---|
int | 返回码 0:成功 其他值:失败,参见错误码 |
设置CPU工作频率范围
接口定义:PWR_API int PWR_CPU_SetFreqRange(const PWR_CPU_FreqRange *freqRange)
接口描述:设置CPU工作频率范围(把所有调频域设置成指定的频率范围)。
参数描述:
参数 | 类型 | 描述 |
---|---|---|
freqRange | PWR_CPU_FreqRange* | 设置的工作频率范围 |
返回值:
类型 | 描述 |
---|---|
int | 返回码 0:成功 其他值:失败,参见错误码 |
获取CPU当前频率
接口定义:PWR_API int PWR_CPU_GetFreq(PWR_CPU_CurFreq curFreq[], uint32_t *num, int spec)
接口描述:获取调频域的当前频率。
参数描述:
参数 | 类型 | 描述 |
---|---|---|
curFreq | PWR_CPU_CurFreq[] | 表示要查询的policy当前调频域的频率信息。 spec=1时需要设置对应成员的policyId。 输出调频域的当前频率。 |
num | uint32_t * | curFreq数组空间长度,代表要查询的policy的个数。 输出时为系统实际返回的有效数据长度(表现为实际policy的个数与输入num的较小值)。 |
spec | int | 释放获取特定某个或某几个调频域的信息。 0:否 1:是,此时需要在curFreq成员中设定具体的调频域所对应的policyId,如32,64等。 |
返回值:
类型 | 描述 |
---|---|
int | 返回码 0:成功 其他值:失败,参见错误码 |
设置CPU当前频率
接口定义:PWR_API int PWR_CPU_SetFreq(const PWR_CPU_CurFreq curFreq[], uint32_t num)
接口描述:设置调频域的工作频率(CPUFreq governor为userspace时才可设置)。
参数描述:
参数 | 类型 | 描述 |
---|---|---|
curFreq | PWR_CPU_CurFreq[] | 要设置的调频域及其频率列表。 |
num | uint32_t | curFreq数组空间长度,即调整policy的个数。 |
返回值:
类型 | 描述 |
---|---|
int | 返回码 0:成功 其他值:失败,参见错误码 |
获取CPU休眠能力和状态信息
接口定义:PWR_API int PWR_CPU_GetIdleInfo(PWR_CPU_IdleInfo *idleInfo)
接口描述:获取CPUIdele能力和状态信息。
参数描述:
参数 | 类型 | 描述 |
---|---|---|
idleInfo | PWR_CPU_IdleInfo* | CPUIdele能力和状态信息 |
返回值:
类型 | 描述 |
---|---|
int | 返回码 0:成功 其他值:失败,参见错误码 |
获取CPU休眠governor
接口定义:PWR_API int PWR_CPU_GetIdleGovernor(char idleGov[], uint32_t size)
接口描述:获取CPU休眠模式。
参数描述:
参数 | 类型 | 描述 |
---|---|---|
idleGov | char[] | governor名称 |
size | uint32_t | idleGov缓存区大小,最小值PWR_MAX_ELEMENT_NAME_LEN(32) |
返回值:
类型 | 描述 |
---|---|
int | 返回码 0:成功 其他值:失败,参见错误码 |
设置CPU休眠governor
接口定义:PWR_API int PWR_CPU_SetIdleGovernor(const char idleGov[])
接口描述:设置CPU休眠模式。
参数描述:
参数 | 类型 | 描述 |
---|---|---|
idleGov | char[] | governor名称,如: ladder menu teo haltpoll |
返回值:
类型 | 描述 |
---|---|
int | 返回码 0:成功 其他值:失败,参见错误码 |
获取CPU&DMA时延
接口定义:PWR_API int PWR_CPU_DmaGetLatency(int *latency)
接口描述:获取CPU&DMA可忍受时延。
参数描述:
参数 | 类型 | 描述 |
---|---|---|
latency | int* | 时延(单位:us)。 |
返回值:
类型 | 描述 |
---|---|
int | 返回码 0:成功 其他值:失败,参见错误码 |
设置CPU&DMA时延
接口定义:PWR_API int PWR_CPU_DmaSetLatency(int latency)
接口描述:设置CPU&DMA可忍受时延。
参数描述:
参数 | 类型 | 描述 |
---|---|---|
latency | int* | 时延(单位:us)。取值范围:[0,2000000000] |
返回值:
类型 | 描述 |
---|---|
int | 返回码 0:成功 其他值:失败,参见错误码 |
注:
不同的C-state,被唤醒所需时间不同,睡得越深,唤醒时延越大,因而系统在进入C-state前会判断CPU&DMA latency,如果对应C-state的时延大于CPU&DMA latency,则不会进入C-state。
各个C-state唤醒时延参考(单位:us)
C-state name | latency |
---|---|
C0 POLL | 0 |
C1 | 2 |
C1E | 10 |
C3 | 40 |
C6 | 133 |
C7S | 166 |
C8 | 300 |
C9 | 600 |
C10 | 2600 |
使用用例
将以下代码保存为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;
}
使用gcc编译:
gcc powerapi_test.c -o powerapi_test -lpwrapi
运行查看结果:
./powerapi_test