diff options
author | Emmanuele Bassi <ebassi@gnome.org> | 2018-01-19 20:02:11 +0000 |
---|---|---|
committer | Emmanuele Bassi <ebassi@gnome.org> | 2018-01-19 20:02:11 +0000 |
commit | 49150ba51524a3ae423a8fb649c543718d41b4d9 (patch) | |
tree | ca36b307643bd61bb9261f6eefebcaf98620cb1b | |
parent | 552d944f76f1c0961cd2b3bd39fa44eaa8a95f56 (diff) |
Add show command to eos-profile
The `show` command loads a list of profile capture files and prints the
metadata and sample summary.
-rw-r--r-- | tools/Makefile.am.inc | 21 | ||||
-rw-r--r-- | tools/eos-profile-tool/eos-profile-cmd-help.c | 3 | ||||
-rw-r--r-- | tools/eos-profile-tool/eos-profile-cmd-show.c | 278 | ||||
-rw-r--r-- | tools/eos-profile-tool/eos-profile-cmds.h | 17 | ||||
-rw-r--r-- | tools/eos-profile-tool/eos-profile-main.c | 31 | ||||
-rw-r--r-- | tools/eos-profile-tool/eos-profile-utils.c | 93 | ||||
-rw-r--r-- | tools/eos-profile-tool/eos-profile-utils.h | 23 |
7 files changed, 446 insertions, 20 deletions
diff --git a/tools/Makefile.am.inc b/tools/Makefile.am.inc index c2db497..d8751bb 100644 --- a/tools/Makefile.am.inc +++ b/tools/Makefile.am.inc @@ -47,11 +47,26 @@ bin_PROGRAMS = \ $(NULL) eos_profile_SOURCES = \ - tools/eos-profile-tool/eos-profile-main.c \ tools/eos-profile-tool/eos-profile-cmds.h \ tools/eos-profile-tool/eos-profile-cmd-help.c \ + tools/eos-profile-tool/eos-profile-cmd-show.c \ + tools/eos-profile-tool/eos-profile-main.c \ + tools/eos-profile-tool/eos-profile-utils.c \ + tools/eos-profile-tool/eos-profile-utils.h \ + endless/gvdb/gvdb-reader.c \ + $(NULL) + +eos_profile_CPPFLAGS = \ + @EOS_SDK_CFLAGS@ \ + -DCOMPILING_EOS_SDK \ + -DG_LOG_DOMAIN=\"EosProfile\" \ + -I$(top_builddir) \ + -I$(top_srcdir) \ + -I$(top_srcdir)/endless/ \ + -I$(top_builddir)/endless/ \ + -I$(top_srcdir)/endless/gvdb \ + -I$(top_srcdir)/tools/eos-profile-tool \ $(NULL) -eos_profile_CPPFLAGS = @EOS_SDK_CFLAGS@ -DG_LOG_DOMAIN=\"EosProfile\" eos_profile_CFLAGS = $(AM_CFLAGS) -eos_profile_LDADD = $(top_builddir)/libendless-@EOS_SDK_API_VERSION@.la @EOS_SDK_LIBS@ +eos_profile_LDADD = $(top_builddir)/libendless-@EOS_SDK_API_VERSION@.la -lm @EOS_SDK_LIBS@ diff --git a/tools/eos-profile-tool/eos-profile-cmd-help.c b/tools/eos-profile-tool/eos-profile-cmd-help.c index 88f8b4e..754714f 100644 --- a/tools/eos-profile-tool/eos-profile-cmd-help.c +++ b/tools/eos-profile-tool/eos-profile-cmd-help.c @@ -1,6 +1,6 @@ #include "config.h" -#include <glib.h> +#include "eos-profile-cmds.h" gboolean eos_profile_cmd_help_parse_args (int argc, @@ -20,6 +20,7 @@ eos_profile_cmd_help_main (void) "Examples:\n" "\n" " eos-profile help - This help screen\n" + " eos-profile show FILE - Shows a capture file\n" "\n" ); diff --git a/tools/eos-profile-tool/eos-profile-cmd-show.c b/tools/eos-profile-tool/eos-profile-cmd-show.c new file mode 100644 index 0000000..1645331 --- /dev/null +++ b/tools/eos-profile-tool/eos-profile-cmd-show.c @@ -0,0 +1,278 @@ +#include "config.h" + +#include "eos-profile-cmds.h" +#include "eos-profile-utils.h" + +#include "endless/eosprofile-private.h" +#include "endless/gvdb/gvdb-reader.h" + +#include <math.h> + +static GPtrArray *files; + +static const double +scale_val (double val) +{ + if (val >= G_USEC_PER_SEC) + return val / G_USEC_PER_SEC; + + if (val >= 1000) + return val / 1000.0; + + return val; +} + +static const char * +unit_for (double val) +{ + enum { + SECONDS, + MILLISECONDS, + MICROSECONDS + }; + + const char *units[] = { + [SECONDS] = "s", + [MILLISECONDS] = "ms", + [MICROSECONDS] = "µs", + }; + + if (val >= G_USEC_PER_SEC) + return units[SECONDS]; + + if (val >= 1000) + return units[MILLISECONDS]; + + return units[MICROSECONDS]; +} + +gboolean +eos_profile_cmd_show_parse_args (int argc, + char **argv) +{ + files = g_ptr_array_new (); + + for (int i = 1; i < argc; i++) + g_ptr_array_add (files, argv[i]); + + if (files->len == 0) + { + g_printerr ("Usage: eos-profile show FILE [FILE...]\n"); + g_ptr_array_unref (files); + + return FALSE; + } + + return TRUE; +} + +static void +print_probe (const char *name) +{ + eos_profile_util_print_message ("PROBE", EOS_PRINT_COLOR_GREEN, + "%s", + name); +} + +static void +print_location (const char *file, + gint32 line, + const char *function) +{ + eos_profile_util_print_message (NULL, EOS_PRINT_COLOR_NONE, + " `- %s at %s:%d", + function, + file, + line); +} + +static void +print_samples (const char *name, + gint32 n_samples, + GVariant *array) +{ + g_autoptr(GArray) samples = g_array_new (FALSE, FALSE, sizeof (ProfileSample)); + + GVariantIter iter; + g_variant_iter_init (&iter, array); + + gint64 start, end; + while (g_variant_iter_next (&iter, "(xx)", &start, &end)) + { + g_array_append_vals (samples, + &(ProfileSample) { + .start_time = start, + .end_time = end, + }, + 1); + } + + gint64 min_sample = G_MAXINT64, max_sample = 0; + gint64 total = 0; + + g_autoptr(GArray) valid_samples = g_array_new (FALSE, FALSE, sizeof (guint)); + + for (int i = 0; i < samples->len; i++) + { + const ProfileSample *sample = &g_array_index (samples, ProfileSample, i); + + gint64 delta = sample->end_time - sample->start_time; + + /* If the probe never got stopped we need to skip this sample */ + if (delta < 0) + continue; + + g_array_append_val (valid_samples, i); + + if (delta < min_sample) + min_sample = delta; + if (delta > max_sample) + max_sample = delta; + + total += delta; + } + + g_autofree char *msg = NULL; + + if (valid_samples->len > 1) + { + double avg = total / (double) valid_samples->len; + double s = 0; + double s_part = 0; + + for (int i = 1; i < valid_samples->len - 1; i++) + { + guint idx = g_array_index (valid_samples, guint, i); + const ProfileSample *sample = &g_array_index (samples, ProfileSample, idx); + + gint64 delta = sample->end_time - sample->start_time; + g_assert (delta >= 0); + + double deviation = delta - avg; + s_part += (deviation * deviation); + } + + if (valid_samples->len > 1) + s = sqrt (s_part / (double) valid_samples->len - 1); + else + s = 0.0; + + g_autofree char *stddev = g_strdup_printf (", σ: %g", s); + + msg = + g_strdup_printf ("%d samples: total time: %d %s, avg: %g %s, min: %d %s, max: %d %s%s", + valid_samples->len, + (int) scale_val (total), unit_for (total), + scale_val (avg), unit_for (avg), + (int) scale_val (min_sample), unit_for (min_sample), + (int) scale_val (max_sample), unit_for (max_sample), + s == 0.0 ? "" : stddev); + } + else if (valid_samples->len == 1) + { + msg = g_strdup_printf ("1 sample: total time: %d %s", + (int) scale_val (total), + unit_for (total)); + } + else + { + msg = g_strdup ("Not enough valid samples found"); + } + + eos_profile_util_print_message (NULL, EOS_PRINT_COLOR_NONE, + " `- %s", + msg); +} + +int +eos_profile_cmd_show_main (void) +{ + g_assert (files != NULL); + + for (int i = 0; i < files->len; i++) + { + const char *filename = g_ptr_array_index (files, i); + g_autoptr(GError) error = NULL; + + eos_profile_util_print_message ("INFO", EOS_PRINT_COLOR_BLUE, + "Loading profiling data from '%s'", + filename); + + GvdbTable *db = gvdb_table_new (filename, TRUE, &error); + + if (error != NULL) + { + eos_profile_util_print_error ("Unable to load '%s': %s\n", filename, error->message); + return 1; + } + + g_autoptr(GVariant) v = gvdb_table_get_raw_value (db, PROBE_DB_META_VERSION_KEY); + gint32 version = v != NULL ? g_variant_get_int32 (v) : -1; + + if (version != PROBE_DB_VERSION) + { + eos_profile_util_print_error ("Unable to load '%s': invalid version\n"); + return 1; + } + + int names_len = 0; + g_auto(GStrv) names = gvdb_table_get_names (db, &names_len); + + for (int j = 0; j < names_len; j++) + { + const char *name = names[j]; + + if (g_strcmp0 (name, PROBE_DB_META_VERSION_KEY) == 0) + continue; + + g_autoptr(GVariant) value = gvdb_table_get_raw_value (db, name); + if (value == NULL) + continue; + + if (g_strcmp0 (name, PROBE_DB_META_APPID_KEY) == 0) + { + const char *appid = g_variant_get_string (value, NULL); + + eos_profile_util_print_message ("INFO", EOS_PRINT_COLOR_BLUE, + "Application: %s", + appid); + continue; + } + + if (g_strcmp0 (name, PROBE_DB_META_PROFILE_KEY) == 0) + { + gint64 profile_time = g_variant_get_int64 (value); + + eos_profile_util_print_message ("INFO", EOS_PRINT_COLOR_BLUE, + "Profile time: %d %s", + (int) scale_val (profile_time), + unit_for (profile_time)); + continue; + } + + const char *file = NULL; + const char *function = NULL; + const char *probe_name = NULL; + g_autoptr(GVariant) samples = NULL; + gint32 line, n_samples; + + g_variant_get (value, "(&s&s&suu@a(xx))", + &probe_name, + &function, + &file, + &line, + &n_samples, + &samples); + + print_probe (probe_name); + print_location (file, line, function); + if (n_samples > 0) + print_samples (probe_name, n_samples, samples); + + } + + gvdb_table_free (db); + } + + return 0; +} diff --git a/tools/eos-profile-tool/eos-profile-cmds.h b/tools/eos-profile-tool/eos-profile-cmds.h index f06781c..c6da7d4 100644 --- a/tools/eos-profile-tool/eos-profile-cmds.h +++ b/tools/eos-profile-tool/eos-profile-cmds.h @@ -8,19 +8,6 @@ typedef int (* EosProfileCmdMain) (void); gboolean eos_profile_cmd_help_parse_args (int argc, char **argv); int eos_profile_cmd_help_main (void); -const struct { - const char *name; - const char *description; +gboolean eos_profile_cmd_show_parse_args (int argc, char **argv); +int eos_profile_cmd_show_main (void); - EosProfileCmdParseArgs parse_args; - EosProfileCmdMain main; -} profile_commands[] = { - { - .name = "help", - .description = "Prints help", - .parse_args = eos_profile_cmd_help_parse_args, - .main = eos_profile_cmd_help_main, - }, - - { NULL, }, -}; diff --git a/tools/eos-profile-tool/eos-profile-main.c b/tools/eos-profile-tool/eos-profile-main.c index 4b76870..6879cb6 100644 --- a/tools/eos-profile-tool/eos-profile-main.c +++ b/tools/eos-profile-tool/eos-profile-main.c @@ -4,16 +4,45 @@ #include <string.h> #include <stdio.h> +#include <locale.h> #include <glib.h> +#include <glib/gi18n.h> #include "eos-profile-cmds.h" -static gboolean opt_cmd = FALSE; +static const struct { + const char *name; + const char *description; + + EosProfileCmdParseArgs parse_args; + EosProfileCmdMain main; +} profile_commands[] = { + { + .name = "help", + .description = "Prints help", + .parse_args = eos_profile_cmd_help_parse_args, + .main = eos_profile_cmd_help_main, + }, + { + .name = "show", + .description = "Shows a capture", + .parse_args = eos_profile_cmd_show_parse_args, + .main = eos_profile_cmd_show_main, + }, + + { NULL, }, +}; int main (int argc, char *argv[]) { + setlocale (LC_ALL, ""); + textdomain (GETTEXT_PACKAGE); + + bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR); + bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); + const char *cmd = NULL; if (argc < 2) diff --git a/tools/eos-profile-tool/eos-profile-utils.c b/tools/eos-profile-tool/eos-profile-utils.c new file mode 100644 index 0000000..2d63804 --- /dev/null +++ b/tools/eos-profile-tool/eos-profile-utils.c @@ -0,0 +1,93 @@ +#include "config.h" + +#include "eos-profile-utils.h" + +#include <stdlib.h> +#include <stdarg.h> +#include <stdio.h> +#include <string.h> + +#include <math.h> + +#include <sys/types.h> +#include <sys/ioctl.h> +#include <unistd.h> +#include <termios.h> +#include <fcntl.h> + +static const char *ansi_colors[] = { + [EOS_PRINT_COLOR_GREEN] = "[1;32m", + [EOS_PRINT_COLOR_BLUE] = "[1;34m", + [EOS_PRINT_COLOR_YELLOW] = "[1;33m", + [EOS_PRINT_COLOR_RED] = "[1;31m", + [EOS_PRINT_COLOR_NONE] = "[0m", +}; + +static char * +gen_color_message (const char *prefix, + EosPrintColor color, + const char *fmt, + va_list args) +{ + g_autofree char *res = NULL; + + if (prefix != NULL) + { + g_autofree char *msg = g_strdup_vprintf (fmt, args); + + res = g_strdup_printf ("\033%s%s\033%s: %s", + ansi_colors[color], + prefix, + ansi_colors[EOS_PRINT_COLOR_NONE], + msg); + + } + else + res = g_strdup_vprintf (fmt, args); + + return g_steal_pointer (&res); +} + +void +eos_profile_util_print_message (const char *prefix, + EosPrintColor color, + const char *fmt, + ...) +{ + g_autofree char *msg = NULL; + va_list args; + + va_start (args, fmt); + msg = gen_color_message (prefix, color, fmt, args); + va_end (args); + + g_print ("%s\n", msg); +} + +void +eos_profile_util_print_error (const char *fmt, + ...) +{ + g_autofree char *msg = NULL; + va_list args; + + va_start (args, fmt); + msg = gen_color_message ("ERROR", EOS_PRINT_COLOR_RED, fmt, args); + va_end (args); + + g_printerr ("%s\n", msg); +} + +void +eos_profile_util_print_warning (const char *fmt, + ...) +{ + g_autofree char *msg = NULL; + va_list args; + + va_start (args, fmt); + msg = gen_color_message ("WARNING", EOS_PRINT_COLOR_YELLOW, fmt, args); + va_end (args); + + g_printerr ("%s\n", msg); +} diff --git a/tools/eos-profile-tool/eos-profile-utils.h b/tools/eos-profile-tool/eos-profile-utils.h new file mode 100644 index 0000000..b6030c2 --- /dev/null +++ b/tools/eos-profile-tool/eos-profile-utils.h @@ -0,0 +1,23 @@ +#pragma once + +#include <glib.h> + +typedef enum { + EOS_PRINT_COLOR_GREEN, + EOS_PRINT_COLOR_BLUE, + EOS_PRINT_COLOR_YELLOW, + EOS_PRINT_COLOR_RED, + + EOS_PRINT_COLOR_NONE +} EosPrintColor; + +void eos_profile_util_print_message (const char *prefix, + EosPrintColor color, + const char *fmt, + ...) G_GNUC_PRINTF (3, 4); + +void eos_profile_util_print_error (const char *msg, + ...) G_GNUC_PRINTF (1, 2); + +void eos_profile_util_print_warning (const char *msg, + ...) G_GNUC_PRINTF (1, 2); |