cpuidle-info.c 4.6 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
/*
 *  (C) 2004-2009  Dominik Brodowski <linux@dominikbrodowski.de>
 *  (C) 2010       Thomas Renninger <trenn@suse.de>
 *
 *  Licensed under the terms of the GNU GPL License version 2.
 */


#include <unistd.h>
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <getopt.h>
#include <cpufreq.h>

#include "helpers/helpers.h"
#include "helpers/sysfs.h"
#include "helpers/bitmask.h"

#define LINE_LEN 10

static void cpuidle_cpu_output(unsigned int cpu, int verbose)
{
25
	unsigned int idlestates, idlestate;
26 27 28 29 30 31 32 33 34
	char *tmp;

	printf(_ ("Analyzing CPU %d:\n"), cpu);

	idlestates = sysfs_get_idlestate_count(cpu);
	if (idlestates == 0) {
		printf(_("CPU %u: No idle states\n"), cpu);
		return;
	}
35

36 37
	printf(_("Number of idle states: %d\n"), idlestates);
	printf(_("Available idle states:"));
38
	for (idlestate = 0; idlestate < idlestates; idlestate++) {
39 40 41 42 43 44 45 46 47 48 49
		tmp = sysfs_get_idlestate_name(cpu, idlestate);
		if (!tmp)
			continue;
		printf(" %s", tmp);
		free(tmp);
	}
	printf("\n");

	if (!verbose)
		return;

50
	for (idlestate = 0; idlestate < idlestates; idlestate++) {
51 52 53 54
		int disabled = sysfs_is_idlestate_disabled(cpu, idlestate);
		/* Disabled interface not supported on older kernels */
		if (disabled < 0)
			disabled = 0;
55 56 57
		tmp = sysfs_get_idlestate_name(cpu, idlestate);
		if (!tmp)
			continue;
58
		printf("%s%s:\n", tmp, (disabled) ? " (DISABLED) " : "");
59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87
		free(tmp);

		tmp = sysfs_get_idlestate_desc(cpu, idlestate);
		if (!tmp)
			continue;
		printf(_("Flags/Description: %s\n"), tmp);
		free(tmp);

		printf(_("Latency: %lu\n"),
		       sysfs_get_idlestate_latency(cpu, idlestate));
		printf(_("Usage: %lu\n"),
		       sysfs_get_idlestate_usage(cpu, idlestate));
		printf(_("Duration: %llu\n"),
		       sysfs_get_idlestate_time(cpu, idlestate));
	}
	printf("\n");
}

static void cpuidle_general_output(void)
{
	char *tmp;

	tmp = sysfs_get_cpuidle_driver();
	if (!tmp) {
		printf(_("Could not determine cpuidle driver\n"));
		return;
	}

	printf(_("CPUidle driver: %s\n"), tmp);
88
	free(tmp);
89 90 91 92 93 94 95 96

	tmp = sysfs_get_cpuidle_governor();
	if (!tmp) {
		printf(_("Could not determine cpuidle governor\n"));
		return;
	}

	printf(_("CPUidle governor: %s\n"), tmp);
97
	free(tmp);
98 99 100 101 102
}

static void proc_cpuidle_cpu_output(unsigned int cpu)
{
	long max_allowed_cstate = 2000000000;
103
	unsigned int cstate, cstates;
104 105 106

	cstates = sysfs_get_idlestate_count(cpu);
	if (cstates == 0) {
107
		printf(_("CPU %u: No C-states info\n"), cpu);
108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128
		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] "),
		       sysfs_get_idlestate_latency(cpu, cstate));
		printf(_("usage[%08lu] "),
		       sysfs_get_idlestate_usage(cpu, cstate));
		printf(_("duration[%020Lu] \n"),
		       sysfs_get_idlestate_time(cpu, cstate));
	}
}

static struct option info_opts[] = {
129 130
	{ .name = "silent",	.has_arg = no_argument,	.flag = NULL,	.val = 's'},
	{ .name = "proc",	.has_arg = no_argument,	.flag = NULL,	.val = 'o'},
131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146
	{ },
};

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 {
147
		ret = getopt_long(argc, argv, "os", info_opts, NULL);
148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169
		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;
		}
170
	} while (cont);
171 172 173 174 175 176 177 178 179 180 181 182 183 184

	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);
185

186 187
	if (output_param == 0)
		cpuidle_general_output();
188

189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206
	for (cpu = bitmask_first(cpus_chosen);
	     cpu <= bitmask_last(cpus_chosen); cpu++) {

		if (!bitmask_isbitset(cpus_chosen, cpu) ||
		    cpufreq_cpu_exists(cpu))
			continue;

		switch (output_param) {

		case 'o':
			proc_cpuidle_cpu_output(cpu);
			break;
		case 0:
			printf("\n");
			cpuidle_cpu_output(cpu, verbose);
			break;
		}
	}
207
	return EXIT_SUCCESS;
208
}