g2: add multi-track time-slew controls 10/6010/2
authorDave Barach <dave@barachs.net>
Mon, 3 Apr 2017 14:22:17 +0000 (10:22 -0400)
committerFlorin Coras <florin.coras@gmail.com>
Mon, 3 Apr 2017 15:24:50 +0000 (15:24 +0000)
Create an elog_merge utility, extracted from test_elog.

Change-Id: Ide137b4858c88b3a2885583b7fbb15ddc4963af9
Signed-off-by: Dave Barach <dave@barachs.net>
src/perftool.am
src/tools/g2/g2.h
src/tools/g2/view1.c
src/tools/perftool/elog_merge.c [new file with mode: 0644]

index 09f1681..23e4503 100644 (file)
@@ -11,7 +11,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-bin_PROGRAMS += c2cpel cpelatency cpeldump cpelinreg cpelstate
+bin_PROGRAMS += c2cpel cpelatency cpeldump cpelinreg cpelstate elog_merge
 
 lib_LTLIBRARIES += libcperf.la
 
@@ -38,4 +38,7 @@ cpelinreg_LDADD = $(PERFTOOL_LIBS)
 cpelstate_SOURCES = tools/perftool/cpelstate.c
 cpelstate_LDADD = $(PERFTOOL_LIBS)
 
+elog_merge_SOURCES = tools/perftool/elog_merge.c
+elog_merge_LDADD = $(PERFTOOL_LIBS)
+
 # vi:syntax=automake
