Merge branches 'acpica', 'acpidump', 'intel-idle', 'misc', 'module_acpi_driver-simplify', 'turbostat' and 'usb3' into release

add acpidump utility
intel_idle driver now supports IVB Xeon
turbostat can now count SMIs
ACPI can now bind to USB3 hubs
misc fixes
This commit is contained in:
Len Brown
2012-10-06 16:00:32 -04:00
51 ha cambiato i file con 2070 aggiunte e 734 eliminazioni

18
tools/power/acpi/Makefile Normal file
Vedi File

@@ -0,0 +1,18 @@
PROG= acpidump
SRCS= acpidump.c
KERNEL_INCLUDE := ../../../include
CFLAGS += -Wall -Wstrict-prototypes -Wdeclaration-after-statement -Os -s -D_LINUX -DDEFINE_ALTERNATE_TYPES -I$(KERNEL_INCLUDE)
all: acpidump
$(PROG) : $(SRCS)
$(CC) $(CFLAGS) $(SRCS) -o $(PROG)
CLEANFILES= $(PROG)
clean :
rm -f $(CLEANFILES) $(patsubst %.c,%.o, $(SRCS)) *~
install :
install acpidump /usr/bin/acpidump
install acpidump.8 /usr/share/man/man8

Vedi File

@@ -0,0 +1,59 @@
.TH ACPIDUMP 8
.SH NAME
acpidump \- Dump system's ACPI tables to an ASCII file.
.SH SYNOPSIS
.ft B
.B acpidump > acpidump.out
.SH DESCRIPTION
\fBacpidump \fP dumps the systems ACPI tables to an ASCII file
appropriate for attaching to a bug report.
Subsequently, they can be processed by utilities in the ACPICA package.
.SS Options
no options worth worrying about.
.PP
.SH EXAMPLE
.nf
# acpidump > acpidump.out
$ acpixtract -a acpidump.out
Acpi table [DSDT] - 15974 bytes written to DSDT.dat
Acpi table [FACS] - 64 bytes written to FACS.dat
Acpi table [FACP] - 116 bytes written to FACP.dat
Acpi table [APIC] - 120 bytes written to APIC.dat
Acpi table [MCFG] - 60 bytes written to MCFG.dat
Acpi table [SSDT] - 444 bytes written to SSDT1.dat
Acpi table [SSDT] - 439 bytes written to SSDT2.dat
Acpi table [SSDT] - 439 bytes written to SSDT3.dat
Acpi table [SSDT] - 439 bytes written to SSDT4.dat
Acpi table [SSDT] - 439 bytes written to SSDT5.dat
Acpi table [RSDT] - 76 bytes written to RSDT.dat
Acpi table [RSDP] - 20 bytes written to RSDP.dat
$ iasl -d *.dat
...
.fi
creates *.dsl, a human readable form which can be edited
and compiled using iasl.
.SH NOTES
.B "acpidump "
must be run as root.
.SH REFERENCES
ACPICA: https://acpica.org/
.SH FILES
.ta
.nf
/dev/mem
/sys/firmware/acpi/tables/dynamic/*
.fi
.PP
.SH AUTHOR
.nf
Written by Len Brown <len.brown@intel.com>

560
tools/power/acpi/acpidump.c Normal file
Vedi File

@@ -0,0 +1,560 @@
/*
* (c) Alexey Starikovskiy, Intel, 2005-2006.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions, and the following disclaimer,
* without modification.
* 2. Redistributions in binary form must reproduce at minimum a disclaimer
* substantially similar to the "NO WARRANTY" disclaimer below
* ("Disclaimer") and any redistribution must be conditioned upon
* including a substantially similar Disclaimer requirement for further
* binary redistribution.
* 3. Neither the names of the above-listed copyright holders nor the names
* of any contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* Alternatively, this software may be distributed under the terms of the
* GNU General Public License ("GPL") version 2 as published by the Free
* Software Foundation.
*
* NO WARRANTY
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGES.
*/
#ifdef DEFINE_ALTERNATE_TYPES
/* hack to enable building old application with new headers -lenb */
#define acpi_fadt_descriptor acpi_table_fadt
#define acpi_rsdp_descriptor acpi_table_rsdp
#define DSDT_SIG ACPI_SIG_DSDT
#define FACS_SIG ACPI_SIG_FACS
#define FADT_SIG ACPI_SIG_FADT
#define xfirmware_ctrl Xfacs
#define firmware_ctrl facs
typedef int s32;
typedef unsigned char u8;
typedef unsigned short u16;
typedef unsigned int u32;
typedef unsigned long long u64;
typedef long long s64;
#endif
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <getopt.h>
#include <sys/types.h>
#include <dirent.h>
#include <acpi/acconfig.h>
#include <acpi/platform/acenv.h>
#include <acpi/actypes.h>
#include <acpi/actbl.h>
static inline u8 checksum(u8 * buffer, u32 length)
{
u8 sum = 0, *i = buffer;
buffer += length;
for (; i < buffer; sum += *(i++));
return sum;
}
static unsigned long psz, addr, length;
static int print, connect, skip;
static u8 select_sig[4];
static unsigned long read_efi_systab( void )
{
char buffer[80];
unsigned long addr;
FILE *f = fopen("/sys/firmware/efi/systab", "r");
if (f) {
while (fgets(buffer, 80, f)) {
if (sscanf(buffer, "ACPI20=0x%lx", &addr) == 1)
return addr;
}
fclose(f);
}
return 0;
}
static u8 *acpi_map_memory(unsigned long where, unsigned length)
{
unsigned long offset;
u8 *there;
int fd = open("/dev/mem", O_RDONLY);
if (fd < 0) {
fprintf(stderr, "acpi_os_map_memory: cannot open /dev/mem\n");
exit(1);
}
offset = where % psz;
there = mmap(NULL, length + offset, PROT_READ, MAP_PRIVATE,
fd, where - offset);
close(fd);
if (there == MAP_FAILED) return 0;
return (there + offset);
}
static void acpi_unmap_memory(u8 * there, unsigned length)
{
unsigned long offset = (unsigned long)there % psz;
munmap(there - offset, length + offset);
}
static struct acpi_table_header *acpi_map_table(unsigned long where, char *sig)
{
unsigned size;
struct acpi_table_header *tbl = (struct acpi_table_header *)
acpi_map_memory(where, sizeof(struct acpi_table_header));
if (!tbl || (sig && memcmp(sig, tbl->signature, 4))) return 0;
size = tbl->length;
acpi_unmap_memory((u8 *) tbl, sizeof(struct acpi_table_header));
return (struct acpi_table_header *)acpi_map_memory(where, size);
}
static void acpi_unmap_table(struct acpi_table_header *tbl)
{
acpi_unmap_memory((u8 *)tbl, tbl->length);
}
static struct acpi_rsdp_descriptor *acpi_scan_for_rsdp(u8 *begin, u32 length)
{
struct acpi_rsdp_descriptor *rsdp;
u8 *i, *end = begin + length;
/* Search from given start address for the requested length */
for (i = begin; i < end; i += ACPI_RSDP_SCAN_STEP) {
/* The signature and checksum must both be correct */
if (memcmp((char *)i, "RSD PTR ", 8)) continue;
rsdp = (struct acpi_rsdp_descriptor *)i;
/* Signature matches, check the appropriate checksum */
if (!checksum((u8 *) rsdp, (rsdp->revision < 2) ?
ACPI_RSDP_CHECKSUM_LENGTH :
ACPI_RSDP_XCHECKSUM_LENGTH))
/* Checksum valid, we have found a valid RSDP */
return rsdp;
}
/* Searched entire block, no RSDP was found */
return 0;
}
/*
* Output data
*/
static void acpi_show_data(int fd, u8 * data, int size)
{
char buffer[256];
int len;
int i, remain = size;
while (remain > 0) {
len = snprintf(buffer, 256, " %04x:", size - remain);
for (i = 0; i < 16 && i < remain; i++) {
len +=
snprintf(&buffer[len], 256 - len, " %02x", data[i]);
}
for (; i < 16; i++) {
len += snprintf(&buffer[len], 256 - len, " ");
}
len += snprintf(&buffer[len], 256 - len, " ");
for (i = 0; i < 16 && i < remain; i++) {
buffer[len++] = (isprint(data[i])) ? data[i] : '.';
}
buffer[len++] = '\n';
write(fd, buffer, len);
data += 16;
remain -= 16;
}
}
/*
* Output ACPI table
*/
static void acpi_show_table(int fd, struct acpi_table_header *table, unsigned long addr)
{
char buff[80];
int len = snprintf(buff, 80, "%.4s @ %p\n", table->signature, (void *)addr);
write(fd, buff, len);
acpi_show_data(fd, (u8 *) table, table->length);
buff[0] = '\n';
write(fd, buff, 1);
}
static void write_table(int fd, struct acpi_table_header *tbl, unsigned long addr)
{
static int select_done = 0;
if (!select_sig[0]) {
if (print) {
acpi_show_table(fd, tbl, addr);
} else {
write(fd, tbl, tbl->length);
}
} else if (!select_done && !memcmp(select_sig, tbl->signature, 4)) {
if (skip > 0) {
--skip;
return;
}
if (print) {
acpi_show_table(fd, tbl, addr);
} else {
write(fd, tbl, tbl->length);
}
select_done = 1;
}
}
static void acpi_dump_FADT(int fd, struct acpi_table_header *tbl, unsigned long xaddr) {
struct acpi_fadt_descriptor x;
unsigned long addr;
size_t len = sizeof(struct acpi_fadt_descriptor);
if (len > tbl->length) len = tbl->length;
memcpy(&x, tbl, len);
x.header.length = len;
if (checksum((u8 *)tbl, len)) {
fprintf(stderr, "Wrong checksum for FADT!\n");
}
if (x.header.length >= 148 && x.Xdsdt) {
addr = (unsigned long)x.Xdsdt;
if (connect) {
x.Xdsdt = lseek(fd, 0, SEEK_CUR);
}
} else if (x.header.length >= 44 && x.dsdt) {
addr = (unsigned long)x.dsdt;
if (connect) {
x.dsdt = lseek(fd, 0, SEEK_CUR);
}
} else {
fprintf(stderr, "No DSDT in FADT!\n");
goto no_dsdt;
}
tbl = acpi_map_table(addr, DSDT_SIG);
if (!tbl) goto no_dsdt;
if (checksum((u8 *)tbl, tbl->length))
fprintf(stderr, "Wrong checksum for DSDT!\n");
write_table(fd, tbl, addr);
acpi_unmap_table(tbl);
no_dsdt:
if (x.header.length >= 140 && x.xfirmware_ctrl) {
addr = (unsigned long)x.xfirmware_ctrl;
if (connect) {
x.xfirmware_ctrl = lseek(fd, 0, SEEK_CUR);
}
} else if (x.header.length >= 40 && x.firmware_ctrl) {
addr = (unsigned long)x.firmware_ctrl;
if (connect) {
x.firmware_ctrl = lseek(fd, 0, SEEK_CUR);
}
} else {
fprintf(stderr, "No FACS in FADT!\n");
goto no_facs;
}
tbl = acpi_map_table(addr, FACS_SIG);
if (!tbl) goto no_facs;
/* do not checksum FACS */
write_table(fd, tbl, addr);
acpi_unmap_table(tbl);
no_facs:
write_table(fd, (struct acpi_table_header *)&x, xaddr);
}
static int acpi_dump_SDT(int fd, struct acpi_rsdp_descriptor *rsdp)
{
struct acpi_table_header *sdt, *tbl = 0;
int xsdt = 1, i, num;
char *offset;
unsigned long addr;
if (rsdp->revision > 1 && rsdp->xsdt_physical_address) {
tbl = acpi_map_table(rsdp->xsdt_physical_address, "XSDT");
}
if (!tbl && rsdp->rsdt_physical_address) {
xsdt = 0;
tbl = acpi_map_table(rsdp->rsdt_physical_address, "RSDT");
}
if (!tbl) return 0;
sdt = malloc(tbl->length);
memcpy(sdt, tbl, tbl->length);
acpi_unmap_table(tbl);
if (checksum((u8 *)sdt, sdt->length))
fprintf(stderr, "Wrong checksum for %s!\n", (xsdt)?"XSDT":"RSDT");
num = (sdt->length - sizeof(struct acpi_table_header))/((xsdt)?sizeof(u64):sizeof(u32));
offset = (char *)sdt + sizeof(struct acpi_table_header);
for (i = 0; i < num; ++i, offset += ((xsdt) ? sizeof(u64) : sizeof(u32))) {
addr = (xsdt) ? (unsigned long)(*(u64 *)offset):
(unsigned long)(*(u32 *)offset);
if (!addr) continue;
tbl = acpi_map_table(addr, 0);
if (!tbl) continue;
if (!memcmp(tbl->signature, FADT_SIG, 4)) {
acpi_dump_FADT(fd, tbl, addr);
} else {
if (checksum((u8 *)tbl, tbl->length))
fprintf(stderr, "Wrong checksum for generic table!\n");
write_table(fd, tbl, addr);
}
acpi_unmap_table(tbl);
if (connect) {
if (xsdt)
(*(u64*)offset) = lseek(fd, 0, SEEK_CUR);
else
(*(u32*)offset) = lseek(fd, 0, SEEK_CUR);
}
}
if (xsdt) {
addr = (unsigned long)rsdp->xsdt_physical_address;
if (connect) {
rsdp->xsdt_physical_address = lseek(fd, 0, SEEK_CUR);
}
} else {
addr = (unsigned long)rsdp->rsdt_physical_address;
if (connect) {
rsdp->rsdt_physical_address = lseek(fd, 0, SEEK_CUR);
}
}
write_table(fd, sdt, addr);
free (sdt);
return 1;
}
#define DYNAMIC_SSDT "/sys/firmware/acpi/tables/dynamic"
static void acpi_dump_dynamic_SSDT(int fd)
{
struct stat file_stat;
char filename[256], *ptr;
DIR *tabledir;
struct dirent *entry;
FILE *fp;
int count, readcount, length;
struct acpi_table_header table_header, *ptable;
if (stat(DYNAMIC_SSDT, &file_stat) == -1) {
/* The directory doesn't exist */
return;
}
tabledir = opendir(DYNAMIC_SSDT);
if(!tabledir){
/*can't open the directory */
return;
}
while ((entry = readdir(tabledir)) != 0){
/* skip the file of . /.. */
if (entry->d_name[0] == '.')
continue;
sprintf(filename, "%s/%s", DYNAMIC_SSDT, entry->d_name);
fp = fopen(filename, "r");
if (fp == NULL) {
fprintf(stderr, "Can't open the file of %s\n",
filename);
continue;
}
/* Read the Table header to parse the table length */
count = fread(&table_header, 1, sizeof(struct acpi_table_header), fp);
if (count < sizeof(table_header)) {
/* the length is lessn than ACPI table header. skip it */
fclose(fp);
continue;
}
length = table_header.length;
ptr = malloc(table_header.length);
fseek(fp, 0, SEEK_SET);
readcount = 0;
while(!feof(fp) && readcount < length) {
count = fread(ptr + readcount, 1, 256, fp);
readcount += count;
}
fclose(fp);
ptable = (struct acpi_table_header *) ptr;
if (checksum((u8 *) ptable, ptable->length))
fprintf(stderr, "Wrong checksum "
"for dynamic SSDT table!\n");
write_table(fd, ptable, 0);
free(ptr);
}
closedir(tabledir);
return;
}
static void usage(const char *progname)
{
puts("Usage:");
printf("%s [--addr 0x1234][--table DSDT][--output filename]"
"[--binary][--length 0x456][--help]\n", progname);
puts("\t--addr 0x1234 or -a 0x1234 -- look for tables at this physical address");
puts("\t--table DSDT or -t DSDT -- only dump table with DSDT signature");
puts("\t--output filename or -o filename -- redirect output from stdin to filename");
puts("\t--binary or -b -- dump data in binary form rather than in hex-dump format");
puts("\t--length 0x456 or -l 0x456 -- works only with --addr, dump physical memory"
"\n\t\tregion without trying to understand it's contents");
puts("\t--skip 2 or -s 2 -- skip 2 tables of the given name and output only 3rd one");
puts("\t--help or -h -- this help message");
exit(0);
}
static struct option long_options[] = {
{"addr", 1, 0, 0},
{"table", 1, 0, 0},
{"output", 1, 0, 0},
{"binary", 0, 0, 0},
{"length", 1, 0, 0},
{"skip", 1, 0, 0},
{"help", 0, 0, 0},
{0, 0, 0, 0}
};
int main(int argc, char **argv)
{
int option_index, c, fd;
u8 *raw;
struct acpi_rsdp_descriptor rsdpx, *x = 0;
char *filename = 0;
char buff[80];
memset(select_sig, 0, 4);
print = 1;
connect = 0;
addr = length = 0;
skip = 0;
while (1) {
option_index = 0;
c = getopt_long(argc, argv, "a:t:o:bl:s:h",
long_options, &option_index);
if (c == -1)
break;
switch (c) {
case 0:
switch (option_index) {
case 0:
addr = strtoul(optarg, (char **)NULL, 16);
break;
case 1:
memcpy(select_sig, optarg, 4);
break;
case 2:
filename = optarg;
break;
case 3:
print = 0;
break;
case 4:
length = strtoul(optarg, (char **)NULL, 16);
break;
case 5:
skip = strtoul(optarg, (char **)NULL, 10);
break;
case 6:
usage(argv[0]);
exit(0);
}
break;
case 'a':
addr = strtoul(optarg, (char **)NULL, 16);
break;
case 't':
memcpy(select_sig, optarg, 4);
break;
case 'o':
filename = optarg;
break;
case 'b':
print = 0;
break;
case 'l':
length = strtoul(optarg, (char **)NULL, 16);
break;
case 's':
skip = strtoul(optarg, (char **)NULL, 10);
break;
case 'h':
usage(argv[0]);
exit(0);
default:
printf("Unknown option!\n");
usage(argv[0]);
exit(0);
}
}
fd = STDOUT_FILENO;
if (filename) {
fd = creat(filename, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
if (fd < 0)
return fd;
}
if (!select_sig[0] && !print) {
connect = 1;
}
psz = sysconf(_SC_PAGESIZE);
if (length && addr) {
/* We know length and address, it means we just want a memory dump */
if (!(raw = acpi_map_memory(addr, length)))
goto not_found;
write(fd, raw, length);
acpi_unmap_memory(raw, length);
close(fd);
return 0;
}
length = sizeof(struct acpi_rsdp_descriptor);
if (!addr) {
addr = read_efi_systab();
if (!addr) {
addr = ACPI_HI_RSDP_WINDOW_BASE;
length = ACPI_HI_RSDP_WINDOW_SIZE;
}
}
if (!(raw = acpi_map_memory(addr, length)) ||
!(x = acpi_scan_for_rsdp(raw, length)))
goto not_found;
/* Find RSDP and print all found tables */
memcpy(&rsdpx, x, sizeof(struct acpi_rsdp_descriptor));
acpi_unmap_memory(raw, length);
if (connect) {
lseek(fd, sizeof(struct acpi_rsdp_descriptor), SEEK_SET);
}
if (!acpi_dump_SDT(fd, &rsdpx))
goto not_found;
if (connect) {
lseek(fd, 0, SEEK_SET);
write(fd, x, (rsdpx.revision < 2) ?
ACPI_RSDP_CHECKSUM_LENGTH : ACPI_RSDP_XCHECKSUM_LENGTH);
} else if (!select_sig[0] || !memcmp("RSD PTR ", select_sig, 4)) {
addr += (long)x - (long)raw;
length = snprintf(buff, 80, "RSD PTR @ %p\n", (void *)addr);
write(fd, buff, length);
acpi_show_data(fd, (u8 *) & rsdpx, (rsdpx.revision < 2) ?
ACPI_RSDP_CHECKSUM_LENGTH : ACPI_RSDP_XCHECKSUM_LENGTH);
buff[0] = '\n';
write(fd, buff, 1);
}
acpi_dump_dynamic_SSDT(fd);
close(fd);
return 0;
not_found:
close(fd);
fprintf(stderr, "ACPI tables were not found. If you know location "
"of RSD PTR table (from dmesg, etc), "
"supply it with either --addr or -a option\n");
return 1;
}

Vedi File

@@ -4,15 +4,11 @@ turbostat \- Report processor frequency and idle statistics
.SH SYNOPSIS
.ft B
.B turbostat
.RB [ "\-s" ]
.RB [ "\-v" ]
.RB [ "\-M MSR#" ]
.RB [ Options ]
.RB command
.br
.B turbostat
.RB [ "\-s" ]
.RB [ "\-v" ]
.RB [ "\-M MSR#" ]
.RB [ Options ]
.RB [ "\-i interval_sec" ]
.SH DESCRIPTION
\fBturbostat \fP reports processor topology, frequency
@@ -27,16 +23,23 @@ supports an "invariant" TSC, plus the APERF and MPERF MSRs.
on processors that additionally support C-state residency counters.
.SS Options
The \fB-s\fP option limits output to a 1-line system summary for each interval.
The \fB-p\fP option limits output to the 1st thread in 1st core of each package.
.PP
The \fB-c\fP option limits output to the 1st thread in each core.
The \fB-P\fP option limits output to the 1st thread in each Package.
.PP
The \fB-p\fP option limits output to the 1st thread in each package.
The \fB-S\fP option limits output to a 1-line System Summary for each interval.
.PP
The \fB-v\fP option increases verbosity.
.PP
The \fB-M MSR#\fP option dumps the specified MSR,
in addition to the usual frequency and idle statistics.
The \fB-s\fP option prints the SMI counter, equivalent to "-c 0x34"
.PP
The \fB-c MSR#\fP option includes the delta of the specified 32-bit MSR counter.
.PP
The \fB-C MSR#\fP option includes the delta of the specified 64-bit MSR counter.
.PP
The \fB-m MSR#\fP option includes the the specified 32-bit MSR value.
.PP
The \fB-M MSR#\fP option includes the the specified 64-bit MSR value.
.PP
The \fB-i interval_sec\fP option prints statistics every \fiinterval_sec\fP seconds.
The default is 5 seconds.
@@ -150,6 +153,29 @@ Note that turbostat reports average GHz of 3.63, while
the arithmetic average of the GHz column above is lower.
This is a weighted average, where the weight is %c0. ie. it is the total number of
un-halted cycles elapsed per time divided by the number of CPUs.
.SH SMI COUNTING EXAMPLE
On Intel Nehalem and newer processors, MSR 0x34 is a System Management Mode Interrupt (SMI) counter.
Using the -m option, you can display how many SMIs have fired since reset, or if there
are SMIs during the measurement interval, you can display the delta using the -d option.
.nf
[root@x980 ~]# turbostat -m 0x34
cor CPU %c0 GHz TSC MSR 0x034 %c1 %c3 %c6 %pc3 %pc6
1.41 1.82 3.38 0x00000000 8.92 37.82 51.85 17.37 0.55
0 0 3.73 2.03 3.38 0x00000055 1.72 48.25 46.31 17.38 0.55
0 6 0.14 1.63 3.38 0x00000056 5.30
1 2 2.51 1.80 3.38 0x00000056 15.65 29.33 52.52
1 8 0.10 1.65 3.38 0x00000056 18.05
2 4 1.16 1.68 3.38 0x00000056 5.87 24.47 68.50
2 10 0.10 1.63 3.38 0x00000056 6.93
8 1 3.84 1.91 3.38 0x00000056 1.36 50.65 44.16
8 7 0.08 1.64 3.38 0x00000056 5.12
9 3 1.82 1.73 3.38 0x00000056 7.59 24.21 66.38
9 9 0.09 1.68 3.38 0x00000056 9.32
10 5 1.66 1.65 3.38 0x00000056 15.10 50.00 33.23
10 11 1.72 1.65 3.38 0x00000056 15.05
^C
[root@x980 ~]#
.fi
.SH NOTES
.B "turbostat "
@@ -165,6 +191,13 @@ may work poorly on Linux-2.6.20 through 2.6.29,
as \fBacpi-cpufreq \fPperiodically cleared the APERF and MPERF
in those kernels.
If the TSC column does not make sense, then
the other numbers will also make no sense.
Turbostat is lightweight, and its data collection is not atomic.
These issues are usually caused by an extremely short measurement
interval (much less than 1 second), or system activity that prevents
turbostat from being able to run on all CPUS to quickly collect data.
The APERF, MPERF MSRs are defined to count non-halted cycles.
Although it is not guaranteed by the architecture, turbostat assumes
that they count at TSC rate, which is true on all processors tested to date.

Vedi File

@@ -35,9 +35,9 @@
#include <ctype.h>
#include <sched.h>
#define MSR_TSC 0x10
#define MSR_NEHALEM_PLATFORM_INFO 0xCE
#define MSR_NEHALEM_TURBO_RATIO_LIMIT 0x1AD
#define MSR_IVT_TURBO_RATIO_LIMIT 0x1AE
#define MSR_APERF 0xE8
#define MSR_MPERF 0xE7
#define MSR_PKG_C2_RESIDENCY 0x60D /* SNB only */
@@ -62,7 +62,11 @@ unsigned int genuine_intel;
unsigned int has_invariant_tsc;
unsigned int do_nehalem_platform_info;
unsigned int do_nehalem_turbo_ratio_limit;
unsigned int extra_msr_offset;
unsigned int do_ivt_turbo_ratio_limit;
unsigned int extra_msr_offset32;
unsigned int extra_msr_offset64;
unsigned int extra_delta_offset32;
unsigned int extra_delta_offset64;
double bclk;
unsigned int show_pkg;
unsigned int show_core;
@@ -83,7 +87,10 @@ struct thread_data {
unsigned long long aperf;
unsigned long long mperf;
unsigned long long c1; /* derived */
unsigned long long extra_msr;
unsigned long long extra_msr64;
unsigned long long extra_delta64;
unsigned long long extra_msr32;
unsigned long long extra_delta32;
unsigned int cpu_id;
unsigned int flags;
#define CPU_IS_FIRST_THREAD_IN_CORE 0x2
@@ -222,6 +229,14 @@ void print_header(void)
if (has_aperf)
outp += sprintf(outp, " GHz");
outp += sprintf(outp, " TSC");
if (extra_delta_offset32)
outp += sprintf(outp, " count 0x%03X", extra_delta_offset32);
if (extra_delta_offset64)
outp += sprintf(outp, " COUNT 0x%03X", extra_delta_offset64);
if (extra_msr_offset32)
outp += sprintf(outp, " MSR 0x%03X", extra_msr_offset32);
if (extra_msr_offset64)
outp += sprintf(outp, " MSR 0x%03X", extra_msr_offset64);
if (do_nhm_cstates)
outp += sprintf(outp, " %%c1");
if (do_nhm_cstates)
@@ -238,8 +253,6 @@ void print_header(void)
outp += sprintf(outp, " %%pc6");
if (do_snb_cstates)
outp += sprintf(outp, " %%pc7");
if (extra_msr_offset)
outp += sprintf(outp, " MSR 0x%x ", extra_msr_offset);
outp += sprintf(outp, "\n");
}
@@ -255,8 +268,14 @@ int dump_counters(struct thread_data *t, struct core_data *c,
fprintf(stderr, "aperf: %016llX\n", t->aperf);
fprintf(stderr, "mperf: %016llX\n", t->mperf);
fprintf(stderr, "c1: %016llX\n", t->c1);
fprintf(stderr, "msr0x%x: %08llX\n",
extra_delta_offset32, t->extra_delta32);
fprintf(stderr, "msr0x%x: %016llX\n",
extra_msr_offset, t->extra_msr);
extra_delta_offset64, t->extra_delta64);
fprintf(stderr, "msr0x%x: %08llX\n",
extra_msr_offset32, t->extra_msr32);
fprintf(stderr, "msr0x%x: %016llX\n",
extra_msr_offset64, t->extra_msr64);
}
if (c) {
@@ -360,6 +379,21 @@ int format_counters(struct thread_data *t, struct core_data *c,
/* TSC */
outp += sprintf(outp, "%5.2f", 1.0 * t->tsc/units/interval_float);
/* delta */
if (extra_delta_offset32)
outp += sprintf(outp, " %11llu", t->extra_delta32);
/* DELTA */
if (extra_delta_offset64)
outp += sprintf(outp, " %11llu", t->extra_delta64);
/* msr */
if (extra_msr_offset32)
outp += sprintf(outp, " 0x%08llx", t->extra_msr32);
/* MSR */
if (extra_msr_offset64)
outp += sprintf(outp, " 0x%016llx", t->extra_msr64);
if (do_nhm_cstates) {
if (!skip_c1)
outp += sprintf(outp, " %6.2f", 100.0 * t->c1/t->tsc);
@@ -391,8 +425,6 @@ int format_counters(struct thread_data *t, struct core_data *c,
if (do_snb_cstates)
outp += sprintf(outp, " %6.2f", 100.0 * p->pc7/t->tsc);
done:
if (extra_msr_offset)
outp += sprintf(outp, " 0x%016llx", t->extra_msr);
outp += sprintf(outp, "\n");
return 0;
@@ -502,10 +534,16 @@ delta_thread(struct thread_data *new, struct thread_data *old,
old->mperf = 1; /* divide by 0 protection */
}
old->extra_delta32 = new->extra_delta32 - old->extra_delta32;
old->extra_delta32 &= 0xFFFFFFFF;
old->extra_delta64 = new->extra_delta64 - old->extra_delta64;
/*
* for "extra msr", just copy the latest w/o subtracting
* Extra MSR is just a snapshot, simply copy latest w/o subtracting
*/
old->extra_msr = new->extra_msr;
old->extra_msr32 = new->extra_msr32;
old->extra_msr64 = new->extra_msr64;
}
int delta_cpu(struct thread_data *t, struct core_data *c,
@@ -533,6 +571,9 @@ void clear_counters(struct thread_data *t, struct core_data *c, struct pkg_data
t->mperf = 0;
t->c1 = 0;
t->extra_delta32 = 0;
t->extra_delta64 = 0;
/* tells format_counters to dump all fields from this set */
t->flags = CPU_IS_FIRST_THREAD_IN_CORE | CPU_IS_FIRST_CORE_IN_PACKAGE;
@@ -553,6 +594,9 @@ int sum_counters(struct thread_data *t, struct core_data *c,
average.threads.mperf += t->mperf;
average.threads.c1 += t->c1;
average.threads.extra_delta32 += t->extra_delta32;
average.threads.extra_delta64 += t->extra_delta64;
/* sum per-core values only for 1st thread in core */
if (!(t->flags & CPU_IS_FIRST_THREAD_IN_CORE))
return 0;
@@ -588,6 +632,11 @@ void compute_average(struct thread_data *t, struct core_data *c,
average.threads.mperf /= topo.num_cpus;
average.threads.c1 /= topo.num_cpus;
average.threads.extra_delta32 /= topo.num_cpus;
average.threads.extra_delta32 &= 0xFFFFFFFF;
average.threads.extra_delta64 /= topo.num_cpus;
average.cores.c3 /= topo.num_cores;
average.cores.c6 /= topo.num_cores;
average.cores.c7 /= topo.num_cores;
@@ -629,8 +678,24 @@ int get_counters(struct thread_data *t, struct core_data *c, struct pkg_data *p)
return -4;
}
if (extra_msr_offset)
if (get_msr(cpu, extra_msr_offset, &t->extra_msr))
if (extra_delta_offset32) {
if (get_msr(cpu, extra_delta_offset32, &t->extra_delta32))
return -5;
t->extra_delta32 &= 0xFFFFFFFF;
}
if (extra_delta_offset64)
if (get_msr(cpu, extra_delta_offset64, &t->extra_delta64))
return -5;
if (extra_msr_offset32) {
if (get_msr(cpu, extra_msr_offset32, &t->extra_msr32))
return -5;
t->extra_msr32 &= 0xFFFFFFFF;
}
if (extra_msr_offset64)
if (get_msr(cpu, extra_msr_offset64, &t->extra_msr64))
return -5;
/* collect core counters only for 1st thread in core */
@@ -677,6 +742,9 @@ void print_verbose_header(void)
get_msr(0, MSR_NEHALEM_PLATFORM_INFO, &msr);
if (verbose > 1)
fprintf(stderr, "MSR_NEHALEM_PLATFORM_INFO: 0x%llx\n", msr);
ratio = (msr >> 40) & 0xFF;
fprintf(stderr, "%d * %.0f = %.0f MHz max efficiency\n",
ratio, bclk, ratio * bclk);
@@ -685,14 +753,84 @@ void print_verbose_header(void)
fprintf(stderr, "%d * %.0f = %.0f MHz TSC frequency\n",
ratio, bclk, ratio * bclk);
if (!do_ivt_turbo_ratio_limit)
goto print_nhm_turbo_ratio_limits;
get_msr(0, MSR_IVT_TURBO_RATIO_LIMIT, &msr);
if (verbose > 1)
fprintf(stderr, "MSR_NEHALEM_PLATFORM_INFO: 0x%llx\n", msr);
fprintf(stderr, "MSR_IVT_TURBO_RATIO_LIMIT: 0x%llx\n", msr);
ratio = (msr >> 56) & 0xFF;
if (ratio)
fprintf(stderr, "%d * %.0f = %.0f MHz max turbo 16 active cores\n",
ratio, bclk, ratio * bclk);
ratio = (msr >> 48) & 0xFF;
if (ratio)
fprintf(stderr, "%d * %.0f = %.0f MHz max turbo 15 active cores\n",
ratio, bclk, ratio * bclk);
ratio = (msr >> 40) & 0xFF;
if (ratio)
fprintf(stderr, "%d * %.0f = %.0f MHz max turbo 14 active cores\n",
ratio, bclk, ratio * bclk);
ratio = (msr >> 32) & 0xFF;
if (ratio)
fprintf(stderr, "%d * %.0f = %.0f MHz max turbo 13 active cores\n",
ratio, bclk, ratio * bclk);
ratio = (msr >> 24) & 0xFF;
if (ratio)
fprintf(stderr, "%d * %.0f = %.0f MHz max turbo 12 active cores\n",
ratio, bclk, ratio * bclk);
ratio = (msr >> 16) & 0xFF;
if (ratio)
fprintf(stderr, "%d * %.0f = %.0f MHz max turbo 11 active cores\n",
ratio, bclk, ratio * bclk);
ratio = (msr >> 8) & 0xFF;
if (ratio)
fprintf(stderr, "%d * %.0f = %.0f MHz max turbo 10 active cores\n",
ratio, bclk, ratio * bclk);
ratio = (msr >> 0) & 0xFF;
if (ratio)
fprintf(stderr, "%d * %.0f = %.0f MHz max turbo 9 active cores\n",
ratio, bclk, ratio * bclk);
print_nhm_turbo_ratio_limits:
if (!do_nehalem_turbo_ratio_limit)
return;
get_msr(0, MSR_NEHALEM_TURBO_RATIO_LIMIT, &msr);
if (verbose > 1)
fprintf(stderr, "MSR_NEHALEM_TURBO_RATIO_LIMIT: 0x%llx\n", msr);
ratio = (msr >> 56) & 0xFF;
if (ratio)
fprintf(stderr, "%d * %.0f = %.0f MHz max turbo 8 active cores\n",
ratio, bclk, ratio * bclk);
ratio = (msr >> 48) & 0xFF;
if (ratio)
fprintf(stderr, "%d * %.0f = %.0f MHz max turbo 7 active cores\n",
ratio, bclk, ratio * bclk);
ratio = (msr >> 40) & 0xFF;
if (ratio)
fprintf(stderr, "%d * %.0f = %.0f MHz max turbo 6 active cores\n",
ratio, bclk, ratio * bclk);
ratio = (msr >> 32) & 0xFF;
if (ratio)
fprintf(stderr, "%d * %.0f = %.0f MHz max turbo 5 active cores\n",
ratio, bclk, ratio * bclk);
ratio = (msr >> 24) & 0xFF;
if (ratio)
fprintf(stderr, "%d * %.0f = %.0f MHz max turbo 4 active cores\n",
@@ -712,7 +850,6 @@ void print_verbose_header(void)
if (ratio)
fprintf(stderr, "%d * %.0f = %.0f MHz max turbo 1 active cores\n",
ratio, bclk, ratio * bclk);
}
void free_all_buffers(void)
@@ -1038,7 +1175,7 @@ int has_nehalem_turbo_ratio_limit(unsigned int family, unsigned int model)
case 0x2A: /* SNB */
case 0x2D: /* SNB Xeon */
case 0x3A: /* IVB */
case 0x3D: /* IVB Xeon */
case 0x3E: /* IVB Xeon */
return 1;
case 0x2E: /* Nehalem-EX Xeon - Beckton */
case 0x2F: /* Westmere-EX Xeon - Eagleton */
@@ -1046,6 +1183,22 @@ int has_nehalem_turbo_ratio_limit(unsigned int family, unsigned int model)
return 0;
}
}
int has_ivt_turbo_ratio_limit(unsigned int family, unsigned int model)
{
if (!genuine_intel)
return 0;
if (family != 6)
return 0;
switch (model) {
case 0x3E: /* IVB Xeon */
return 1;
default:
return 0;
}
}
int is_snb(unsigned int family, unsigned int model)
{
@@ -1056,7 +1209,7 @@ int is_snb(unsigned int family, unsigned int model)
case 0x2A:
case 0x2D:
case 0x3A: /* IVB */
case 0x3D: /* IVB Xeon */
case 0x3E: /* IVB Xeon */
return 1;
}
return 0;
@@ -1145,12 +1298,13 @@ void check_cpuid()
bclk = discover_bclk(family, model);
do_nehalem_turbo_ratio_limit = has_nehalem_turbo_ratio_limit(family, model);
do_ivt_turbo_ratio_limit = has_ivt_turbo_ratio_limit(family, model);
}
void usage()
{
fprintf(stderr, "%s: [-v] [-M MSR#] [-i interval_sec | command ...]\n",
fprintf(stderr, "%s: [-v][-p|-P|-S][-c MSR# | -s]][-C MSR#][-m MSR#][-M MSR#][-i interval_sec | command ...]\n",
progname);
exit(1);
}
@@ -1440,15 +1594,15 @@ void cmdline(int argc, char **argv)
progname = argv[0];
while ((opt = getopt(argc, argv, "+cpsvi:M:")) != -1) {
while ((opt = getopt(argc, argv, "+pPSvisc:sC:m:M:")) != -1) {
switch (opt) {
case 'c':
case 'p':
show_core_only++;
break;
case 'p':
case 'P':
show_pkg_only++;
break;
case 's':
case 'S':
summary_only++;
break;
case 'v':
@@ -1457,10 +1611,20 @@ void cmdline(int argc, char **argv)
case 'i':
interval_sec = atoi(optarg);
break;
case 'c':
sscanf(optarg, "%x", &extra_delta_offset32);
break;
case 's':
extra_delta_offset32 = 0x34; /* SMI counter */
break;
case 'C':
sscanf(optarg, "%x", &extra_delta_offset64);
break;
case 'm':
sscanf(optarg, "%x", &extra_msr_offset32);
break;
case 'M':
sscanf(optarg, "%x", &extra_msr_offset);
if (verbose > 1)
fprintf(stderr, "MSR 0x%X\n", extra_msr_offset);
sscanf(optarg, "%x", &extra_msr_offset64);
break;
default:
usage();
@@ -1473,7 +1637,7 @@ int main(int argc, char **argv)
cmdline(argc, argv);
if (verbose > 1)
fprintf(stderr, "turbostat v2.0 May 16, 2012"
fprintf(stderr, "turbostat v2.1 October 6, 2012"
" - Len Brown <lenb@kernel.org>\n");
turbostat_init();