HelenOS sources
This source file includes following definitions.
- list_tasks
- list_threads
- list_ipccs
- list_cpus
- print_load
- print_uptime
- escape_dot
- print_arch
- usage
- main
#include <stdio.h>
#include <task.h>
#include <stats.h>
#include <errno.h>
#include <stdlib.h>
#include <stdlib.h>
#include <inttypes.h>
#include <stdbool.h>
#include <str.h>
#include <arg_parse.h>
#define NAME "stats"
#define DAY 86400
#define HOUR 3600
#define MINUTE 60
#define KERNEL_NAME "kernel"
#define INIT_PREFIX "init:"
typedef enum {
LIST_TASKS,
LIST_THREADS,
LIST_IPCCS,
LIST_CPUS,
PRINT_LOAD,
PRINT_UPTIME,
PRINT_ARCH
} output_toggle_t;
static void list_tasks(void)
{
size_t count;
stats_task_t *stats_tasks = stats_get_tasks(&count);
if (stats_tasks == NULL) {
fprintf(stderr, "%s: Unable to get tasks\n", NAME);
return;
}
printf("[taskid] [thrds] [resident] [virtual] [ucycles]"
" [kcycles] [name\n");
for (size_t i = 0; i < count; i++) {
uint64_t resmem;
uint64_t virtmem;
uint64_t ucycles;
uint64_t kcycles;
const char *resmem_suffix;
const char *virtmem_suffix;
char usuffix;
char ksuffix;
bin_order_suffix(stats_tasks[i].resmem, &resmem, &resmem_suffix, true);
bin_order_suffix(stats_tasks[i].virtmem, &virtmem, &virtmem_suffix, true);
order_suffix(stats_tasks[i].ucycles, &ucycles, &usuffix);
order_suffix(stats_tasks[i].kcycles, &kcycles, &ksuffix);
printf("%-8" PRIu64 " %7zu %7" PRIu64 "%s %6" PRIu64 "%s"
" %8" PRIu64 "%c %8" PRIu64 "%c %s\n",
stats_tasks[i].task_id, stats_tasks[i].threads,
resmem, resmem_suffix, virtmem, virtmem_suffix,
ucycles, usuffix, kcycles, ksuffix, stats_tasks[i].name);
}
free(stats_tasks);
}
static void list_threads(task_id_t task_id, bool all)
{
size_t count;
stats_thread_t *stats_threads = stats_get_threads(&count);
if (stats_threads == NULL) {
fprintf(stderr, "%s: Unable to get threads\n", NAME);
return;
}
printf("[taskid] [threadid] [state ] [prio] [cpu ] [ucycles] [kcycles]\n");
for (size_t i = 0; i < count; i++) {
if ((all) || (stats_threads[i].task_id == task_id)) {
uint64_t ucycles, kcycles;
char usuffix, ksuffix;
order_suffix(stats_threads[i].ucycles, &ucycles, &usuffix);
order_suffix(stats_threads[i].kcycles, &kcycles, &ksuffix);
printf("%-8" PRIu64 " %-10" PRIu64 " %-8s %6d ",
stats_threads[i].task_id, stats_threads[i].thread_id,
thread_get_state(stats_threads[i].state),
stats_threads[i].priority);
if (stats_threads[i].on_cpu)
printf("%6u ", stats_threads[i].cpu);
else
printf("(none) ");
printf("%8" PRIu64 "%c %8" PRIu64 "%c\n",
ucycles, usuffix, kcycles, ksuffix);
}
}
free(stats_threads);
}
static void list_ipccs(task_id_t task_id, bool all)
{
size_t count;
stats_ipcc_t *stats_ipccs = stats_get_ipccs(&count);
if (stats_ipccs == NULL) {
fprintf(stderr, "%s: Unable to get IPC connections\n", NAME);
return;
}
printf("[caller] [callee]\n");
for (size_t i = 0; i < count; i++) {
if ((all) || (stats_ipccs[i].caller == task_id)) {
printf("%-8" PRIu64 " %-8" PRIu64 "\n",
stats_ipccs[i].caller, stats_ipccs[i].callee);
}
}
free(stats_ipccs);
}
static void list_cpus(void)
{
size_t count;
stats_cpu_t *cpus = stats_get_cpus(&count);
if (cpus == NULL) {
fprintf(stderr, "%s: Unable to get CPU statistics\n", NAME);
return;
}
printf("[id] [MHz ] [busy cycles] [idle cycles]\n");
for (size_t i = 0; i < count; i++) {
printf("%-4u ", cpus[i].id);
if (cpus[i].active) {
uint64_t bcycles, icycles;
char bsuffix, isuffix;
order_suffix(cpus[i].busy_cycles, &bcycles, &bsuffix);
order_suffix(cpus[i].idle_cycles, &icycles, &isuffix);
printf("%10" PRIu16 " %12" PRIu64 "%c %12" PRIu64 "%c\n",
cpus[i].frequency_mhz, bcycles, bsuffix,
icycles, isuffix);
} else
printf("inactive\n");
}
free(cpus);
}
static void print_load(void)
{
size_t count;
load_t *load = stats_get_load(&count);
if (load == NULL) {
fprintf(stderr, "%s: Unable to get load\n", NAME);
return;
}
printf("%s: Load average: ", NAME);
for (size_t i = 0; i < count; i++) {
if (i > 0)
printf(" ");
stats_print_load_fragment(load[i], 2);
}
printf("\n");
free(load);
}
static void print_uptime(void)
{
struct timespec uptime;
getuptime(&uptime);
printf("%s: Up %lld days, %lld hours, %lld minutes, %lld seconds\n",
NAME, uptime.tv_sec / DAY, (uptime.tv_sec % DAY) / HOUR,
(uptime.tv_sec % HOUR) / MINUTE, uptime.tv_sec % MINUTE);
}
static char *escape_dot(const char *str)
{
size_t size = 0;
for (size_t i = 0; str[i] != 0; i++) {
if (str[i] == '"')
size++;
size++;
}
char *escaped_str = calloc(size + 1, sizeof(char));
if (escaped_str == NULL)
return NULL;
size_t pos = 0;
for (size_t i = 0; str[i] != 0; i++) {
if (str[i] == '"') {
escaped_str[pos] = '\\';
pos++;
}
escaped_str[pos] = str[i];
pos++;
}
escaped_str[pos] = 0;
return escaped_str;
}
static void print_arch(void)
{
size_t count_tasks;
stats_task_t *stats_tasks = stats_get_tasks(&count_tasks);
if (stats_tasks == NULL) {
fprintf(stderr, "%s: Unable to get tasks\n", NAME);
return;
}
size_t count_ipccs;
stats_ipcc_t *stats_ipccs = stats_get_ipccs(&count_ipccs);
if (stats_ipccs == NULL) {
fprintf(stderr, "%s: Unable to get IPC connections\n", NAME);
return;
}
printf("digraph HelenOS {\n");
printf("\tlayout=sfdp\n");
printf("\t// layout=neato\n");
printf("\tsplines=true\n");
printf("\t// splines=ortho\n");
printf("\tconcentrate=true\n");
printf("\tcenter=true\n");
printf("\toverlap=false\n");
printf("\toutputorder=edgesfirst\n");
printf("\tfontsize=12\n");
printf("\tnode [shape=component style=filled color=red "
"fillcolor=yellow]\n\t\n");
bool kernel_found = false;
task_id_t kernel_id = 0;
for (size_t i = 0; i < count_tasks; i++) {
bool kernel = (str_cmp(stats_tasks[i].name, KERNEL_NAME) == 0);
bool init = str_test_prefix(stats_tasks[i].name, INIT_PREFIX);
char *escaped_name = NULL;
if (init)
escaped_name = escape_dot(str_suffix(stats_tasks[i].name,
str_length(INIT_PREFIX)));
else
escaped_name = escape_dot(stats_tasks[i].name);
if (escaped_name == NULL)
continue;
if (kernel) {
if (kernel_found) {
fprintf(stderr, "%s: Duplicate kernel tasks\n", NAME);
} else {
kernel_found = true;
kernel_id = stats_tasks[i].task_id;
}
printf("\ttask%" PRIu64 " [label=\"%s\" shape=invtrapezium "
"fillcolor=gold]\n", stats_tasks[i].task_id, escaped_name);
} else if (init)
printf("\ttask%" PRIu64 " [label=\"%s\" fillcolor=orange]\n",
stats_tasks[i].task_id, escaped_name);
else
printf("\ttask%" PRIu64 " [label=\"%s\"]\n", stats_tasks[i].task_id,
escaped_name);
free(escaped_name);
}
printf("\t\n");
if (kernel_found) {
for (size_t i = 0; i < count_tasks; i++) {
if (stats_tasks[i].task_id == kernel_id)
continue;
printf("\ttask%" PRIu64 " -> task%" PRIu64 " [style=\"invis\"]\n",
stats_tasks[i].task_id, kernel_id);
}
}
printf("\t\n");
for (size_t i = 0; i < count_ipccs; i++) {
printf("\ttask%" PRIu64 " -> task%" PRIu64 "\n",
stats_ipccs[i].caller, stats_ipccs[i].callee);
}
printf("}\n");
free(stats_tasks);
free(stats_ipccs);
}
static void usage(const char *name)
{
printf(
"Usage: %s [-t task_id] [-i task_id] [-at] [-ai] [-c] [-l] [-u] [-d]\n"
"\n"
"Options:\n"
"\t-t task_id | --task=task_id\n"
"\t\tList threads of the given task\n"
"\n"
"\t-i task_id | --ipcc=task_id\n"
"\t\tList IPC connections of the given task\n"
"\n"
"\t-at | --all-threads\n"
"\t\tList all threads\n"
"\n"
"\t-ai | --all-ipccs\n"
"\t\tList all IPC connections\n"
"\n"
"\t-c | --cpus\n"
"\t\tList CPUs\n"
"\n"
"\t-l | --load\n"
"\t\tPrint system load\n"
"\n"
"\t-u | --uptime\n"
"\t\tPrint system uptime\n"
"\n"
"\t-d | --design\n"
"\t\tPrint the current system architecture graph\n"
"\n"
"\t-h | --help\n"
"\t\tPrint this usage information\n"
"\n"
"Without any options all tasks are listed\n",
name);
}
int main(int argc, char *argv[])
{
output_toggle_t output_toggle = LIST_TASKS;
bool toggle_all = false;
task_id_t task_id = 0;
for (int i = 1; i < argc; i++) {
int off;
if ((off = arg_parse_short_long(argv[i], "-h", "--help")) != -1) {
usage(argv[0]);
return 0;
}
if ((off = arg_parse_short_long(argv[i], "-ai", "--all-ipccs")) != -1) {
output_toggle = LIST_IPCCS;
toggle_all = true;
continue;
}
if ((off = arg_parse_short_long(argv[i], "-at", "--all-threads")) != -1) {
output_toggle = LIST_THREADS;
toggle_all = true;
continue;
}
if ((off = arg_parse_short_long(argv[i], "-i", "--ipcc=")) != -1) {
int tmp;
errno_t ret = arg_parse_int(argc, argv, &i, &tmp, off);
if (ret != EOK) {
printf("%s: Malformed task id '%s'\n", NAME, argv[i]);
return -1;
}
task_id = tmp;
output_toggle = LIST_IPCCS;
continue;
}
if ((off = arg_parse_short_long(argv[i], "-t", "--task=")) != -1) {
int tmp;
errno_t ret = arg_parse_int(argc, argv, &i, &tmp, off);
if (ret != EOK) {
printf("%s: Malformed task id '%s'\n", NAME, argv[i]);
return -1;
}
task_id = tmp;
output_toggle = LIST_THREADS;
continue;
}
if ((off = arg_parse_short_long(argv[i], "-c", "--cpus")) != -1) {
output_toggle = LIST_CPUS;
continue;
}
if ((off = arg_parse_short_long(argv[i], "-l", "--load")) != -1) {
output_toggle = PRINT_LOAD;
continue;
}
if ((off = arg_parse_short_long(argv[i], "-u", "--uptime")) != -1) {
output_toggle = PRINT_UPTIME;
continue;
}
if ((off = arg_parse_short_long(argv[i], "-d", "--design")) != -1) {
output_toggle = PRINT_ARCH;
continue;
}
}
switch (output_toggle) {
case LIST_TASKS:
list_tasks();
break;
case LIST_THREADS:
list_threads(task_id, toggle_all);
break;
case LIST_IPCCS:
list_ipccs(task_id, toggle_all);
break;
case LIST_CPUS:
list_cpus();
break;
case PRINT_LOAD:
print_load();
break;
case PRINT_UPTIME:
print_uptime();
break;
case PRINT_ARCH:
print_arch();
break;
}
return 0;
}
HelenOS homepage, sources at GitHub