summaryrefslogtreecommitdiffstats
path: root/tools/power/cpupower/utils/cpuidle-info.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/power/cpupower/utils/cpuidle-info.c')
-rw-r--r--tools/power/cpupower/utils/cpuidle-info.c213
1 files changed, 213 insertions, 0 deletions
diff --git a/tools/power/cpupower/utils/cpuidle-info.c b/tools/power/cpupower/utils/cpuidle-info.c
new file mode 100644
index 000000000..f2b202c55
--- /dev/null
+++ b/tools/power/cpupower/utils/cpuidle-info.c
@@ -0,0 +1,213 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * (C) 2004-2009 Dominik Brodowski <linux@dominikbrodowski.de>
+ * (C) 2010 Thomas Renninger <trenn@suse.de>
+ */
+
+
+#include <unistd.h>
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <getopt.h>
+
+#include <cpuidle.h>
+
+#include "helpers/sysfs.h"
+#include "helpers/helpers.h"
+#include "helpers/bitmask.h"
+
+#define LINE_LEN 10
+
+static void cpuidle_cpu_output(unsigned int cpu, int verbose)
+{
+ unsigned int idlestates, idlestate;
+ char *tmp;
+
+ idlestates = cpuidle_state_count(cpu);
+ if (idlestates == 0) {
+ printf(_("CPU %u: No idle states\n"), cpu);
+ return;
+ }
+
+ printf(_("Number of idle states: %d\n"), idlestates);
+ printf(_("Available idle states:"));
+ for (idlestate = 0; idlestate < idlestates; idlestate++) {
+ tmp = cpuidle_state_name(cpu, idlestate);
+ if (!tmp)
+ continue;
+ printf(" %s", tmp);
+ free(tmp);
+ }
+ printf("\n");
+
+ if (!verbose)
+ return;
+
+ for (idlestate = 0; idlestate < idlestates; idlestate++) {
+ int disabled = cpuidle_is_state_disabled(cpu, idlestate);
+ /* Disabled interface not supported on older kernels */
+ if (disabled < 0)
+ disabled = 0;
+ tmp = cpuidle_state_name(cpu, idlestate);
+ if (!tmp)
+ continue;
+ printf("%s%s:\n", tmp, (disabled) ? " (DISABLED) " : "");
+ free(tmp);
+
+ tmp = cpuidle_state_desc(cpu, idlestate);
+ if (!tmp)
+ continue;
+ printf(_("Flags/Description: %s\n"), tmp);
+ free(tmp);
+
+ printf(_("Latency: %lu\n"),
+ cpuidle_state_latency(cpu, idlestate));
+ printf(_("Usage: %lu\n"),
+ cpuidle_state_usage(cpu, idlestate));
+ printf(_("Duration: %llu\n"),
+ cpuidle_state_time(cpu, idlestate));
+ }
+}
+
+static void cpuidle_general_output(void)
+{
+ char *tmp;
+
+ tmp = cpuidle_get_driver();
+ if (!tmp) {
+ printf(_("Could not determine cpuidle driver\n"));
+ return;
+ }
+
+ printf(_("CPUidle driver: %s\n"), tmp);
+ free(tmp);
+
+ tmp = cpuidle_get_governor();
+ if (!tmp) {
+ printf(_("Could not determine cpuidle governor\n"));
+ return;
+ }
+
+ printf(_("CPUidle governor: %s\n"), tmp);
+ free(tmp);
+}
+
+static void proc_cpuidle_cpu_output(unsigned int cpu)
+{
+ long max_allowed_cstate = 2000000000;
+ unsigned int cstate, cstates;
+
+ cstates = cpuidle_state_count(cpu);
+ if (cstates == 0) {
+ printf(_("CPU %u: No C-states info\n"), cpu);
+ return;
+ }
+
+ printf(_("active state: C0\n"));
+ printf(_("max_cstate: C%u\n"), cstates-1);
+ printf(_("maximum allowed latency: %lu usec\n"), max_allowed_cstate);
+ printf(_("states:\t\n"));
+ for (cstate = 1; cstate < cstates; cstate++) {
+ printf(_(" C%d: "
+ "type[C%d] "), cstate, cstate);
+ printf(_("promotion[--] demotion[--] "));
+ printf(_("latency[%03lu] "),
+ cpuidle_state_latency(cpu, cstate));
+ printf(_("usage[%08lu] "),
+ cpuidle_state_usage(cpu, cstate));
+ printf(_("duration[%020Lu] \n"),
+ cpuidle_state_time(cpu, cstate));
+ }
+}
+
+static struct option info_opts[] = {
+ {"silent", no_argument, NULL, 's'},
+ {"proc", no_argument, NULL, 'o'},
+ { },
+};
+
+static inline void cpuidle_exit(int fail)
+{
+ exit(EXIT_FAILURE);
+}
+
+int cmd_idle_info(int argc, char **argv)
+{
+ extern char *optarg;
+ extern int optind, opterr, optopt;
+ int ret = 0, cont = 1, output_param = 0, verbose = 1;
+ unsigned int cpu = 0;
+
+ do {
+ ret = getopt_long(argc, argv, "os", info_opts, NULL);
+ if (ret == -1)
+ break;
+ switch (ret) {
+ case '?':
+ output_param = '?';
+ cont = 0;
+ break;
+ case 's':
+ verbose = 0;
+ break;
+ case -1:
+ cont = 0;
+ break;
+ case 'o':
+ if (output_param) {
+ output_param = -1;
+ cont = 0;
+ break;
+ }
+ output_param = ret;
+ break;
+ }
+ } while (cont);
+
+ switch (output_param) {
+ case -1:
+ printf(_("You can't specify more than one "
+ "output-specific argument\n"));
+ cpuidle_exit(EXIT_FAILURE);
+ case '?':
+ printf(_("invalid or unknown argument\n"));
+ cpuidle_exit(EXIT_FAILURE);
+ }
+
+ /* Default is: show output of CPU 0 only */
+ if (bitmask_isallclear(cpus_chosen))
+ bitmask_setbit(cpus_chosen, 0);
+
+ if (output_param == 0)
+ cpuidle_general_output();
+
+ for (cpu = bitmask_first(cpus_chosen);
+ cpu <= bitmask_last(cpus_chosen); cpu++) {
+
+ if (!bitmask_isbitset(cpus_chosen, cpu))
+ continue;
+
+ printf(_("analyzing CPU %d:\n"), cpu);
+
+ if (sysfs_is_cpu_online(cpu) != 1) {
+ printf(_(" *is offline\n"));
+ printf("\n");
+ continue;
+ }
+
+ switch (output_param) {
+
+ case 'o':
+ proc_cpuidle_cpu_output(cpu);
+ break;
+ case 0:
+ printf("\n");
+ cpuidle_cpu_output(cpu, verbose);
+ break;
+ }
+ printf("\n");
+ }
+ return EXIT_SUCCESS;
+}