[BACK]Return to pctr.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / pctr

Annotation of src/usr.bin/pctr/pctr.c, Revision 1.21

1.21    ! deraadt     1: /*     $OpenBSD: pctr.c,v 1.20 2008/07/08 21:39:52 sobrado Exp $       */
1.13      deraadt     2:
                      3: /*
                      4:  * Copyright (c) 2007 Mike Belopuhov, Aleksey Lomovtsev
                      5:  *
                      6:  * Permission to use, copy, modify, and distribute this software for any
                      7:  * purpose with or without fee is hereby granted, provided that the above
                      8:  * copyright notice and this permission notice appear in all copies.
                      9:  *
                     10:  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
                     11:  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
                     12:  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
                     13:  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
                     14:  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
                     15:  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
                     16:  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
                     17:  */
1.1       dm         18:
                     19: /*
                     20:  * Pentium performance counter control program for OpenBSD.
                     21:  * Copyright 1996 David Mazieres <dm@lcs.mit.edu>.
                     22:  *
                     23:  * Modification and redistribution in source and binary forms is
                     24:  * permitted provided that due credit is given to the author and the
1.5       pvalchev   25:  * OpenBSD project by leaving this copyright notice intact.
1.1       dm         26:  */
                     27:
                     28: #include <sys/types.h>
                     29: #include <sys/stat.h>
1.4       downsj     30: #include <sys/sysctl.h>
1.1       dm         31: #include <sys/ioctl.h>
1.13      deraadt    32:
1.1       dm         33: #include <machine/cpu.h>
                     34: #include <machine/pctr.h>
1.4       downsj     35: #include <machine/specialreg.h>
1.1       dm         36:
1.13      deraadt    37: #include <errno.h>
                     38: #include <err.h>
                     39: #include <fcntl.h>
                     40: #include <stdio.h>
                     41: #include <stdlib.h>
                     42: #include <string.h>
                     43: #include <unistd.h>
                     44:
                     45: #include "pctrvar.h"
                     46:
                     47: static int      cpu_type;
                     48: static int      tsc_avail;
                     49:
                     50: static int      ctr, func, masku, thold;
                     51: static int      cflag, eflag, iflag, kflag, uflag;
                     52: static int      Mflag, Eflag, Sflag, Iflag, Aflag;
                     53:
1.18      mikeb      54: static void     pctr_cpu_creds(void);
1.13      deraadt    55: static char    *pctr_fn2str(u_int32_t);
                     56: static void     pctr_printvals(struct pctrst *);
1.19      deraadt    57: static int      pctr_read(struct pctrst *);
                     58: static int      pctr_write(int, u_int32_t);
1.13      deraadt    59: static void     pctr_list_fnct(void);
                     60: static int      pctr_set_cntr(void);
                     61: static void     usage(void);
                     62:
                     63: int
                     64: main(int argc, char **argv)
                     65: {
                     66:        const char *errstr;
                     67:        struct pctrst st;
                     68:        int ch = -1;
                     69:        int list_mode = 0, set_mode = 0;
                     70:
1.18      mikeb      71:        pctr_cpu_creds();
1.13      deraadt    72:
1.18      mikeb      73:        while ((ch = getopt(argc, argv, "AcEef:IiklMm:Ss:t:u")) != -1)
1.13      deraadt    74:                switch (ch) {
1.17      mikeb      75:                case 'A':
                     76:                        Aflag++;
                     77:                        break;
                     78:                case 'c':
                     79:                        cflag++;
1.13      deraadt    80:                        break;
1.17      mikeb      81:                case 'E':
1.18      mikeb      82:                        Eflag++;
                     83:                        break;
1.17      mikeb      84:                case 'e':
                     85:                        eflag++;
1.13      deraadt    86:                        break;
                     87:                case 'f':
                     88:                        if (sscanf(optarg, "%x", &func) <= 0 || func < 0 ||
                     89:                            func > PCTR_MAX_FUNCT)
                     90:                                errx(1, "invalid function number");
                     91:                        break;
1.18      mikeb      92:                case 'I':
                     93:                        Iflag++;
                     94:                        break;
1.17      mikeb      95:                case 'i':
                     96:                        iflag++;
                     97:                        break;
                     98:                case 'k':
                     99:                        kflag++;
                    100:                        break;
                    101:                case 'l':
                    102:                        list_mode++;
                    103:                        break;
1.18      mikeb     104:                case 'M':
                    105:                        Mflag++;
                    106:                        break;
1.13      deraadt   107:                case 'm':
                    108:                        if (sscanf(optarg, "%x", &masku) <= 0 || masku < 0 ||
                    109:                            masku > PCTR_MAX_UMASK)
                    110:                                errx(1, "invalid unit mask number");
                    111:                        break;
1.18      mikeb     112:                case 'S':
                    113:                        Sflag++;
                    114:                        break;
1.17      mikeb     115:                case 's':
                    116:                        set_mode++;
                    117:                        ctr = strtonum(optarg, 0, PCTR_NUM-1, &errstr);
                    118:                        if (errstr)
                    119:                                errx(1, "counter number is %s: %s", errstr,
                    120:                                    optarg);
                    121:                        break;
1.13      deraadt   122:                case 't':
                    123:                        thold = strtonum(optarg, 0, 0xff, &errstr);
                    124:                        if (errstr)
                    125:                                errx(1, "threshold is %s: %s", errstr, optarg);
                    126:                        break;
                    127:                case 'u':
                    128:                        uflag++;
                    129:                        break;
                    130:                default:
                    131:                        usage();
                    132:                        /* NOTREACHED */
                    133:                }
                    134:        argc -= optind;
                    135:        argv += optind;
                    136:
1.18      mikeb     137:        if (argc)
                    138:                usage();
                    139:
                    140:        if (Aflag && (Mflag || Eflag || Sflag || Iflag))
                    141:                usage();
                    142:
1.13      deraadt   143:        if (list_mode)
                    144:                pctr_list_fnct();
                    145:        else if (set_mode) {
                    146:                if (pctr_set_cntr() < 0)
                    147:                        err(1, "pctr_set_cntr");
                    148:        } else {
                    149:                bzero(&st, sizeof(st));
                    150:                if (pctr_read(&st) < 0)
                    151:                        err(1, "pctr_read");
                    152:                pctr_printvals(&st);
                    153:        }
                    154:        return (0);
                    155: }
                    156:
