213 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * (C) 2010,2011 Thomas Renninger <trenn@suse.de>, Novell Inc4 */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 1017static 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;22static struct 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 else36 *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#else138void map_power_idle_state_name(char *tmp) { }139#endif140 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 .flags.needs_root = 0,211 .overflow_s = UINT_MAX,212};213