Logo Search packages:      
Sourcecode: numactl version File versions  Download package

numamon.c

/* Copyright (C) 2003,2004 Andi Kleen, SuSE Labs.

   numamon is free software; you can redistribute it and/or
   modify it under the terms of the GNU General Public
   License as published by the Free Software Foundation; version
   2.

   numamon is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   General Public License for more details.

   You should find a copy of v2 of the GNU General Public License somewhere
   on your Linux system; if not, write to the Free Software Foundation, 
   Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 

   Display some numa statistics collected by the CPU.
   Opteron specific. Also not reliable because the counters
   are not quite correct in hardware. */
#define _LARGE_FILE_SOURCE 1
#define _GNU_SOURCE 1
#include <string.h>
#include <errno.h>
#include <stdio.h>
#include <unistd.h>
#include <dirent.h>
#include <getopt.h>
#include <stdarg.h>
#include <stdlib.h>
#include <sys/fcntl.h>

enum { LOCALLOCAL = 0, LOCALREMOTE = 1, REMOTELOCAL = 2 }; 
static int mem[] = { [LOCALLOCAL] = 0xa8, [LOCALREMOTE] = 0x98, [REMOTELOCAL] = 0x68 };
static int io[] = {  [LOCALLOCAL] = 0xa4, [LOCALREMOTE] = 0x94, [REMOTELOCAL] = 0x64 }; 
static int *masks = mem;

#define err(x) perror(x),exit(1)

#define PERFEVTSEL0 0xc0010000
#define PERFEVTSEL1 0xc0010001
#define PERFEVTSEL2 0xc0010002
#define PERFEVTSEL3 0xc0010003

#define PERFCTR0 0xc0010004
#define PERFCTR1 0xc0010005
#define PERFCTR2 0xc0010006
#define PERFCTR3 0xc0010007

#define EVENT 0xe9
#define PERFEVTSEL_EN (1 << 22)
#define PERFEVTSEL_OS (1 << 17)
#define PERFEVTSEL_USR (1 << 16)

#define BASE (EVENT | PERFEVTSEL_EN | PERFEVTSEL_OS | PERFEVTSEL_USR)

#define MAXCPU 8

int force = 0;
int msrfd[MAXCPU];
int delay;
int absolute;
char *cfilter; 
int verbose;

void usage(void);

void Vprintf(char *fmt, ...)
{
      va_list ap;
      va_start(ap,fmt);
      if (verbose)
            vfprintf(stderr,fmt,ap);
      va_end(ap);
}

unsigned long long rdmsr(int cpu, unsigned long msr) 
{ 
      unsigned long long val; 
      if (pread(msrfd[cpu], &val, 8, msr) != 8) {
            fprintf(stderr, "rdmsr of %lx failed: %s\n", msr, strerror(errno));  
            exit(1);
      }
      return val;
} 

void wrmsr(int cpu, unsigned long msr, unsigned long long value)
{ 
      if (pwrite(msrfd[cpu], &value, 8, msr) != 8) { 
            fprintf(stderr, "wdmsr of %lx failed: %s\n", msr, strerror(errno));  
            exit(1);
      } 
} 

int cpufilter(int cpu) 
{ 
      long num; 
      char *end;
      char *s;
      
      if (!cfilter)
            return 1;   
      for (s = cfilter;;) { 
            num = strtoul(s, &end, 0); 
            if (end == s) 
                  usage(); 
            if (cpu == num)
                  return 1;
            if (*end == ',') 
                  s = end+1;
            else if (*end == 0) 
                  break;
            else
                  usage(); 
      }
      return 0;
} 

void checkcounter(int cpu, int clear)
{ 
      int i;
      for (i = 1; i < 4; i++) { 
            int clear_this = clear;
            unsigned long long evtsel = rdmsr(cpu, PERFEVTSEL0 + i); 
            Vprintf("%d: %x %Lx\n", cpu, PERFEVTSEL0 + i, evtsel);
            if (!(evtsel & PERFEVTSEL_EN)) { 
                  Vprintf("reinit %d\n", cpu);  
                  wrmsr(cpu, PERFEVTSEL0 + i, BASE | masks[i - 1]); 
                  clear_this = 1;
            } else if (evtsel == (BASE | (masks[i-1] << 8))) { 
                  /* everything fine */ 
            } else if (force) { 
                  Vprintf("reinit force %d\n", cpu); 
                  wrmsr(cpu, PERFEVTSEL0 + i, BASE | (masks[i - 1] << 8)); 
                  clear_this = 1;
            } else {
                  fprintf(stderr, "perfctr %d cpu %d already used with %Lx\n",
                        i, cpu, evtsel); 
                  fprintf(stderr, "Consider using -f if you know what you're doing.\n");
                  exit(1);
            }
            if (clear_this) { 
                  Vprintf("clearing %d\n", cpu);
                  wrmsr(cpu, PERFCTR0 + i, 0); 
            }
      } 
} 

