Development Using powerapi

(Optional) Source Code Download

Source code download: https://atomgit.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:

sh
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:

c
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:

ParameterTypeDescription
LogCallBackvoid(*)Log callback function pointer

Returns:

TypeDescription
int0: Succeeded.
4: Failed. The callback function pointer is empty.

Setting Server Information

Definition:

c
PWR_API int PWR_SetServerInfo(const char* socketPath)

Description:
Sets the address of the Unix domain socket communication server.

Parameters:

ParameterTypeDescription
socketPathconst char*Path of the server.

Returns:

TypeDescription
int0: 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:

c
PWR_API int PWR_Register(void)

Description:
Registers with the powerapi service.

Parameters: None
Returns:

TypeDescription
int0: Succeeded.
1: Failed to initialize the socket client.

Deregistration

Definition:

c
PWR_API int PWR_UnRegister(void)

Description:
Deregisters with the powerapi service.

Parameters: None
Returns:

TypeDescription
int0: Succeeded.

Requesting Energy Efficiency Control

Definition:

c
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:

TypeDescription
int0: Succeeded.
Other value: Failed. See the error codes for details.

Releasing Energy Efficiency Control

Definition:

c
PWR_API int PWR_ReleaseControlAuth(void)

Description:
Releases control of the system energy efficiency.

Parameters: None
Returns:

TypeDescription
int0: Succeeded.
Other value: Failed. See the error codes for details.

CPU

Obtaining CPU Information

Definition:

c
PWR_API int PWR_CPU_GetInfo(PWR_CPU_Info *cpuInfo)

Description:
Obtains CPU information, including basic CPU information and NUMA information.

Parameters:

ParameterTypeDescription
cpuinfoPWR_CPU_Info*CPU information.

Returns:

TypeDescription
int0: Succeeded.
Other value: Failed. See the error codes for details.

Obtaining the CPU Frequency Ability

Definition:

c
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:

ParameterTypeDescription
freqAbiPWR_CPU_FreqAbility*CPU frequency ability information
bufferSizeuint32_tSize 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:

TypeDescription
int0: Succeeded.
Other value: Failed. See the error codes for details.

Obtaining the CPU Frequency Governor

Definition:

c
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:

ParameterTypeDescription
govchar[]Governor name. The value can contain a maximum of 31 characters.
sizeuint32_tSize of the gov array. The value must be greater than or equal to PWR_MAX_ELEMENT_NAME_LEN(32).

Returns:

TypeDescription
int0: Succeeded.
Other value: Failed. See the error codes for details.

Setting the CPU Frequency Governor

Definition:

c
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:

ParameterTypeDescription
govchar[]Governor name. The value can contain a maximum of 31 characters.
Examples:
conservative
ondemand
userspace
powersave
performance
schedutil
seep

Returns:

TypeDescription
int0: Succeeded.
Other value: Failed. See the error codes for details.

Obtaining All Attributes of the CPU Frequency Governor

Definition:

c
PWR_API int PWR_CPU_GetFreqGovAttrs(PWR_CPU_FreqGovAttrs *govAttrs)

Description:
Obtains all attributes of the CPU frequency governor in use.

Parameters:

ParameterTypeDescription
govAttrsPWR_CPU_FreqGovAttrs*Attributes of the frequency governor.

Returns:

TypeDescription
int0: Succeeded.
Other value: Failed. See the error codes for details.

Obtaining an Attribute of the CPU Frequency Governor

Definition:

c
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:

ParameterTypeDescription
govAttrsPWR_CPU_FreqGovAttrs*Attributes of the frequency governor.

Returns:

TypeDescription
int0: Succeeded.
Other value: Failed. See the error codes for details.

Setting an Attribute of the CPU Frequency Governor

Definition:

c
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:

ParameterTypeDescription
govAttrsPWR_CPU_FreqGovAttrs*Attribute of the frequency governor.
You need to specify the name and value of the attribute to be set.

Returns:

TypeDescription
int0: 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:

c
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:

ParameterTypeDescription
freqRangePWR_CPU_FreqRange*Frequency range to obtain.

Returns:

TypeDescription
int0: Succeeded.
Other value: Failed. See the error codes for details.

Setting the CPU Frequency Range

Definition:

c
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:

ParameterTypeDescription
freqRangePWR_CPU_FreqRange*Frequency range to set.

Returns:

TypeDescription
int0: Succeeded.
Other value: Failed. See the error codes for details.

Obtaining the Current CPU Frequency

Definition:

c
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:

ParameterTypeDescription
curFreqPWR_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.
numuint32_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).
specintWhether 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:

TypeDescription
int0: Succeeded.
Other value: Failed. See the error codes for details.

Setting the Current CPU Frequency

Definition:

c
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:

ParameterTypeDescription
curFreqPWR_CPU_CurFreq[]Frequency domain to be set and its frequency list.
numuint32_tLength of the curFreq array, indicating the number of policies to be set.

Returns:

TypeDescription
int0: Succeeded.
Other value: Failed. See the error codes for details.

Obtaining the CPU Idle Ability and Status Information

Definition:

c
PWR_API int PWR_CPU_GetIdleInfo(PWR_CPU_IdleInfo *idleInfo)

Description:
Obtains the CPU idle ability and status information.

Parameters:

ParameterTypeDescription
idleInfoPWR_CPU_IdleInfo*CPU idle ability and status information.

Returns:

TypeDescription
int0: Succeeded.
Other value: Failed. See the error codes for details.

Obtaining the CPU Idle Governor

Definition:

c
PWR_API int PWR_CPU_GetIdleGovernor(char idleGov[], uint32_t size)

Description:
Obtains the CPU idle mode.

Parameters:

ParameterTypeDescription
idleGovchar[]Governor name.
sizeuint32_tSize of the idleGov buffer. The minimum value is PWR_MAX_ELEMENT_NAME_LEN(32).

Returns:

TypeDescription
int0: Succeeded.
Other value: Failed. See the error codes for details.

Setting the CPU Idle Governor

Definition:

c
PWR_API int PWR_CPU_SetIdleGovernor(const char idleGov[])

Description:
Sets the CPU idle mode.

Parameters:

ParameterTypeDescription
idleGovchar[]Governor name, for example:
ladder
menu
teo
haltpoll

Returns:

TypeDescription
int0: Succeeded.
Other value: Failed. See the error codes for details.

Obtaining the CPU and DMA Latency

Definition:

c
PWR_API int PWR_CPU_DmaGetLatency(int *latency)

Description:
Obtains the acceptable latency of the CPU and DMA.

Parameters:

ParameterTypeDescription
latencyint*Latency (us).

Returns:

TypeDescription
int0: Succeeded.
Other value: Failed. See the error codes for details.

Setting the CPU and DMA Latency

Definition:

c
PWR_API int PWR_CPU_DmaSetLatency(int latency)

Description:
Sets the acceptable latency of the CPU and DMA.

Parameters:

ParameterTypeDescription
latencyint*Latency (us). Value range: [0, 2000000000]

Returns:

TypeDescription
int0: 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-stateLatency
C0 POLL0
C12
C1E10
C340
C6133
C7S166
C8300
C9600
C102600

Usage

Save the following code as powerapi_test.c.

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.

sh
gcc powerapi_test.c -o powerapi_test -lpwrapi

Run the program to view the result.

sh
./powerapi_test