index 1ab4219..f1f268a 100644 (file)
@@ -157,6 +157,7 @@ typedef struct pid_sort {
      * This is a bit of a hack, since this is used only by the view:
      */
     unsigned color_index;
+    int selected;
 } pid_sort_t;
 
 typedef struct event {
index ec394cc..c524c81 100644 (file)
  */
 
 GdkFont *g_font;                /* a fixed-width font to use */
+/* color format: 0 (for static colors), r (0-64k), g (0-64k), b (0-64k) */
 GdkColor fg_black = {0, 0, 0, 0};
+GdkColor fg_red   = {0, 65535, 0, 0};
 GdkColor bg_white = {0, 65535, 65535, 65535};
 static boolean summary_mode = TRUE; /* start out in summary mode */
-static boolean color_mode   = FALSE; /* start out in color mode   */
+static boolean color_mode   = FALSE; /* start out in monochrome mode   */
 
 /*
  * Locals
@@ -98,6 +100,8 @@ enum view1_button_click {
     BACKWARD_BUTTON,
     SUMMARY_BUTTON,
     NOSUMMARY_BUTTON,
+    SLEW_LEFT_BUTTON,
+    SLEW_RIGHT_BUTTON,
 };
 
 enum chase_mode {
@@ -139,6 +143,7 @@ typedef struct v1_geometry {
     int event_offset;           /* Vertical offset of the event boxes */
     int total_height;           /* total height of da, see configure_event */
     int total_width;            /* ditto, for width */
+    double last_time_interval;  /* last time interval, in f64 seconds */
     
     /* Derived values */
     int first_pid_index;        /* Index of first displayed PID */
@@ -210,6 +215,9 @@ static GtkWidget *s_view1_backward_button;
 static GtkWidget *s_view1_summary_button;
 static GtkWidget *s_view1_nosummary_button;
 
+static GtkWidget *s_view1_time_slew_right_button;
+static GtkWidget *s_view1_time_slew_left_button;
+
 static GtkWidget *s_view1_hscroll;
 static GtkObject *s_view1_hsadj;
 
@@ -774,7 +782,13 @@ static void read_snapshot(void)
 #define COLOR_DEFAULT (-1)
 static void set_color(int pid_index)
 {
-    if (pid_index == COLOR_DEFAULT || !color_mode) {
+    pid_sort_t *psp;
+
+    psp = (g_pids + pid_index);
+    
+    if (psp->selected)
+        gdk_gc_set_foreground(da->style->black_gc, &s_color[0]);
+    else if (pid_index == COLOR_DEFAULT || !color_mode) {
         gdk_gc_set_foreground(da->style->black_gc, &fg_black);
     } else {
         gdk_gc_set_foreground(da->style->black_gc, 
@@ -786,7 +800,7 @@ static void set_color(int pid_index)
 * toggle_event_select
 ****************************************************************************/
 
-static void toggle_event_select(GdkEventButton *event, v1_geometry_t *vp)
+static int toggle_event_select(GdkEventButton *event, v1_geometry_t *vp)
 {
     int pid_index, start_index;
     int x, y;
@@ -799,7 +813,7 @@ static void toggle_event_select(GdkEventButton *event, v1_geometry_t *vp)
     double time_per_pixel;
 
     if (g_nevents == 0)
-        return;
+        return 0;
 
     time_per_pixel = dtime_per_pixel(vp);
 
@@ -807,7 +821,7 @@ static void toggle_event_select(GdkEventButton *event, v1_geometry_t *vp)
 
     /* Too far right? */
     if (start_index >= g_nevents)
-        return;
+        return 0;
     
     /* 
      * To see if the mouse hit a visible event, use a variant
@@ -864,7 +878,7 @@ static void toggle_event_select(GdkEventButton *event, v1_geometry_t *vp)
             if (gdk_rectangle_intersect(rp, &hit_rect, &dummy)) {
                 ep->flags &= ~EVENT_FLAG_SELECT;
                 view1_display_when_idle();
-                break;
+                return 0;
             }
         } 
 
@@ -878,7 +892,7 @@ static void toggle_event_select(GdkEventButton *event, v1_geometry_t *vp)
             if (ep->flags & EVENT_FLAG_SELECT) {
                 ep->flags &= ~EVENT_FLAG_SELECT;
                 view1_display_when_idle();
-                break;
+                return 0;
             } else {
                 set_color(ep->pid->pid_index);
 
@@ -890,12 +904,62 @@ static void toggle_event_select(GdkEventButton *event, v1_geometry_t *vp)
                 ep->flags &= ~EVENT_FLAG_SEARCHRSLT;
                 s_last_selected_event = ep;
             }
-            break;
+            return 0;
         }
         ep++;
     }
+    return -1;
 }
 
+/****************************************************************************
+* toggle_track_select
+****************************************************************************/
+
+static void toggle_track_select (GdkEventButton *event, 
+                                 v1_geometry_t  *vp)
+{
+    int i;
+    int pid_index;
+    int y, delta_y;
+    pid_sort_t *psp;
+    
+    if (g_nevents == 0)
+        return;
+
+    /* Scan pid/track axis locations, looking for a match */
+    for (i = 0; i < vp->npids; i++) {
+        y = i*vp->strip_height + vp->pid_ax_offset;
+        delta_y = y - event->y;
+        if (delta_y < 0)
+            delta_y = -delta_y;
+        if (delta_y < 10) {
+            goto found;
+        }
+
+    }
+    infobox("NOTE", "\nNo PID/Track In Range\nPlease Try Again");
+    return;
+    
+ found:
+    pid_index = i + vp->first_pid_index;
+    psp = (g_pids + pid_index);
+    psp->selected ^= 1;
+    view1_display_when_idle();
+}
+
+/****************************************************************************
+* deselect_tracks
+****************************************************************************/
+static void deselect_tracks (void)
+{
+    int i;
+
+    for (i = 0; i < g_npids; i++)
+        g_pids[i].selected = 0;
+
+}
+
+
 /****************************************************************************
 * move_current_track
 ****************************************************************************/
@@ -1241,8 +1305,9 @@ button_press_event (GtkWidget *widget, GdkEventButton *event)
                            GDK_SHIFT_MASK) {
                     move_current_track(event, s_v1, MOVE_TOP);
                 } else {
-                    /* No modifiers: toggle the event */
-                    toggle_event_select(event, s_v1);
+                    /* No modifiers: toggle the event / select track */
+                    if (toggle_event_select(event, s_v1))
+                        toggle_track_select(event, s_v1);
                 }
                 /* Repaint to get rid of the zoom bar */
                 if (zoom_bar_up) {
@@ -1332,6 +1397,7 @@ button_press_event (GtkWidget *widget, GdkEventButton *event)
             } else {
                 sprintf(tmpbuf, "%8.0f nsec", nsec);
             }
+            s_v1->last_time_interval = nsec;
             tbox(tmpbuf, (int)(press3_event.x), s_v1->pop_offset,
                  TBOX_DRAW_BOXED);
             return(TRUE);
@@ -1575,13 +1641,16 @@ static void init_track_colors(void)
         /*
          * First time through: allocate the array to hold the GCs.
          */
-        s_color = g_malloc(sizeof(GdkColor) * g_npids);
+        s_color = g_malloc(sizeof(GdkColor) * (g_npids+1));
     }
 
     /*
      * Go through and assign a color for each track.
      */
-    for (i = 0; i < g_npids; i++) {
+    /* Setup entry 0 in the colormap as pure red (for selection) */
+    s_color[0] = fg_red;
+
+    for (i = 1; i < g_npids; i++) {
         /*
          * We compute the color from a hash of the thread name. That way we get
          * a distribution of different colors, and the same thread has the same
@@ -1633,7 +1702,7 @@ static void init_track_colors(void)
      * values.
      */
     gdk_colormap_alloc_colors(gtk_widget_get_colormap(da), 
-                              s_color, g_npids, FALSE, TRUE, dont_care);
+                              s_color, g_npids+1, FALSE, TRUE, dont_care);
 }
 
 
@@ -1892,6 +1961,69 @@ static boolean print_screen_callback(char *filename)
     return(TRUE);
 }
 
+int event_time_cmp (const void *a, const void *b)
+{
+    const event_t *e1 = a;
+    const event_t *e2 = b;
+
+    if (e1->time < e2->time)
+        return -1;
+    else if (e1->time > e2->time)
+        return 1;
+    return 0;
+}
+
+/****************************************************************************
+* slew_tracks
+****************************************************************************/
+static void slew_tracks (v1_geometry_t *vp, enum view1_button_click which)
+{
+    event_t *ep;
+    pid_sort_t *pp;
+    int pid_index;
+    ulonglong delta;
+    
+    delta = (ulonglong) (vp->last_time_interval);
+
+    /* Make sure we don't push events to the left of the big bang */
+    if (which == SLEW_LEFT_BUTTON) {
+        for (ep = g_events; ep < (g_events + g_nevents); ep++) {
+            pid_index = ep->pid->pid_index;
+            pp = (g_pids + pid_index);
+            
+            if (pp->selected) {
+                if (ep->time < delta) {
+                    infobox("Slew Range Error", 
+                            "\nCan't slew selected data left that far..."
+                            "\nEvents would preceed the Big Bang (t=0)...");
+                    goto out;
+                }
+            }
+        }
+    }
+
+    for (ep = g_events; ep < (g_events + g_nevents); ep++) {
+        pid_index = ep->pid->pid_index;
+        pp = (g_pids + pid_index);
+
+        if (pp->selected) {
+            if (which == SLEW_LEFT_BUTTON)
+                ep->time -= delta;
+            else
+                ep->time += delta;
+        }
+    }
+
+    /* Re-sort the events, to avoid screwing up the event display */
+    qsort (g_events, g_nevents, sizeof(event_t), event_time_cmp);
+
+    /* De-select tracks */
+    deselect_tracks();
+
+out:
+    view1_display_when_idle();
+}
+
 /****************************************************************************
 * view1_button_click_callback 
 ****************************************************************************/
@@ -1904,7 +2036,6 @@ static void view1_button_click_callback(GtkButton *item, gpointer data)
     ulonglong current_width;
     ulonglong zoom_delta;
 
-
     current_width = s_v1->maxvistime - s_v1->minvistime;
     event_incdec = (current_width) / 3;
 
@@ -2060,6 +2191,15 @@ static void view1_button_click_callback(GtkButton *item, gpointer data)
         gtk_widget_show (s_view1_summary_button);
         gtk_widget_hide (s_view1_nosummary_button);
         break;
+
+    case SLEW_LEFT_BUTTON:
+    case SLEW_RIGHT_BUTTON:
+        if (s_v1->last_time_interval < 10e-9) {
+            infobox("slew", "\nNo time interval set...\n");        
+            break;
+        }
+        slew_tracks (s_v1, click);
+        break;
     }
 
     view1_display_when_idle();
@@ -2351,6 +2491,9 @@ void view1_init(void)
     s_view1_summary_button = gtk_button_new_with_label("Summary");
     s_view1_nosummary_button = gtk_button_new_with_label("NoSummary");
 
+    s_view1_time_slew_left_button = gtk_button_new_with_label("<-TimeSlew");
+    s_view1_time_slew_right_button = gtk_button_new_with_label("TimeSlew->");
+
     gtk_signal_connect (GTK_OBJECT(s_view1_snapbutton), "clicked",
                         GTK_SIGNAL_FUNC(view1_button_click_callback), 
                         (gpointer) SNAP_BUTTON);
@@ -2395,6 +2538,14 @@ void view1_init(void)
                         GTK_SIGNAL_FUNC(view1_button_click_callback), 
                         (gpointer) NOSUMMARY_BUTTON);
 
+    gtk_signal_connect (GTK_OBJECT(s_view1_time_slew_left_button), "clicked",
+                        GTK_SIGNAL_FUNC(view1_button_click_callback), 
+                        (gpointer) SLEW_LEFT_BUTTON);
+
+    gtk_signal_connect (GTK_OBJECT(s_view1_time_slew_right_button), "clicked",
+                        GTK_SIGNAL_FUNC(view1_button_click_callback), 
+                        (gpointer) SLEW_RIGHT_BUTTON);
+
     gtk_box_pack_start (GTK_BOX(s_view1_vbox), s_view1_hmenubox2,
                         FALSE, FALSE, 0);
     
@@ -2431,6 +2582,14 @@ void view1_init(void)
     gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2), s_view1_nosummary_button,
                         FALSE, FALSE, 0);
 
