summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEmmanuele Bassi <ebassi@gnome.org>2018-01-19 20:02:11 +0000
committerEmmanuele Bassi <ebassi@gnome.org>2018-01-19 20:02:11 +0000
commit49150ba51524a3ae423a8fb649c543718d41b4d9 (patch)
treeca36b307643bd61bb9261f6eefebcaf98620cb1b
parent552d944f76f1c0961cd2b3bd39fa44eaa8a95f56 (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.inc21
-rw-r--r--tools/eos-profile-tool/eos-profile-cmd-help.c3
-rw-r--r--tools/eos-profile-tool/eos-profile-cmd-show.c278
-rw-r--r--tools/eos-profile-tool/eos-profile-cmds.h17
-rw-r--r--tools/eos-profile-tool/eos-profile-main.c31
-rw-r--r--tools/eos-profile-tool/eos-profile-utils.c93
-rw-r--r--tools/eos-profile-tool/eos-profile-utils.h23
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);