|
Packit |
577717 |
/* rtop.c - a simple PMU-based CPU utilization tool
|
|
Packit |
577717 |
*
|
|
Packit |
577717 |
* Copyright (c) 2009 Google, Inc
|
|
Packit |
577717 |
* Contributed by Stephane Eranian <eranian@gmail.com>
|
|
Packit |
577717 |
*
|
|
Packit |
577717 |
* Based on:
|
|
Packit |
577717 |
* Copyright (c) 2004-2006 Hewlett-Packard Development Company, L.P.
|
|
Packit |
577717 |
* Contributed by Stephane Eranian <eranian@hpl.hp.com>
|
|
Packit |
577717 |
*
|
|
Packit |
577717 |
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
Packit |
577717 |
* of this software and associated documentation files (the "Software"), to deal
|
|
Packit |
577717 |
* in the Software without restriction, including without limitation the rights
|
|
Packit |
577717 |
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
|
Packit |
577717 |
* of the Software, and to permit persons to whom the Software is furnished to do so,
|
|
Packit |
577717 |
* subject to the following conditions:
|
|
Packit |
577717 |
*
|
|
Packit |
577717 |
* The above copyright notice and this permission notice shall be included in all
|
|
Packit |
577717 |
* copies or substantial portions of the Software.
|
|
Packit |
577717 |
*
|
|
Packit |
577717 |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
|
Packit |
577717 |
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
|
Packit |
577717 |
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
|
Packit |
577717 |
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
|
Packit |
577717 |
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
|
|
Packit |
577717 |
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
Packit |
577717 |
*/
|
|
Packit |
577717 |
#include <sys/types.h>
|
|
Packit |
577717 |
#include <inttypes.h>
|
|
Packit |
577717 |
#include <stdio.h>
|
|
Packit |
577717 |
#include <stdlib.h>
|
|
Packit |
577717 |
#include <stdarg.h>
|
|
Packit |
577717 |
#include <errno.h>
|
|
Packit |
577717 |
#include <unistd.h>
|
|
Packit |
577717 |
#include <string.h>
|
|
Packit |
577717 |
#include <time.h>
|
|
Packit |
577717 |
#include <getopt.h>
|
|
Packit |
577717 |
#include <curses.h>
|
|
Packit |
577717 |
#include <termios.h>
|
|
Packit |
577717 |
#include <signal.h>
|
|
Packit |
577717 |
#include <ctype.h>
|
|
Packit |
577717 |
#include <math.h>
|
|
Packit |
577717 |
#include <limits.h>
|
|
Packit |
577717 |
#include <err.h>
|
|
Packit |
577717 |
|
|
Packit |
577717 |
#include "perf_util.h"
|
|
Packit |
577717 |
|
|
Packit |
577717 |
#define RTOP_VERSION "0.2"
|
|
Packit |
577717 |
/*
|
|
Packit |
577717 |
* max number of cpus (threads) supported
|
|
Packit |
577717 |
*/
|
|
Packit |
577717 |
#define RTOP_MAX_CPUS 2048 /* MUST BE power of 2 */
|
|
Packit |
577717 |
#define RTOP_CPUMASK_BITS (sizeof(unsigned long)<<3)
|
|
Packit |
577717 |
#define RTOP_CPUMASK_COUNT (RTOP_MAX_CPUS/RTOP_CPUMASK_BITS)
|
|
Packit |
577717 |
|
|
Packit |
577717 |
#define RTOP_CPUMASK_SET(m, g) ((m)[(g)/RTOP_CPUMASK_BITS] |= (1UL << ((g) % RTOP_CPUMASK_BITS)))
|
|
Packit |
577717 |
#define RTOP_CPUMASK_CLEAR(m, g) ((m)[(g)/RTOP_CPUMASK_BITS] &= ~(1UL << ((g) % RTOP_CPUMASK_BITS)))
|
|
Packit |
577717 |
#define RTOP_CPUMASK_ISSET(m, g) ((m)[(g)/RTOP_CPUMASK_BITS] & (1UL << ((g) % RTOP_CPUMASK_BITS)))
|
|
Packit |
577717 |
|
|
Packit |
577717 |
typedef unsigned long rtop_cpumask_t[RTOP_CPUMASK_COUNT];
|
|
Packit |
577717 |
|
|
Packit |
577717 |
typedef struct {
|
|
Packit |
577717 |
struct {
|
|
Packit |
577717 |
int opt_verbose;
|
|
Packit |
577717 |
int opt_delay; /* refresh delay in second */
|
|
Packit |
577717 |
int opt_delay_set;
|
|
Packit |
577717 |
} program_opt_flags;
|
|
Packit |
577717 |
rtop_cpumask_t cpu_mask; /* which CPUs to use in system wide mode */
|
|
Packit |
577717 |
long online_cpus;
|
|
Packit |
577717 |
long selected_cpus;
|
|
Packit |
577717 |
unsigned long cpu_mhz;
|
|
Packit |
577717 |
} program_options_t;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
#define opt_verbose program_opt_flags.opt_verbose
|
|
Packit |
577717 |
#define opt_delay program_opt_flags.opt_delay
|
|
Packit |
577717 |
#define opt_delay_set program_opt_flags.opt_delay_set
|
|
Packit |
577717 |
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static program_options_t options;
|
|
Packit |
577717 |
static struct termios saved_tty;
|
|
Packit |
577717 |
static int time_to_quit;
|
|
Packit |
577717 |
static int term_rows, term_cols;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static void
|
|
Packit |
577717 |
get_term_size(void)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
int ret;
|
|
Packit |
577717 |
struct winsize ws;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
ret = ioctl(1, TIOCGWINSZ, &ws);
|
|
Packit |
577717 |
if (ret)
|
|
Packit |
577717 |
err(1, "cannot determine screen size");
|
|
Packit |
577717 |
|
|
Packit |
577717 |
if (ws.ws_row > 10) {
|
|
Packit |
577717 |
term_cols = ws.ws_col;
|
|
Packit |
577717 |
term_rows = ws.ws_row;
|
|
Packit |
577717 |
} else {
|
|
Packit |
577717 |
term_cols = 80;
|
|
Packit |
577717 |
term_rows = 24;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
if (term_rows < options.selected_cpus)
|
|
Packit |
577717 |
errx(1, "you need at least %ld rows on your terminal to display all CPUs", options.selected_cpus);
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static void
|
|
Packit |
577717 |
sigwinch_handler(int n)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
get_term_size();
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static void
|
|
Packit |
577717 |
setup_screen(void)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
int ret;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
ret = tcgetattr(0, &saved_tty);
|
|
Packit |
577717 |
if (ret == -1)
|
|
Packit |
577717 |
errx(1, "cannot save tty settings\n");
|
|
Packit |
577717 |
|
|
Packit |
577717 |
get_term_size();
|
|
Packit |
577717 |
|
|
Packit |
577717 |
initscr();
|
|
Packit |
577717 |
nocbreak();
|
|
Packit |
577717 |
resizeterm(term_rows, term_cols);
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static void
|
|
Packit |
577717 |
close_screen(void)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
endwin();
|
|
Packit |
577717 |
|
|
Packit |
577717 |
tcsetattr(0, TCSAFLUSH, &saved_tty);
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static void
|
|
Packit |
577717 |
fatal_errorw(char *fmt, ...)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
va_list ap;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
close_screen();
|
|
Packit |
577717 |
|
|
Packit |
577717 |
va_start(ap, fmt);
|
|
Packit |
577717 |
vfprintf(stderr, fmt, ap);
|
|
Packit |
577717 |
va_end(ap);
|
|
Packit |
577717 |
|
|
Packit |
577717 |
exit(1);
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static void
|
|
Packit |
577717 |
sigint_handler(int n)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
time_to_quit = 1;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static unsigned long
|
|
Packit |
577717 |
find_cpu_speed(void)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
FILE *fp1;
|
|
Packit |
577717 |
unsigned long f1 = 0, f2 = 0;
|
|
Packit |
577717 |
char buffer[128], *p, *value;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
memset(buffer, 0, sizeof(buffer));
|
|
Packit |
577717 |
|
|
Packit |
577717 |
fp1 = fopen("/proc/cpuinfo", "r");
|
|
Packit |
577717 |
if (fp1 == NULL)
|
|
Packit |
577717 |
return 0;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
for (;;) {
|
|
Packit |
577717 |
buffer[0] = '\0';
|
|
Packit |
577717 |
|
|
Packit |
577717 |
p = fgets(buffer, 127, fp1);
|
|
Packit |
577717 |
if (p == NULL)
|
|
Packit |
577717 |
break;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/* skip blank lines */
|
|
Packit |
577717 |
if (*p == '\n') continue;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
p = strchr(buffer, ':');
|
|
Packit |
577717 |
if (p == NULL)
|
|
Packit |
577717 |
break;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/*
|
|
Packit |
577717 |
* p+2: +1 = space, +2= firt character
|
|
Packit |
577717 |
* strlen()-1 gets rid of \n
|
|
Packit |
577717 |
*/
|
|
Packit |
577717 |
*p = '\0';
|
|
Packit |
577717 |
value = p+2;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
value[strlen(value)-1] = '\0';
|
|
Packit |
577717 |
|
|
Packit |
577717 |
if (!strncasecmp("cpu MHz", buffer, 7)) {
|
|
Packit |
577717 |
float fl;
|
|
Packit |
577717 |
sscanf(value, "%f", &fl);
|
|
Packit |
577717 |
f1 = lroundf(fl);
|
|
Packit |
577717 |
break;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
if (!strncasecmp("BogoMIPS", buffer, 8)) {
|
|
Packit |
577717 |
float fl;
|
|
Packit |
577717 |
sscanf(value, "%f", &fl);
|
|
Packit |
577717 |
f2 = lroundf(fl);
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
fclose(fp1);
|
|
Packit |
577717 |
return f1 == 0 ? f2 : f1;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static void
|
|
Packit |
577717 |
setup_signals(void)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
struct sigaction act;
|
|
Packit |
577717 |
sigset_t my_set;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/*
|
|
Packit |
577717 |
* SIGINT is a asynchronous signal
|
|
Packit |
577717 |
* sent to the process (not a specific thread). POSIX states
|
|
Packit |
577717 |
* that one and only one thread will execute the handler. This
|
|
Packit |
577717 |
* could be any thread that does not have the signal blocked.
|
|
Packit |
577717 |
*/
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/*
|
|
Packit |
577717 |
* install SIGINT handler
|
|
Packit |
577717 |
*/
|
|
Packit |
577717 |
memset(&act,0,sizeof(act));
|
|
Packit |
577717 |
sigemptyset(&my_set);
|
|
Packit |
577717 |
act.sa_handler = sigint_handler;
|
|
Packit |
577717 |
sigaction (SIGINT, &act, 0);
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/*
|
|
Packit |
577717 |
* install SIGWINCH handler
|
|
Packit |
577717 |
*/
|
|
Packit |
577717 |
memset(&act,0,sizeof(act));
|
|
Packit |
577717 |
sigemptyset(&my_set);
|
|
Packit |
577717 |
act.sa_handler = sigwinch_handler;
|
|
Packit |
577717 |
sigaction (SIGWINCH, &act, 0);
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static struct option rtop_cmd_options[]={
|
|
Packit |
577717 |
{ "help", 0, 0, 1 },
|
|
Packit |
577717 |
{ "version", 0, 0, 2 },
|
|
Packit |
577717 |
{ "delay", 0, 0, 3 },
|
|
Packit |
577717 |
{ "cpu-list", 1, 0, 4 },
|
|
Packit |
577717 |
|
|
Packit |
577717 |
{ "verbose", 0, &options.opt_verbose, 1 },
|
|
Packit |
577717 |
{ 0, 0, 0, 0}
|
|
Packit |
577717 |
};
|
|
Packit |
577717 |
|
|
Packit |
577717 |
#define MAX_EVENTS 2
|
|
Packit |
577717 |
|
|
Packit |
577717 |
typedef struct {
|
|
Packit |
577717 |
uint64_t prev_values[MAX_EVENTS];
|
|
Packit |
577717 |
int fd[MAX_EVENTS];
|
|
Packit |
577717 |
int cpu;
|
|
Packit |
577717 |
} cpudesc_t;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/*
|
|
Packit |
577717 |
* { u64 nr;
|
|
Packit |
577717 |
* { u64 time_enabled; } && PERF_FORMAT_ENABLED
|
|
Packit |
577717 |
* { u64 time_running; } && PERF_FORMAT_RUNNING
|
|
Packit |
577717 |
* { u64 value;
|
|
Packit |
577717 |
* { u64 id; } && PERF_FORMAT_ID
|
|
Packit |
577717 |
* } cntr[nr];
|
|
Packit |
577717 |
*/
|
|
Packit |
577717 |
typedef struct {
|
|
Packit |
577717 |
uint64_t nr;
|
|
Packit |
577717 |
uint64_t time_enabled;
|
|
Packit |
577717 |
uint64_t time_running;
|
|
Packit |
577717 |
uint64_t values[2];
|
|
Packit |
577717 |
} rtop_grp_t;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static void
|
|
Packit |
577717 |
mainloop(void)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
struct perf_event_attr ev[MAX_EVENTS];
|
|
Packit |
577717 |
unsigned long itc_delta;
|
|
Packit |
577717 |
cpudesc_t *cpus;
|
|
Packit |
577717 |
int i, j = 0, k, ncpus = 0;
|
|
Packit |
577717 |
int num, ret;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
ncpus = options.selected_cpus;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
cpus = calloc(ncpus, sizeof(cpudesc_t));
|
|
Packit |
577717 |
if (!cpus)
|
|
Packit |
577717 |
err(1, "cannot allocate file descriptors");
|
|
Packit |
577717 |
|
|
Packit |
577717 |
memset(ev, 0, sizeof(ev));
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/* measure user cycles */
|
|
Packit |
577717 |
ev[0].type = PERF_TYPE_HARDWARE;
|
|
Packit |
577717 |
ev[0].config = PERF_COUNT_HW_CPU_CYCLES;
|
|
Packit |
577717 |
ev[0].read_format = PERF_FORMAT_SCALE|PERF_FORMAT_GROUP;
|
|
Packit |
577717 |
ev[0].exclude_kernel = 1;
|
|
Packit |
577717 |
ev[0].disabled = 1;
|
|
Packit |
577717 |
ev[0].pinned = 0;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/* measure kernel cycles */
|
|
Packit |
577717 |
ev[1].type = PERF_TYPE_HARDWARE;
|
|
Packit |
577717 |
ev[1].config = PERF_COUNT_HW_CPU_CYCLES;
|
|
Packit |
577717 |
ev[1].exclude_user = 1;
|
|
Packit |
577717 |
ev[1].disabled = 1;
|
|
Packit |
577717 |
ev[1].pinned = 0;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
num = 2;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
for(i=0, k = 0; ncpus; i++) {
|
|
Packit |
577717 |
if (RTOP_CPUMASK_ISSET(options.cpu_mask, i) == 0)
|
|
Packit |
577717 |
continue;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
cpus[k].cpu = i;
|
|
Packit |
577717 |
cpus[k].fd[0] = -1;
|
|
Packit |
577717 |
for(j=0 ; j < num; j++) {
|
|
Packit |
577717 |
cpus[k].fd[j] = perf_event_open(ev+j, -1, i, cpus[k].fd[0], 0);
|
|
Packit |
577717 |
if (cpus[k].fd[j] == -1)
|
|
Packit |
577717 |
fatal_errorw("cannot open event %d on CPU%d: %s\n", j, i, strerror(errno));
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
ncpus--;
|
|
Packit |
577717 |
k++;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
ncpus = options.selected_cpus;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
itc_delta = options.opt_delay * options.cpu_mhz * 1000000;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
for(i=0; i < ncpus; i++)
|
|
Packit |
577717 |
for(j=0; j < num; j++)
|
|
Packit |
577717 |
ioctl(cpus[i].fd[j], PERF_EVENT_IOC_ENABLE, 0);
|
|
Packit |
577717 |
|
|
Packit |
577717 |
for(;time_to_quit == 0;) {
|
|
Packit |
577717 |
|
|
Packit |
577717 |
sleep(options.opt_delay);
|
|
Packit |
577717 |
|
|
Packit |
577717 |
move(0, 0);
|
|
Packit |
577717 |
|
|
Packit |
577717 |
for(i=0; i < ncpus; i++) {
|
|
Packit |
577717 |
uint64_t values[MAX_EVENTS];
|
|
Packit |
577717 |
uint64_t raw_values[5];
|
|
Packit |
577717 |
double k_cycles, u_cycles, i_cycles, ratio;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/*
|
|
Packit |
577717 |
* given our events are in the same group, we can do a
|
|
Packit |
577717 |
* group read and get both counts + scaling information
|
|
Packit |
577717 |
*/
|
|
Packit |
577717 |
ret = read(cpus[i].fd[0], raw_values, sizeof(raw_values));
|
|
Packit |
577717 |
if (ret != sizeof(raw_values))
|
|
Packit |
577717 |
fatal_errorw("cannot read count for event %d on CPU%d\n", j, cpus[i].cpu);
|
|
Packit |
577717 |
|
|
Packit |
577717 |
printw("nr=%"PRIu64"\n", raw_values[0]);
|
|
Packit |
577717 |
printw("ena=%"PRIu64"\n", raw_values[1]);
|
|
Packit |
577717 |
printw("run=%"PRIu64"\n", raw_values[2]);
|
|
Packit |
577717 |
|
|
Packit |
577717 |
raw_values[0] = raw_values[3];
|
|
Packit |
577717 |
values[0] = perf_scale(raw_values);
|
|
Packit |
577717 |
|
|
Packit |
577717 |
raw_values[0] = raw_values[4];
|
|
Packit |
577717 |
values[1] = perf_scale(raw_values);
|
|
Packit |
577717 |
|
|
Packit |
577717 |
ratio = perf_scale_ratio(raw_values);
|
|
Packit |
577717 |
|
|
Packit |
577717 |
k_cycles = (double)(values[1] - cpus[i].prev_values[1])*100.0/ (double)itc_delta;
|
|
Packit |
577717 |
u_cycles = (double)(values[0] - cpus[i].prev_values[0])*100.0/ (double)itc_delta;
|
|
Packit |
577717 |
i_cycles = 100.0 - (k_cycles + u_cycles);
|
|
Packit |
577717 |
|
|
Packit |
577717 |
cpus[i].prev_values[0] = values[0];
|
|
Packit |
577717 |
cpus[i].prev_values[1] = values[1];
|
|
Packit |
577717 |
/*
|
|
Packit |
577717 |
* adjust for rounding errors
|
|
Packit |
577717 |
*/
|
|
Packit |
577717 |
if (i_cycles < 0.0) i_cycles = 0.0;
|
|
Packit |
577717 |
if (i_cycles > 100.0) i_cycles = 100.0;
|
|
Packit |
577717 |
if (k_cycles > 100.0) k_cycles = 100.0;
|
|
Packit |
577717 |
if (u_cycles > 100.0) u_cycles = 100.0;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
printw("CPU%-2ld %6.2f%% usr %6.2f%% sys %6.2f%% idle (scaling ratio %.2f%%)\n",
|
|
Packit |
577717 |
i,
|
|
Packit |
577717 |
u_cycles,
|
|
Packit |
577717 |
k_cycles,
|
|
Packit |
577717 |
i_cycles,
|
|
Packit |
577717 |
ratio*100.0);
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
refresh();
|
|
Packit |
577717 |
|
|
Packit |
577717 |
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
for(i=0; i < ncpus; i++)
|
|
Packit |
577717 |
for(j=0; j < num; j++)
|
|
Packit |
577717 |
close(cpus[i].fd[j]);
|
|
Packit |
577717 |
free(cpus);
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
void
|
|
Packit |
577717 |
populate_cpumask(char *cpu_list)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
char *p;
|
|
Packit |
577717 |
unsigned long start_cpu, end_cpu = 0;
|
|
Packit |
577717 |
unsigned long i, count = 0;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
options.online_cpus = sysconf(_SC_NPROCESSORS_ONLN);
|
|
Packit |
577717 |
if (options.online_cpus == -1)
|
|
Packit |
577717 |
errx(1, "cannot figure out the number of online processors");
|
|
Packit |
577717 |
|
|
Packit |
577717 |
if (cpu_list == NULL) {
|
|
Packit |
577717 |
if (options.online_cpus >= RTOP_MAX_CPUS)
|
|
Packit |
577717 |
errx(1, "rtop can only handle to %u CPUs", RTOP_MAX_CPUS);
|
|
Packit |
577717 |
|
|
Packit |
577717 |
for(i=0; i < options.online_cpus; i++)
|
|
Packit |
577717 |
RTOP_CPUMASK_SET(options.cpu_mask, i);
|
|
Packit |
577717 |
|
|
Packit |
577717 |
options.selected_cpus = options.online_cpus;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
return;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
while(isdigit(*cpu_list)) {
|
|
Packit |
577717 |
p = NULL;
|
|
Packit |
577717 |
start_cpu = strtoul(cpu_list, &p, 0); /* auto-detect base */
|
|
Packit |
577717 |
|
|
Packit |
577717 |
if (start_cpu == ULONG_MAX || (*p != '\0' && *p != ',' && *p != '-'))
|
|
Packit |
577717 |
goto invalid;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
if (p && *p == '-') {
|
|
Packit |
577717 |
cpu_list = ++p;
|
|
Packit |
577717 |
p = NULL;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
end_cpu = strtoul(cpu_list, &p, 0); /* auto-detect base */
|
|
Packit |
577717 |
|
|
Packit |
577717 |
if (end_cpu == ULONG_MAX || (*p != '\0' && *p != ','))
|
|
Packit |
577717 |
goto invalid;
|
|
Packit |
577717 |
if (end_cpu < start_cpu)
|
|
Packit |
577717 |
goto invalid_range;
|
|
Packit |
577717 |
} else {
|
|
Packit |
577717 |
end_cpu = start_cpu;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
if (start_cpu >= RTOP_MAX_CPUS || end_cpu >= RTOP_MAX_CPUS)
|
|
Packit |
577717 |
goto too_big;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
for (; start_cpu <= end_cpu; start_cpu++) {
|
|
Packit |
577717 |
|
|
Packit |
577717 |
if (start_cpu >= options.online_cpus)
|
|
Packit |
577717 |
goto not_online; /* XXX: assume contiguous range of CPUs */
|
|
Packit |
577717 |
|
|
Packit |
577717 |
if (RTOP_CPUMASK_ISSET(options.cpu_mask, start_cpu))
|
|
Packit |
577717 |
continue;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
RTOP_CPUMASK_SET(options.cpu_mask, start_cpu);
|
|
Packit |
577717 |
|
|
Packit |
577717 |
count++;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
if (*p) ++p;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
cpu_list = p;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
options.selected_cpus = count;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
return;
|
|
Packit |
577717 |
invalid:
|
|
Packit |
577717 |
errx(1, "invalid cpu list argument: %s", cpu_list);
|
|
Packit |
577717 |
/* no return */
|
|
Packit |
577717 |
not_online:
|
|
Packit |
577717 |
errx(1, "cpu %lu is not online", start_cpu);
|
|
Packit |
577717 |
/* no return */
|
|
Packit |
577717 |
invalid_range:
|
|
Packit |
577717 |
errx(1, "cpu range %lu - %lu is invalid", start_cpu, end_cpu);
|
|
Packit |
577717 |
/* no return */
|
|
Packit |
577717 |
too_big:
|
|
Packit |
577717 |
errx(1, "rtop is limited to %u CPUs", RTOP_MAX_CPUS);
|
|
Packit |
577717 |
/* no return */
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static void
|
|
Packit |
577717 |
usage(void)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
printf( "usage: rtop [options]:\n"
|
|
Packit |
577717 |
"-h, --help\t\t\tdisplay this help and exit\n"
|
|
Packit |
577717 |
"-v, --verbose\t\t\tverbose output\n"
|
|
Packit |
577717 |
"-V, --version\t\t\tshow version and exit\n"
|
|
Packit |
577717 |
"-d nsec, --delay=nsec\t\tnumber of seconds between refresh (default=1s)\n"
|
|
Packit |
577717 |
"--cpu-list=cpu1,cpu2\t\tlist of CPUs to monitor(default=all)\n"
|
|
Packit |
577717 |
);
|
|
Packit |
577717 |
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
int
|
|
Packit |
577717 |
main(int argc, char **argv)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
int c;
|
|
Packit |
577717 |
char *cpu_list = NULL;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
//if (geteuid()) err(1, "perf_event requires root privileges to create system-wide measurments\n");
|
|
Packit |
577717 |
|
|
Packit |
577717 |
while ((c=getopt_long(argc, argv,"+vhVd:", rtop_cmd_options, 0)) != -1) {
|
|
Packit |
577717 |
switch(c) {
|
|
Packit |
577717 |
case 0: continue; /* fast path for options */
|
|
Packit |
577717 |
case 'v': options.opt_verbose = 1;
|
|
Packit |
577717 |
break;
|
|
Packit |
577717 |
case 1:
|
|
Packit |
577717 |
case 'h':
|
|
Packit |
577717 |
usage();
|
|
Packit |
577717 |
exit(0);
|
|
Packit |
577717 |
case 2:
|
|
Packit |
577717 |
case 'V':
|
|
Packit |
577717 |
printf("rtop version " RTOP_VERSION " Date: " __DATE__ "\n"
|
|
Packit |
577717 |
"Copyright (C) 2009 Google, Inc\n");
|
|
Packit |
577717 |
exit(0);
|
|
Packit |
577717 |
case 3:
|
|
Packit |
577717 |
case 'd':
|
|
Packit |
577717 |
options.opt_delay = atoi(optarg);
|
|
Packit |
577717 |
if (options.opt_delay < 0)
|
|
Packit |
577717 |
errx(1, "invalid delay, must be >= 0");
|
|
Packit |
577717 |
options.opt_delay_set = 1;
|
|
Packit |
577717 |
break;
|
|
Packit |
577717 |
case 4:
|
|
Packit |
577717 |
if (*optarg == '\0')
|
|
Packit |
577717 |
errx(1, "--cpu-list needs an argument\n");
|
|
Packit |
577717 |
cpu_list = optarg;
|
|
Packit |
577717 |
break;
|
|
Packit |
577717 |
default:
|
|
Packit |
577717 |
errx(1, "unknown option\n");
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
/*
|
|
Packit |
577717 |
* default refresh delay
|
|
Packit |
577717 |
*/
|
|
Packit |
577717 |
if (options.opt_delay_set == 0)
|
|
Packit |
577717 |
options.opt_delay = 1;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
options.cpu_mhz = find_cpu_speed();
|
|
Packit |
577717 |
|
|
Packit |
577717 |
populate_cpumask(cpu_list);
|
|
Packit |
577717 |
|
|
Packit |
577717 |
setup_signals();
|
|
Packit |
577717 |
setup_screen();
|
|
Packit |
577717 |
mainloop();
|
|
Packit |
577717 |
close_screen();
|
|
Packit |
577717 |
|
|
Packit |
577717 |
return 0;
|
|
Packit |
577717 |
}
|