+    gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2), 
+                        s_view1_time_slew_left_button,
+                        FALSE, FALSE, 0);
+
+    gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2), 
+                        s_view1_time_slew_right_button,
+                        FALSE, FALSE, 0);
+
     s_view1_label = gtk_label_new(NULL);
 
     gtk_box_pack_start (GTK_BOX(s_view1_vbox), s_view1_label,
@@ -2750,9 +2909,10 @@ static void display_pid_axis(v1_geometry_t *vp)
         if (pid_index >= g_npids)
             break;
 
-        set_color(pid_index);
         pp = (g_pids + pid_index);
 
+        set_color(pid_index);
+
         label_fmt = get_track_label(pp->pid_value);
         snprintf(tmpbuf, sizeof(tmpbuf)-1, label_fmt, pp->pid_value);
 
diff --git a/src/tools/perftool/elog_merge.c b/src/tools/perftool/elog_merge.c
new file mode 100644 (file)
index 0000000..46b19dd
--- /dev/null
@@ -0,0 +1,181 @@
+/*
+ * Copyright (c) 2015 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/*
+  Copyright (c) 2005 Eliot Dresselhaus
+
+  Permission is hereby granted, free of charge, to any person obtaining
+  a copy of this software and associated documentation files (the
+  "Software"), to deal in the Software without restriction, including
+  without limitation the rights to use, copy, modify, merge, publish,
+  distribute, sublicense, and/or sell copies of the Software, and to
+  permit persons to whom the Software is furnished to do so, subject to
+  the following conditions:
+
+  The above copyright notice and this permission notice shall be
+  included in all copies or substantial portions of the Software.
+
+  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+  LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+  OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+  WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#include <vppinfra/elog.h>
+#include <vppinfra/error.h>
+#include <vppinfra/format.h>
+#include <vppinfra/random.h>
+#include <vppinfra/serialize.h>
+#include <vppinfra/unix.h>
+#include <vppinfra/pool.h>
+#include <vppinfra/hash.h>
+
+int
+elog_merge_main (unformat_input_t * input)
+{
+  clib_error_t *error = 0;
+  elog_main_t _em, *em = &_em;
+  u32 verbose;
+  char *dump_file, *merge_file, **merge_files;
+  u8 *tag, **tags;
+  f64 align_tweak;
+  f64 *align_tweaks;
+  uword i;
+  elog_main_t *ems;
+
+  verbose = 0;
+  dump_file = 0;
+  merge_files = 0;
+  tags = 0;
+  align_tweaks = 0;
+
+  while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
+    {
+      if (unformat (input, "dump %s", &dump_file))
+       ;
+      else if (unformat (input, "tag %s", &tag))
+       vec_add1 (tags, tag);
+      else if (unformat (input, "merge %s", &merge_file))
+       vec_add1 (merge_files, merge_file);
+
+      else if (unformat (input, "verbose %=", &verbose, 1))
+       ;
+      else if (unformat (input, "align-tweak %f", &align_tweak))
+       vec_add1 (align_tweaks, align_tweak);
+      else
+       {
+         error = clib_error_create ("unknown input `%U'\n",
+                                    format_unformat_error, input);
+         goto done;
+       }
+    }
+
+  vec_clone (ems, merge_files);
+
+  /* Supply default tags as needed */
+  if (vec_len (tags) < vec_len (ems))
+    {
+      for (i = vec_len (tags); i < vec_len (ems); i++)
+       vec_add1 (tags, format (0, "F%d%c", i, 0));
+    }
+
+  for (i = 0; i < vec_len (ems); i++)
+    {
+      if ((error = elog_read_file ((i == 0) ? em : &ems[i], merge_files[i])))
+       goto done;
+      if (i > 0)
+       {
+         align_tweak = 0.0;
+         if (i <= vec_len (align_tweaks))
+           align_tweak = align_tweaks[i - 1];
+         elog_merge (em, tags[0], &ems[i], tags[i], align_tweak);
+         tags[0] = 0;
+       }
+    }
+
+  if (dump_file)
+    {
+      if ((error =
+          elog_write_file (em, dump_file, 0 /* do not flush ring */ )))
+       goto done;
+    }
+
+  if (verbose)
+    {
+      elog_event_t *e, *es;
+      es = elog_get_events (em);
+      vec_foreach (e, es)
+      {
+       clib_warning ("%18.9f: %12U %U\n", e->time,
+                     format_elog_track, em, e, format_elog_event, em, e);
+      }
+    }
+
+done:
+  if (error)
+    clib_error_report (error);
+  return 0;
+}
+
+int
+main (int argc, char *argv[])
+{
+  unformat_input_t i;
+  int r;
+
+  clib_mem_init (0, 3ULL << 30);
+
+  unformat_init_command_line (&i, argv);
+  r = elog_merge_main (&i);
+  unformat_free (&i);
+  return r;
+}
+
+/*
+ * GDB callable function: vl - Return vector length of vector
+ */
+u32
+vl (void *p)
+{
+  return vec_len (p);
+}
+
+/*
+ * GDB callable function: pe - call pool_elts - number of elements in a pool
+ */
+uword
+pe (void *v)
+{
+  return (pool_elts (v));
+}
+
+/*
+ * GDB callable function: he - call hash_elts - number of elements in a hash
+ */
+uword
+he (void *v)
+{
+  return (hash_elts (v));
+}
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */