Path: blob/master/tools/power/x86/turbostat/turbostat.c
10821 views
/*1* turbostat -- show CPU frequency and C-state residency2* on modern Intel turbo-capable processors.3*4* Copyright (c) 2010, Intel Corporation.5* Len Brown <[email protected]>6*7* This program is free software; you can redistribute it and/or modify it8* under the terms and conditions of the GNU General Public License,9* version 2, as published by the Free Software Foundation.10*11* This program is distributed in the hope it will be useful, but WITHOUT12* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or13* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for14* more details.15*16* You should have received a copy of the GNU General Public License along with17* this program; if not, write to the Free Software Foundation, Inc.,18* 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.19*/2021#include <stdio.h>22#include <unistd.h>23#include <sys/types.h>24#include <sys/wait.h>25#include <sys/stat.h>26#include <sys/resource.h>27#include <fcntl.h>28#include <signal.h>29#include <sys/time.h>30#include <stdlib.h>31#include <dirent.h>32#include <string.h>33#include <ctype.h>3435#define MSR_TSC 0x1036#define MSR_NEHALEM_PLATFORM_INFO 0xCE37#define MSR_NEHALEM_TURBO_RATIO_LIMIT 0x1AD38#define MSR_APERF 0xE839#define MSR_MPERF 0xE740#define MSR_PKG_C2_RESIDENCY 0x60D /* SNB only */41#define MSR_PKG_C3_RESIDENCY 0x3F842#define MSR_PKG_C6_RESIDENCY 0x3F943#define MSR_PKG_C7_RESIDENCY 0x3FA /* SNB only */44#define MSR_CORE_C3_RESIDENCY 0x3FC45#define MSR_CORE_C6_RESIDENCY 0x3FD46#define MSR_CORE_C7_RESIDENCY 0x3FE /* SNB only */4748char *proc_stat = "/proc/stat";49unsigned int interval_sec = 5; /* set with -i interval_sec */50unsigned int verbose; /* set with -v */51unsigned int skip_c0;52unsigned int skip_c1;53unsigned int do_nhm_cstates;54unsigned int do_snb_cstates;55unsigned int has_aperf;56unsigned int units = 1000000000; /* Ghz etc */57unsigned int genuine_intel;58unsigned int has_invariant_tsc;59unsigned int do_nehalem_platform_info;60unsigned int do_nehalem_turbo_ratio_limit;61unsigned int extra_msr_offset;62double bclk;63unsigned int show_pkg;64unsigned int show_core;65unsigned int show_cpu;6667int aperf_mperf_unstable;68int backwards_count;69char *progname;70int need_reinitialize;7172int num_cpus;7374struct counters {75unsigned long long tsc; /* per thread */76unsigned long long aperf; /* per thread */77unsigned long long mperf; /* per thread */78unsigned long long c1; /* per thread (calculated) */79unsigned long long c3; /* per core */80unsigned long long c6; /* per core */81unsigned long long c7; /* per core */82unsigned long long pc2; /* per package */83unsigned long long pc3; /* per package */84unsigned long long pc6; /* per package */85unsigned long long pc7; /* per package */86unsigned long long extra_msr; /* per thread */87int pkg;88int core;89int cpu;90struct counters *next;91};9293struct counters *cnt_even;94struct counters *cnt_odd;95struct counters *cnt_delta;96struct counters *cnt_average;97struct timeval tv_even;98struct timeval tv_odd;99struct timeval tv_delta;100101unsigned long long get_msr(int cpu, off_t offset)102{103ssize_t retval;104unsigned long long msr;105char pathname[32];106int fd;107108sprintf(pathname, "/dev/cpu/%d/msr", cpu);109fd = open(pathname, O_RDONLY);110if (fd < 0) {111perror(pathname);112need_reinitialize = 1;113return 0;114}115116retval = pread(fd, &msr, sizeof msr, offset);117if (retval != sizeof msr) {118fprintf(stderr, "cpu%d pread(..., 0x%zx) = %jd\n",119cpu, offset, retval);120exit(-2);121}122123close(fd);124return msr;125}126127void print_header(void)128{129if (show_pkg)130fprintf(stderr, "pkg ");131if (show_core)132fprintf(stderr, "core");133if (show_cpu)134fprintf(stderr, " CPU");135if (do_nhm_cstates)136fprintf(stderr, " %%c0 ");137if (has_aperf)138fprintf(stderr, " GHz");139fprintf(stderr, " TSC");140if (do_nhm_cstates)141fprintf(stderr, " %%c1 ");142if (do_nhm_cstates)143fprintf(stderr, " %%c3 ");144if (do_nhm_cstates)145fprintf(stderr, " %%c6 ");146if (do_snb_cstates)147fprintf(stderr, " %%c7 ");148if (do_snb_cstates)149fprintf(stderr, " %%pc2 ");150if (do_nhm_cstates)151fprintf(stderr, " %%pc3 ");152if (do_nhm_cstates)153fprintf(stderr, " %%pc6 ");154if (do_snb_cstates)155fprintf(stderr, " %%pc7 ");156if (extra_msr_offset)157fprintf(stderr, " MSR 0x%x ", extra_msr_offset);158159putc('\n', stderr);160}161162void dump_cnt(struct counters *cnt)163{164fprintf(stderr, "package: %d ", cnt->pkg);165fprintf(stderr, "core:: %d ", cnt->core);166fprintf(stderr, "CPU: %d ", cnt->cpu);167fprintf(stderr, "TSC: %016llX\n", cnt->tsc);168fprintf(stderr, "c3: %016llX\n", cnt->c3);169fprintf(stderr, "c6: %016llX\n", cnt->c6);170fprintf(stderr, "c7: %016llX\n", cnt->c7);171fprintf(stderr, "aperf: %016llX\n", cnt->aperf);172fprintf(stderr, "pc2: %016llX\n", cnt->pc2);173fprintf(stderr, "pc3: %016llX\n", cnt->pc3);174fprintf(stderr, "pc6: %016llX\n", cnt->pc6);175fprintf(stderr, "pc7: %016llX\n", cnt->pc7);176fprintf(stderr, "msr0x%x: %016llX\n", extra_msr_offset, cnt->extra_msr);177}178179void dump_list(struct counters *cnt)180{181printf("dump_list 0x%p\n", cnt);182183for (; cnt; cnt = cnt->next)184dump_cnt(cnt);185}186187void print_cnt(struct counters *p)188{189double interval_float;190191interval_float = tv_delta.tv_sec + tv_delta.tv_usec/1000000.0;192193/* topology columns, print blanks on 1st (average) line */194if (p == cnt_average) {195if (show_pkg)196fprintf(stderr, " ");197if (show_core)198fprintf(stderr, " ");199if (show_cpu)200fprintf(stderr, " ");201} else {202if (show_pkg)203fprintf(stderr, "%4d", p->pkg);204if (show_core)205fprintf(stderr, "%4d", p->core);206if (show_cpu)207fprintf(stderr, "%4d", p->cpu);208}209210/* %c0 */211if (do_nhm_cstates) {212if (!skip_c0)213fprintf(stderr, "%7.2f", 100.0 * p->mperf/p->tsc);214else215fprintf(stderr, " ****");216}217218/* GHz */219if (has_aperf) {220if (!aperf_mperf_unstable) {221fprintf(stderr, "%5.2f",2221.0 * p->tsc / units * p->aperf /223p->mperf / interval_float);224} else {225if (p->aperf > p->tsc || p->mperf > p->tsc) {226fprintf(stderr, " ****");227} else {228fprintf(stderr, "%4.1f*",2291.0 * p->tsc /230units * p->aperf /231p->mperf / interval_float);232}233}234}235236/* TSC */237fprintf(stderr, "%5.2f", 1.0 * p->tsc/units/interval_float);238239if (do_nhm_cstates) {240if (!skip_c1)241fprintf(stderr, "%7.2f", 100.0 * p->c1/p->tsc);242else243fprintf(stderr, " ****");244}245if (do_nhm_cstates)246fprintf(stderr, "%7.2f", 100.0 * p->c3/p->tsc);247if (do_nhm_cstates)248fprintf(stderr, "%7.2f", 100.0 * p->c6/p->tsc);249if (do_snb_cstates)250fprintf(stderr, "%7.2f", 100.0 * p->c7/p->tsc);251if (do_snb_cstates)252fprintf(stderr, "%7.2f", 100.0 * p->pc2/p->tsc);253if (do_nhm_cstates)254fprintf(stderr, "%7.2f", 100.0 * p->pc3/p->tsc);255if (do_nhm_cstates)256fprintf(stderr, "%7.2f", 100.0 * p->pc6/p->tsc);257if (do_snb_cstates)258fprintf(stderr, "%7.2f", 100.0 * p->pc7/p->tsc);259if (extra_msr_offset)260fprintf(stderr, " 0x%016llx", p->extra_msr);261putc('\n', stderr);262}263264void print_counters(struct counters *counters)265{266struct counters *cnt;267268print_header();269270if (num_cpus > 1)271print_cnt(cnt_average);272273for (cnt = counters; cnt != NULL; cnt = cnt->next)274print_cnt(cnt);275276}277278#define SUBTRACT_COUNTER(after, before, delta) (delta = (after - before), (before > after))279280int compute_delta(struct counters *after,281struct counters *before, struct counters *delta)282{283int errors = 0;284int perf_err = 0;285286skip_c0 = skip_c1 = 0;287288for ( ; after && before && delta;289after = after->next, before = before->next, delta = delta->next) {290if (before->cpu != after->cpu) {291printf("cpu configuration changed: %d != %d\n",292before->cpu, after->cpu);293return -1;294}295296if (SUBTRACT_COUNTER(after->tsc, before->tsc, delta->tsc)) {297fprintf(stderr, "cpu%d TSC went backwards %llX to %llX\n",298before->cpu, before->tsc, after->tsc);299errors++;300}301/* check for TSC < 1 Mcycles over interval */302if (delta->tsc < (1000 * 1000)) {303fprintf(stderr, "Insanely slow TSC rate,"304" TSC stops in idle?\n");305fprintf(stderr, "You can disable all c-states"306" by booting with \"idle=poll\"\n");307fprintf(stderr, "or just the deep ones with"308" \"processor.max_cstate=1\"\n");309exit(-3);310}311if (SUBTRACT_COUNTER(after->c3, before->c3, delta->c3)) {312fprintf(stderr, "cpu%d c3 counter went backwards %llX to %llX\n",313before->cpu, before->c3, after->c3);314errors++;315}316if (SUBTRACT_COUNTER(after->c6, before->c6, delta->c6)) {317fprintf(stderr, "cpu%d c6 counter went backwards %llX to %llX\n",318before->cpu, before->c6, after->c6);319errors++;320}321if (SUBTRACT_COUNTER(after->c7, before->c7, delta->c7)) {322fprintf(stderr, "cpu%d c7 counter went backwards %llX to %llX\n",323before->cpu, before->c7, after->c7);324errors++;325}326if (SUBTRACT_COUNTER(after->pc2, before->pc2, delta->pc2)) {327fprintf(stderr, "cpu%d pc2 counter went backwards %llX to %llX\n",328before->cpu, before->pc2, after->pc2);329errors++;330}331if (SUBTRACT_COUNTER(after->pc3, before->pc3, delta->pc3)) {332fprintf(stderr, "cpu%d pc3 counter went backwards %llX to %llX\n",333before->cpu, before->pc3, after->pc3);334errors++;335}336if (SUBTRACT_COUNTER(after->pc6, before->pc6, delta->pc6)) {337fprintf(stderr, "cpu%d pc6 counter went backwards %llX to %llX\n",338before->cpu, before->pc6, after->pc6);339errors++;340}341if (SUBTRACT_COUNTER(after->pc7, before->pc7, delta->pc7)) {342fprintf(stderr, "cpu%d pc7 counter went backwards %llX to %llX\n",343before->cpu, before->pc7, after->pc7);344errors++;345}346347perf_err = SUBTRACT_COUNTER(after->aperf, before->aperf, delta->aperf);348if (perf_err) {349fprintf(stderr, "cpu%d aperf counter went backwards %llX to %llX\n",350before->cpu, before->aperf, after->aperf);351}352perf_err |= SUBTRACT_COUNTER(after->mperf, before->mperf, delta->mperf);353if (perf_err) {354fprintf(stderr, "cpu%d mperf counter went backwards %llX to %llX\n",355before->cpu, before->mperf, after->mperf);356}357if (perf_err) {358if (!aperf_mperf_unstable) {359fprintf(stderr, "%s: APERF or MPERF went backwards *\n", progname);360fprintf(stderr, "* Frequency results do not cover entire interval *\n");361fprintf(stderr, "* fix this by running Linux-2.6.30 or later *\n");362363aperf_mperf_unstable = 1;364}365/*366* mperf delta is likely a huge "positive" number367* can not use it for calculating c0 time368*/369skip_c0 = 1;370skip_c1 = 1;371}372373/*374* As mperf and tsc collection are not atomic,375* it is possible for mperf's non-halted cycles376* to exceed TSC's all cycles: show c1 = 0% in that case.377*/378if (delta->mperf > delta->tsc)379delta->c1 = 0;380else /* normal case, derive c1 */381delta->c1 = delta->tsc - delta->mperf382- delta->c3 - delta->c6 - delta->c7;383384if (delta->mperf == 0)385delta->mperf = 1; /* divide by 0 protection */386387/*388* for "extra msr", just copy the latest w/o subtracting389*/390delta->extra_msr = after->extra_msr;391if (errors) {392fprintf(stderr, "ERROR cpu%d before:\n", before->cpu);393dump_cnt(before);394fprintf(stderr, "ERROR cpu%d after:\n", before->cpu);395dump_cnt(after);396errors = 0;397}398}399return 0;400}401402void compute_average(struct counters *delta, struct counters *avg)403{404struct counters *sum;405406sum = calloc(1, sizeof(struct counters));407if (sum == NULL) {408perror("calloc sum");409exit(1);410}411412for (; delta; delta = delta->next) {413sum->tsc += delta->tsc;414sum->c1 += delta->c1;415sum->c3 += delta->c3;416sum->c6 += delta->c6;417sum->c7 += delta->c7;418sum->aperf += delta->aperf;419sum->mperf += delta->mperf;420sum->pc2 += delta->pc2;421sum->pc3 += delta->pc3;422sum->pc6 += delta->pc6;423sum->pc7 += delta->pc7;424}425avg->tsc = sum->tsc/num_cpus;426avg->c1 = sum->c1/num_cpus;427avg->c3 = sum->c3/num_cpus;428avg->c6 = sum->c6/num_cpus;429avg->c7 = sum->c7/num_cpus;430avg->aperf = sum->aperf/num_cpus;431avg->mperf = sum->mperf/num_cpus;432avg->pc2 = sum->pc2/num_cpus;433avg->pc3 = sum->pc3/num_cpus;434avg->pc6 = sum->pc6/num_cpus;435avg->pc7 = sum->pc7/num_cpus;436437free(sum);438}439440void get_counters(struct counters *cnt)441{442for ( ; cnt; cnt = cnt->next) {443cnt->tsc = get_msr(cnt->cpu, MSR_TSC);444if (do_nhm_cstates)445cnt->c3 = get_msr(cnt->cpu, MSR_CORE_C3_RESIDENCY);446if (do_nhm_cstates)447cnt->c6 = get_msr(cnt->cpu, MSR_CORE_C6_RESIDENCY);448if (do_snb_cstates)449cnt->c7 = get_msr(cnt->cpu, MSR_CORE_C7_RESIDENCY);450if (has_aperf)451cnt->aperf = get_msr(cnt->cpu, MSR_APERF);452if (has_aperf)453cnt->mperf = get_msr(cnt->cpu, MSR_MPERF);454if (do_snb_cstates)455cnt->pc2 = get_msr(cnt->cpu, MSR_PKG_C2_RESIDENCY);456if (do_nhm_cstates)457cnt->pc3 = get_msr(cnt->cpu, MSR_PKG_C3_RESIDENCY);458if (do_nhm_cstates)459cnt->pc6 = get_msr(cnt->cpu, MSR_PKG_C6_RESIDENCY);460if (do_snb_cstates)461cnt->pc7 = get_msr(cnt->cpu, MSR_PKG_C7_RESIDENCY);462if (extra_msr_offset)463cnt->extra_msr = get_msr(cnt->cpu, extra_msr_offset);464}465}466467void print_nehalem_info(void)468{469unsigned long long msr;470unsigned int ratio;471472if (!do_nehalem_platform_info)473return;474475msr = get_msr(0, MSR_NEHALEM_PLATFORM_INFO);476477ratio = (msr >> 40) & 0xFF;478fprintf(stderr, "%d * %.0f = %.0f MHz max efficiency\n",479ratio, bclk, ratio * bclk);480481ratio = (msr >> 8) & 0xFF;482fprintf(stderr, "%d * %.0f = %.0f MHz TSC frequency\n",483ratio, bclk, ratio * bclk);484485if (verbose > 1)486fprintf(stderr, "MSR_NEHALEM_PLATFORM_INFO: 0x%llx\n", msr);487488if (!do_nehalem_turbo_ratio_limit)489return;490491msr = get_msr(0, MSR_NEHALEM_TURBO_RATIO_LIMIT);492493ratio = (msr >> 24) & 0xFF;494if (ratio)495fprintf(stderr, "%d * %.0f = %.0f MHz max turbo 4 active cores\n",496ratio, bclk, ratio * bclk);497498ratio = (msr >> 16) & 0xFF;499if (ratio)500fprintf(stderr, "%d * %.0f = %.0f MHz max turbo 3 active cores\n",501ratio, bclk, ratio * bclk);502503ratio = (msr >> 8) & 0xFF;504if (ratio)505fprintf(stderr, "%d * %.0f = %.0f MHz max turbo 2 active cores\n",506ratio, bclk, ratio * bclk);507508ratio = (msr >> 0) & 0xFF;509if (ratio)510fprintf(stderr, "%d * %.0f = %.0f MHz max turbo 1 active cores\n",511ratio, bclk, ratio * bclk);512513}514515void free_counter_list(struct counters *list)516{517struct counters *p;518519for (p = list; p; ) {520struct counters *free_me;521522free_me = p;523p = p->next;524free(free_me);525}526}527528void free_all_counters(void)529{530free_counter_list(cnt_even);531cnt_even = NULL;532533free_counter_list(cnt_odd);534cnt_odd = NULL;535536free_counter_list(cnt_delta);537cnt_delta = NULL;538539free_counter_list(cnt_average);540cnt_average = NULL;541}542543void insert_counters(struct counters **list,544struct counters *new)545{546struct counters *prev;547548/*549* list was empty550*/551if (*list == NULL) {552new->next = *list;553*list = new;554return;555}556557show_cpu = 1; /* there is more than one CPU */558559/*560* insert on front of list.561* It is sorted by ascending package#, core#, cpu#562*/563if (((*list)->pkg > new->pkg) ||564(((*list)->pkg == new->pkg) && ((*list)->core > new->core)) ||565(((*list)->pkg == new->pkg) && ((*list)->core == new->core) && ((*list)->cpu > new->cpu))) {566new->next = *list;567*list = new;568return;569}570571prev = *list;572573while (prev->next && (prev->next->pkg < new->pkg)) {574prev = prev->next;575show_pkg = 1; /* there is more than 1 package */576}577578while (prev->next && (prev->next->pkg == new->pkg)579&& (prev->next->core < new->core)) {580prev = prev->next;581show_core = 1; /* there is more than 1 core */582}583584while (prev->next && (prev->next->pkg == new->pkg)585&& (prev->next->core == new->core)586&& (prev->next->cpu < new->cpu)) {587prev = prev->next;588}589590/*591* insert after "prev"592*/593new->next = prev->next;594prev->next = new;595}596597void alloc_new_counters(int pkg, int core, int cpu)598{599struct counters *new;600601if (verbose > 1)602printf("pkg%d core%d, cpu%d\n", pkg, core, cpu);603604new = (struct counters *)calloc(1, sizeof(struct counters));605if (new == NULL) {606perror("calloc");607exit(1);608}609new->pkg = pkg;610new->core = core;611new->cpu = cpu;612insert_counters(&cnt_odd, new);613614new = (struct counters *)calloc(1,615sizeof(struct counters));616if (new == NULL) {617perror("calloc");618exit(1);619}620new->pkg = pkg;621new->core = core;622new->cpu = cpu;623insert_counters(&cnt_even, new);624625new = (struct counters *)calloc(1, sizeof(struct counters));626if (new == NULL) {627perror("calloc");628exit(1);629}630new->pkg = pkg;631new->core = core;632new->cpu = cpu;633insert_counters(&cnt_delta, new);634635new = (struct counters *)calloc(1, sizeof(struct counters));636if (new == NULL) {637perror("calloc");638exit(1);639}640new->pkg = pkg;641new->core = core;642new->cpu = cpu;643cnt_average = new;644}645646int get_physical_package_id(int cpu)647{648char path[64];649FILE *filep;650int pkg;651652sprintf(path, "/sys/devices/system/cpu/cpu%d/topology/physical_package_id", cpu);653filep = fopen(path, "r");654if (filep == NULL) {655perror(path);656exit(1);657}658fscanf(filep, "%d", &pkg);659fclose(filep);660return pkg;661}662663int get_core_id(int cpu)664{665char path[64];666FILE *filep;667int core;668669sprintf(path, "/sys/devices/system/cpu/cpu%d/topology/core_id", cpu);670filep = fopen(path, "r");671if (filep == NULL) {672perror(path);673exit(1);674}675fscanf(filep, "%d", &core);676fclose(filep);677return core;678}679680/*681* run func(index, cpu) on every cpu in /proc/stat682*/683684int for_all_cpus(void (func)(int, int, int))685{686FILE *fp;687int cpu_count;688int retval;689690fp = fopen(proc_stat, "r");691if (fp == NULL) {692perror(proc_stat);693exit(1);694}695696retval = fscanf(fp, "cpu %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d\n");697if (retval != 0) {698perror("/proc/stat format");699exit(1);700}701702for (cpu_count = 0; ; cpu_count++) {703int cpu;704705retval = fscanf(fp, "cpu%u %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d\n", &cpu);706if (retval != 1)707break;708709func(get_physical_package_id(cpu), get_core_id(cpu), cpu);710}711fclose(fp);712return cpu_count;713}714715void re_initialize(void)716{717printf("turbostat: topology changed, re-initializing.\n");718free_all_counters();719num_cpus = for_all_cpus(alloc_new_counters);720need_reinitialize = 0;721printf("num_cpus is now %d\n", num_cpus);722}723724void dummy(int pkg, int core, int cpu) { return; }725/*726* check to see if a cpu came on-line727*/728void verify_num_cpus(void)729{730int new_num_cpus;731732new_num_cpus = for_all_cpus(dummy);733734if (new_num_cpus != num_cpus) {735if (verbose)736printf("num_cpus was %d, is now %d\n",737num_cpus, new_num_cpus);738need_reinitialize = 1;739}740}741742void turbostat_loop()743{744restart:745get_counters(cnt_even);746gettimeofday(&tv_even, (struct timezone *)NULL);747748while (1) {749verify_num_cpus();750if (need_reinitialize) {751re_initialize();752goto restart;753}754sleep(interval_sec);755get_counters(cnt_odd);756gettimeofday(&tv_odd, (struct timezone *)NULL);757758compute_delta(cnt_odd, cnt_even, cnt_delta);759timersub(&tv_odd, &tv_even, &tv_delta);760compute_average(cnt_delta, cnt_average);761print_counters(cnt_delta);762if (need_reinitialize) {763re_initialize();764goto restart;765}766sleep(interval_sec);767get_counters(cnt_even);768gettimeofday(&tv_even, (struct timezone *)NULL);769compute_delta(cnt_even, cnt_odd, cnt_delta);770timersub(&tv_even, &tv_odd, &tv_delta);771compute_average(cnt_delta, cnt_average);772print_counters(cnt_delta);773}774}775776void check_dev_msr()777{778struct stat sb;779780if (stat("/dev/cpu/0/msr", &sb)) {781fprintf(stderr, "no /dev/cpu/0/msr\n");782fprintf(stderr, "Try \"# modprobe msr\"\n");783exit(-5);784}785}786787void check_super_user()788{789if (getuid() != 0) {790fprintf(stderr, "must be root\n");791exit(-6);792}793}794795int has_nehalem_turbo_ratio_limit(unsigned int family, unsigned int model)796{797if (!genuine_intel)798return 0;799800if (family != 6)801return 0;802803switch (model) {804case 0x1A: /* Core i7, Xeon 5500 series - Bloomfield, Gainstown NHM-EP */805case 0x1E: /* Core i7 and i5 Processor - Clarksfield, Lynnfield, Jasper Forest */806case 0x1F: /* Core i7 and i5 Processor - Nehalem */807case 0x25: /* Westmere Client - Clarkdale, Arrandale */808case 0x2C: /* Westmere EP - Gulftown */809case 0x2A: /* SNB */810case 0x2D: /* SNB Xeon */811return 1;812case 0x2E: /* Nehalem-EX Xeon - Beckton */813case 0x2F: /* Westmere-EX Xeon - Eagleton */814default:815return 0;816}817}818819int is_snb(unsigned int family, unsigned int model)820{821if (!genuine_intel)822return 0;823824switch (model) {825case 0x2A:826case 0x2D:827return 1;828}829return 0;830}831832double discover_bclk(unsigned int family, unsigned int model)833{834if (is_snb(family, model))835return 100.00;836else837return 133.33;838}839840void check_cpuid()841{842unsigned int eax, ebx, ecx, edx, max_level;843unsigned int fms, family, model, stepping;844845eax = ebx = ecx = edx = 0;846847asm("cpuid" : "=a" (max_level), "=b" (ebx), "=c" (ecx), "=d" (edx) : "a" (0));848849if (ebx == 0x756e6547 && edx == 0x49656e69 && ecx == 0x6c65746e)850genuine_intel = 1;851852if (verbose)853fprintf(stderr, "%.4s%.4s%.4s ",854(char *)&ebx, (char *)&edx, (char *)&ecx);855856asm("cpuid" : "=a" (fms), "=c" (ecx), "=d" (edx) : "a" (1) : "ebx");857family = (fms >> 8) & 0xf;858model = (fms >> 4) & 0xf;859stepping = fms & 0xf;860if (family == 6 || family == 0xf)861model += ((fms >> 16) & 0xf) << 4;862863if (verbose)864fprintf(stderr, "%d CPUID levels; family:model:stepping 0x%x:%x:%x (%d:%d:%d)\n",865max_level, family, model, stepping, family, model, stepping);866867if (!(edx & (1 << 5))) {868fprintf(stderr, "CPUID: no MSR\n");869exit(1);870}871872/*873* check max extended function levels of CPUID.874* This is needed to check for invariant TSC.875* This check is valid for both Intel and AMD.876*/877ebx = ecx = edx = 0;878asm("cpuid" : "=a" (max_level), "=b" (ebx), "=c" (ecx), "=d" (edx) : "a" (0x80000000));879880if (max_level < 0x80000007) {881fprintf(stderr, "CPUID: no invariant TSC (max_level 0x%x)\n", max_level);882exit(1);883}884885/*886* Non-Stop TSC is advertised by CPUID.EAX=0x80000007: EDX.bit8887* this check is valid for both Intel and AMD888*/889asm("cpuid" : "=a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx) : "a" (0x80000007));890has_invariant_tsc = edx & (1 << 8);891892if (!has_invariant_tsc) {893fprintf(stderr, "No invariant TSC\n");894exit(1);895}896897/*898* APERF/MPERF is advertised by CPUID.EAX=0x6: ECX.bit0899* this check is valid for both Intel and AMD900*/901902asm("cpuid" : "=a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx) : "a" (0x6));903has_aperf = ecx & (1 << 0);904if (!has_aperf) {905fprintf(stderr, "No APERF MSR\n");906exit(1);907}908909do_nehalem_platform_info = genuine_intel && has_invariant_tsc;910do_nhm_cstates = genuine_intel; /* all Intel w/ non-stop TSC have NHM counters */911do_snb_cstates = is_snb(family, model);912bclk = discover_bclk(family, model);913914do_nehalem_turbo_ratio_limit = has_nehalem_turbo_ratio_limit(family, model);915}916917918void usage()919{920fprintf(stderr, "%s: [-v] [-M MSR#] [-i interval_sec | command ...]\n",921progname);922exit(1);923}924925926/*927* in /dev/cpu/ return success for names that are numbers928* ie. filter out ".", "..", "microcode".929*/930int dir_filter(const struct dirent *dirp)931{932if (isdigit(dirp->d_name[0]))933return 1;934else935return 0;936}937938int open_dev_cpu_msr(int dummy1)939{940return 0;941}942943void turbostat_init()944{945check_cpuid();946947check_dev_msr();948check_super_user();949950num_cpus = for_all_cpus(alloc_new_counters);951952if (verbose)953print_nehalem_info();954}955956int fork_it(char **argv)957{958int retval;959pid_t child_pid;960get_counters(cnt_even);961gettimeofday(&tv_even, (struct timezone *)NULL);962963child_pid = fork();964if (!child_pid) {965/* child */966execvp(argv[0], argv);967} else {968int status;969970/* parent */971if (child_pid == -1) {972perror("fork");973exit(1);974}975976signal(SIGINT, SIG_IGN);977signal(SIGQUIT, SIG_IGN);978if (waitpid(child_pid, &status, 0) == -1) {979perror("wait");980exit(1);981}982}983get_counters(cnt_odd);984gettimeofday(&tv_odd, (struct timezone *)NULL);985retval = compute_delta(cnt_odd, cnt_even, cnt_delta);986987timersub(&tv_odd, &tv_even, &tv_delta);988compute_average(cnt_delta, cnt_average);989if (!retval)990print_counters(cnt_delta);991992fprintf(stderr, "%.6f sec\n", tv_delta.tv_sec + tv_delta.tv_usec/1000000.0);993994return 0;995}996997void cmdline(int argc, char **argv)998{999int opt;10001001progname = argv[0];10021003while ((opt = getopt(argc, argv, "+vi:M:")) != -1) {1004switch (opt) {1005case 'v':1006verbose++;1007break;1008case 'i':1009interval_sec = atoi(optarg);1010break;1011case 'M':1012sscanf(optarg, "%x", &extra_msr_offset);1013if (verbose > 1)1014fprintf(stderr, "MSR 0x%X\n", extra_msr_offset);1015break;1016default:1017usage();1018}1019}1020}10211022int main(int argc, char **argv)1023{1024cmdline(argc, argv);10251026if (verbose > 1)1027fprintf(stderr, "turbostat Dec 6, 2010"1028" - Len Brown <[email protected]>\n");1029if (verbose > 1)1030fprintf(stderr, "http://userweb.kernel.org/~lenb/acpi/utils/pmtools/turbostat/\n");10311032turbostat_init();10331034/*1035* if any params left, it must be a command to fork1036*/1037if (argc - optind)1038return fork_it(argv + optind);1039else1040turbostat_loop();10411042return 0;1043}104410451046