diff --git a/src/emu/CMakeLists.txt b/src/emu/CMakeLists.txt index 29c7762..bd467ee 100644 --- a/src/emu/CMakeLists.txt +++ b/src/emu/CMakeLists.txt @@ -66,6 +66,9 @@ target_link_libraries(ovnidump emu parson-static ovni-static) add_executable(ovnisort ovnisort.c) target_link_libraries(ovnisort emu parson-static ovni-static) +add_executable(ovnitop ovnitop.c) +target_link_libraries(ovnitop emu parson-static ovni-static) + set(USE_MPI ON CACHE BOOL "Use MPI (required by ovnisync)") if(USE_MPI) # Use _ROOT variables if available, commonly used by MPI @@ -81,4 +84,4 @@ else() message(STATUS "Disabling ovnisync as MPI is disabled") endif() -install(TARGETS ovniemu ovnidump ovnisort RUNTIME DESTINATION bin) +install(TARGETS ovniemu ovnidump ovnisort ovnitop RUNTIME DESTINATION bin) diff --git a/src/emu/ovnitop.c b/src/emu/ovnitop.c new file mode 100644 index 0000000..59580d1 --- /dev/null +++ b/src/emu/ovnitop.c @@ -0,0 +1,157 @@ +/* Copyright (c) 2023 Barcelona Supercomputing Center (BSC) + * SPDX-License-Identifier: GPL-3.0-or-later */ + +#include +#include +#include +#include +#include "common.h" +#include "emu_ev.h" +#include "emu_stat.h" +#include "ovni.h" +#include "player.h" +#include "trace.h" +#include "uthash.h" + +struct entry { + char mcv[4]; + long count; + UT_hash_handle hh; +}; + +char *tracedir; +struct entry *table = NULL; + +static void +accum(struct player *player) +{ + struct emu_ev *ev = player_ev(player); + struct entry *e = NULL; + HASH_FIND_STR(table, ev->mcv, e); + + if (e == NULL) { + e = calloc(1, sizeof(struct entry)); + if (e == NULL) + die("calloc failed:"); + + strcpy(e->mcv, ev->mcv); + e->count = 1; + HASH_ADD_STR(table, mcv, e); + } else { + e->count++; + } +} + +static int +by_count(struct entry *a, struct entry *b) +{ + if (a->count < b->count) + return +1; + if (a->count > b->count) + return -1; + + /* Otherwise they have the same count, sort by mcv */ + return strcmp(a->mcv, b->mcv); +} + +static void +report(void) +{ + HASH_SORT(table, by_count); + + for (struct entry *e = table; e; e = e->hh.next) + printf("%s %10ld\n", e->mcv, e->count); +} + +static void +usage(void) +{ + rerr("Usage: ovnitop DIR\n"); + rerr("\n"); + rerr("Show most common events in a trace.\n"); + rerr("\n"); + rerr(" DIR Directory containing ovni traces (%s) or single stream.\n", + OVNI_STREAM_EXT); + rerr("\n"); + + exit(EXIT_FAILURE); +} + +static void +parse_args(int argc, char *argv[]) +{ + int opt; + + while ((opt = getopt(argc, argv, "h")) != -1) { + switch (opt) { + case 'h': + default: /* '?' */ + usage(); + } + } + + if (optind >= argc) { + err("bad usage: missing directory"); + usage(); + } + + tracedir = argv[optind]; +} + +int +main(int argc, char *argv[]) +{ + progname_set("ovnitop"); + + parse_args(argc, argv); + + struct trace *trace = calloc(1, sizeof(struct trace)); + + if (trace == NULL) { + err("calloc failed:"); + return 1; + } + + if (trace_load(trace, tracedir) != 0) { + err("failed to load trace: %s", tracedir); + return 1; + } + + struct player *player = calloc(1, sizeof(struct player)); + if (player == NULL) { + err("calloc failed:"); + return 1; + } + + if (player_init(player, trace, 1) != 0) { + err("player_init failed"); + return 1; + } + + int ret; + + struct emu_stat stat; + + emu_stat_init(&stat); + + while ((ret = player_step(player)) == 0) { + accum(player); + emu_stat_update(&stat, player); + } + + emu_stat_report(&stat, player, 1); + + /* Report events */ + report(); + + /* Error happened */ + if (ret < 0) { + err("player_step failed"); + return 1; + } + + free(trace); + free(player); + + return 0; +}