1.18      mikeb     157: static void
1.13      deraadt   158: pctr_cpu_creds(void)
                    159: {
                    160:        int atype;
                    161:        char arch[16], vendor[64];
                    162:        int mib[2], cpu_id, cpu_feature;
                    163:        size_t len;
                    164:
                    165:        /* Get the architecture */
                    166:        mib[0] = CTL_HW;
                    167:        mib[1] = HW_MACHINE;
                    168:        len = sizeof(arch) - 1;
                    169:        bzero(arch, sizeof(arch));
                    170:        if (sysctl(mib, 2, arch, &len, NULL, 0) == -1)
                    171:                err(1, "HW_MACHINE");
                    172:        arch[len] = '\0';
                    173:
                    174:        if (strcmp(arch, "i386") == 0)
                    175:                atype = ARCH_I386;
                    176:        else if (strcmp(arch, "amd64") == 0)
                    177:                atype = ARCH_AMD64;
                    178:        else
1.18      mikeb     179:                errx(1, "architecture %s is not supported", arch);
1.13      deraadt   180:
                    181:        /* Get the CPU id */
                    182:        mib[0] = CTL_MACHDEP;
                    183:        mib[1] = CPU_CPUID;
                    184:        len = sizeof(cpu_id);
                    185:        if (sysctl(mib, 2, &cpu_id, &len, NULL, 0) == -1)
                    186:                err(1, "CPU_CPUID");
                    187:
                    188:        /* Get the CPU features */
                    189:        mib[1] = CPU_CPUFEATURE;
                    190:        len = sizeof(cpu_feature);
                    191:        if (sysctl(mib, 2, &cpu_feature, &len, NULL, 0) == -1)
                    192:                err(1, "CPU_CPUFEATURE");
                    193:
                    194:        /* Get the processor vendor */
                    195:        mib[0] = CTL_MACHDEP;
                    196:        mib[1] = CPU_CPUVENDOR;
                    197:        len = sizeof(vendor) - 1;
                    198:        bzero(vendor, sizeof(vendor));
                    199:        if (sysctl(mib, 2, vendor, &len, NULL, 0) == -1)
                    200:                err(1, "CPU_CPUVENDOR");
                    201:        vendor[len] = '\0';
                    202:
                    203:        switch (atype) {
                    204:        case ARCH_I386:
                    205:                if (strcmp(vendor, "AuthenticAMD") == 0) {
                    206:                        if (((cpu_id >> 8) & 15) >= 6)
                    207:                                cpu_type = CPU_AMD;
                    208:                        else
                    209:                                cpu_type = CPU_UNDEF;   /* old AMD cpu */
                    210:
                    211:                } else if (strcmp(vendor, "GenuineIntel") == 0) {
                    212:                        if (((cpu_id >> 8) & 15) == 6 &&
                    213:                            ((cpu_id >> 4) & 15) > 14)
                    214:                                cpu_type = CPU_CORE;
                    215:                        else if (((cpu_id >> 8) & 15) >= 6)
                    216:                                cpu_type = CPU_P6;
                    217:                        else if (((cpu_id >> 4) & 15) > 0)
                    218:                                cpu_type = CPU_P5;
                    219:                        else
                    220:                                cpu_type = CPU_UNDEF;   /* old Intel cpu */
                    221:                }
                    222:                if (cpu_feature & CPUID_TSC)
                    223:                        tsc_avail = 1;
                    224:                break;
                    225:        case ARCH_AMD64:
                    226:                if (strcmp(vendor, "AuthenticAMD") == 0)
                    227:                        cpu_type = CPU_AMD;
                    228:                else if (strcmp(vendor, "GenuineIntel") == 0)
                    229:                        cpu_type = CPU_CORE;
                    230:                if (cpu_feature & CPUID_TSC)
                    231:                        tsc_avail = 1;
                    232:                break;
                    233:        }
                    234: }
                    235:
                    236: static __inline int
                    237: pctr_ctrfn_index(struct ctrfn *cfnp, u_int32_t func)
                    238: {
                    239:        int i;
                    240:
                    241:        for (i = 0; cfnp[i].name != NULL; i++)
                    242:                if (cfnp[i].fn == func)
                    243:                        return (i);
                    244:        return (-1);
                    245: }
                    246:
                    247: static char *
                    248: pctr_fn2str(u_int32_t sel)
                    249: {
                    250:        static char buf[128];
                    251:        struct ctrfn *cfnp = NULL;
                    252:        char th[6], um[5], *msg;
                    253:        u_int32_t fn;
                    254:        int ind;
                    255:
                    256:        bzero(buf, sizeof(buf));
                    257:        bzero(th, sizeof(th));
                    258:        bzero(um, sizeof(um));
                    259:        switch (cpu_type) {
                    260:        case CPU_P5:
                    261:                fn = sel & 0x3f;
                    262:                if ((ind = pctr_ctrfn_index(p5fn, fn)) < 0)
                    263:                        msg = "unknown function";
                    264:                else
                    265:                        msg = p5fn[ind].name;
                    266:                snprintf(buf, sizeof(buf), "%c%c%c %02x %s",
1.15      deraadt   267:                    sel & P5CTR_C ? 'c' : '-',
                    268:                    sel & P5CTR_U ? 'u' : '-',
                    269:                    sel & P5CTR_K ? 'k' : '-',
1.13      deraadt   270:                    fn, msg);
                    271:                break;
                    272:        case CPU_P6:
                    273:                cfnp = p6fn;
                    274:        case CPU_CORE:
1.14      deraadt   275:                if (cpu_type == CPU_CORE)
                    276:                        cfnp = corefn;
1.13      deraadt   277:                fn = sel & 0xff;
                    278:                if ((ind = pctr_ctrfn_index(cfnp, fn)) < 0)
                    279:                        msg = "unknown function";
                    280:                else
                    281:                        msg = cfnp[ind].name;
                    282:                if (cfnp[ind].name && cfnp[ind].flags & CFL_MESI)
                    283:                        snprintf(um, sizeof (um), "%c%c%c%c",
1.15      deraadt   284:                            sel & PCTR_UM_M ? 'M' : '-',
                    285:                            sel & PCTR_UM_E ? 'E' : '-',
                    286:                            sel & PCTR_UM_S ? 'S' : '-',
                    287:                            sel & PCTR_UM_I ? 'I' : '-');
1.13      deraadt   288:                else if (cfnp[ind].name && cfnp[ind].flags & CFL_SA)
                    289:                        snprintf(um, sizeof(um), "%c",
1.15      deraadt   290:                            sel & PCTR_UM_A ? 'A' : '-');
                    291:                if (sel >> PCTR_CM_SHIFT)
1.13      deraadt   292:                        snprintf(th, sizeof(th), "+%d",
1.15      deraadt   293:                            sel >> PCTR_CM_SHIFT);
1.13      deraadt   294:                snprintf(buf, sizeof(buf), "%c%c%c%c %02x %02x %s %s %s",
1.15      deraadt   295:                    sel & PCTR_I ? 'i' : '-',
                    296:                    sel & PCTR_E ? 'e' : '-',
                    297:                    sel & PCTR_K ? 'k' : '-',
                    298:                    sel & PCTR_U ? 'u' : '-',
                    299:                    fn, (sel >> PCTR_UM_SHIFT) & 0xff, th, um, msg);
1.13      deraadt   300:                break;
                    301:        case CPU_AMD:
                    302:                fn = sel & 0xff;
1.15      deraadt   303:                if (sel >> PCTR_CM_SHIFT)
1.13      deraadt   304:                        snprintf(th, sizeof(th), "+%d",
1.15      deraadt   305:                            sel >> PCTR_CM_SHIFT);
1.13      deraadt   306:                snprintf(buf, sizeof(buf), "%c%c%c%c %02x %02x %s",
1.15      deraadt   307:                    sel & PCTR_I ? 'i' : '-',
                    308:                    sel & PCTR_E ? 'e' : '-',
                    309:                    sel & PCTR_K ? 'k' : '-',
                    310:                    sel & PCTR_U ? 'u' : '-',
                    311:                    fn, (sel >> PCTR_UM_SHIFT) & 0xff, th);
1.13      deraadt   312:                break;
                    313:        }
                    314:        return (buf);
                    315: }
