1
0
Files
irix-657m-src/eoe/cmd/profiler/prfstat.c
2022-09-29 17:59:04 +03:00

211 lines
6.1 KiB
C

/* Copyright (c) 1984 AT&T */
/* All Rights Reserved */
/* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T */
/* The copyright notice above does not evidence any */
/* actual or intended publication of such source code. */
#ident "$Revision: 1.12 $"
/*
* prfstat - change and/or report profiler status
*/
#include <stddef.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <sys/prf.h>
/*
* Profiling range and domain name decoding.
*/
typedef struct { /* range and domain parameter descriptions */
char *name;
unsigned int value;
char *description;
} nameval_t;
static int lookupname(const nameval_t *, const char *, unsigned int *);
static int lookupval(const nameval_t *, unsigned int, const char **);
static nameval_t rangetab[] = {
"off", PRF_RANGE_NONE, "turn off kernel profiling",
"pc", PRF_RANGE_PC, "PCs (function profiling)",
"stack", PRF_RANGE_STACK, "call stacks (gprof-like)",
NULL, 0, NULL
};
static nameval_t domaintab[] = {
"time", PRF_DOMAIN_TIME, "time",
"switch", PRF_DOMAIN_SWTCH, "context switches",
"ipl", PRF_DOMAIN_IPL, "non-zero interrupt priority level",
"cycles", PRF_DOMAIN_CYCLES, "cycle time (*)",
"dcache1", PRF_DOMAIN_DCACHE1, "primary data cache misses (*)",
"dcache2", PRF_DOMAIN_DCACHE2, "secondary data cache misses (*)",
"icache1", PRF_DOMAIN_ICACHE1, "primary instruction cache misses (*)",
"icache2", PRF_DOMAIN_ICACHE2, "secondary instruction cache misses (*)",
"scfail", PRF_DOMAIN_SCFAIL, "store-conditional failures (*)",
"brmiss", PRF_DOMAIN_BRMISS, "branch mispredicted (*)",
"upgclean", PRF_DOMAIN_UPGCLEAN, "exclusive upgrade on clean secondary cache line (*)",
"upgshared",PRF_DOMAIN_UPGSHARED, "exclusive upgrade on shared secondary cache line (*)",
NULL, 0, NULL
};
/*
* Argument processing.
*/
static char *myname; /* name we were invoked under */
static void
usage(void)
{
nameval_t *tp;
fprintf(stderr,
"usage: %s [ range [ domain ] ]\n"
" Range values are sampled from a subset of the domain. If no\n"
" range/domain is specified, the current sampling range and\n"
" domain are displayed.\n",
myname);
fprintf(stderr, " Range options are:\n");
for (tp = rangetab; tp->name; tp++)
fprintf(stderr, " %-10s %s\n", tp->name, tp->description);
fprintf(stderr, " Domain options are:\n");
for (tp = domaintab; tp->name; tp++)
fprintf(stderr, " %-10s %s\n", tp->name, tp->description);
fprintf(stderr, " (*) Only available on systems based on R10K or later CPUs.\n");
exit(EXIT_FAILURE);
/*NOTREACHED*/
}
int
main(int argc, char *const*argv)
{
unsigned int range, domain, prfstatus;
int prffd;
/*
* Parse arguments.
*/
myname = strrchr(argv[0], '/');
if (myname != NULL)
myname++;
else
myname = argv[0];
if(argc > 3)
usage();
if (argc >= 2) {
if (!lookupname(rangetab, argv[1], &range)) {
fprintf(stderr, "%s: invalid range specification \"%s\"\n",
myname, argv[1]);
usage();
}
if (argc == 2) {
domain = ((range == PRF_RANGE_NONE)
? PRF_DOMAIN_NONE
: PRF_DOMAIN_TIME);
} else {
if (range == PRF_RANGE_NONE) {
fprintf(stderr, "%s: can't specify domain for range \"off\"\n",
myname);
exit(EXIT_FAILURE);
/*NOTREACHED*/
}
if (!lookupname(domaintab, argv[2], &domain)) {
fprintf(stderr, "%s: invalid domain specification \"%s\"\n",
myname, argv[2]);
usage();
}
}
}
/*
* The prf driver unfortunately returns EINVAL in a number of cases
* because there aren't more specific error numbers to return. When
* we get an EINVAL we attempt to offer a more precise error or at
* least a hint as to what might be wrong ...
*/
prffd = open("/dev/prf", O_RDWR);
if (prffd < 0) {
int open_err = errno;
fprintf(stderr, "%s: can't open /dev/prf: %s\n",
myname, strerror(open_err));
if (open_err == EINVAL)
fprintf(stderr, " --> make sure that %s and /unix are both 32- or"
" both 64-bit\n", myname);
exit(EXIT_FAILURE);
/*NOTREACHED*/
}
/*
* If any arguments were supplied, try to set the profiling status.
*/
if (argc >= 2 && ioctl(prffd, PRF_SETPROFTYPE, range|domain) < 0) {
fprintf(stderr, "%s: can't set status on /dev/prf: %s\n",
myname, strerror(errno));
if (errno == EINVALSTATE)
fprintf(stderr, " --> kernel symbol table not loaded, run prfld\n");
else if (errno == ENOTSUP && domain != PRF_DOMAIN_TIME)
fprintf(stderr, " --> this machine may not support the requested"
" domain \"%s\"\n", argv[2]);
exit(EXIT_FAILURE);
/*NOTREACHED*/
}
/*
* Always display the current status.
*/
prfstatus = ioctl(prffd, PRF_GETSTATUS);
if ((int)prfstatus < 0) {
fprintf(stderr, "%s: can't get status for /dev/prf: %s\n",
myname, strerror(errno));
exit(EXIT_FAILURE);
/*NOTREACHED*/
}
if ((prfstatus & PRF_PROFTYPE_MASK) == PRF_PROFTYPE_NONE)
puts("profiling disabled");
else {
const char *rangename, *domainname;
rangename = domainname = "UNKNOWN";
if (!lookupval(rangetab, prfstatus & PRF_RANGE_MASK, &rangename)
|| !lookupval(domaintab, prfstatus & PRF_DOMAIN_MASK, &domainname))
printf("profiling enabled: range = %s (%#x), domain = %s (%#x)\n",
rangename, prfstatus & PRF_RANGE_MASK,
domainname, prfstatus & PRF_DOMAIN_MASK);
else
printf("profiling enabled: range = %s, domain = %s\n",
rangename, domainname);
}
printf("%d kernel functions in symbol table\n",
prfstatus & PRF_VALID_SYMTAB ? ioctl(prffd, PRF_GETNSYMS) : 0);
exit(EXIT_SUCCESS);
/*NOTREACHED*/
}
static int
lookupname(const nameval_t *table, const char *name, unsigned int *value)
{
for (/*empty*/; table->name; table++)
if (strcmp(table->name, name) == 0) {
*value = table->value;
return 1;
}
return 0;
}
static int
lookupval(const nameval_t *table, unsigned int value, const char **name)
{
for (/*empty*/; table->name; table++)
if (table->value == value) {
*name = table->name;
return 1;
}
return 0;
}