|
Packit |
577717 |
/* $Id: perfex.c,v 1.35 2005/01/16 22:51:20 mikpe Exp $
|
|
Packit |
577717 |
*
|
|
Packit |
577717 |
* NAME
|
|
Packit |
577717 |
* perfex - a command-line interface to processor performance counters
|
|
Packit |
577717 |
*
|
|
Packit |
577717 |
* SYNOPSIS
|
|
Packit |
577717 |
* perfex [-e event] .. [--p4pe=value] [--p4pmv=value] [-o file] command
|
|
Packit |
577717 |
* perfex { -i | -l | -L }
|
|
Packit |
577717 |
*
|
|
Packit |
577717 |
* DESCRIPTION
|
|
Packit |
577717 |
* The given command is executed; after it is complete, perfex
|
|
Packit |
577717 |
* prints the values of the various hardware performance counters.
|
|
Packit |
577717 |
*
|
|
Packit |
577717 |
* OPTIONS
|
|
Packit |
577717 |
* -e event | --event=event
|
|
Packit |
577717 |
* Specify an event to be counted.
|
|
Packit |
577717 |
* Multiple event specifiers may be given, limited by the
|
|
Packit |
577717 |
* number of available performance counters in the processor.
|
|
Packit |
577717 |
*
|
|
Packit |
577717 |
* The full syntax of an event specifier is "evntsel/escr@pmc".
|
|
Packit |
577717 |
* All three components are 32-bit processor-specific numbers,
|
|
Packit |
577717 |
* written in decimal or hexadecimal notation.
|
|
Packit |
577717 |
*
|
|
Packit |
577717 |
* "evntsel" is the primary processor-specific event selection
|
|
Packit |
577717 |
* code to use for this event. This field is mandatory.
|
|
Packit |
577717 |
*
|
|
Packit |
577717 |
* "/escr" is used to specify additional event selection data
|
|
Packit |
577717 |
* for Pentium 4 processors. "evntsel" is put in the counter's
|
|
Packit |
577717 |
* CCCR register, and "escr" is put in the associated ESCR
|
|
Packit |
577717 |
* register.
|
|
Packit |
577717 |
*
|
|
Packit |
577717 |
* "@pmc" describes which CPU counter number to assign this
|
|
Packit |
577717 |
* event to. When omitted, the events are assigned in the
|
|
Packit |
577717 |
* order listed, starting from 0. Either all or none of the
|
|
Packit |
577717 |
* event specifiers should use the "@pmc" notation.
|
|
Packit |
577717 |
* Explicit counter assignment via "@pmc" is required on
|
|
Packit |
577717 |
* Pentium 4 and VIA C3 processors.
|
|
Packit |
577717 |
*
|
|
Packit |
577717 |
* The counts, together with an event description are written
|
|
Packit |
577717 |
* to the result file (default is stderr).
|
|
Packit |
577717 |
*
|
|
Packit |
577717 |
* --p4pe=value | --p4_pebs_enable=value
|
|
Packit |
577717 |
* --p4pmv=value | --p4_pebs_matrix_vert=value
|
|
Packit |
577717 |
* Specify the value to be stored in the auxiliary control
|
|
Packit |
577717 |
* register PEBS_ENABLE or PEBS_MATRIX_VERT, which are used
|
|
Packit |
577717 |
* for replay tagging events on Pentium 4 processors.
|
|
Packit |
577717 |
* Note: Intel's documentation states that bit 25 should be
|
|
Packit |
577717 |
* set in PEBS_ENABLE, but this is not true and the driver
|
|
Packit |
577717 |
* will disallow it.
|
|
Packit |
577717 |
*
|
|
Packit |
577717 |
* -i | --info
|
|
Packit |
577717 |
* Instead of running a command, generate output which
|
|
Packit |
577717 |
* identifies the current processor and its capabilities.
|
|
Packit |
577717 |
*
|
|
Packit |
577717 |
* -l | --list
|
|
Packit |
577717 |
* Instead of running a command, generate output which
|
|
Packit |
577717 |
* identifies the current processor and its capabilities,
|
|
Packit |
577717 |
* and lists its countable events.
|
|
Packit |
577717 |
*
|
|
Packit |
577717 |
* -L | --long-list
|
|
Packit |
577717 |
* Like -l, but list the events in a more detailed format.
|
|
Packit |
577717 |
*
|
|
Packit |
577717 |
* -o file | --output=file
|
|
Packit |
577717 |
* Write the results to file instead of stderr.
|
|
Packit |
577717 |
*
|
|
Packit |
577717 |
* EXAMPLES
|
|
Packit |
577717 |
* The following commands count the number of retired instructions
|
|
Packit |
577717 |
* in user-mode on an Intel P6 processor:
|
|
Packit |
577717 |
*
|
|
Packit |
577717 |
* perfex -e 0x004100C0 some_program
|
|
Packit |
577717 |
* perfex --event=0x004100C0 some_program
|
|
Packit |
577717 |
*
|
|
Packit |
577717 |
* The following command does the same on an Intel Pentium 4 processor:
|
|
Packit |
577717 |
*
|
|
Packit |
577717 |
* perfex -e 0x00039000/0x04000204@0x8000000C some_program
|
|
Packit |
577717 |
*
|
|
Packit |
577717 |
* Explanation: Program IQ_CCCR0 with required flags, ESCR select 4
|
|
Packit |
577717 |
* (== CRU_ESCR0), and Enable. Program CRU_ESCR0 with event 2
|
|
Packit |
577717 |
* (instr_retired), NBOGUSNTAG, CPL>0. Map this event to IQ_COUNTER0
|
|
Packit |
577717 |
* (0xC) with fast RDPMC enabled.
|
|
Packit |
577717 |
*
|
|
Packit |
577717 |
* The following command counts the number of L1 cache read misses
|
|
Packit |
577717 |
* on a Pentium 4 processor:
|
|
Packit |
577717 |
*
|
|
Packit |
577717 |
* perfex -e 0x0003B000/0x12000204@0x8000000C --p4pe=0x01000001 --p4pmv=0x1 some_program
|
|
Packit |
577717 |
*
|
|
Packit |
577717 |
* Explanation: IQ_CCCR0 is bound to CRU_ESCR2, CRU_ESCR2 is set up
|
|
Packit |
577717 |
* for replay_event with non-bogus uops and CPL>0, and PEBS_ENABLE
|
|
Packit |
577717 |
* and PEBS_MATRIX_VERT are set up for the 1stL_cache_load_miss_retired
|
|
Packit |
577717 |
* metric. Note that bit 25 is NOT set in PEBS_ENABLE.
|
|
Packit |
577717 |
*
|
|
Packit |
577717 |
* DEPENDENCIES
|
|
Packit |
577717 |
* perfex only works on Linux systems which have been modified
|
|
Packit |
577717 |
* to include the perfctr kernel extension. Perfctr is available at
|
|
Packit |
577717 |
* http://www.csd.uu.se/~mikpe/linux/perfctr/.
|
|
Packit |
577717 |
*
|
|
Packit |
577717 |
* NOTES
|
|
Packit |
577717 |
* perfex is superficially similar to IRIX' perfex(1).
|
|
Packit |
577717 |
* The -a, -mp, -s, and -x options are not yet implemented.
|
|
Packit |
577717 |
*
|
|
Packit |
577717 |
* Copyright (C) 1999-2004 Mikael Pettersson
|
|
Packit |
577717 |
*/
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/*
|
|
Packit |
577717 |
* Theory of operation:
|
|
Packit |
577717 |
* - Parent creates a socketpair().
|
|
Packit |
577717 |
* - Parent forks.
|
|
Packit |
577717 |
* - Child creates and sets up its perfctrs.
|
|
Packit |
577717 |
* - Child sends its perfctr fd to parent via the socketpair().
|
|
Packit |
577717 |
* - Child exec:s the command.
|
|
Packit |
577717 |
* - Parent waits for child to exit.
|
|
Packit |
577717 |
* - Parent receives child's perfctr fd via the socketpair().
|
|
Packit |
577717 |
* - Parent retrieves child's final control and counts via the fd.
|
|
Packit |
577717 |
*/
|
|
Packit |
577717 |
|
|
Packit |
577717 |
#include <sys/socket.h>
|
|
Packit |
577717 |
#include <sys/uio.h>
|
|
Packit |
577717 |
#include <sys/wait.h>
|
|
Packit |
577717 |
#include <errno.h>
|
|
Packit |
577717 |
#include <getopt.h>
|
|
Packit |
577717 |
#include <stddef.h> /* for offsetof() */
|
|
Packit |
577717 |
#include <stdio.h>
|
|
Packit |
577717 |
#include <stdlib.h>
|
|
Packit |
577717 |
#include <string.h> /* for strerror() */
|
|
Packit |
577717 |
#include <unistd.h>
|
|
Packit |
577717 |
#include "libperfctr.h"
|
|
Packit |
577717 |
#include "arch.h"
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/*
|
|
Packit |
577717 |
* Our child-to-parent protocol is the following:
|
|
Packit |
577717 |
* There is an int-sized data packet, with an optional 'struct cmsg_fd'
|
|
Packit |
577717 |
* control message attached.
|
|
Packit |
577717 |
* The data packet (which must be present, as control messages don't
|
|
Packit |
577717 |
* work with zero-sized payloads) contains an 'int' status.
|
|
Packit |
577717 |
* If status != 0, then it is an 'errno' value from the child's
|
|
Packit |
577717 |
* perfctr setup code.
|
|
Packit |
577717 |
*/
|
|
Packit |
577717 |
|
|
Packit |
577717 |
struct cmsg_fd {
|
|
Packit |
577717 |
struct cmsghdr hdr;
|
|
Packit |
577717 |
int fd;
|
|
Packit |
577717 |
/* 64-bit machines pad here, which causes problems since
|
|
Packit |
577717 |
the kernel derives the number of fds from the size.
|
|
Packit |
577717 |
The CMSG_FD_TRUE_SIZE macro gives the true payload size. */
|
|
Packit |
577717 |
};
|
|
Packit |
577717 |
#define CMSG_FD_TRUE_SIZE (offsetof(struct cmsg_fd, fd) + sizeof(int))
|
|
Packit |
577717 |
#define CMSG_FD_PADDED_SIZE sizeof(struct cmsg_fd)
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static int my_send(int sock, int fd, int status)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
struct msghdr msg;
|
|
Packit |
577717 |
struct iovec iov;
|
|
Packit |
577717 |
struct cmsg_fd cmsg_fd;
|
|
Packit |
577717 |
int buf[1];
|
|
Packit |
577717 |
|
|
Packit |
577717 |
msg.msg_name = NULL;
|
|
Packit |
577717 |
msg.msg_namelen = 0;
|
|
Packit |
577717 |
msg.msg_flags = 0;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
buf[0] = status;
|
|
Packit |
577717 |
iov.iov_base = buf;
|
|
Packit |
577717 |
iov.iov_len = sizeof buf;
|
|
Packit |
577717 |
msg.msg_iov = &iov;
|
|
Packit |
577717 |
msg.msg_iovlen = 1;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
if( status != 0 ) { /* errno, don't send fd */
|
|
Packit |
577717 |
msg.msg_control = 0;
|
|
Packit |
577717 |
msg.msg_controllen = 0;
|
|
Packit |
577717 |
} else {
|
|
Packit |
577717 |
cmsg_fd.hdr.cmsg_len = CMSG_FD_TRUE_SIZE;
|
|
Packit |
577717 |
cmsg_fd.hdr.cmsg_level = SOL_SOCKET;
|
|
Packit |
577717 |
cmsg_fd.hdr.cmsg_type = SCM_RIGHTS;
|
|
Packit |
577717 |
cmsg_fd.fd = fd;
|
|
Packit |
577717 |
msg.msg_control = &cmsg_fd;
|
|
Packit |
577717 |
msg.msg_controllen = CMSG_FD_TRUE_SIZE;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
return sendmsg(sock, &msg, 0) == sizeof buf ? 0 : -1;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static int my_send_fd(int sock, int fd)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
return my_send(sock, fd, 0);
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static int my_send_err(int sock)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
return my_send(sock, -1, errno);
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static int my_receive(int sock, int *fd)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
struct msghdr msg;
|
|
Packit |
577717 |
struct iovec iov;
|
|
Packit |
577717 |
struct cmsg_fd cmsg_fd;
|
|
Packit |
577717 |
int buf[1];
|
|
Packit |
577717 |
|
|
Packit |
577717 |
msg.msg_name = NULL;
|
|
Packit |
577717 |
msg.msg_namelen = 0;
|
|
Packit |
577717 |
msg.msg_flags = 0;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
buf[0] = -1;
|
|
Packit |
577717 |
iov.iov_base = buf;
|
|
Packit |
577717 |
iov.iov_len = sizeof(buf);
|
|
Packit |
577717 |
msg.msg_iov = &iov;
|
|
Packit |
577717 |
msg.msg_iovlen = 1;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
memset(&cmsg_fd, ~0, sizeof cmsg_fd);
|
|
Packit |
577717 |
msg.msg_control = &cmsg_fd;
|
|
Packit |
577717 |
msg.msg_controllen = CMSG_FD_TRUE_SIZE;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
if( recvmsg(sock, &msg, 0) != sizeof buf )
|
|
Packit |
577717 |
return -1;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
if( buf[0] == 0 &&
|
|
Packit |
577717 |
msg.msg_control == &cmsg_fd &&
|
|
Packit |
577717 |
msg.msg_controllen == CMSG_FD_PADDED_SIZE &&
|
|
Packit |
577717 |
cmsg_fd.hdr.cmsg_type == SCM_RIGHTS &&
|
|
Packit |
577717 |
cmsg_fd.hdr.cmsg_level == SOL_SOCKET &&
|
|
Packit |
577717 |
cmsg_fd.hdr.cmsg_len == CMSG_FD_TRUE_SIZE &&
|
|
Packit |
577717 |
cmsg_fd.fd >= 0 ) {
|
|
Packit |
577717 |
*fd = cmsg_fd.fd;
|
|
Packit |
577717 |
return 0;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
if( msg.msg_controllen == 0 && buf[0] != 0 )
|
|
Packit |
577717 |
errno = buf[0];
|
|
Packit |
577717 |
else
|
|
Packit |
577717 |
errno = EPROTO;
|
|
Packit |
577717 |
return -1;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static int do_open_self(int creat)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
int fd;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
fd = _vperfctr_open(creat);
|
|
Packit |
577717 |
if( fd >= 0 && perfctr_abi_check_fd(fd) < 0 ) {
|
|
Packit |
577717 |
close(fd);
|
|
Packit |
577717 |
return -1;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
return fd;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static int do_child(int sock, const struct vperfctr_control *control, char **argv)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
int fd;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
fd = do_open_self(1);
|
|
Packit |
577717 |
if( fd < 0 ) {
|
|
Packit |
577717 |
my_send_err(sock);
|
|
Packit |
577717 |
return 1;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
if( _vperfctr_control(fd, control) < 0 ) {
|
|
Packit |
577717 |
my_send_err(sock);
|
|
Packit |
577717 |
return 1;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
if( my_send_fd(sock, fd) < 0 ) {
|
|
Packit |
577717 |
my_send_err(sock); /* well, we can try.. */
|
|
Packit |
577717 |
return 1;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
close(fd);
|
|
Packit |
577717 |
close(sock);
|
|
Packit |
577717 |
execvp(argv[0], argv);
|
|
Packit |
577717 |
perror(argv[0]);
|
|
Packit |
577717 |
return 1;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static int do_parent(int sock, int child_pid, FILE *resfile)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
int child_status;
|
|
Packit |
577717 |
int fd;
|
|
Packit |
577717 |
struct perfctr_sum_ctrs sum;
|
|
Packit |
577717 |
struct vperfctr_control control;
|
|
Packit |
577717 |
struct perfctr_sum_ctrs children;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/* this can be done before or after the recvmsg() */
|
|
Packit |
577717 |
if( waitpid(child_pid, &child_status, 0) < 0 ) {
|
|
Packit |
577717 |
perror("perfex: waitpid");
|
|
Packit |
577717 |
return 1;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
if( !WIFEXITED(child_status) ) {
|
|
Packit |
577717 |
fprintf(stderr, "perfex: child did not exit normally\n");
|
|
Packit |
577717 |
return 1;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
if( my_receive(sock, &fd) < 0 ) {
|
|
Packit |
577717 |
perror("perfex: receiving fd/status");
|
|
Packit |
577717 |
return 1;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
close(sock);
|
|
Packit |
577717 |
/* XXX: surely we don't need to repeat the ABI check here? */
|
|
Packit |
577717 |
if( _vperfctr_read_sum(fd, &sum) < 0 ) {
|
|
Packit |
577717 |
perror("perfex: read_sum");
|
|
Packit |
577717 |
return 1;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
if( _vperfctr_read_control(fd, &control) < 0 ) {
|
|
Packit |
577717 |
perror("perfex: read_control");
|
|
Packit |
577717 |
return 1;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
if( _vperfctr_read_children(fd, &children) < 0 ) {
|
|
Packit |
577717 |
perror("perfex: read_children");
|
|
Packit |
577717 |
return 1;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
close(fd);
|
|
Packit |
577717 |
|
|
Packit |
577717 |
do_print(resfile, &control.cpu_control, &sum, &children);
|
|
Packit |
577717 |
|
|
Packit |
577717 |
return WEXITSTATUS(child_status);
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static int do_perfex(const struct vperfctr_control *control, char **argv, FILE *resfile)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
int pid;
|
|
Packit |
577717 |
int sv[2];
|
|
Packit |
577717 |
|
|
Packit |
577717 |
if( socketpair(AF_UNIX, SOCK_DGRAM, 0, sv) < 0 ) {
|
|
Packit |
577717 |
perror("perfex: socketpair");
|
|
Packit |
577717 |
return 1;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
pid = fork();
|
|
Packit |
577717 |
if( pid < 0 ) {
|
|
Packit |
577717 |
perror("perfex: fork");
|
|
Packit |
577717 |
return 1;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
if( pid == 0 ) {
|
|
Packit |
577717 |
close(sv[0]);
|
|
Packit |
577717 |
return do_child(sv[1], control, argv);
|
|
Packit |
577717 |
} else {
|
|
Packit |
577717 |
close(sv[1]);
|
|
Packit |
577717 |
return do_parent(sv[0], pid, resfile);
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static int get_info(struct perfctr_info *info)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
int fd;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
fd = do_open_self(0);
|
|
Packit |
577717 |
if( fd < 0 ) {
|
|
Packit |
577717 |
perror("perfex: open perfctrs");
|
|
Packit |
577717 |
return -1;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
if( perfctr_info(fd, info) < 0 ) {
|
|
Packit |
577717 |
perror("perfex: perfctr_info");
|
|
Packit |
577717 |
close(fd);
|
|
Packit |
577717 |
return -1;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
close(fd);
|
|
Packit |
577717 |
return 0;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static struct perfctr_cpus_info *get_cpus_info(void)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
int fd;
|
|
Packit |
577717 |
struct perfctr_cpus_info *cpus_info;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
fd = do_open_self(0);
|
|
Packit |
577717 |
if( fd < 0 ) {
|
|
Packit |
577717 |
perror("perfex: open perfctrs");
|
|
Packit |
577717 |
return NULL;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
cpus_info = perfctr_cpus_info(fd);
|
|
Packit |
577717 |
if( !cpus_info )
|
|
Packit |
577717 |
perror("perfex: perfctr_cpus_info");
|
|
Packit |
577717 |
close(fd);
|
|
Packit |
577717 |
return cpus_info;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static int do_info(const struct perfctr_info *info)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
struct perfctr_cpus_info *cpus_info;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
cpus_info = get_cpus_info();
|
|
Packit |
577717 |
printf("PerfCtr Info:\n");
|
|
Packit |
577717 |
perfctr_info_print(info);
|
|
Packit |
577717 |
if( cpus_info ) {
|
|
Packit |
577717 |
perfctr_cpus_info_print(cpus_info);
|
|
Packit |
577717 |
free(cpus_info);
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
return 0;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static void do_print_event(const struct perfctr_event *event, int long_format,
|
|
Packit |
577717 |
const char *event_prefix)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
printf("%s%s", event_prefix, event->name);
|
|
Packit |
577717 |
if( long_format )
|
|
Packit |
577717 |
printf(":0x%02X:0x%X:0x%X",
|
|
Packit |
577717 |
event->evntsel,
|
|
Packit |
577717 |
event->counters_set,
|
|
Packit |
577717 |
event->unit_mask ? event->unit_mask->default_value : 0);
|
|
Packit |
577717 |
printf("\n");
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static void do_print_event_set(const struct perfctr_event_set *event_set,
|
|
Packit |
577717 |
int long_format)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
unsigned int i;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
if( event_set->include )
|
|
Packit |
577717 |
do_print_event_set(event_set->include, long_format);
|
|
Packit |
577717 |
for(i = 0; i < event_set->nevents; ++i)
|
|
Packit |
577717 |
do_print_event(&event_set->events[i], long_format, event_set->event_prefix);
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static int do_list(const struct perfctr_info *info, int long_format)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
const struct perfctr_event_set *event_set;
|
|
Packit |
577717 |
unsigned int nrctrs;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
printf("CPU type %s\n", perfctr_info_cpu_name(info));
|
|
Packit |
577717 |
printf("%s time-stamp counter available\n",
|
|
Packit |
577717 |
(info->cpu_features & PERFCTR_FEATURE_RDTSC) ? "One" : "No");
|
|
Packit |
577717 |
nrctrs = perfctr_info_nrctrs(info);
|
|
Packit |
577717 |
printf("%u performance counter%s available\n",
|
|
Packit |
577717 |
nrctrs, (nrctrs == 1) ? "" : "s");
|
|
Packit |
577717 |
printf("Overflow interrupts%s available\n",
|
|
Packit |
577717 |
(info->cpu_features & PERFCTR_FEATURE_PCINT) ? "" : " not");
|
|
Packit |
577717 |
|
|
Packit |
577717 |
event_set = perfctr_cpu_event_set(info->cpu_type);
|
|
Packit |
577717 |
if( !event_set ) {
|
|
Packit |
577717 |
fprintf(stderr, "perfex: perfctr_cpu_event_set(%u) failed\n",
|
|
Packit |
577717 |
info->cpu_type);
|
|
Packit |
577717 |
return 1;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
if( !event_set->nevents ) /* the 'generic' CPU type */
|
|
Packit |
577717 |
return 0;
|
|
Packit |
577717 |
printf("\nEvents Available:\n");
|
|
Packit |
577717 |
if( long_format )
|
|
Packit |
577717 |
printf("Name:EvntSel:CounterSet:DefaultUnitMask\n");
|
|
Packit |
577717 |
do_print_event_set(event_set, long_format);
|
|
Packit |
577717 |
return 0;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/* Hack while phasing out an old number parsing bug. */
|
|
Packit |
577717 |
static unsigned int strtoul_base = 16;
|
|
Packit |
577717 |
static unsigned int quiet;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
unsigned long my_strtoul(const char *nptr, char **endptr)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
unsigned long val1;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
val1 = strtoul(nptr, endptr, strtoul_base);
|
|
Packit |
577717 |
if (strtoul_base == 16 && !quiet) {
|
|
Packit |
577717 |
unsigned long val2 = strtoul(nptr, NULL, 0);
|
|
Packit |
577717 |
if (val1 != val2)
|
|
Packit |
577717 |
fprintf(stderr, "perfex: warning: string '%s' is base-dependent, assuming base 16."
|
|
Packit |
577717 |
" Please prefix hexadecimal numbers with '0x'.\n",
|
|
Packit |
577717 |
nptr);
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
return val1;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static const struct option long_options[] = {
|
|
Packit |
577717 |
{ "decimal", 0, NULL, 'd' },
|
|
Packit |
577717 |
{ "event", 1, NULL, 'e' },
|
|
Packit |
577717 |
{ "help", 0, NULL, 'h' },
|
|
Packit |
577717 |
{ "hex", 0, NULL, 'x' },
|
|
Packit |
577717 |
{ "info", 0, NULL, 'i' },
|
|
Packit |
577717 |
{ "list", 0, NULL, 'l' },
|
|
Packit |
577717 |
{ "long-list", 0, NULL, 'L' },
|
|
Packit |
577717 |
{ "output", 1, NULL, 'o' },
|
|
Packit |
577717 |
ARCH_LONG_OPTIONS
|
|
Packit |
577717 |
{ 0 }
|
|
Packit |
577717 |
};
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static void do_usage(void)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
fprintf(stderr, "Usage: perfex [options] <command> [<command arg>] ...\n");
|
|
Packit |
577717 |
fprintf(stderr, "\tperfex -i\n");
|
|
Packit |
577717 |
fprintf(stderr, "\tperfex -h\n");
|
|
Packit |
577717 |
fprintf(stderr, "\n");
|
|
Packit |
577717 |
fprintf(stderr, "Options:\n");
|
|
Packit |
577717 |
fprintf(stderr, "\t-e <event> | --event=<event>\tEvent to be counted\n");
|
|
Packit |
577717 |
fprintf(stderr, "\t-h | --help\t\t\tPrint this help text\n");
|
|
Packit |
577717 |
fprintf(stderr, "\t-o <file> | --output=<file>\tWrite output to file (default is stderr)\n");
|
|
Packit |
577717 |
fprintf(stderr, "\t-i | --info\t\t\tPrint PerfCtr driver information\n");
|
|
Packit |
577717 |
fprintf(stderr, "\t-l | --list\t\t\tList available events\n");
|
|
Packit |
577717 |
fprintf(stderr, "\t-L | --long-list\t\tList available events in long format\n");
|
|
Packit |
577717 |
fprintf(stderr, "\t-d | --decimal\t\t\tAllow decimal numbers in event specifications\n");
|
|
Packit |
577717 |
fprintf(stderr, "\t-x | --hex\t\t\tOnly accept hexadecimal numbers in event specifications\n");
|
|
Packit |
577717 |
do_arch_usage();
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
int main(int argc, char **argv)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
struct perfctr_info info;
|
|
Packit |
577717 |
struct vperfctr_control control;
|
|
Packit |
577717 |
int n;
|
|
Packit |
577717 |
FILE *resfile;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/* prime info, as we'll need it in most cases */
|
|
Packit |
577717 |
if( get_info(&info) )
|
|
Packit |
577717 |
return 1;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
memset(&control, 0, sizeof control);
|
|
Packit |
577717 |
if( info.cpu_features & PERFCTR_FEATURE_RDTSC )
|
|
Packit |
577717 |
control.cpu_control.tsc_on = 1;
|
|
Packit |
577717 |
n = 0;
|
|
Packit |
577717 |
resfile = stderr;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
for(;;) {
|
|
Packit |
577717 |
/* the '+' is there to prevent permutation of argv[] */
|
|
Packit |
577717 |
int ch = getopt_long(argc, argv, "+de:hilLo:x", long_options, NULL);
|
|
Packit |
577717 |
switch( ch ) {
|
|
Packit |
577717 |
case -1: /* no more options */
|
|
Packit |
577717 |
if( optind >= argc ) {
|
|
Packit |
577717 |
fprintf(stderr, "perfex: command missing\n");
|
|
Packit |
577717 |
return 1;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
argv += optind;
|
|
Packit |
577717 |
break;
|
|
Packit |
577717 |
case 'h':
|
|
Packit |
577717 |
do_usage();
|
|
Packit |
577717 |
return 0;
|
|
Packit |
577717 |
case 'i':
|
|
Packit |
577717 |
return do_info(&info;;
|
|
Packit |
577717 |
case 'l':
|
|
Packit |
577717 |
return do_list(&info, 0);
|
|
Packit |
577717 |
case 'L':
|
|
Packit |
577717 |
return do_list(&info, 1);
|
|
Packit |
577717 |
case 'o':
|
|
Packit |
577717 |
if( (resfile = fopen(optarg, "w")) == NULL ) {
|
|
Packit |
577717 |
fprintf(stderr, "perfex: %s: %s\n", optarg, strerror(errno));
|
|
Packit |
577717 |
return 1;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
continue;
|
|
Packit |
577717 |
case 'd':
|
|
Packit |
577717 |
strtoul_base = 0;
|
|
Packit |
577717 |
continue;
|
|
Packit |
577717 |
case 'x':
|
|
Packit |
577717 |
strtoul_base = 16;
|
|
Packit |
577717 |
quiet = 1;
|
|
Packit |
577717 |
continue;
|
|
Packit |
577717 |
case 'e':
|
|
Packit |
577717 |
n = do_event_spec(n, optarg, &control.cpu_control);
|
|
Packit |
577717 |
continue;
|
|
Packit |
577717 |
default:
|
|
Packit |
577717 |
if( do_arch_option(ch, optarg, &control.cpu_control) < 0 ) {
|
|
Packit |
577717 |
do_usage();
|
|
Packit |
577717 |
return 1;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
continue;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
break;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
return do_perfex(&control, argv, resfile);
|
|
Packit |
577717 |
}
|