1.3       downsj    316:
1.1       dm        317: static void
1.13      deraadt   318: pctr_printvals(struct pctrst *st)
                    319: {
                    320:        int i, n;
                    321:
                    322:        switch (cpu_type) {
                    323:        case CPU_P5:
                    324:        case CPU_P6:
                    325:        case CPU_CORE:
                    326:                n = PCTR_INTEL_NUM;
                    327:        case CPU_AMD:
                    328:                if (cpu_type == CPU_AMD)
                    329:                        n = PCTR_AMD_NUM;
                    330:                for (i = 0; i < n; i++)
                    331:                        printf(" ctr%d = %16llu  [%s]\n", i, st->pctr_hwc[i],
                    332:                            pctr_fn2str(st->pctr_fn[i]));
                    333:                if (tsc_avail)
                    334:                        printf("  tsc = %16llu\n", st->pctr_tsc);
                    335:                break;
                    336:        }
                    337: }
                    338:
                    339: static int
                    340: pctr_read(struct pctrst *st)
                    341: {
                    342:        int fd, se;
                    343:
                    344:        fd = open(_PATH_PCTR, O_RDONLY);
                    345:        if (fd < 0)
                    346:                return (-1);
                    347:        if (ioctl(fd, PCIOCRD, st) < 0) {
                    348:                se = errno;
                    349:                close(fd);
                    350:                errno = se;
                    351:                return (-1);
                    352:        }
                    353:        return (close(fd));
                    354: }
                    355:
                    356: static int
                    357: pctr_write(int ctr, u_int32_t val)
                    358: {
                    359:        int fd, se;
                    360:
                    361:        fd = open(_PATH_PCTR, O_WRONLY);
                    362:        if (fd < 0)
                    363:                return (-1);
                    364:        if (ioctl(fd, PCIOCS0 + ctr, &val) < 0) {
                    365:                se = errno;
                    366:                close(fd);
                    367:                errno = se;
                    368:                return (-1);
                    369:        }
                    370:        return (close(fd));
                    371: }
                    372:
                    373: static __inline void
                    374: pctr_printdesc(char *desc)
