blob: 35880cd1197a5ff92d05462f19a9c3884d6eb3f4 [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 <time.h>
#include <unistd.h>
#include <style.h>
#include "ktop.h"
#include "plot.h"
#include "syscall.h"
#include "tickcounter.h"
enum { HELP_ROW = 0,
HELP_COL = 0,
RW_ROW = HELP_ROW + 1,
RW_COL = 0,
PID_ROW = RW_ROW + 6,
PID_COL = 0,
TOP_ROW = RW_ROW + 6,
TOP_COL = 70,
SELF_ROW = HELP_ROW + 1,
SELF_COL = 40 };
typedef struct Top_ten_s {
int syscall;
int value;
} Top_ten_s;
bool Plot = FALSE;
static u64 A[NUM_SYS_CALLS];
static u64 B[NUM_SYS_CALLS];
static u64 *Old = A;
static u64 *New = B;
static int Delta[NUM_SYS_CALLS];
static Top_ten_s Top_ten[10];
static TickCounter_s TotalDelta;
static graph_s TotalGraph = {{0, 0}, {{0, 10}, {60, 20}}};
static void help(void)
{
mvprintw(HELP_ROW, HELP_COL,
"q - quit c - clear");
}
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;
name[rc] = '\0';
return name; //strdup(name);
}
static void read_write(void)
{
mvprintw(RW_ROW, RW_COL, " total hits/sec");
mvprintw(RW_ROW+1, RW_COL, "read: %10lld %10d",
New[sys_read], Delta[sys_read]);
mvprintw(RW_ROW+2, RW_COL, "write: %10lld %10d",
New[sys_write], Delta[sys_write]);
mvprintw(RW_ROW+3, RW_COL, "pread: %10lld %10d",
New[sys_pread64], Delta[sys_pread64]);
mvprintw(RW_ROW+4, RW_COL, "pwrite:%10lld %10d",
New[sys_pwrite64], Delta[sys_pwrite64]);
}
static void self(void)
{
mvprintw(SELF_ROW, SELF_COL, "Skipped: %8lld", MyPidCount);
mvprintw(SELF_ROW+1, SELF_COL, "Slept: %8lld", Slept);
}
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(TOP_ROW, TOP_COL, "max: %d %d", pid, max);
}
static void display_pidcall(void)
{
Pidcall_s *p = Pidcall;
int row = PID_ROW;
int col = PID_COL;
int pid;
int i;
mvprintw(row++, col, " pid total");
for (i = 0; i < 25; i++, p++, row++) {
if (p == Pidnext) return;
pid = get_pid(p->pidcall);
mvprintw(row, col, "%3d. %5d %6d %-22.22s %-28.28s",
i+1, pid, p->count,
Syscall[get_call(p->pidcall)],
getpidname(pid));
}
}
static void display_top_ten(void)
{
int row = TOP_ROW + 1;
int i;
mvprintw(row++, TOP_COL, " hits 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 delta(void)
{
u64 *tmp;
int sum;
int i;
tmp = Old;
Old = New;
New = tmp;
memmove(New, Syscall_count, sizeof(Syscall_count));
sum = 0;
for (i = 0; i < NUM_SYS_CALLS; i++) {
Delta[i] = New[i] - Old[i];
sum += Delta[i];
}
tick(&TotalDelta, sum);
top_ten();
}
static void graph_total(void)
{
vector_s v = new_vector(WHEEL_SIZE);
int i;
int j;
j = TotalDelta.itick;
for (i = 0; i < WHEEL_SIZE; i++) {
v.p[i].x = j;
v.p[i].y = TotalDelta.tick[j];
if (++j == WHEEL_SIZE) {
j = 0;
}
}
vplot(&TotalGraph, v, '*');
}
static void init(void)
{
initscr();
cbreak();
noecho();
nonl();
idlok(stdscr, TRUE);
keypad(stdscr, TRUE);
init_counter(&TotalDelta, 1);
}
void *display(void *arg)
{
struct timespec sleep = { 1, 0 };
ignore_pid(gettid());
init();
for (;;) {
if (Command) {
return NULL;
}
delta();
if (Plot) {
clear();
graph_total();
} else {
top_pid();
display_pidcall();
display_top_ten();
}
help();
read_write();
self();
refresh();
nanosleep(&sleep, NULL);
}
}
void clear_display(void)
{
zero(A);
zero(B);
zero(Pid);
zero(Syscall_count);
MyPidCount = 0;
Slept = 0;
}
void cleanup_display(void)
{
endwin();
}