linux/tools/power/cpupower/utils/idle_monitor/cpuidle_sysfs.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 *  (C) 2010,2011       Thomas Renninger <trenn@suse.de>, Novell Inc
   4 */
   5
   6#include <stdio.h>
   7#include <stdlib.h>
   8#include <stdint.h>
   9#include <string.h>
  10#include <limits.h>
  11#include <cpuidle.h>
  12
  13#include "helpers/helpers.h"
  14#include "idle_monitor/cpupower-monitor.h"
  15
  16#define CPUIDLE_STATES_MAX 10
  17static cstate_t cpuidle_cstates[CPUIDLE_STATES_MAX];
  18struct cpuidle_monitor cpuidle_sysfs_monitor;
  19
  20static unsigned long long **previous_count;
  21static unsigned long long **current_count;
  22struct timespec start_time;
  23static unsigned long long timediff;
  24
  25static int cpuidle_get_count_percent(unsigned int id, double *percent,
  26                                     unsigned int cpu)
  27{
  28        unsigned long long statediff = current_count[cpu][id]
  29                - previous_count[cpu][id];
  30        dprint("%s: - diff: %llu - percent: %f (%u)\n",
  31               cpuidle_cstates[id].name, timediff, *percent, cpu);
  32
  33        if (timediff == 0)
  34                *percent = 0.0;
  35        else
  36                *percent = ((100.0 * statediff) / timediff);
  37
  38        dprint("%s: - timediff: %llu - statediff: %llu - percent: %f (%u)\n",
  39               cpuidle_cstates[id].name, timediff, statediff, *percent, cpu);
  40
  41        return 0;
  42}
  43
  44static int cpuidle_start(void)
  45{
  46        int cpu, state;
  47        clock_gettime(CLOCK_REALTIME, &start_time);
  48        for (cpu = 0; cpu < cpu_count; cpu++) {
  49                for (state = 0; state < cpuidle_sysfs_monitor.hw_states_num;
  50                     state++) {
  51                        previous_count[cpu][state] =
  52                                cpuidle_state_time(cpu, state);
  53                        dprint("CPU %d - State: %d - Val: %llu\n",
  54                               cpu, state, previous_count[cpu][state]);
  55                }
  56        };
  57        return 0;
  58}
  59
  60static int cpuidle_stop(void)
  61{
  62        int cpu, state;
  63        struct timespec end_time;
  64        clock_gettime(CLOCK_REALTIME, &end_time);
  65        timediff = timespec_diff_us(start_time, end_time);
  66
  67        for (cpu = 0; cpu < cpu_count; cpu++) {
  68                for (state = 0; state < cpuidle_sysfs_monitor.hw_states_num;
  69                     state++) {
  70                        current_count[cpu][state] =
  71                                cpuidle_state_time(cpu, state);
  72                        dprint("CPU %d - State: %d - Val: %llu\n",
  73                               cpu, state, previous_count[cpu][state]);
  74                }
  75        };
  76        return 0;
  77}
  78
  79void fix_up_intel_idle_driver_name(char *tmp, int num)
  80{
  81        /* fix up cpuidle name for intel idle driver */
  82        if (!strncmp(tmp, "NHM-", 4)) {
  83                switch (num) {
  84                case 1:
  85                        strcpy(tmp, "C1");
  86                        break;
  87                case 2:
  88                        strcpy(tmp, "C3");
  89                        break;
  90                case 3:
  91                        strcpy(tmp, "C6");
  92                        break;
  93                }
  94        } else if (!strncmp(tmp, "SNB-", 4)) {
  95                switch (num) {
  96                case 1:
  97                        strcpy(tmp, "C1");
  98                        break;
  99                case 2:
 100                        strcpy(tmp, "C3");
 101                        break;
 102                case 3:
 103                        strcpy(tmp, "C6");
 104                        break;
 105                case 4:
 106                        strcpy(tmp, "C7");
 107                        break;
 108                }
 109        } else if (!strncmp(tmp, "ATM-", 4)) {
 110                switch (num) {
 111                case 1:
 112                        strcpy(tmp, "C1");
 113                        break;
 114                case 2:
 115                        strcpy(tmp, "C2");
 116                        break;
 117                case 3:
 118                        strcpy(tmp, "C4");
 119                        break;
 120                case 4:
 121                        strcpy(tmp, "C6");
 122                        break;
 123                }
 124        }
 125}
 126
 127#ifdef __powerpc__
 128void map_power_idle_state_name(char *tmp)
 129{
 130        if (!strncmp(tmp, "stop0_lite", CSTATE_NAME_LEN))
 131                strcpy(tmp, "stop0L");
 132        else if (!strncmp(tmp, "stop1_lite", CSTATE_NAME_LEN))
 133                strcpy(tmp, "stop1L");
 134        else if (!strncmp(tmp, "stop2_lite", CSTATE_NAME_LEN))
 135                strcpy(tmp, "stop2L");
 136}
 137#else
 138void map_power_idle_state_name(char *tmp) { }
 139#endif
 140
 141static struct cpuidle_monitor *cpuidle_register(void)
 142{
 143        int num;
 144        char *tmp;
 145        int this_cpu;
 146
 147        this_cpu = sched_getcpu();
 148
 149        /* Assume idle state count is the same for all CPUs */
 150        cpuidle_sysfs_monitor.hw_states_num = cpuidle_state_count(this_cpu);
 151
 152        if (cpuidle_sysfs_monitor.hw_states_num <= 0)
 153                return NULL;
 154
 155        for (num = 0; num < cpuidle_sysfs_monitor.hw_states_num; num++) {
 156                tmp = cpuidle_state_name(this_cpu, num);
 157                if (tmp == NULL)
 158                        continue;
 159
 160                map_power_idle_state_name(tmp);
 161                fix_up_intel_idle_driver_name(tmp, num);
 162                strncpy(cpuidle_cstates[num].name, tmp, CSTATE_NAME_LEN - 1);
 163                free(tmp);
 164
 165                tmp = cpuidle_state_desc(this_cpu, num);
 166                if (tmp == NULL)
 167                        continue;
 168                strncpy(cpuidle_cstates[num].desc, tmp, CSTATE_DESC_LEN - 1);
 169                free(tmp);
 170
 171                cpuidle_cstates[num].range = RANGE_THREAD;
 172                cpuidle_cstates[num].id = num;
 173                cpuidle_cstates[num].get_count_percent =
 174                        cpuidle_get_count_percent;
 175        };
 176
 177        /* Free this at program termination */
 178        previous_count = malloc(sizeof(long long *) * cpu_count);
 179        current_count = malloc(sizeof(long long *) * cpu_count);
 180        for (num = 0; num < cpu_count; num++) {
 181                previous_count[num] = malloc(sizeof(long long) *
 182                                        cpuidle_sysfs_monitor.hw_states_num);
 183                current_count[num] = malloc(sizeof(long long) *
 184                                        cpuidle_sysfs_monitor.hw_states_num);
 185        }
 186
 187        cpuidle_sysfs_monitor.name_len = strlen(cpuidle_sysfs_monitor.name);
 188        return &cpuidle_sysfs_monitor;
 189}
 190
 191void cpuidle_unregister(void)
 192{
 193        int num;
 194
 195        for (num = 0; num < cpu_count; num++) {
 196                free(previous_count[num]);
 197                free(current_count[num]);
 198        }
 199        free(previous_count);
 200        free(current_count);
 201}
 202
 203struct cpuidle_monitor cpuidle_sysfs_monitor = {
 204        .name                   = "Idle_Stats",
 205        .hw_states              = cpuidle_cstates,
 206        .start                  = cpuidle_start,
 207        .stop                   = cpuidle_stop,
 208        .do_register            = cpuidle_register,
 209        .unregister             = cpuidle_unregister,
 210        .needs_root             = 0,
 211        .overflow_s             = UINT_MAX,
 212};
 213