blob: 3745a3060f11a0a82e532ce89235c0881875d0f5 [file] [log] [blame]
/*
* Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
* Distributed under the terms of the GNU General Public License v2
*/
#include <ncurses.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <debug.h>
#include <eprintf.h>
#include <style.h>
#include "ktop.h"
#include "plot.h"
#include "reduce.h"
#include "syscall.h"
#include "tickcounter.h"
enum { HELP_ROW = 0,
HELP_COL = 0,
TOP_ROW = HELP_ROW + 1,
TOP_COL = 0,
RW_ROW = HELP_ROW + 1,
RW_COL = 0,
PID_ROW = TOP_ROW + 12,
PID_COL = 0,
SELF_ROW = HELP_ROW + 1,
SELF_COL = 0,
MAX_ROW = SELF_ROW,
MAX_COL = SELF_COL + 40,
TOP_PID_CALL_ROW = TOP_ROW,
TOP_PID_CALL_COL = 35,
};
typedef struct Top_ten_s {
int syscall;
int value;
} Top_ten_s;
typedef struct Display_call_s {
char *name;
int index;
} Display_call_s;
/* Top ten highest count for pid/sys_call */
static Top_ten_s Top_ten[10];
/* Defines graph area for total system calls */
static graph_s TotalGraph = {{0, 0}, {{0, 10}, {60, 20}}};
Display_call_s Display_call[] = {
{ "read: ", sys_read },
{ "write: ", sys_write },
{ "pread: ", sys_pread64 },
{ "pwrite:", sys_pwrite64 },
{ "sync: ", sys_sync },
{ "fsync: ", sys_fsync },
{ "open: ", sys_open },
{ "close: ", sys_close },
{ "creat: ", sys_creat },
{ "unlink:", sys_unlink },
{ "stat: ", sys_stat64 },
{ "fstat: ", sys_fstat64 },
{ "fork: ", ptregs_fork },
{ "vfork: ", ptregs_vfork },
{ NULL, 0 }};
static void help(void)
{
mvprintw(HELP_ROW, HELP_COL,
"q quit c clear k kernel ops g graph op"
" i internal ops f file ops"
" p pause"
" < shorter > longer %d.%.3d",
Sleep.tv_sec, Sleep.tv_nsec / ONE_MILLION);
}
static void file_system(void)
{
Display_call_s *d;
int row = RW_ROW;
mvprintw(row, RW_COL, " total hits/sec");
for (d = Display_call; d->name; d++) {
mvprintw(++row, RW_COL, "%s %10lld %10d",
d->name, New[d->index], Delta[d->index]);
}
}
static void self(void)
{
static double max = 0;
double avg;
mvprintw(SELF_ROW, SELF_COL, "Skipped: %12lld", Ignored_pid_count);
mvprintw(SELF_ROW+1, SELF_COL, "Slept: %12lld", Slept);
mvprintw(SELF_ROW+2, SELF_COL, "Tick: %12zd", sizeof(TickCounter_s));
mvprintw(SELF_ROW+3, SELF_COL, "No_enter: %12lld", No_enter);
mvprintw(SELF_ROW+4, SELF_COL, "Found: %12lld", Found);
mvprintw(SELF_ROW+5, SELF_COL, "Out_of_order:%12lld", Out_of_order);
mvprintw(SELF_ROW+6, SELF_COL, "No_start: %12lld", No_start);
mvprintw(SELF_ROW+7, SELF_COL, "Bad type: %12lld", Bad_type);
if (1) {
mvprintw(SELF_ROW+10, SELF_COL, "Ticks: %12lld", Pidcall_tick);
if (Pidcall_record == 0) return;
avg = (double)Pidcall_iterations / (double)Pidcall_record;
Pidcall_iterations = Pidcall_record = 0;
if (avg > max) max =avg;
mvprintw(SELF_ROW+11, SELF_COL, "Avg: %g", avg);
mvprintw(SELF_ROW+12, SELF_COL, "Max: %g", max);
}
mvprintw(SELF_ROW+14, SELF_COL, "COLS: %12d", COLS);
mvprintw(SELF_ROW+15, SELF_COL, "LINES: %12d", LINES);
}
static void top_pid(void)
{
int max = 0;
int pid = 0;
int i;
for (i = 0; i < MAX_PID; i++) {
if (Pid[i] > max) {
max = Pid[i];
pid = i;
}
}
mvprintw(MAX_ROW, MAX_COL, "max: %d %d", pid, max);
}
static char *getpidname(int pid)
{
char path[100];
static char name[4096];
int rc;
snprintf(path, sizeof(path), "/proc/%d/exe", pid);
rc = readlink(path, name, sizeof(name));
if (rc == -1) {
return NULL;
}
if (rc == sizeof(name)) {
fatal("pid name too long");
}
name[rc] = '\0';
return strdup(name);
}
static void display_pidcall(void)
{
Pidcall_s *pc;
int row = PID_ROW;
int col = PID_COL;
int pid;
int i;
mvprintw(row++, col, "%3d pid count duration", Num_rank);
for (i = 0; i < 25 && i < Num_rank; i++, row++) {
pc = Rank_pidcall[i];
pid = get_pid(pc->pidcall);
if (!pc->name) {
pc->name = getpidname(pid);
if (!pc->name) {
pc->name = strdup("(unknown)");
}
}
mvprintw(row, col, "%3d. %5d %6d %10lld %-22.22s %-28.28s",
i + 1, pid, pc->save.count,
pc->save.count ? pc->save.time / pc->save.count : 0LL,
Syscall[get_call(pc->pidcall)],
pc->name);
mvprintw(row, col+80, "%8lx %8lx %8lx",
pc->arg[0], pc->arg[1], pc->arg[2]);
}
}
static void display_top_pidcall(void)
{
TopPidcall_s *tc;
int row = TOP_PID_CALL_ROW;
int col = TOP_PID_CALL_COL;
mvprintw(row++, col, " count duration when pid");
for (tc = Top_pidcall; tc < &Top_pidcall[MAX_TOP]; tc++, row++) {
if (tc->count == 0) return;
mvprintw(row, col,
"%8d %10lld %6d %6d %-22.22s %-30.30s",
tc->count, tc->time / tc->count,
tc->tick, get_pid(tc->pidcall),
Syscall[get_call(tc->pidcall)],
tc->name);
}
}
static void display_top_ten(void)
{
int row = TOP_ROW;
int i;
mvprintw(row++, TOP_COL, " count sys_call");
for (i = 0; i < 10; i++, row++) {
if (Top_ten[i].value == 0) return;
mvprintw(row, TOP_COL, "%8d %-22.22s",
Top_ten[i].value, Syscall[Top_ten[i].syscall]);
}
}
static void top_ten_insert(int x, int syscall)
{
int i;
for (i = 0; i < 10; i++) {
if (x > Top_ten[i].value) {
memmove( &Top_ten[i+1], &Top_ten[i],
(10 - (i + 1)) * sizeof(Top_ten[i]));
Top_ten[i].value = x;
Top_ten[i].syscall = syscall;
return;
}
}
}
static void top_ten(void)
{
int x;
int i;
zero(Top_ten);
for (i = 0; i < NUM_SYS_CALLS; i++) {
x = Delta[i];
if (x > Top_ten[9].value) {
top_ten_insert(x, i);
}
}
}
static void graph_total(void)
{
vector_s v = new_vector(WHEEL_SIZE);
int i;
int j;
j = Total_delta.itick;
for (i = 0; i < WHEEL_SIZE; i++) {
v.p[i].x = j;
v.p[i].y = Total_delta.tick[j];
if (++j == WHEEL_SIZE) {
j = 0;
}
}
vplot(&TotalGraph, v, '*');
}
void init_display(void)
{
initscr();
cbreak();
noecho();
nonl();
idlok(stdscr, TRUE);
keypad(stdscr, TRUE);
init_counter(&Total_delta, 1);
}
void kernel_display(void)
{
clear();
top_ten();
display_pidcall();
display_top_ten();
display_top_pidcall();
help();
refresh();
}
void plot_display(void)
{
clear();
top_ten();
graph_total();
help();
refresh();
}
void internal_display(void)
{
clear();
help();
self();
top_pid();
refresh();
}
void file_system_display(void)
{
clear();
help();
file_system();
refresh();
}
void cleanup_display(void)
{
endwin();
}