void setup(int clear)
{ 
      DIR *dir; 
      struct dirent *d;
      int numcpus = 0;

      memset(msrfd, -1, sizeof(msrfd)); 
      dir = opendir("/dev/cpu");
      if (!dir) 
            err("cannot open /dev/cpu"); 
      while ((d = readdir(dir)) != NULL) { 
            char buf[64];
            char *end; 
            long cpunum = strtoul(d->d_name, &end, 0); 
            if (*end != 0) 
                  continue; 
            if (cpunum > MAXCPU) {
                  fprintf(stderr, "too many cpus %ld %s\n", cpunum, d->d_name); 
                  continue;
            }
            if (!cpufilter(cpunum))
                  continue; 
            snprintf(buf, 63, "/dev/cpu/%ld/msr", cpunum);
            msrfd[cpunum] = open64(buf, O_RDWR); 
            if (msrfd[cpunum] < 0)
                  continue;
            numcpus++;
            checkcounter(cpunum, clear); 
      } 
      closedir(dir);          
      if (numcpus == 0) {
            fprintf(stderr, "No CPU found using MSR driver.\n"); 
            exit(1);
      }
} 

void printf_padded(int pad, char *fmt, ...)
{
      char buf[pad + 1]; 
      va_list ap;
      va_start(ap, fmt);
      vsnprintf(buf, pad, fmt, ap); 
      printf("%-*s", pad, buf); 
      va_end(ap);
}

void print_header(void)
{
      printf_padded(4, "CPU "); 
      printf_padded(16, "LOCAL"); 
      printf_padded(16, "LOCAL->REMOTE"); 
      printf_padded(16, "REMOTE->LOCAL"); 
      putchar('\n');
}

void print_cpu(int cpu)
{ 
      int i;
      static unsigned long long lastval[4]; 
      printf_padded(4, "%d", cpu);
      for (i = 1; i < 4; i++) { 
            unsigned long long val = rdmsr(cpu, PERFCTR0 + i);
            if (absolute) 
                  printf_padded(16, "%Lu", val); 
            else
                  printf_padded(16, "%Lu", val - lastval[i]);           
            lastval[i] = val;
      } 
      putchar('\n');
} 

void dumpall(void)
{
      int cnt = 0;
      int cpu;
      print_header();
      for (;;) { 
            for (cpu = 0; cpu < MAXCPU; ++cpu) { 
                  if (msrfd[cpu] < 0) 
                        continue;
                  print_cpu(cpu);
            }
            if (!delay) 
                  break;
            sleep(delay);
            if (++cnt > 40) { 
                  cnt = 0;
                  print_header();
            }
      }           
} 

void checkk8(void)
{ 
      char *line = NULL;
      size_t size = 0;
      int bad = 0;
      FILE *f = fopen("/proc/cpuinfo", "r");
      if (!f) 
            return;     
      while (getline(&line, &size, f) > 0) { 
            if (!strncmp("vendor_id", line, 9)) { 
                  if (!strstr(line, "AMD"))
                        bad++; 
            } 
            if (!strncmp("cpu family", line, 10)) { 
                  char *s = line + strcspn(line,":");
                  int family;
                  if (*s == ':') ++s;
                  family = strtoul(s, NULL, 0); 
                  if (family != 15)
                        bad++;
            } 
      } 
      if (bad) {
            printf("not a opteron cpu\n"); 
            exit(1);
      }
      free(line);
      fclose(f);
} 

void usage(void)
{
      fprintf(stderr, "usage: numamon [args] [delay]\n"); 
      fprintf(stderr, "       -f forcibly overwrite counters\n");
      fprintf(stderr, "       -i count IO (default memory)\n");   
      fprintf(stderr, "       -a print absolute counter values (with delay)\n");
      fprintf(stderr, "       -s setup counters and exit\n");     
      fprintf(stderr, "       -c clear counters and exit\n");     
      fprintf(stderr, "       -m Print memory traffic (default)\n");    
      fprintf(stderr, "       -C cpu{,cpu} only print for cpus\n"); 
      fprintf(stderr, "       -v Be verbose\n");
      exit(1);
} 

int main(int ac, char **av) 
{ 
      int opt;
      checkk8(); 
      while ((opt = getopt(ac,av,"ifscmaC:v")) != -1) { 
            switch (opt) { 
            case 'f': 
                  force = 1; 
                  break;
            case 'c': 
                  setup(1);
                  exit(0); 
            case 's': 
                  setup(0); 
                  exit(0); 
            case 'm':
                  masks = mem;
                  break;
            case 'i':
                  masks = io;
                  break;
            case 'a':
                  absolute = 1;
                  break;
            case 'C':
                  cfilter = optarg;
                  break;
            case 'v':
                  verbose = 1;
                  break;
            default: 
                  usage();
            }
      } 
      if (av[optind]) { 
            char *end; 
            delay = strtoul(av[optind], &end, 10); 
            if (*end) 
                  usage(); 
            if (av[optind+1])
                  usage();
      } 

      setup(0); 
      dumpall();
      return 0;
} 

Generated by  Doxygen 1.6.0   Back to index