^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * (C) 2004-2009 Dominik Brodowski <linux@dominikbrodowski.de>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) * (C) 2010 Thomas Renninger <trenn@suse.de>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) #include <unistd.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include <stdio.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <errno.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <stdlib.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <string.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <getopt.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <cpuidle.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include "helpers/sysfs.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include "helpers/helpers.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include "helpers/bitmask.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #define LINE_LEN 10
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) static void cpuidle_cpu_output(unsigned int cpu, int verbose)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) unsigned int idlestates, idlestate;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) char *tmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) idlestates = cpuidle_state_count(cpu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) if (idlestates == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) printf(_("CPU %u: No idle states\n"), cpu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) printf(_("Number of idle states: %d\n"), idlestates);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) printf(_("Available idle states:"));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) for (idlestate = 0; idlestate < idlestates; idlestate++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) tmp = cpuidle_state_name(cpu, idlestate);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) if (!tmp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) printf(" %s", tmp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) free(tmp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) printf("\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) if (!verbose)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) for (idlestate = 0; idlestate < idlestates; idlestate++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) int disabled = cpuidle_is_state_disabled(cpu, idlestate);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) /* Disabled interface not supported on older kernels */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) if (disabled < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) disabled = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) tmp = cpuidle_state_name(cpu, idlestate);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) if (!tmp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) printf("%s%s:\n", tmp, (disabled) ? " (DISABLED) " : "");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) free(tmp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) tmp = cpuidle_state_desc(cpu, idlestate);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) if (!tmp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) printf(_("Flags/Description: %s\n"), tmp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) free(tmp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) printf(_("Latency: %lu\n"),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) cpuidle_state_latency(cpu, idlestate));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) printf(_("Usage: %lu\n"),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) cpuidle_state_usage(cpu, idlestate));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) printf(_("Duration: %llu\n"),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) cpuidle_state_time(cpu, idlestate));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) static void cpuidle_general_output(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) char *tmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) tmp = cpuidle_get_driver();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) if (!tmp) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) printf(_("Could not determine cpuidle driver\n"));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) printf(_("CPUidle driver: %s\n"), tmp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) free(tmp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) tmp = cpuidle_get_governor();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) if (!tmp) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) printf(_("Could not determine cpuidle governor\n"));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) printf(_("CPUidle governor: %s\n"), tmp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) free(tmp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) static void proc_cpuidle_cpu_output(unsigned int cpu)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) long max_allowed_cstate = 2000000000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) unsigned int cstate, cstates;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) cstates = cpuidle_state_count(cpu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) if (cstates == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) printf(_("CPU %u: No C-states info\n"), cpu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) printf(_("active state: C0\n"));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) printf(_("max_cstate: C%u\n"), cstates-1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) printf(_("maximum allowed latency: %lu usec\n"), max_allowed_cstate);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) printf(_("states:\t\n"));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) for (cstate = 1; cstate < cstates; cstate++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) printf(_(" C%d: "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) "type[C%d] "), cstate, cstate);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) printf(_("promotion[--] demotion[--] "));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) printf(_("latency[%03lu] "),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) cpuidle_state_latency(cpu, cstate));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) printf(_("usage[%08lu] "),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) cpuidle_state_usage(cpu, cstate));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) printf(_("duration[%020Lu] \n"),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) cpuidle_state_time(cpu, cstate));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) static struct option info_opts[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) {"silent", no_argument, NULL, 's'},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) {"proc", no_argument, NULL, 'o'},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) { },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) static inline void cpuidle_exit(int fail)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) exit(EXIT_FAILURE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) int cmd_idle_info(int argc, char **argv)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) extern char *optarg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) extern int optind, opterr, optopt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) int ret = 0, cont = 1, output_param = 0, verbose = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) unsigned int cpu = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) do {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) ret = getopt_long(argc, argv, "os", info_opts, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) if (ret == -1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) switch (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) case '?':
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) output_param = '?';
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) cont = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) case 's':
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) verbose = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) case -1:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) cont = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) case 'o':
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) if (output_param) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) output_param = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) cont = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) output_param = ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) } while (cont);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) switch (output_param) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) case -1:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) printf(_("You can't specify more than one "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) "output-specific argument\n"));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) cpuidle_exit(EXIT_FAILURE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) case '?':
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) printf(_("invalid or unknown argument\n"));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) cpuidle_exit(EXIT_FAILURE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) /* Default is: show output of CPU 0 only */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) if (bitmask_isallclear(cpus_chosen))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) bitmask_setbit(cpus_chosen, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) if (output_param == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) cpuidle_general_output();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) for (cpu = bitmask_first(cpus_chosen);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) cpu <= bitmask_last(cpus_chosen); cpu++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) if (!bitmask_isbitset(cpus_chosen, cpu))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) printf(_("analyzing CPU %d:\n"), cpu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) if (sysfs_is_cpu_online(cpu) != 1) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) printf(_(" *is offline\n"));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) printf("\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) switch (output_param) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) case 'o':
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) proc_cpuidle_cpu_output(cpu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) case 0:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) printf("\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) cpuidle_cpu_output(cpu, verbose);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) printf("\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) return EXIT_SUCCESS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) }