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