/*
* Copyright (c) 2008, The Android Open Source Project
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google, Inc. nor the names of its contributors
* may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <ctype.h>
#include <dirent.h>
#include <grp.h>
#include <pwd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include "sched_policy.h"
struct cpu_info {
long unsigned utime, ntime, stime, itime;
long unsigned iowtime, irqtime, sirqtime;
};
#define PROC_NAME_LEN 64
#define THREAD_NAME_LEN 32
#define POLICY_NAME_LEN 4
struct proc_info {
struct proc_info *next;
pid_t pid;
pid_t tid;
uid_t uid;
gid_t gid;
char name[PROC_NAME_LEN];
char tname[THREAD_NAME_LEN];
char state;
long unsigned utime;
long unsigned stime;
long unsigned delta_utime;
long unsigned delta_stime;
long unsigned delta_time;
long vss;
long rss;
int prs;
int num_threads;
char policy[POLICY_NAME_LEN];
};
struct proc_list {
struct proc_info **array;
int size;
};
#define die(...) { fprintf(stderr, __VA_ARGS__); exit(EXIT_FAILURE); }
#define INIT_PROCS 50
#define THREAD_MULT 8
static struct proc_info **old_procs, **new_procs;
static int num_old_procs, num_new_procs;
static struct proc_info *free_procs;
static int num_used_procs, num_free_procs;
static int max_procs, delay, iterations, threads;
static struct cpu_info old_cpu, new_cpu;
static struct proc_info *alloc_proc(void);
static void free_proc(struct proc_info *proc);
static void read_procs(void);
static int read_stat(char *filename, struct proc_info *proc);
static void read_policy(int pid, struct proc_info *proc);
static void add_proc(int proc_num, struct proc_info *proc);
static int read_cmdline(char *filename, struct proc_info *proc);
static int read_status(char *filename, struct proc_info *proc);
static void print_procs(void);
static struct proc_info *find_old_proc(pid_t pid, pid_t tid);
static void free_old_procs(void);
static int (*proc_cmp)(const void *a, const void *b);
static int proc_cpu_cmp(const void *a, const void *b);
static int proc_vss_cmp(const void *a, const void *b);
static int proc_rss_cmp(const void *a, const void *b);
static int proc_thr_cmp(const void *a, const void *b);
static int numcmp(long long a, long long b);
static void usage(char *cmd);
int top_main(int argc, char *argv[]) {
int i;
num_used_procs = num_free_procs = 0;
max_procs = 0;
delay = 3;
iterations = -1;
proc_cmp = &proc_cpu_cmp;
for (i = 1; i < argc; i++) {
if (!strcmp(argv[i], "-m")) {
if (i + 1 >= argc) {
fprintf(stderr, "Option -m expects an argument.\n");
usage(argv[0]);
exit(EXIT_FAILURE);
}
max_procs = atoi(argv[++i]);
continue;
}
if (!strcmp(argv[i], "-n")) {
if (i + 1 >= argc) {
fprintf(stderr, "Option -n expects an argument.\n");
usage(argv[0]);
exit(EXIT_FAILURE);
}
iterations = atoi(argv[++i]);
continue;
}
if (!strcmp(argv[i], "-d")) {
if (i + 1 >= argc) {
fprintf(stderr, "Option -d expects an argument.\n");
usage(argv[0]);
exit(EXIT_FAILURE);
}
delay = atoi(argv[++i]);
continue;
}
if (!strcmp(argv[i], "-s")) {
if (i + 1 >= argc) {
fprintf(stderr, "Option -s expects an argument.\n");
usage(argv[0]);
exit(EXIT_FAILURE);
}
++i;
if (!strcmp(argv[i], "cpu")) { proc_cmp = &proc_cpu_cmp; continue; }
if (!strcmp(argv[i], "vss")) { proc_cmp = &proc_vss_cmp; continue; }
if (!strcmp(argv[i], "rss")) { proc_cmp = &proc_rss_cmp; continue; }
if (!strcmp(argv[i], "thr")) { proc_cmp = &proc_thr_cmp; continue; }
fprintf(stderr, "Invalid argument \"%s\" for option -s.\n", argv[i]);
exit(EXIT_FAILURE);
}
if (!strcmp(argv[i], "-t")) { threads = 1; continue; }
if (!strcmp(argv[i], "-h")) {
usage(argv[0]);
exit(EXIT_SUCCESS);
}
fprintf(stderr, "Invalid argument \"%s\".\n", argv[i]);
usage(argv[0]);
exit(EXIT_FAILURE);
}
if (threads && proc_cmp == &proc_thr_cmp) {
fprintf(stderr, "Sorting by threads per thread makes no sense!\n");
exit(EXIT_FAILURE);
}
free_procs = NULL;
num_new_procs = num_old_procs = 0;
new_procs = old_procs = NULL;
read_procs();
while ((iterations == -1) || (iterations-- > 0)) {
old_procs = new_procs;
num_old_procs = num_new_procs;
memcpy(&old_cpu, &new_cpu, sizeof(old_cpu));
sleep(delay);
read_procs();
print_procs();
free_old_procs();
}
return 0;
}
int main(int argc, char *argv[]) {
return top_main(argc, argv);
}
static struct proc_info *alloc_proc(void) {
struct proc_info *proc;
if (free_procs) {
proc = free_procs;
free_procs = free_procs->next;
num_free_procs--;
} else {
proc = malloc(sizeof(*proc));
if (!proc) die("Could not allocate struct process_info.\n");
}
num_used_procs++;
return proc;
}
static void free_proc(struct proc_info *proc) {
proc->next = free_procs;
free_procs = proc;
num_used_procs--;
num_free_procs++;
}
#define MAX_LINE 256
static void read_procs(void) {
DIR *proc_dir, *task_dir;
struct dirent *pid_dir, *tid_dir;
char filename[64];
FILE *file;
int proc_num;
struct proc_info *proc;
pid_t pid, tid;
int i;
proc_dir = opendir("/proc");
if (!proc_dir) die("Could not open /proc.\n");
new_procs = calloc(INIT_PROCS * (threads ? THREAD_MULT : 1), sizeof(struct proc_info *));
num_new_procs = INIT_PROCS * (threads ? THREAD_MULT : 1);
file = fopen("/proc/stat", "r");
if (!file) die("Could not open /proc/stat.\n");
fscanf(file, "cpu %lu %lu %lu %lu %lu %lu %lu", &new_cpu.utime, &new_cpu.ntime, &new_cpu.stime,
&new_cpu.itime, &new_cpu.iowtime, &new_cpu.irqtime, &new_cpu.sirqtime);
fclose(file);
proc_num = 0;
while ((pid_dir = readdir(proc_dir))) {
if (!isdigit(pid_dir->d_name[0]))
continue;
pid = atoi(pid_dir->d_name);
struct proc_info cur_proc;
if (