Back to index

numactl  2.0.8~rc4
numamon.c
Go to the documentation of this file.
00001 /* Copyright (C) 2003,2004 Andi Kleen, SuSE Labs.
00002 
00003    numamon is free software; you can redistribute it and/or
00004    modify it under the terms of the GNU General Public
00005    License as published by the Free Software Foundation; version
00006    2.
00007 
00008    numamon is distributed in the hope that it will be useful,
00009    but WITHOUT ANY WARRANTY; without even the implied warranty of
00010    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00011    General Public License for more details.
00012 
00013    You should find a copy of v2 of the GNU General Public License somewhere
00014    on your Linux system; if not, write to the Free Software Foundation,
00015    Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
00016 
00017    Display some numa statistics collected by the CPU.
00018    Opteron specific. Also not reliable because the counters
00019    are not quite correct in hardware.  */
00020 
00021 #define _LARGE_FILE_SOURCE 1
00022 #define _GNU_SOURCE 1
00023 #include <string.h>
00024 #include <errno.h>
00025 #include <stdio.h>
00026 #include <unistd.h>
00027 #include <dirent.h>
00028 #include <getopt.h>
00029 #include <stdarg.h>
00030 #include <stdlib.h>
00031 #include <sys/fcntl.h>
00032 
00033 enum { LOCALLOCAL = 0, LOCALREMOTE = 1, REMOTELOCAL = 2 };
00034 static int mem[] = { [LOCALLOCAL] = 0xa8, [LOCALREMOTE] = 0x98, [REMOTELOCAL] = 0x68 };
00035 static int io[] = {  [LOCALLOCAL] = 0xa4, [LOCALREMOTE] = 0x94, [REMOTELOCAL] = 0x64 };
00036 static int *masks = mem;
00037 
00038 #define err(x) perror(x),exit(1)
00039 
00040 #define PERFEVTSEL0 0xc0010000
00041 #define PERFEVTSEL1 0xc0010001
00042 #define PERFEVTSEL2 0xc0010002
00043 #define PERFEVTSEL3 0xc0010003
00044 
00045 #define PERFCTR0 0xc0010004
00046 #define PERFCTR1 0xc0010005
00047 #define PERFCTR2 0xc0010006
00048 #define PERFCTR3 0xc0010007
00049 
00050 #define EVENT 0xe9
00051 #define PERFEVTSEL_EN (1 << 22)
00052 #define PERFEVTSEL_OS (1 << 17)
00053 #define PERFEVTSEL_USR (1 << 16)
00054 
00055 #define BASE (EVENT | PERFEVTSEL_EN | PERFEVTSEL_OS | PERFEVTSEL_USR)
00056 
00057 #define MAXCPU 8
00058 
00059 int force = 0;
00060 int msrfd[MAXCPU];
00061 int delay;
00062 int absolute;
00063 char *cfilter;
00064 int verbose;
00065 
00066 void usage(void);
00067 
00068 void Vprintf(char *fmt, ...)
00069 {
00070        va_list ap;
00071        va_start(ap,fmt);
00072        if (verbose)
00073               vfprintf(stderr,fmt,ap);
00074        va_end(ap);
00075 }
00076 
00077 unsigned long long rdmsr(int cpu, unsigned long msr)
00078 {
00079        unsigned long long val;
00080        if (pread(msrfd[cpu], &val, 8, msr) != 8) {
00081               fprintf(stderr, "rdmsr of %lx failed: %s\n", msr, strerror(errno));
00082               exit(1);
00083        }
00084        return val;
00085 }
00086 
00087 void wrmsr(int cpu, unsigned long msr, unsigned long long value)
00088 {
00089        if (pwrite(msrfd[cpu], &value, 8, msr) != 8) {
00090               fprintf(stderr, "wdmsr of %lx failed: %s\n", msr, strerror(errno));
00091               exit(1);
00092        }
00093 }
00094 
00095 int cpufilter(int cpu)
00096 {
00097        long num;
00098        char *end;
00099        char *s;
00100        
00101        if (!cfilter)
00102               return 1;     
00103        for (s = cfilter;;) {
00104               num = strtoul(s, &end, 0);
00105               if (end == s)
00106                      usage();
00107               if (cpu == num)
00108                      return 1;
00109               if (*end == ',')
00110                      s = end+1;
00111               else if (*end == 0)
00112                      break;
00113               else
00114                      usage();
00115        }
00116        return 0;
00117 }
00118 
00119 void checkcounter(int cpu, int clear)
00120 {
00121        int i;
00122        for (i = 1; i < 4; i++) {
00123               int clear_this = clear;
00124               unsigned long long evtsel = rdmsr(cpu, PERFEVTSEL0 + i);
00125               Vprintf("%d: %x %Lx\n", cpu, PERFEVTSEL0 + i, evtsel);
00126               if (!(evtsel & PERFEVTSEL_EN)) {
00127                      Vprintf("reinit %d\n", cpu);
00128                      wrmsr(cpu, PERFEVTSEL0 + i, BASE | masks[i - 1]);
00129                      clear_this = 1;
00130               } else if (evtsel == (BASE | (masks[i-1] << 8))) {
00131                      /* everything fine */
00132               } else if (force) {
00133                      Vprintf("reinit force %d\n", cpu);
00134                      wrmsr(cpu, PERFEVTSEL0 + i, BASE | (masks[i - 1] << 8));
00135                      clear_this = 1;
00136               } else {
00137                      fprintf(stderr, "perfctr %d cpu %d already used with %Lx\n",
00138                             i, cpu, evtsel);
00139                      fprintf(stderr, "Consider using -f if you know what you're doing.\n");
00140                      exit(1);
00141               }
00142               if (clear_this) {
00143                      Vprintf("clearing %d\n", cpu);
00144                      wrmsr(cpu, PERFCTR0 + i, 0);
00145               }
00146        }
00147 }
00148 
00149 void setup(int clear)
00150 {
00151        DIR *dir;
00152        struct dirent *d;
00153        int numcpus = 0;
00154 
00155        memset(msrfd, -1, sizeof(msrfd));
00156        dir = opendir("/dev/cpu");
00157        if (!dir)
00158               err("cannot open /dev/cpu");
00159        while ((d = readdir(dir)) != NULL) {
00160               char buf[64];
00161               char *end;
00162               long cpunum = strtoul(d->d_name, &end, 0);
00163               if (*end != 0)
00164                      continue;
00165               if (cpunum > MAXCPU) {
00166                      fprintf(stderr, "too many cpus %ld %s\n", cpunum, d->d_name);
00167                      continue;
00168               }
00169               if (!cpufilter(cpunum))
00170                      continue;
00171               snprintf(buf, 63, "/dev/cpu/%ld/msr", cpunum);
00172               msrfd[cpunum] = open64(buf, O_RDWR);
00173               if (msrfd[cpunum] < 0)
00174                      continue;
00175               numcpus++;
00176               checkcounter(cpunum, clear);
00177        }
00178        closedir(dir);              
00179        if (numcpus == 0) {
00180               fprintf(stderr, "No CPU found using MSR driver.\n");
00181               exit(1);
00182        }
00183 }
00184 
00185 void printf_padded(int pad, char *fmt, ...)
00186 {
00187        char buf[pad + 1];
00188        va_list ap;
00189        va_start(ap, fmt);
00190        vsnprintf(buf, pad, fmt, ap);
00191        printf("%-*s", pad, buf);
00192        va_end(ap);
00193 }
00194 
00195 void print_header(void)
00196 {
00197        printf_padded(4, "CPU ");
00198        printf_padded(16, "LOCAL");
00199        printf_padded(16, "LOCAL->REMOTE");
00200        printf_padded(16, "REMOTE->LOCAL");
00201        putchar('\n');
00202 }
00203 
00204 void print_cpu(int cpu)
00205 {
00206        int i;
00207        static unsigned long long lastval[4];
00208        printf_padded(4, "%d", cpu);
00209        for (i = 1; i < 4; i++) {
00210               unsigned long long val = rdmsr(cpu, PERFCTR0 + i);
00211               if (absolute)
00212                      printf_padded(16, "%Lu", val);
00213               else
00214                      printf_padded(16, "%Lu", val - lastval[i]);             
00215               lastval[i] = val;
00216        }
00217        putchar('\n');
00218 }
00219 
00220 void dumpall(void)
00221 {
00222        int cnt = 0;
00223        int cpu;
00224        print_header();
00225        for (;;) {
00226               for (cpu = 0; cpu < MAXCPU; ++cpu) {
00227                      if (msrfd[cpu] < 0)
00228                             continue;
00229                      print_cpu(cpu);
00230               }
00231               if (!delay)
00232                      break;
00233               sleep(delay);
00234               if (++cnt > 40) {
00235                      cnt = 0;
00236                      print_header();
00237               }
00238        }             
00239 }
00240 
00241 void checkk8(void)
00242 {
00243        char *line = NULL;
00244        size_t size = 0;
00245        int bad = 0;
00246        FILE *f = fopen("/proc/cpuinfo", "r");
00247        if (!f)
00248               return;       
00249        while (getline(&line, &size, f) > 0) {
00250               if (!strncmp("vendor_id", line, 9)) {
00251                      if (!strstr(line, "AMD"))
00252                             bad++;
00253               }
00254               if (!strncmp("cpu family", line, 10)) {
00255                      char *s = line + strcspn(line,":");
00256                      int family;
00257                      if (*s == ':') ++s;
00258                      family = strtoul(s, NULL, 0);
00259                      if (family != 15)
00260                             bad++;
00261               }
00262        }
00263        if (bad) {
00264               printf("not a opteron cpu\n");
00265               exit(1);
00266        }
00267        free(line);
00268        fclose(f);
00269 }
00270 
00271 void usage(void)
00272 {
00273        fprintf(stderr, "usage: numamon [args] [delay]\n");
00274        fprintf(stderr, "       -f forcibly overwrite counters\n");
00275        fprintf(stderr, "       -i count IO (default memory)\n");      
00276        fprintf(stderr, "       -a print absolute counter values (with delay)\n");
00277        fprintf(stderr, "       -s setup counters and exit\n");        
00278        fprintf(stderr, "       -c clear counters and exit\n");        
00279        fprintf(stderr, "       -m Print memory traffic (default)\n");        
00280        fprintf(stderr, "       -C cpu{,cpu} only print for cpus\n");
00281        fprintf(stderr, "       -v Be verbose\n");
00282        exit(1);
00283 }
00284 
00285 int main(int ac, char **av)
00286 {
00287        int opt;
00288        checkk8();
00289        while ((opt = getopt(ac,av,"ifscmaC:v")) != -1) {
00290               switch (opt) {
00291               case 'f':
00292                      force = 1;
00293                      break;
00294               case 'c':
00295                      setup(1);
00296                      exit(0);
00297               case 's':
00298                      setup(0);
00299                      exit(0);
00300               case 'm':
00301                      masks = mem;
00302                      break;
00303               case 'i':
00304                      masks = io;
00305                      break;
00306               case 'a':
00307                      absolute = 1;
00308                      break;
00309               case 'C':
00310                      cfilter = optarg;
00311                      break;
00312               case 'v':
00313                      verbose = 1;
00314                      break;
00315               default:
00316                      usage();
00317               }
00318        }
00319        if (av[optind]) {
00320               char *end;
00321               delay = strtoul(av[optind], &end, 10);
00322               if (*end)
00323                      usage();
00324               if (av[optind+1])
00325                      usage();
00326        }
00327 
00328        setup(0);
00329        dumpall();
00330        return 0;
00331 }