Scientific Operations Bellum Gratia Artis

testing - 1998 - March - this message

[ previous , next ]

Subject: [9fans] pentium msr support

From: schwartz+9fans@[REDACTED]
Date: 9 Mar 1998 08:18:36 -0000

Anyone want to help me test something? Support for Pentium performance
monitor counters, like the other unixie systems have these days. The
enclosed code has only been tried on a Pentium, and it won't do the
right thing on a multiprocessor (I didn't want to tinker with clock.c,
to keep the changes to a minimum.)

Unpack in a fresh directory:

# To unbundle, run this file
echo README
sed 's/.//' >README <<'//GO.SYSIN DD README'
-To install:
-
-cp msr.s msr.h devmsr.c /sys/src/9/pc
-cd /sys/src/9/port; patch < print.c-diff
-add “msr Ψ” to dev in 9pc
-
-bind -a '#Ψ' /dev
-
-usage:
-
-#Ψ/cpuid
- read: type features vendor
-#Ψ/msr
- no user serviceable parts
-#Ψ/pmc
- read: timestamp counter-0 counter-1
- write: clears counters
-#Ψ/pmcctl
- read: current mode
- write: counter ring number event,
- c{0,1} r{u,s,us} n{e,c} e0xff
-
- counter arg is an integer (0 or 1)
- ring arg is u(ser), s(ystem) or both,
- number arg is e(vents) or c(locks),
- event arg is integer as read by atol
-
//GO.SYSIN DD README
echo rdtsc.c
sed 's/.//' >rdtsc.c <<'//GO.SYSIN DD rdtsc.c'
-#include 
-#include 
-#include "msr.h"
-
-void main()
-{
- int r = print("%ulld\n", rdtsc());
- exits(r>0?0:"print");
-}
//GO.SYSIN DD rdtsc.c
echo cpuid.c
sed 's/.//' >cpuid.c <<'//GO.SYSIN DD cpuid.c'
-#include 
-#include 
-#include "msr.h"
-
-void err(const char* msg)
-{
- perror(msg);
- exits("err");
-}
-
-enum {
- Etype = 0x3<<12,
- Efamily = 0x7<<8,
- Emodel = 0xf<<4,
-
-};
-
-static char* type[] = {
- "primary", "overdrive", "secondary", "reserved"
-};
-
-
-static char *flags[] = {
- "fpu", "vme", "de", "pse", "tsc", "msr", "pae", "mce",
- "cx8", "apic", "10", "sysent", "mtrr", "pge", "mca", "cmov",
- "pat", "17", "18", "19", "20", "21", "22", "mmx",
- "fxsave", "25", "26", "27", "28", "29", "30", "31"
-};
-
-void main()
-{
- char buf[512];
- char *flds[32];
- int n, fd, cpu;
-
- if ((fd = open("/dev/cpuid", OREAD)) < 0)
- err("open");
- if ((n = read(fd, buf, sizeof(buf))) < 0)
- err("read");
- buf[n-1] = 0;
- close(fd);
-
- setfields("\n");
- n = getfields(buf, flds, sizeof(flds)/sizeof(flds[0]));
- for (cpu = 0; cpu < n; ++cpu) {
- char *p;
- unsigned long a = strtoul(flds[cpu], &p, 10);
- unsigned long d = strtoul(p, &p, 10);
- int i;
-
- print("cpu %d\n", cpu);
- print("vendor %s\n", p+1);
- print("type %ud\n", (a>>12) & 0x3);
- print("family %ud\n", (a>>8) & 0xf);
- print("model %ud\n", (a>>4) & 0xf);
- print("stepping %d\n", (a>>0) & 0xf);
- print("features ");
- for (i = 0; i < 32; ++i)
- if (d & (1<pmc.c <<'//GO.SYSIN DD pmc.c'
-#include 
-#include 
-#include "msr.h"
-
-void err(const char* msg)
-{
- perror(msg);
- exits("err");
-}
-
-void readat(int fd, int off, char* buf, int size)
-{
- if (seek(fd, off, 0) < 0)
- err("seek");
- if (read(fd, buf, size) != size)
- err("read");
-}
-
-int fd = -1;
-
-uvlong readmsr(int msr)
-{
- uvlong val;
- readat(fd, msr, (char*)&val, sizeof val);
- return val;
-}
-
-void main()
-{
- uvlong a, b;
-
- if ((fd = open("/dev/msr", ORDWR)) < 0)
- err("open");
-
- a = readmsr(0x10);
- if (print("tsc %ulld₁₀\n", a) < 0)
- err("print");
-
- a = readmsr(0x11);
- if (print("cesr %ullo₈\n", a) < 0)
- err("print");
-
- a = readmsr(0x12);
- b = readmsr(0x13);
- if (print("pmc %ulld₁₀ %ulld₁₀\n", a, b) < 0)
- err("print");
-
-#ifdef PPRO
- a = rdmsr(0x12);
- b = rdmsr(0x13);
- if (print("pmc %ulld₁₀ %ulld₁₀\n", a, b) < 0)
- err("print");
-#endif
-
- exits(0);
-}
//GO.SYSIN DD pmc.c
echo watch-pmc.c
sed 's/.//' >watch-pmc.c <<'//GO.SYSIN DD watch-pmc.c'
-#include 
-#include 
-
-void err(const char* msg)
-{
- perror(msg);
- exits("err");
-}
-
-int isnum(char c) {
- return '0' <= c && c <='9';
-}
-
-char *atoull(char *s, unsigned long long *n)
-{
- *n = 0;
- while (!isnum(*s)) ++s;
- while (isnum(*s)) *n = (*n)*10 + *s++ - '0';
- return s;
-}
-
-void main(int argc, char *argv[])
-{
- uvlong t, a, b;
- uvlong ot, oa, ob;
- int fd, delay;
- char buf[128];
-
- delay = (argc > 1) ? atol(argv[1])*1000 : 2000;
-
- if ((fd = open("/dev/pmc", OREAD)) < 0)
- err("open");
-
- t = a = b = ot = oa = ob = 0;
- while ((seek(fd, 0, 0) != -1) && (read(fd, buf, sizeof buf) > 0)) {
- char *p = buf;
- ot = t;
- oa = a;
- ob = b;
- p = atoull(p, &t);
- p = atoull(p, &a);
- p = atoull(p, &b);
- if (print("%ulld(%ulld) %ulld(%ulld) %ulld(%ulld)\n", t, t-ot, a, a-oa, b, b-ob) < 0)
- err("print");
- sleep(delay);
- }
- exits(0);
-}
//GO.SYSIN DD watch-pmc.c
echo msr.s
sed 's/.//' >msr.s <<'//GO.SYSIN DD msr.s'
-/* uvlong rdtsc(void); */
-TEXT rdtsc(SB),$0
- MOVL .ret+0(FP),CX
- BYTE $0x0f
- BYTE $0x31
- MOVL AX,0(CX)
- MOVL DX,4(CX)
- RET ,
- END ,
-
-/* uvlong rdmsr(uint msr); */
-TEXT rdmsr(SB),$0
- MOVL .msr+4(FP),CX
- BYTE $0x0f
- BYTE $0x32
- MOVL .ret+0(FP),CX
- MOVL AX,0(CX)
- MOVL DX,4(CX)
- RET ,
- END ,
-
-/* void wrmsr(uint msr, uvlong val); */
-TEXT wrmsr(SB),$0
- MOVL .msr+0(FP), CX
- MOVL .val0+4(FP), AX
- MOVL .val1+8(FP), DX
- BYTE $0x0f
- BYTE $0x30
- RET ,
- END ,
-
-/* void x86_cpuid(int n, ulong *a, ulong *b, ulong *c, ulong *d); */
-TEXT x86_cpuid(SB),$0
- MOVL n+0(FP),AX
- /* CPUID */
- BYTE $0x0F
- BYTE $0xA2
- MOVL AX,SI
- MOVL a+4(FP),AX
- MOVL SI,(AX)
- MOVL b+8(FP),AX
- MOVL BX,(AX)
- MOVL c+12(FP),AX
- MOVL CX,(AX)
- MOVL d+16(FP),AX
- MOVL DX,(AX)
- RET
- END
//GO.SYSIN DD msr.s
echo msr.h
sed 's/.//' >msr.h <<'//GO.SYSIN DD msr.h'
-#ifndef MSR_H
-#define MSR_H
-typedef unsigned long long msr_t; /* 64 bits */
-msr_t rdtsc(void);
-msr_t rdmsr(unsigned int msr);
-void wrmsr(unsigned int msr, msr_t val);
-extern x86_cpuid(int n, unsigned long *a, unsigned long *b, unsigned long *c, unsigned long *d);
-#endif
//GO.SYSIN DD msr.h
echo devmsr.c
sed 's/.//' >devmsr.c <<'//GO.SYSIN DD devmsr.c'
-#include "u.h"
-#include "../port/lib.h"
-#include "mem.h"
-#include "dat.h"
-#include "fns.h"
-#include "../port/error.h"
-#include "devtab.h"
-#include "msr.h"
-
-char Enfields[] = "wrong number of fields";
-
-static void pmcctl_write(char *);
-static void check_msr(int);
-static char* fmt_pmcctl(char *, int);
-
-static int valid_msr_0(int);
-static msr_t rdmsr_ctr_0(int);
-static msr_t rdmsr_tsc_0(void);
-static void wrmsr_ctr_0(int, msr_t);
-static void wrmsr_cesr_0(int);
-static int valid_msr_5(int);
-static msr_t rdmsr_ctr_5(int);
-static void wrmsr_ctr_5(int, msr_t);
-static void wrmsr_cesr_5(int);
-static int valid_msr_6(int);
-static msr_t rdmsr_ctr_6(int);
-static void wrmsr_ctr_6(int, msr_t);
-static void wrmsr_cesr_6(int);
-
-enum {
- Qdir = 0,
- Qmsr,
- Qpmc,
- Qpmcctl,
- Qcpuid,
- Nmsrdir = Qcpuid,
-
- Nfield = 10,
- Ncntr = 2
-};
-
-Dirtab const msrdir[] = {
- "msr", {Qmsr}, 0, 0664,
- "pmc", {Qpmc}, 0, 0664,
- "pmcctl", {Qpmcctl}, 0, 0664,
- "cpuid", {Qcpuid}, 0, 0444,
-};
-
-typedef struct
-{
- unsigned int processor, features;
- char vendor[12+1];
-} cpuid_t;
-
-typedef struct
-{
- unsigned short msr;
- unsigned char event;
- unsigned char user, sys, edge; /* “I'd use plan 9 before i'd use bitfields -- pjw” */
-} pmcctl_t;
-
-static cpuid_t cpuid[MAXMACH];
-static pmcctl_t pmcctl[MAXMACH][Ncntr];
-
-static int (*valid_msr)(int);
-static void (*wrmsr_cesr)(int);
-static msr_t (*rdmsr_ctr)(int);
-static void (*wrmsr_ctr)(int, msr_t);
-static msr_t (*rdmsr_tsc)(void);
-
-QLock msrlock;
-
-/* ----- */
-
-void msrreset(void)
-{
-}
-
-void msrinit(void)
-{
- ulong a, b, c, d;
- int x = x86();
-
- valid_msr = valid_msr_0;
- wrmsr_cesr = wrmsr_cesr_0;
- wrmsr_ctr = wrmsr_ctr_0;
- rdmsr_ctr = rdmsr_ctr_0;
- rdmsr_tsc = rdmsr_tsc_0;
-
- switch (x) {
- case 3:
- case 4:
- strcpy(cpuid[0].vendor, "unknown x86");
- cpuid[0].processor = 0;
- cpuid[0].features = 0;
- return;
- case 5:
- valid_msr = valid_msr_5;
- wrmsr_cesr = wrmsr_cesr_5;
- wrmsr_ctr = wrmsr_ctr_5;
- rdmsr_ctr = rdmsr_ctr_5;
- break;
- case 6:
- valid_msr = valid_msr_6;
- wrmsr_cesr = wrmsr_cesr_6;
- wrmsr_ctr = wrmsr_ctr_6;
- rdmsr_ctr = rdmsr_ctr_6;
- break;
- }
- rdmsr_tsc = rdtsc;
-
- x86_cpuid(0, &a, &b, &c, &d);
- memmove(cpuid[0].vendor+0, (char*)&b, 4);
- memmove(cpuid[0].vendor+4, (char*)&d, 4);
- memmove(cpuid[0].vendor+8, (char*)&c, 4);
- cpuid[0].vendor[sizeof(cpuid[0].vendor)-1] = 0;
-
- x86_cpuid(1, &a, &b, &c, &d);
- cpuid[0].processor = a;
- cpuid[0].features = d;
-}
-
-Chan* msrattach(char *spec)
-{
- return devattach(L'Ψ', spec);
-}
-
-Chan* msrclone(Chan *c, Chan *nc)
-{
- return devclone(c, nc);
-}
-
-int msrwalk(Chan *c, char *name)
-{
- return devwalk(c, name, msrdir, Nmsrdir, devgen);
-}
-
-void msrstat(Chan *c, char *dp)
-{
- devstat(c, dp, msrdir, Nmsrdir, devgen);
-}
-
-Chan* msropen(Chan *c, int omode)
-{
- omode = openmode(omode);
- switch (c->qid.path) {
- case Qmsr:
- /* sensitive */
- if (strcmp(u->p->user, eve) != 0)
- error(Eperm);
- break;
- }
- return devopen(c, omode, msrdir, Nmsrdir, devgen);
-}
-
-void msrcreate(Chan *c, char *name, int omode, ulong perm)
-{
- USED(c, name, omode, perm);
- error(Eperm);
-}
-
-void msrclose(Chan *c)
-{
- USED(c);
-}
-
-long msrread(Chan *c, void *buf, long n, ulong offset)
-{
- msr_t t, a, b;
- char tmp[255];
-
- switch (c->qid.path &~ CHDIR) {
- case Qdir:
- return devdirread(c, buf, n, msrdir, Nmsrdir, devgen);
- case Qmsr:
- check_msr(offset);
- if (n > sizeof(a))
- n = sizeof(a);
- qlock(&msrlock);
- a = rdmsr(offset);
- qunlock(&msrlock);
- memmove(buf, (char*)&a, n);
- return n;
- case Qpmc:
- qlock(&msrlock);
- t = rdmsr_tsc();
- a = rdmsr_ctr(0);
- b = rdmsr_ctr(1);
- qunlock(&msrlock);
- snprint(tmp, sizeof tmp, "%ulld %ulld %ulld\n", t, a, b);
- /* XXX - %ulld requires fix to kernel doprint */
- return readstr(offset, buf, n, tmp);
- case Qpmcctl:
- return readstr(offset, buf, n, fmt_pmcctl(tmp, sizeof tmp));
- case Qcpuid:
- snprint(tmp, sizeof tmp, "%ud %ud %s\n",
- cpuid[0].processor, cpuid[0].features, cpuid[0].vendor);
- return readstr(offset, buf, n, tmp);
- }
- error(Ebadarg);
- return 0;
-}
-
-long msrwrite(Chan *c, void *buf, long n, ulong offset)
-{
- msr_t val;
- char cbuf[64];
-
- switch (c->qid.path &~ CHDIR) {
- case Qdir:
- error(Eperm);
- case Qmsr:
- check_msr(offset);
- if (0 > n || n > sizeof(val))
- error(Ebadarg);
- memmove((char*)&val, buf, n);
- qlock(&msrlock);
- wrmsr(offset, val);
- qunlock(&msrlock);
- return n;
- case Qpmc:
- qlock(&msrlock);
- wrmsr_ctr(0, 0LL);
- wrmsr_ctr(1, 0LL);
- qunlock(&msrlock);
- return n;
- case Qpmcctl:
- if(offset != 0 || n >= sizeof(cbuf))
- error(Ebadarg);
- memmove(cbuf, buf, n);
- cbuf[n] = 0;
- pmcctl_write(cbuf);
- return n;
- }
- error(Ebadarg);
- return 0;
-}
-
-void msrremove(Chan *c)
-{
- USED(c);
- error(Eperm);
-}
-
-void msrwstat(Chan *c, char *dp)
-{
- USED(c, dp);
- error(Eperm);
-}
-
-/* ----- */
-
-static unsigned long get_ulong(char *buf, unsigned int lo, unsigned int hi, char const *err)
-{
- char *p = 0;
- unsigned long i = strtoul(buf, &p, 0);
- if (p == buf) error(Ebadarg);
- if (!(lo <= i && i <= hi))
- error(err);
- return i;
-}
-
-static char* fmt_pmcctl(char *buf, int size)
-{
- int i, n;
- char *bp = buf;
-
- qlock(&msrlock);
- for (i = 0; i < Ncntr; ++i) {
- n = snprint(bp, size, "c%ud r%s%s n%c e%ud\n",
- i,
- pmcctl[0][i].user?"u":"",
- pmcctl[0][i].sys?"s":"",
- pmcctl[0][i].edge?'c':'e',
- pmcctl[0][i].event);
- bp += n;
- size -= n;
- }
- qunlock(&msrlock);
- return buf;
-}
-
-static void pmcctl_write(char *arg)
-{
- int i, n, nf;
- pmcctl_t *pp;
- char *f[16];
- int z[Ncntr];
- int c[Ncntr];
-
- /* counter ring number event zero */
- /* c{0,1} r[u][s] n{e,c} e0x22 z */
-
- nf = getfields(arg, f, sizeof(f)/sizeof(f[0]), " \t\n");
- pp = pmcctl[0];
- c[0] = c[1] = z[0] = z[1] = n = 0;
- qlock(&msrlock);
- for (i = 0; i < nf; ++i) {
- switch (*f[i]) {
- case 'c':
- n = get_ulong(f[i]+1, 0, 1, "bad counter");
- c[n] = 1;
- break;
- case 'r':
- pp[n].user = !!strchr(f[i]+1, 'u');
- pp[n].sys = !!strchr(f[i]+1, 's');
- break;
- case 'n':
- pp[n].edge = !!strchr(f[i]+1, 'c');
- break;
- case 'e':
- pp[n].event = get_ulong(f[i]+1, 0, 0xff, "bad event");
- break;
- case 'z':
- z[n] = 1;
- break;
- }
- }
- for (i = 0; i < Ncntr; ++i)
- if (c[i]) wrmsr_cesr(i);
- for (i = 0; i < Ncntr; ++i)
- if (z[i]) wrmsr_ctr(i, 0LL);
- qunlock(&msrlock);
-}
-
-static void check_msr(int msr)
-{
- if (!valid_msr(msr)) {
- char tmp[64];
- snprint(tmp, sizeof(tmp), "bad msr #%ud", msr);
- error(tmp);
- }
-}
-
-/* ----- */
-
-static int valid_msr_0(int msr) { USED(msr); error(Ebadctl); return 0;}
-static msr_t rdmsr_ctr_0(int n) { USED(n); return 0; }
-static msr_t rdmsr_tsc_0(void) { return 0; }
-static void wrmsr_ctr_0(int n, msr_t v) { USED(n, v); return; }
-static void wrmsr_cesr_0(int n) { USED(n); return; }
-
-static int valid_msr_5(int msr) { return (0 <= msr && msr <= 0x13); }
-static msr_t rdmsr_ctr_5(int n) { return rdmsr(0x12+n); }
-static void wrmsr_ctr_5(int n, msr_t val) { wrmsr(0x12+n, val); }
-static void wrmsr_cesr_5(int n)
-{
- pmcctl_t *pp = pmcctl[0];
- wrmsr(0x11,
- (pp[1].edge<<24)|(pp[1].user<<23)|(pp[1].sys<<22)|(pp[1].event<<16)|
- (pp[0].edge<<8)|(pp[0].user<<7)|(pp[0].sys<<6)|(pp[0].event));
- USED(n);
-}
-
-static int valid_msr_6(int msr) { return (0 <= msr && msr <= 0x406); /* ?? */ }
-static msr_t rdmsr_ctr_6(int n) { return rdmsr(0xC1+n); }
-static void wrmsr_ctr_6(int n, msr_t val) { wrmsr(0xC1+n, val); }
-static void wrmsr_cesr_6(int n)
-{
- pmcctl_t *pp = pmcctl[0];
- wrmsr(0x186+n, (1UL<<22)|(pp[n].edge<<18)|(pp[n].sys<<17)|(pp[n].user<<16)|(pp[n].event));
-}
-
//GO.SYSIN DD devmsr.c
echo print.c-diff
sed 's/.//' >print.c-diff <<'//GO.SYSIN DD print.c-diff'
-term% diff /n/cd/sys/src/9/port/print.c print.c
-230c230
-< vlong vl;
----
-> long long vl;
-258c258
-< vl = *(vlong*)o;
----
-> vl = *(long long*)o;
-261a262,266
-> case FUNSIGN|FVLONG|FLONG:
-> vl = *(unsigned long long*)o;
-> r = VLONG;
-> break;
->
-301c306
-< n = vl % b;
----
-> n = (unsigned long long)vl % b;
-303c308
-< n = (ulong)v % b;
----
-> n = (unsigned long)v % b;
-314c319
-< vl = vl / b;
----
-> vl = (unsigned long long)vl / b;
-319c324
-< if(fp->f3 & FVLONG)
----
-> if(fp->f3 & FVLONG) {
-321a327,328
-> continue;
-> }
//GO.SYSIN DD print.c-diff