1.1       dm        375: {
1.7       mickey    376:        char *p;
1.1       dm        377:
1.7       mickey    378:        for (;;) {
                    379:                while (*desc == ' ')
                    380:                        desc++;
                    381:                if (strlen(desc) < 70) {
                    382:                        if (*desc)
                    383:                                printf("      %s\n", desc);
                    384:                        return;
                    385:                }
                    386:                p = desc + 72;
                    387:                while (*--p != ' ')
                    388:                        ;
                    389:                while (*--p == ' ')
                    390:                        ;
                    391:                p++;
1.13      deraadt   392:                printf("      %.*s\n", (int)(p-desc), desc);
1.7       mickey    393:                desc = p;
                    394:        }
1.1       dm        395: }
                    396:
                    397: static void
1.13      deraadt   398: pctr_list_fnct(void)
1.1       dm        399: {
1.13      deraadt   400:        struct ctrfn *cfnp = NULL;
1.1       dm        401:
1.13      deraadt   402:        if (cpu_type == CPU_P5)
1.7       mickey    403:                cfnp = p5fn;
1.13      deraadt   404:        else if (cpu_type == CPU_P6)
1.7       mickey    405:                cfnp = p6fn;
1.13      deraadt   406:        else if (cpu_type == CPU_CORE)
                    407:                cfnp = corefn;
                    408:        else if (cpu_type == CPU_AMD)
                    409:                cfnp = amdfn;
                    410:        else
                    411:                return;
                    412:
1.7       mickey    413:        for (; cfnp->name; cfnp++) {
                    414:                printf("%02x  %s", cfnp->fn, cfnp->name);
                    415:                if (cfnp->flags & CFL_MESI)
1.13      deraadt   416:                        printf("  (MESI)");
1.7       mickey    417:                else if (cfnp->flags & CFL_SA)
1.13      deraadt   418:                        printf("  (A)");
1.7       mickey    419:                if (cfnp->flags & CFL_C0)
                    420:                        printf("  (ctr0 only)");
1.13      deraadt   421:                else if (cfnp->flags & CFL_C1)
1.7       mickey    422:                        printf("  (ctr1 only)");
1.18      mikeb     423:                if (cfnp->flags & CFL_UM)
                    424:                        printf("  (needs unit mask)");
1.7       mickey    425:                printf("\n");
                    426:                if (cfnp->desc)
1.13      deraadt   427:                        pctr_printdesc(cfnp->desc);
1.7       mickey    428:        }
1.1       dm        429: }
                    430:
1.13      deraadt   431: static int
                    432: pctr_set_cntr(void)
1.1       dm        433: {
1.13      deraadt   434:        struct ctrfn *cfnp = NULL;
                    435:        u_int32_t val = func;
                    436:        int ind = 0;
                    437:
                    438:        switch (cpu_type) {
                    439:        case CPU_P5:
                    440:                if (ctr >= PCTR_INTEL_NUM)
1.18      mikeb     441:                        errx(1, "only %d counters are supported",
                    442:                            PCTR_INTEL_NUM);
1.13      deraadt   443:                if (cflag)
1.15      deraadt   444:                        val |= P5CTR_C;
1.13      deraadt   445:                if (kflag)
1.15      deraadt   446:                        val |= P5CTR_K;
1.13      deraadt   447:                if (uflag)
1.15      deraadt   448:                        val |= P5CTR_U;
1.13      deraadt   449:                if (func && (!kflag && !uflag))
1.15      deraadt   450:                        val |= P5CTR_K | P5CTR_U;
1.13      deraadt   451:                break;
                    452:        case CPU_P6:
1.7       mickey    453:                cfnp = p6fn;
1.13      deraadt   454:        case CPU_CORE:
1.14      deraadt   455:                if (cpu_type == CPU_CORE)
                    456:                        cfnp = corefn;
1.13      deraadt   457:                if (ctr >= PCTR_INTEL_NUM)
1.18      mikeb     458:                        errx(1, "only %d counters are supported",
                    459:                            PCTR_INTEL_NUM);
1.13      deraadt   460:                if (func && (ind = pctr_ctrfn_index(cfnp, func)) < 0)
1.18      mikeb     461:                        errx(1, "function %02x is not supported", func);
                    462:                if (func && (cfnp[ind].flags & CFL_SA))
1.15      deraadt   463:                        val |= PCTR_UM_A;
1.18      mikeb     464:                if (func && (cfnp[ind].flags & CFL_MESI)) {
                    465:                        if (Mflag)
                    466:                                val |= PCTR_UM_M;
                    467:                        if (Eflag)
                    468:                                val |= PCTR_UM_E;
                    469:                        if (Sflag)
                    470:                                val |= PCTR_UM_S;
                    471:                        if (Iflag)
                    472:                                val |= PCTR_UM_I;
                    473:                        if (!Mflag || !Eflag || !Sflag || !Iflag)
                    474:                                val |= PCTR_UM_MESI;
                    475:                }
1.13      deraadt   476:                if (func && (cfnp[ind].flags & CFL_ED))
1.15      deraadt   477:                        val |= PCTR_E;
1.18      mikeb     478:                if (func && (cfnp[ind].flags & CFL_UM) && !masku)
                    479:                        errx(1, "function %02x needs unit mask specification",
                    480:                            func);
1.13      deraadt   481:        case CPU_AMD:
                    482:                if (cpu_type == CPU_AMD && func &&
                    483:                    ((ind = pctr_ctrfn_index(amdfn, func)) < 0))
1.18      mikeb     484:                        errx(1, "function %02x is not supported", func);
1.13      deraadt   485:                if (ctr >= PCTR_AMD_NUM)
1.18      mikeb     486:                        errx(1, "only %d counters are supported",
                    487:                            PCTR_AMD_NUM);
1.13      deraadt   488:                if (eflag)
1.15      deraadt   489:                        val |= PCTR_E;
1.13      deraadt   490:                if (iflag)
1.15      deraadt   491:                        val |= PCTR_I;
1.13      deraadt   492:                if (kflag)
1.15      deraadt   493:                        val |= PCTR_K;
1.13      deraadt   494:                if (uflag)
1.15      deraadt   495:                        val |= PCTR_U;
1.13      deraadt   496:                if (func && (!kflag && !uflag))
1.15      deraadt   497:                        val |= PCTR_K | PCTR_U;
                    498:                val |= masku << PCTR_UM_SHIFT;
                    499:                val |= thold << PCTR_CM_SHIFT;
1.13      deraadt   500:                if (func)
1.15      deraadt   501:                        val |= PCTR_EN;
1.13      deraadt   502:                break;
1.7       mickey    503:        }
                    504:
1.13      deraadt   505:        return (pctr_write(ctr, val));
1.1       dm        506: }
                    507:
                    508: static void
1.13      deraadt   509: usage(void)
1.1       dm        510: {
1.13      deraadt   511:        extern char *__progname;
                    512:        char *usg = NULL;
1.1       dm        513:
1.13      deraadt   514:        switch (cpu_type) {
                    515:        case CPU_P5:
1.17      mikeb     516:                usg = "[-cklu] [-f funct] [-s ctr]";
1.13      deraadt   517:                break;
                    518:        case CPU_P6:
                    519:        case CPU_CORE:
1.17      mikeb     520:                usg = "[-AEeIiklMSu] [-f funct] [-m umask] [-s ctr] "
1.13      deraadt   521:                    "[-t thold]";
                    522:                break;
                    523:        case CPU_AMD:
1.17      mikeb     524:                usg = "[-eilku] [-f funct] [-m umask] [-s ctr] "
1.13      deraadt   525:                    "[-t thold]";
                    526:                break;
1.7       mickey    527:        }
1.1       dm        528:
1.20      sobrado   529:        fprintf(stderr, "usage: %s %s\n", __progname, usg);
1.18      mikeb     530:        exit(1);
1.1       dm        531: }