#define GET_PKG(pkg_base, pkg_no) (pkg_base + pkg_no)
enum counter_scope {SCOPE_CPU, SCOPE_CORE, SCOPE_PACKAGE};
-enum counter_type {COUNTER_CYCLES, COUNTER_SECONDS};
+enum counter_type {COUNTER_ITEMS, COUNTER_CYCLES, COUNTER_SECONDS, COUNTER_USEC};
enum counter_format {FORMAT_RAW, FORMAT_DELTA, FORMAT_PERCENT};
struct msr_counter {
unsigned int flags;
#define FLAGS_HIDE (1 << 0)
#define FLAGS_SHOW (1 << 1)
+#define SYSFS_PERCPU (1 << 1)
};
struct sys_counters {
{ 0x0, "Core" },
{ 0x0, "CPU" },
{ 0x0, "Mod%c6" },
+ { 0x0, "sysfs" },
};
#define MAX_BIC (sizeof(bic) / sizeof(struct msr_counter))
#define BIC_Core (1ULL << 35)
#define BIC_CPU (1ULL << 36)
#define BIC_Mod_c6 (1ULL << 37)
+#define BIC_sysfs (1ULL << 38)
unsigned long long bic_enabled = 0xFFFFFFFFFFFFFFFFULL;
-unsigned long long bic_present;
+unsigned long long bic_present = BIC_sysfs;
#define DO_BIC(COUNTER_NAME) (bic_enabled & bic_present & COUNTER_NAME)
#define BIC_PRESENT(COUNTER_BIT) (bic_present |= COUNTER_BIT)
if (DO_BIC(BIC_SMI))
outp += sprintf(outp, "\tSMI");
- if (DO_BIC(BIC_CPU_c1))
- outp += sprintf(outp, "\tCPU%%c1");
-
for (mp = sys.tp; mp; mp = mp->next) {
if (mp->format == FORMAT_RAW) {
if (mp->width == 64)
else
outp += sprintf(outp, "\t%10.10s", mp->name);
} else {
- outp += sprintf(outp, "\t%-7.7s", mp->name);
+ outp += sprintf(outp, "\t%s", mp->name);
}
}
+ if (DO_BIC(BIC_CPU_c1))
+ outp += sprintf(outp, "\tCPU%%c1");
if (DO_BIC(BIC_CPU_c3) && !do_slm_cstates && !do_knl_cstates)
outp += sprintf(outp, "\tCPU%%c3");
if (DO_BIC(BIC_CPU_c6))
else
outp += sprintf(outp, "\t%10.10s", mp->name);
} else {
- outp += sprintf(outp, "\t%-7.7s", mp->name);
+ outp += sprintf(outp, "\t%s", mp->name);
}
}
else
outp += sprintf(outp, "\t%10.10s", mp->name);
} else {
- outp += sprintf(outp, "\t%-7.7s", mp->name);
+ outp += sprintf(outp, "\t%s", mp->name);
}
}
if (DO_BIC(BIC_SMI))
outp += sprintf(outp, "\t%d", t->smi_count);
- /* C1 */
- if (DO_BIC(BIC_CPU_c1))
- outp += sprintf(outp, "\t%.2f", 100.0 * t->c1/tsc);
-
/* Added counters */
for (i = 0, mp = sys.tp; mp; i++, mp = mp->next) {
if (mp->format == FORMAT_RAW) {
} else if (mp->format == FORMAT_DELTA) {
outp += sprintf(outp, "\t%lld", t->counter[i]);
} else if (mp->format == FORMAT_PERCENT) {
- outp += sprintf(outp, "\t%.2f", 100.0 * t->counter[i]/tsc);
+ if (mp->type == COUNTER_USEC)
+ outp += sprintf(outp, "\t%.2f", t->counter[i]/interval_float/10000);
+ else
+ outp += sprintf(outp, "\t%.2f", 100.0 * t->counter[i]/tsc);
}
}
+ /* C1 */
+ if (DO_BIC(BIC_CPU_c1))
+ outp += sprintf(outp, "\t%.2f", 100.0 * t->c1/tsc);
+
+
/* print per-core data only for 1st thread in core */
if (!(t->flags & CPU_IS_FIRST_THREAD_IN_CORE))
goto done;
for (i = 0, mp = sys.tp; mp; i++, mp = mp->next) {
if (mp->format == FORMAT_RAW)
continue;
+ if (mp->flags & SYSFS_PERCPU && mp->type == COUNTER_ITEMS)
+ continue;
average.threads.counter[i] /= topo.num_cpus;
}
for (i = 0, mp = sys.cp; mp; i++, mp = mp->next) {
if (get_msr(cpu, mp->msr_num, counterp))
return -1;
} else {
- *counterp = snapshot_sysfs_counter(mp->path);
+ char path[128];
+
+ if (mp->flags & SYSFS_PERCPU) {
+ sprintf(path, "/sys/devices/system/cpu/cpu%d/%s",
+ cpu, mp->path);
+
+ *counterp = snapshot_sysfs_counter(path);
+ } else {
+ *counterp = snapshot_sysfs_counter(mp->path);
+ }
}
return 0;
dump_nhm_cst_cfg();
}
+static void
+dump_sysfs_cstate_config(void)
+{
+ char path[64];
+ char name_buf[16];
+ char desc[64];
+ FILE *input;
+ int state;
+ char *sp;
+
+ if (!DO_BIC(BIC_sysfs))
+ return;
+
+ for (state = 0; state < 10; ++state) {
+
+ sprintf(path, "/sys/devices/system/cpu/cpu%d/cpuidle/state%d/name",
+ base_cpu, state);
+ input = fopen(path, "r");
+ if (input == NULL)
+ continue;
+ fgets(name_buf, sizeof(name_buf), input);
+
+ /* truncate "C1-HSW\n" to "C1", or truncate "C1\n" to "C1" */
+ sp = strchr(name_buf, '-');
+ if (!sp)
+ sp = strchrnul(name_buf, '\n');
+ *sp = '\0';
+
+ fclose(input);
+
+ sprintf(path, "/sys/devices/system/cpu/cpu%d/cpuidle/state%d/desc",
+ base_cpu, state);
+ input = fopen(path, "r");
+ if (input == NULL)
+ continue;
+ fgets(desc, sizeof(desc), input);
+
+ fprintf(outf, "cpu%d: %s: %s", base_cpu, name_buf, desc);
+ fclose(input);
+ }
+}
+
/*
* print_epb()
if (!quiet)
dump_cstate_pstate_config_info(family, model);
+ if (!quiet)
+ dump_sysfs_cstate_config();
+
if (has_skl_msrs(family, model))
calculate_tsc_tweak();
int add_counter(unsigned int msr_num, char *path, char *name,
unsigned int width, enum counter_scope scope,
- enum counter_type type, enum counter_format format)
+ enum counter_type type, enum counter_format format, int flags)
{
struct msr_counter *msrp;
msrp->width = width;
msrp->type = type;
msrp->format = format;
+ msrp->flags = flags;
switch (scope) {
type = COUNTER_SECONDS;
goto next;
}
+ if (!strncmp(add_command, "usec", strlen("usec"))) {
+ type = COUNTER_USEC;
+ goto next;
+ }
if (!strncmp(add_command, "raw", strlen("raw"))) {
format = FORMAT_RAW;
goto next;
}
}
- if (add_counter(msr_num, path, name_buffer, width, scope, type, format))
+ if (add_counter(msr_num, path, name_buffer, width, scope, type, format, 0))
fail++;
if (fail) {
exit(1);
}
}
+
+void probe_sysfs(void)
+{
+ char path[64];
+ char name_buf[16];
+ FILE *input;
+ int state;
+ char *sp;
+
+ if (!DO_BIC(BIC_sysfs))
+ return;
+
+ for (state = 10; state > 0; --state) {
+
+ sprintf(path, "/sys/devices/system/cpu/cpu%d/cpuidle/state%d/name",
+ base_cpu, state);
+ input = fopen(path, "r");
+ if (input == NULL)
+ continue;
+ fgets(name_buf, sizeof(name_buf), input);
+
+ /* truncate "C1-HSW\n" to "C1", or truncate "C1\n" to "C1" */
+ sp = strchr(name_buf, '-');
+ if (!sp)
+ sp = strchrnul(name_buf, '\n');
+ *sp = '%';
+ *(sp + 1) = '\0';
+
+ fclose(input);
+
+ sprintf(path, "cpuidle/state%d/time", state);
+
+ add_counter(0, path, name_buf, 64, SCOPE_CPU, COUNTER_USEC,
+ FORMAT_PERCENT, SYSFS_PERCPU);
+ }
+
+ for (state = 10; state > 0; --state) {
+
+ sprintf(path, "/sys/devices/system/cpu/cpu%d/cpuidle/state%d/name",
+ base_cpu, state);
+ input = fopen(path, "r");
+ if (input == NULL)
+ continue;
+ fgets(name_buf, sizeof(name_buf), input);
+ /* truncate "C1-HSW\n" to "C1", or truncate "C1\n" to "C1" */
+ sp = strchr(name_buf, '-');
+ if (!sp)
+ sp = strchrnul(name_buf, '\n');
+ *sp = '\0';
+ fclose(input);
+
+ sprintf(path, "cpuidle/state%d/usage", state);
+
+ add_counter(0, path, name_buf, 64, SCOPE_CPU, COUNTER_ITEMS,
+ FORMAT_DELTA, SYSFS_PERCPU);
+ }
+
+}
+
/*
* HIDE_LIST - hide this list of counters, show the rest [default]
* SHOW_LIST - show this list of counters, hide the rest
* multiple invocations simply clear more bits in enabled mask
*/
bic_enabled &= ~bic_lookup(optarg);
+
}
void cmdline(int argc, char **argv)
if (!quiet)
print_version();
+ probe_sysfs();
+
turbostat_init();
/* dump counters and exit */