1/*
2 * Copyright (c) 2009, 2010, ETH Zurich.
3 * All rights reserved.
4 *
5 * This file is distributed under the terms in the attached LICENSE file.
6 * If you do not find this file, copies can be found by writing to:
7 * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
8 */
9
10using System;
11using System.Collections.Generic;
12using System.Linq;
13using System.Text;
14using System.Windows;
15using System.Windows.Controls;
16using System.Windows.Data;
17using System.Windows.Documents;
18using System.Windows.Input;
19using System.Windows.Media;
20using System.Windows.Media.Imaging;
21using System.Windows.Navigation;
22using System.Windows.Shapes;
23using System.Windows.Threading;
24
25using System.IO;
26using System.Globalization;
27using System.Windows.Controls.Primitives;
28
29using System.Net.Sockets;
30using System.ComponentModel;
31using System.Net; // IPAddress and Dns
32
33namespace Aquarium
34{
35    /// <summary>
36    /// Interaction logic for Window1.xaml
37    /// </summary>
38    public partial class Window1 : Window
39    {
40        public Window1()
41        {
42            InitializeComponent();
43
44            App app = Application.Current as App;
45            if (app != null)
46            {
47                // Add command line arguemnts to the connect menu
48                foreach (string arg in app.CommandLineArguments)
49                {
50                    MenuItem mi = new MenuItem();
51                    mi.Header = arg;
52                    mi.Click += new RoutedEventHandler(this.Connect_Click);
53                    this.menuitem_Connect.Items.Add(mi);
54                }
55            }
56
57            this.Name = this.Title;
58            Stream stream = System.Reflection.Assembly.GetExecutingAssembly().GetManifestResourceStream("Aquarium.barrelfish.png");
59            this.Icon = BitmapFrame.Create(stream);
60
61            this.mainCanvas.MouseDown += new MouseButtonEventHandler(mainCanvas_MouseDown);
62
63            this.worker = new BackgroundWorker();
64            this.worker.DoWork += new DoWorkEventHandler(worker_DoWork);
65            this.worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(worker_RunWorkerCompleted);
66            this.worker.ProgressChanged += new ProgressChangedEventHandler(worker_ProgressChanged);
67            this.Loaded += new RoutedEventHandler(Window1_Loaded);
68            this.ContentRendered += new EventHandler(Window1_ContentRendered);
69            this.StateChanged += new EventHandler(Window1_StateChanged);
70
71            this.worker.WorkerReportsProgress = true;
72            this.worker.WorkerSupportsCancellation = true;
73
74            this.BlackPen = new Pen(Brushes.Black, 0.5);
75            this.BlackPen.Freeze();
76
77            this.VisHost = new VisualHost();
78
79            this.VisRects = new MyDrawingVisual();
80            this.VisThinRectangles = new MyDrawingVisual();
81            this.VisBlobs = new MyDrawingVisual();
82            this.VisArrows = new MyDrawingVisual();
83
84            this.VisHost.AddVisual(this.VisRects);
85            this.VisHost.AddVisual(this.VisThinRectangles);
86            this.VisHost.AddVisual(this.VisBlobs);
87            this.VisHost.AddVisual(this.VisArrows);
88        }
89
90        void Window1_ContentRendered(object sender, EventArgs e)
91        {
92            if (this.Automatic && !this.worker.IsBusy)
93                this.worker.RunWorkerAsync(null);
94        }
95
96        void Window1_StateChanged(object sender, EventArgs e)
97        {
98            if (this.Automatic && !this.worker.IsBusy)
99                this.worker.RunWorkerAsync(null);
100        }
101
102        void Window1_Loaded(object sender, RoutedEventArgs e)
103        {
104            ReRender();
105        }
106
107        // Barrelfish trace state
108        private readonly BackgroundWorker worker;
109        private string Filename;
110        private bool Automatic;
111        private TraceFetcher TraceFetcher;
112
113        private TemporalTraceEventCollection ttec;
114        private Dictionary<ulong, string> procnames;
115
116        // Misc state
117
118        private Dictionary<ulong, string> dcbstatic;
119
120        // UI Data
121
122        private Highlighting ClickHighlight = new Highlighting(SystemColors.HighlightBrush);
123        private Highlighting HoverHighlight = new Highlighting(SystemColors.HotTrackBrush);
124
125
126        private double PixelsPerCore = 20;
127        private double NumCores = 16;
128        //private double HalfCoreHeight = 8;
129
130        private double TimeMin { get { return this.ttec == null ? 0.0 : this.ttec.MinTime; } }
131        private double TimeMax { get { return this.ttec == null ? 1e6 : this.ttec.MaxTime; } }
132        private double TimeRange { get { return TimeMax - TimeMin; } }
133
134        private double TicksPerSecond = 1e9; // ???
135        private double PixelsPerSecond;
136        private double TicksPerPixel { get { return TicksPerSecond / PixelsPerSecond; } }
137        private double PixelsPerTick { get { return PixelsPerSecond / TicksPerSecond; } }
138        private double VisibleTimeMin;
139        private double VisibleTimeMax;
140
141        // UI State for the 'interactive' version of the trace visualisation
142        // We have to do our own Z by ordering the appends
143        private List<UIElement> Rectangles = new List<UIElement>();
144        private List<UIElement> ThinRectangles = new List<UIElement>();
145        private List<UIElement> Blobs = new List<UIElement>();
146        private List<UIElement> Arrows = new List<UIElement>();
147
148        // UI State for the 'passive' version of the trace visualization
149        private Pen BlackPen;
150        private VisualHost VisHost;
151        private MyDrawingVisual VisRects;
152        private MyDrawingVisual VisThinRectangles;
153        private MyDrawingVisual VisBlobs;
154        private MyDrawingVisual VisArrows;
155
156        //
157        // Various UI
158        //
159
160        void mainCanvas_MouseDown(object sender, MouseButtonEventArgs e)
161        {
162            if (e.ChangedButton != MouseButton.Left)
163                return;
164            if (sender != this.mainCanvas)
165                return;
166            FrameworkElement fe = e.Source as FrameworkElement;
167            if (fe == null)
168                return;
169            if (fe == this.mainCanvas)
170                this.ClickHighlight.Clear();
171            else
172            {
173                this.HoverHighlight.Clear();
174                this.ClickHighlight.Set(fe);
175            }
176        }
177
178        void uie_MouseLeave(object sender, MouseEventArgs e)
179        {
180           this.HoverHighlight.Clear();
181        }
182
183        void uie_MouseEnter(object sender, MouseEventArgs e)
184        {
185            FrameworkElement fe = sender as FrameworkElement;
186            this.HoverHighlight.Set(fe);
187
188        }
189
190        void mainCanvas_AddChild(UIElement uie)
191        {
192            if (this.optTooltips.IsChecked)
193            {
194                uie.MouseEnter += new MouseEventHandler(uie_MouseEnter);
195                uie.MouseLeave += new MouseEventHandler(uie_MouseLeave);
196            }
197            else
198            {
199                uie.IsHitTestVisible = false;
200            }
201            this.mainCanvas.Children.Add(uie);
202        }
203
204
205        private void ShowBackground()
206        {
207            for (int i = 0; i < this.NumCores; i += 2)
208            {
209                Rectangle r = new Rectangle();
210                r.Width = this.mainCanvas.Width;
211                r.Height = PixelsPerCore;
212                // Top left corner
213                r.RenderTransform = new TranslateTransform(0, Y4Core(i)- PixelsPerCore/2.0);
214                r.Fill = Brushes.LightGray;
215                this.mainCanvas.Children.Add(r);
216            }
217        }
218
219        //
220        // Axes
221        //
222
223        private void ShowCpuAxis()
224        {
225            double xshift = (XScrollBar.Value - XScrollBar.Minimum) * PixelsPerTick;
226            for (int i = 0; i < this.NumCores; i++)
227            {
228                TextBlock tb = new TextBlock();
229                tb.Text = i.ToString();
230                tb.RenderTransform = new TranslateTransform(xshift, Y4Core(i) - 5);
231                this.mainCanvas.Children.Add(tb);
232            }
233        }
234
235
236        private void ShowTimeAxis()
237        {
238            double ticks = this.TimeMax;
239            double seconds = ticks / this.TicksPerSecond;
240            long unit = 1;
241            double ideal = TicksPerPixel * (dockPanel3.ActualWidth / 20.0);
242            while (unit < ideal)
243            {
244                unit *= 10;
245            }
246            //unit = Math.Pow(10, Math.Floor(Math.Log10(ideal)));
247
248            // Add a rectangle we can click on to see what's hapening
249            //Rectangle r = Rect(Brushes.LightGray, 0, 0, seconds * PIXELSPERSECOND, 16);
250            //r.ToolTip = "Left click for sampled profile info\nRight click to show running threads";
251            //r.MouseLeftButtonDown += new MouseButtonEventHandler(timeline_MouseLeftButtonDown);
252            //r.MouseRightButtonDown += new MouseButtonEventHandler(timeline_MouseRightButtonDown);
253            //mainCanvas.Children.Add(r);
254
255            // Number the time axis
256            for (long t = 0; t < ticks; t += unit)
257            {
258                TextBlock tb = new TextBlock();
259                tb.Text = String.Format("{0:n0}", t);
260                tb.RenderTransform = new TranslateTransform(t / TicksPerPixel, 0);
261                mainCanvas.Children.Add(tb);
262
263                Line l = new Line();
264                l.X1 = l.X2 = t / TicksPerPixel;
265                l.Y1 = 14; // XXX
266                l.Y2 = Y4Core(-1);
267                l.StrokeThickness = 1.0;
268                l.Stroke = Brushes.Black;
269                this.mainCanvas.Children.Add(l);
270            }
271        }
272
273
274
275
276        // In MSDN for FrameworkElement.VerticalAlignment:
277        // "Canvas does not use VerticalAlignment when composing layout,
278        // because Canvas is based on absolute positioning"
279
280
281        /// <summary>
282        /// Returns the Y value of the middle of the line for the core
283        /// </summary>
284        double Y4Core(int core)
285        {
286            return (NumCores - core + 0.5) * PixelsPerCore + 0.5;
287        }
288
289        private SolidColorBrush BrushForName(string name)
290        {
291            if (string.IsNullOrEmpty(name))
292                return Brushes.Plum;
293            else if (name.Contains("(idle)"))
294                return Brushes.DarkGray;
295            else if (name.Contains("monitor"))
296                return Brushes.CadetBlue;
297            else if (name.Contains("mem_serv"))
298                return Brushes.Red;
299            else if (name.Contains("spantest"))
300                return Brushes.Green;
301            else if (name.Contains("chips"))
302                return Brushes.Yellow;
303            else if (name.Contains("e1000n"))
304                return Brushes.BlueViolet;
305            else if (name.Contains("serial"))
306                return Brushes.OliveDrab;
307            else if (name.Contains("bfscope"))
308                return Brushes.Khaki;
309            else if (name.Contains("fish"))
310                return Brushes.GreenYellow;
311            else if (name.Contains("pixels"))
312                return Brushes.Red;
313            else if (name.Contains("while1"))
314                return Brushes.BlueViolet;
315            else if (name.Contains("bomp_syn"))
316                return Brushes.Red;
317            else if (name.Contains("bomp_cpu"))
318                return Brushes.Blue;
319            else
320                return Brushes.Green;
321        }
322
323
324        private void AddThinRectangle(int core, long start, long end, SolidColorBrush brush, string text)
325        {
326            if (this.optTooltips.IsChecked)
327                AddInteractiveThinRectangle(core, start, end, brush, text);
328            else
329                AddVisThinRectangle(core, start, end, brush);
330        }
331        private void AddInteractiveThinRectangle(int core, long start, long end, SolidColorBrush brush, string text)
332        {
333            double x1 = start - this.TimeMin;
334            double x2 = end - this.TimeMin;
335            x1 /= this.TicksPerPixel;
336            x2 /= this.TicksPerPixel;
337            Rectangle r = new Rectangle();
338            r.Width = x2 - x1;
339            r.Height = 8;
340            r.RenderTransform = new TranslateTransform(x1, Y4Core(core) - 4);
341            r.Fill = brush;
342            r.Stroke = Brushes.Black;
343            if (this.optTooltips.IsChecked)
344                r.ToolTip = text;
345            r.SnapsToDevicePixels = true;
346            this.ThinRectangles.Add(r);
347        }
348        private void AddVisThinRectangle(int core, long start, long end, SolidColorBrush brush)
349        {
350            double x1 = start - this.TimeMin;
351            double x2 = end - this.TimeMin;
352            x1 /= this.TicksPerPixel;
353            x2 /= this.TicksPerPixel;
354            if (x2 - x1 < 0.5) return;
355            Rect r = new Rect(x1, Y4Core(core) - 4, x2 - x1, 8);
356            this.VisThinRectangles.dc.DrawRectangle(brush, this.BlackPen, r);
357        }
358
359        private void AddRectangle(int core, long start, long end, SolidColorBrush brush, string text)
360        {
361            if (this.optTooltips.IsChecked)
362                AddInteractiveRectangle(core, start, end, brush, text);
363            else
364                AddVisRectangle(core, start, end, brush);
365        }
366        private void AddInteractiveRectangle(int core, long start, long end, SolidColorBrush brush, string text)
367        {
368            double x1 = start - this.TimeMin;
369            double x2 = end - this.TimeMin;
370            x1 /= this.TicksPerPixel;
371            x2 /= this.TicksPerPixel;
372
373            if (x2 - x1 < 0.5) return;
374            Rectangle r = new Rectangle();
375            r.Width = x2 - x1;
376            r.Height = 12;
377            // Top left corner
378            r.RenderTransform = new TranslateTransform(x1, Y4Core(core) - 6);
379            r.Fill = brush;
380            r.Stroke = Brushes.Black;
381            if (this.optTooltips.IsChecked)
382                r.ToolTip = text;
383            r.SnapsToDevicePixels = true;
384            this.Rectangles.Add(r);
385        }
386        private void AddVisRectangle(int core, long start, long end, SolidColorBrush brush)
387        {
388            double x1 = start - this.TimeMin;
389            double x2 = end - this.TimeMin;
390            x1 /= this.TicksPerPixel;
391            x2 /= this.TicksPerPixel;
392            if (x2 - x1 < 0.5) return;
393            Rect r = new Rect(x1, Y4Core(core) - 6, x2 - x1, 12);
394            this.VisRects.dc.DrawRectangle(brush, this.BlackPen, r);
395        }
396
397        private void AddLine(int sendcore, long start, int recvcore, long end, SolidColorBrush brush, string text)
398        {
399            if (this.optTooltips.IsChecked)
400            {
401                AddInteractiveLine(sendcore, start, recvcore, end, brush, text);
402            }
403            else
404            {
405                AddVisLine(sendcore, start, recvcore, end, brush);
406            }
407        }
408        private void AddVisLine(int sendcore, long start, int recvcore, long end, SolidColorBrush brush)
409        {
410            double x1 = start - this.TimeMin;
411            double x2 = end - this.TimeMin;
412            x1 /= this.TicksPerPixel;
413            x2 /= this.TicksPerPixel;
414            this.VisArrows.dc.DrawLine(new Pen(brush, 1.0),
415                    new Point(x1, Y4Core(sendcore)),
416                    new Point(x2, Y4Core(recvcore)));
417        }
418        private void AddInteractiveLine(int sendcore, long start, int recvcore, long end, SolidColorBrush brush, string text)
419        {
420            double x1 = start - this.TimeMin;
421            double x2 = end - this.TimeMin;
422            x1 /= this.TicksPerPixel;
423            x2 /= this.TicksPerPixel;
424            Line l = new Line();
425            l.X1 = x1;
426            l.Y1 = Y4Core(sendcore);
427            l.X2 = x2;
428            l.Y2 = Y4Core(recvcore);
429            l.StrokeThickness = 2.0;
430            l.Stroke = brush;
431            if (this.optTooltips.IsChecked)
432                l.ToolTip = text;
433            l.SnapsToDevicePixels = true;
434            this.Arrows.Add(l);
435        }
436
437        private void AddArrow(int sendcore, long start, int recvcore, long end, SolidColorBrush brush, string text)
438        {
439            if (this.optTooltips.IsChecked)
440            {
441                AddInteractiveArrow(sendcore, start, recvcore, end, brush, text);
442            }
443            else
444            {
445                AddVisLine(sendcore, start, recvcore, end, brush);
446            }
447        }
448        private void AddInteractiveArrow(int sendcore, long start, int recvcore, long end, SolidColorBrush brush, string text)
449        {
450            double x1 = ((double)start - this.TimeMin) / TicksPerPixel;
451            double x2 = ((double)end - this.TimeMin) / TicksPerPixel;
452            Point nock = new Point(x1, Y4Core(sendcore));
453            Point tip = new Point(x2, Y4Core(recvcore));
454
455            double mag;
456            Vector unit, norm;
457            MagNormUnit(nock, tip, out mag, out unit, out norm);
458
459            Point left = tip - 5 * unit + 3 * norm;
460            Point right = tip - 5 * unit - 3 * norm;
461
462            Polygon pg = new Polygon();
463            pg.Points = new PointCollection(5);
464            pg.Points.Add(left);
465            pg.Points.Add(tip);
466            pg.Points.Add(nock);
467            pg.Points.Add(tip);
468            pg.Points.Add(right);
469            pg.Points.Freeze();
470            pg.Stroke = brush;
471            pg.StrokeThickness = 1.0;
472            pg.StrokeMiterLimit = 1.0;
473            pg.Fill = brush;
474            if (this.optTooltips.IsChecked)
475                pg.ToolTip = text;
476            pg.SnapsToDevicePixels = true;
477            this.Arrows.Add(pg);
478        }
479
480        private static void MagNormUnit(Point one, Point two,
481            out double mag, out Vector unit, out Vector norm)
482        {
483            double dx = two.X - one.X;
484            double dy = two.Y - one.Y;
485            mag = Math.Sqrt(dx * dx + dy * dy);
486            if (mag < double.Epsilon)
487                throw new DivideByZeroException("two points are co-located");
488            unit = new Vector(dx / mag, dy / mag);
489            norm = new Vector(-unit.Y, unit.X);
490        }
491
492        private void AddDiamond(int core, long time, SolidColorBrush brush, string text)
493        {
494            if (this.optTooltips.IsChecked)
495                AddInteractiveDiamond(core, time, brush, text);
496            else
497                AddVisDiamond(core, time, brush);
498        }
499        private void AddInteractiveDiamond(int core, long time, SolidColorBrush brush, string text)
500        {
501            double x = ((double)time - this.TimeMin) / this.TicksPerPixel;
502            double size = 8;
503            Polygon dia = new Polygon();
504            dia.Points = new PointCollection(4);
505            dia.Points.Add(new Point(0, 0));
506            dia.Points.Add(new Point(+size / 2, size / 2));
507            dia.Points.Add(new Point(0, size));
508            dia.Points.Add(new Point(-size / 2, size / 2));
509            dia.Points.Freeze();
510            dia.Fill = brush;
511            dia.RenderTransform = new TranslateTransform(x, Y4Core(core));
512            if (this.optTooltips.IsChecked)
513                dia.ToolTip = text;
514            dia.SnapsToDevicePixels = true;
515            this.Blobs.Add(dia);
516        }
517        private void AddVisDiamond(int core, long time, SolidColorBrush brush)
518        {
519            double x = ((double)time - this.TimeMin) / this.TicksPerPixel;
520            double y = Y4Core(core);
521            double size = 8;
522            StreamGeometry sg = new StreamGeometry();
523            using (StreamGeometryContext sgc = sg.Open())
524            {
525                sgc.BeginFigure(new Point(x, y), true, true);
526                sgc.LineTo(new Point(x + size / 2, y + size /2), true, false);
527                sgc.LineTo(new Point(x + 0, y + size), true, false);
528                sgc.LineTo(new Point(x - size / 2, y + size / 2), true, false);
529            }
530            sg.Freeze();
531            this.VisBlobs.dc.DrawGeometry(brush, null, sg);
532        }
533
534
535        private void AddInteractiveBlob(int core, long time, SolidColorBrush brush, string text)
536        {
537            double x = ((double)time - this.TimeMin) / this.TicksPerPixel;
538            Ellipse e = new Ellipse();
539            e.Width = e.Height = 6;
540            e.Fill = brush;
541            if (this.optTooltips.IsChecked)
542                e.ToolTip = text;
543            e.RenderTransform = new TranslateTransform(x, Y4Core(core) - e.Height / 2);
544            e.SnapsToDevicePixels = true;
545            this.Blobs.Add(e);
546        }
547        private void AddVisBlob(int core, long time, SolidColorBrush brush, string text)
548        {
549            double x = ((double)time - this.TimeMin) / this.TicksPerPixel;
550            this.VisBlobs.dc.DrawEllipse(brush, null, new Point(x, Y4Core(core)), 3, 3);
551        }
552        private void AddBlob(int core, long time, TraceEvent te)
553        {
554            if (this.optTooltips.IsChecked)
555            {
556                AddInteractiveBlob(core, time, Brushes.Black,
557                    String.Format("At {0:n0}: ", time - this.TimeMin) + te.ToString());
558            }
559            else
560            {
561                AddVisBlob(core, time, Brushes.Black,
562                    String.Format("At {0:n0}: ", time - this.TimeMin) + te.ToString());
563            }
564        }
565
566        private void ReRender()
567        {
568            this.mainCanvas.Children.Clear();
569
570            if (this.ttec != null && this.procnames != null)
571            {
572                ReRenderFromData(ttec, procnames);
573            }
574            else
575            {
576                Stream stream = System.Reflection.Assembly.GetExecutingAssembly().GetManifestResourceStream("Aquarium.barrelfish.png");
577                BitmapImage bi = new BitmapImage();
578                bi.BeginInit();
579                bi.StreamSource = stream;
580                bi.EndInit();
581                bi.Freeze();
582                Image image = new Image();
583                image.Source = bi;
584                // Why do I need to do this?
585                double width = this.dockPanel3.ActualWidth;
586                double height = this.dockPanel3.ActualHeight;
587                image.Width = width;
588                image.Height = height;
589
590                image.RenderTransform = new TranslateTransform(0, 0);
591
592                this.mainCanvas.Children.Add(image);
593                this.mainCanvas.Width = width;
594                this.mainCanvas.Height = height;
595            }
596        }
597
598
599
600        private struct ChannelAction : IComparable<ChannelAction>
601        {
602            public readonly long Time;
603            public readonly int Core;
604            public readonly ulong Channel;
605            public readonly SolidColorBrush Colour;
606
607            public ChannelAction(long time, int core, ulong channel, SolidColorBrush colour)
608            {
609                this.Time = time;
610                this.Core = core;
611                this.Channel = channel;
612                this.Colour = colour;
613            }
614
615            public int CompareTo(ChannelAction other)
616            {
617                return this.Time.CompareTo(other.Time);
618            }
619        } // struct ChannelAction
620
621
622        #region Event type constants
623
624        private const ushort TRACE_SUBSYS_KERNEL = 0xFFFF;
625        private const ushort TRACE_EVENT_CSWITCH = 0xCCCC;
626        private const ushort TRACE_EVENT_BZERO   = 0xB0;
627        private const ushort TRACE_EVENT_TIMERTICK = 0x1;
628        private const ushort TRACE_EVENT_TIMER_SYNC = 0x2;
629
630        private const ushort TRACE_EVENT_SCHED_MAKE_RUNNABLE = 0xED00;
631        private const ushort TRACE_EVENT_SCHED_REMOVE = 0xED01;
632        private const ushort TRACE_EVENT_SCHED_YIELD = 0xED02;
633        private const ushort TRACE_EVENT_SCHED_SCHEDULE = 0xED03;
634        private const ushort TRACE_EVENT_SCHED_CURRENT = 0xED04;
635
636        private const ushort TRACE_EVENT_BMP_RX = 0xBEE1;
637        private const ushort TRACE_EVENT_BMP_PRE_DELIVER = 0xBEE2;
638        private const ushort TRACE_EVENT_BMP_POST_DELIVER = 0xBEE3;
639        private const ushort TRACE_EVENT_BMP_PUMP = 0xBEE4;
640        private const ushort TRACE_EVENT_BMP_SEND = 0xBEE5;
641
642
643        private const ushort TRACE_SUBSYS_THREADS = 0xEEEE;
644        private const ushort TRACE_EVENT_BARRIER_ENTER = 0x0100;
645        private const ushort TRACE_EVENT_BARRIER_LEAVE = 0x0101;
646        private const ushort TRACE_EVENT_MUTEX_LOCK_ENTER = 0x0200;
647        private const ushort TRACE_EVENT_MUTEX_LOCK_LEAVE = 0x0201;
648        private const ushort TRACE_EVENT_MUTEX_LOCK_NESTED_ENTER = 0x0202;
649        private const ushort TRACE_EVENT_MUTEX_LOCK_NESTED_LEAVE = 0x0203;
650        private const ushort TRACE_EVENT_MUTEX_TRYLOCK = 0x0204;
651        private const ushort TRACE_EVENT_MUTEX_UNLOCK = 0x0205;
652
653        private const ushort TRACE_EVENT_COND_WAIT_ENTER = 0x0300;
654        private const ushort TRACE_EVENT_COND_WAIT_LEAVE = 0x0301;
655        private const ushort TRACE_EVENT_COND_SIGNAL = 0x0302;
656        private const ushort TRACE_EVENT_COND_BROADCAST = 0x0303;
657
658        private const ushort TRACE_EVENT_SEM_WAIT_ENTER = 0x0400;
659        private const ushort TRACE_EVENT_SEM_WAIT_LEAVE = 0x0401;
660        private const ushort TRACE_EVENT_SEM_TRYWAIT = 0x0402;
661        private const ushort TRACE_EVENT_SEM_POST = 0x0403;
662
663
664
665        private const ushort TRACE_SUBSYS_MEMSERV = 0xA000;
666        private const ushort TRACE_EVENT_ALLOC    = 0x0001;
667
668
669        private const ushort TRACE_SUBSYS_MONITOR = 0xB000;
670        private const ushort TRACE_EVENT_SPAN0    = 0x0000;
671        private const ushort TRACE_EVENT_SPAN1    = 0x0001;
672        private const ushort TRACE_EVENT_SPAN     = 0x0002;
673        private const ushort TRACE_EVENT_PCREQ    = 0x0003;
674        private const ushort TRACE_EVENT_PCREPLY  = 0x0004;
675        private const ushort TRACE_EVENT_PCREQ_INTER   = 0x0005;
676        private const ushort TRACE_EVENT_PCREPLY_INTER = 0x0006;
677        private const ushort TRACE_EVENT_URPC_BLOCK   = 0x0007;
678        private const ushort TRACE_EVENT_URPC_UNBLOCK = 0x0008;
679        private const ushort TRACE_EVENT_REMOTE_CAP_RETYPE = 0x0009;
680        private const ushort TRACE_EVENT_REMOTE_CAP_RETYPE_RETRY = 0x0010;
681        private const ushort TRACE_EVENT_REMOTE_CAP_RETYPE_MSG = 0x0011;
682        private const ushort TRACE_EVENT_REMOTE_CAP_RETYPE_END = 0x0012;
683        private const ushort TRACE_EVENT_POLLING = 0xBBBB;
684
685
686        private const ushort TRACE_SUBSYS_BFLIB = 0xBFBF;
687
688
689        private const ushort TRACE_SUBSYS_CHIPS   = 0xC000;
690        private const ushort TRACE_EVENT_CHIPS_LISTENCB = 0x0001;
691
692
693        private const ushort TRACE_SUBSYS_TWEED       = 0x2000;
694        private const ushort TRACE_EVENT_TWEED_START  = 0x0000;
695        private const ushort TRACE_EVENT_TWEED_END    = 0x0001;
696        private const ushort TRACE_EVENT_STEAL        = 0x0002;
697        private const ushort TRACE_EVENT_STEAL_END    = 0x0003;
698        private const ushort TRACE_EVENT_WAIT         = 0x0004;
699        private const ushort TRACE_EVENT_WAIT_END     = 0x0005;
700        private const ushort TRACE_EVENT_LOCKING      = 0x0006;
701        private const ushort TRACE_EVENT_LOCKING_END  = 0x0007;
702
703
704        private const ushort TRACE_SUBSYS_ROUTE = 0x3000;
705        private const ushort TRACE_EVENT_BCAST_WITH_CCAST_SEND = 0x0001;
706        private const ushort TRACE_EVENT_BCAST_WITH_CCAST = 0x0002;
707        private const ushort TRACE_EVENT_RECV_BCAST_WITH_CCAST = 0x0003;
708        private const ushort TRACE_EVENT_RECV_CCAST = 0x0004;
709        private const ushort TRACE_EVENT_ROUTE_BENCH_START = 0x005;
710        private const ushort TRACE_EVENT_ROUTE_BENCH_STOP = 0x0006;
711
712
713        private const ushort TRACE_SUBSYS_BENCH = 0x1234;
714        private const ushort TRACE_EVENT_PCBENCH = 0x0000;
715        private const ushort TRACE_EVENT_RXPING = 0x0001;
716        private const ushort TRACE_EVENT_RXPONG = 0x0002;
717
718
719        private const ushort TRACE_SUBSYS_BOMP = 0x4000;
720        private const ushort TRACE_EVENT_BOMP_START = 0x0001;
721        private const ushort TRACE_EVENT_BOMP_STOP = 0x0002;
722        private const ushort TRACE_EVENT_BOMP_ITER = 0x0003;
723
724        #endregion
725
726        private void ReadDataFromStream(StreamReader reader)
727        {
728            DateTime t0 = DateTime.Now;
729
730            DateTime t1 = DateTime.Now;
731
732            if (this.dcbstatic != null)
733                this.procnames = new Dictionary<ulong,string>(this.dcbstatic);
734            else
735                this.procnames = new Dictionary<ulong,string>();
736
737            this.procnames[0] = "(idle)";
738            this.ttec = new TemporalTraceEventCollection();
739
740            string line;
741            while ((line = reader.ReadLine()) != null)
742            {
743                if (line.Length == 0)
744                    continue;
745                string[] tokens = line.Split();
746                if (tokens.Length < 3) continue;
747
748                if (tokens[0] == "#" && tokens[1] == "DCB" && tokens.Length == 5)
749                {
750                    ulong dcb;
751                    if (ulong.TryParse(tokens[3], NumberStyles.AllowHexSpecifier, null, out dcb))
752                    {
753                        // 32-bit dcb with top bit set to identify not timestamp
754                        if ((dcb & 0xffffffff00000000UL) == 0x8000000000000000UL)
755                            dcb ^= 0x8000000000000000UL;
756                        // We set rather than adding in case a duplicate happened somehow
757                        procnames[dcb] = tokens[4];
758                    }
759                    continue;
760                }
761                if (tokens[0] == "#")
762                    continue;
763
764                if (!ttec.Add(tokens[0], tokens[1], tokens[2]))
765                    continue;
766            }
767        }
768
769
770        private string FromTo(string prepend, long from, long to)
771        {
772            string result = String.Format("from {0:n0} to {1:n0}",
773                from - this.TimeMin, to - this.TimeMin);
774            if (!string.IsNullOrEmpty(prepend))
775                result = prepend + result;
776            return result;
777        }
778
779        private void ReRenderFromData(TemporalTraceEventCollection ttec,
780            Dictionary<ulong, string> procnames)
781        {
782            List<ChannelAction> channelactions = new List<ChannelAction>();
783            bool heads = this.optHeads.IsChecked;
784
785            if (this.optTooltips.IsChecked)
786            {
787                this.Rectangles.Clear();
788                this.ThinRectangles.Clear();
789                this.Blobs.Clear();
790                this.Arrows.Clear();
791            }
792            else
793            {
794                this.VisRects.BeginRender();
795                this.VisThinRectangles.BeginRender();
796                this.VisBlobs.BeginRender();
797                this.VisArrows.BeginRender();
798            }
799
800            for (int core = ttec.MinCore; core <= ttec.MaxCore; core++)
801            {
802                // TODO: XXX: This is x64 specific hack.  Also need to look
803                // for both so we can continue to support the standard demo.
804                const ulong OldHighBits = 0xffffff0000000000UL;
805                const ulong NewHighBits = 0xffffff8000000000UL;
806
807                long? bzero = null;
808                long? runningstart = null;
809                long? blockingstart = null;
810                long? pollingstart = null;
811
812                SolidColorBrush msgColour = null;
813
814                long? tweedWorkStart = null;
815                long? tweedWaitStart = null;
816                long? tweedLockStart = null;
817                bool isTweedSteal = false;
818
819                string name = null;
820                ulong? running = null;
821
822                foreach (TemporalTraceEvent tte in ttec.OnCore(core))
823                {
824                    long now = tte.Time;
825                    TraceEvent te = tte.Event;
826
827
828                    //string text = tokens.Length >= 4 ? tokens[3] : null;
829                    //if (string.IsNullOrEmpty(text) && dcb.HasValue)
830                    //    procnames.TryGetValue(dcb.Value, out text);
831
832                    // NB.  Take care when editing this code to not introduce
833                    // serious performance regression.  This is a single if/elif/else
834                    // where the last clause adds a "geneic" event.  Do NOT alter
835                    // the flow control so that regular events also post a generic
836                    // blob, or so that when a option is disabled that it posts
837                    // a generic blob instead of the regular processing.
838
839                    if (te.SubSys == TRACE_SUBSYS_KERNEL)
840                    {
841                        if (!optKernel.IsChecked) continue;
842
843                        if (te.Event == TRACE_EVENT_BZERO)
844                        {
845                            if (te.Data == 1)
846                                bzero = now;
847                            else if (te.Data == 0 && bzero.HasValue)
848                                AddThinRectangle(core, bzero.Value, now, Brushes.Purple,
849                                    FromTo("bzero ", bzero.Value, now));
850                            else
851                                AddBlob(core, now, te);
852                        }
853                        else if (te.Event == TRACE_EVENT_CSWITCH)
854                        {
855                            if (running.HasValue && runningstart.HasValue)
856                            {
857                                if (!procnames.TryGetValue(running.Value, out name))
858                                    if (!procnames.TryGetValue(running.Value | OldHighBits, out name))
859                                        procnames.TryGetValue(running.Value | NewHighBits, out name);
860
861                                AddRectangle(core, runningstart.Value, now, BrushForName(name),
862                                    String.Format("{1}=0x{0:x} ", running.Value,
863                                        string.IsNullOrEmpty(name) ? "?" : name)
864                                        + FromTo(null, runningstart.Value, now));
865                            }
866                            runningstart = now;
867                            running = te.Data;
868                        }
869                        else if (te.Event == TRACE_EVENT_TIMERTICK)
870                        {
871                            AddDiamond(core, now, Brushes.Black, "timer tick");
872                        }
873                        else if (te.Event == TRACE_EVENT_BMP_PUMP)
874                        {
875                            if (te.Data == 0)
876                            {
877                                if (pollingstart.HasValue)
878                                    AddThinRectangle(core, pollingstart.Value, now, Brushes.Cyan,
879                                        FromTo("Polling ", pollingstart.Value, now));
880                                pollingstart = null;
881                            }
882                            else
883                            {
884                                pollingstart = now;
885                            }
886                        }
887                        else
888                            AddBlob(core, now, te);
889                    }
890                    else if (te.SubSys == TRACE_SUBSYS_MONITOR)
891                    {
892                        if (!optMonitor.IsChecked) continue;
893
894                        if (te.Event == TRACE_EVENT_URPC_BLOCK)
895                        {
896                            // We just started blocking
897                            if (runningstart.HasValue)
898                                AddRectangle(core, runningstart.Value, now, BrushForName(name), name);
899                            blockingstart = now;
900                            //name = "monitor"; // XXX?
901                            //running = null; // XXX?
902                        }
903                        else if (te.Event == TRACE_EVENT_URPC_UNBLOCK)
904                        {
905                            if (blockingstart.HasValue)
906                                AddRectangle(core, blockingstart.Value, now, Brushes.DarkGray, "blocked");
907                            else
908                                AddBlob(core, now, te);
909                        }
910                        else if (te.Event == TRACE_EVENT_POLLING)
911                        {
912                            pollingstart = now;
913                        }
914                        else if (te.Event == TRACE_EVENT_REMOTE_CAP_RETYPE_MSG)
915                        {
916                            if (te.Data == 0)
917                            {
918                                msgColour = Brushes.Green;
919                            }
920                            else if (te.Data == 1)
921                            {
922                                msgColour = Brushes.IndianRed;
923                            }
924                            else if (te.Data == 3)
925                            {
926                                msgColour = Brushes.Red;
927                            }
928                        }
929                        else
930                            AddBlob(core, now, te);
931                    }
932                    else if (te.IsRecv)
933                    {
934                        channelactions.Add(new ChannelAction(now, core, te.Raw, null));
935                    }
936                    else if (te.IsSend)
937                    {
938                        channelactions.Add(new ChannelAction(now, core, te.Raw, msgColour));
939                        msgColour = null;
940                    }
941                    else if (te.Raw == 0xBBBB)
942                    {
943                        // We just started blocking
944                        if (runningstart.HasValue && running.HasValue)
945                        {
946                            if (!procnames.TryGetValue(running.Value, out name))
947                                if (!procnames.TryGetValue(running.Value | OldHighBits, out name))
948                                    procnames.TryGetValue(running.Value | NewHighBits, out name);
949
950                            AddRectangle(core, runningstart.Value, now, BrushForName(name),
951                                String.Format("{1}=0x{0:x} ", running.Value,
952                                string.IsNullOrEmpty(name) ? "?" : name)
953                                + FromTo(null, runningstart.Value, now));
954                        }
955                        blockingstart = now;
956                    }
957                    else if (te.Raw == 0xAAAA)
958                    {
959                        runningstart = now;
960                    }
961                    else if (te.Raw == 0xBBB)
962                    {
963                        pollingstart = now;
964                    }
965                    else if (te.Raw == 0xAAA)
966                    {
967                        if (pollingstart.HasValue)
968                            AddThinRectangle(core, pollingstart.Value, now, Brushes.Cyan,
969                                FromTo("Polling ", pollingstart.Value, now));
970                        pollingstart = null;
971                    }
972                    else if (te.SubSys == TRACE_SUBSYS_MEMSERV)
973                    {
974                        if (!optAlloc.IsChecked) continue;
975
976                        if (te.Event == TRACE_EVENT_ALLOC)
977                            AddDiamond(core, now, Brushes.Navy, String.Format("Allocate {0}k",
978                                1 << ((int)te.Data - 10)));
979                        else
980                            AddBlob(core, now, te);
981                    }
982                    else if (te.SubSys == TRACE_SUBSYS_TWEED)
983                    {
984                        if (!optTweed.IsChecked) continue;
985
986                        if (te.Event == TRACE_EVENT_TWEED_START)
987                        {
988                            tweedWorkStart = now;
989                            isTweedSteal = false;
990                        }
991                        else if (te.Event == TRACE_EVENT_STEAL)
992                        {
993                            if (tweedWaitStart.HasValue)
994                            {
995                                AddRectangle(core, tweedWaitStart.Value, now, Brushes.Purple, "Waiting");
996                            }
997                            if (optTweedArrows.IsChecked)
998                            {
999                                SolidColorBrush colour = tweedWaitStart.HasValue ? Brushes.Coral : Brushes.Orange;
1000                                if (heads)
1001                                    AddArrow((int)te.Data, now, core, now, colour,
1002                                          String.Format("Core {0} stealing tasks from core {1}",
1003                                          core, te.Data));
1004                                else
1005                                    AddLine((int)te.Data, now, core, now, colour,
1006                                        String.Format("Core {0} stealing tasks from core {1}",
1007                                        core, te.Data));
1008                            }
1009                            tweedWorkStart = now;
1010                            isTweedSteal = true;
1011                        }
1012                        else if (te.Event == TRACE_EVENT_STEAL_END)
1013                        {
1014                            SolidColorBrush colour = tweedWaitStart.HasValue ? Brushes.Coral : Brushes.Orange;
1015                            if (optTweedArrows.IsChecked)
1016                            {
1017                                if (heads)
1018                                    AddArrow(core, now, (int)te.Data, now, colour,
1019                                        String.Format("Core {0} completed tasks stolen from core {1}",
1020                                        core, te.Data));
1021                                else
1022                                    AddLine(core, now, (int)te.Data, now, colour,
1023                                        String.Format("Core {0} completed tasks stolen from core {1}",
1024                                        core, te.Data));
1025                            }
1026                            if (tweedWorkStart.HasValue)
1027                                AddRectangle(core, tweedWorkStart.Value, now, colour, "Stolen Tasks from core " + te.Data);
1028                            tweedWorkStart = null;
1029                            if (tweedWaitStart.HasValue)
1030                                tweedWaitStart = now;
1031                        }
1032                        else if (te.Event == TRACE_EVENT_TWEED_END)
1033                        {
1034                            if (tweedWorkStart.HasValue)
1035                                AddRectangle(core, tweedWorkStart.Value, now, Brushes.Yellow, "Main Task");
1036                            tweedWorkStart = null;
1037                        }
1038                        else if (te.Event == TRACE_EVENT_WAIT)
1039                        {
1040                            if (tweedWorkStart.HasValue)
1041                            {
1042                                SolidColorBrush colour = tweedWaitStart.HasValue ? Brushes.Coral : Brushes.Orange;
1043                                if (isTweedSteal)
1044                                    AddRectangle(core, tweedWorkStart.Value, now, colour, "Stolen Tasks");
1045                                else
1046                                    AddRectangle(core, tweedWorkStart.Value, now, Brushes.Yellow, "Main Task");
1047                            }
1048
1049                            if (optTweedArrows.IsChecked)
1050                            {
1051                                if (heads)
1052                                    AddArrow(core, now, (int)te.Data, now, Brushes.DarkViolet,
1053                                        String.Format("Core {0} waiting for tasks stolen by core {1}",
1054                                        core, te.Data));
1055                                else
1056                                    AddLine(core, now, (int)te.Data, now, Brushes.DarkViolet,
1057                                        String.Format("Core {0} waiting for tasks stolen by core {1}",
1058                                        core, te.Data));
1059                            }
1060                            tweedWorkStart = null;
1061                            tweedWaitStart = now;
1062                        }
1063                        else if (te.Event == TRACE_EVENT_WAIT_END)
1064                        {
1065                            if (tweedWaitStart.HasValue)
1066                                AddRectangle(core, tweedWaitStart.Value, now, Brushes.DarkViolet, "Waiting for task stolen by core " + te.Data);
1067
1068                            if (optTweedArrows.IsChecked)
1069                            {
1070                                if (heads)
1071                                    AddArrow((int)te.Data, now, core, now, Brushes.DarkViolet,
1072                                        String.Format("Core {0} can now continue, tasks stolen by core {1} completed",
1073                                        core, te.Data));
1074                                else
1075                                    AddLine((int)te.Data, now, core, now, Brushes.DarkViolet,
1076                                        String.Format("Core {0} can now continue, tasks stolen by core {1} completed",
1077                                        core, te.Data));
1078                            }
1079                            tweedWaitStart = null;
1080                            tweedWorkStart = now;
1081                        }
1082                        else if (te.Event == TRACE_EVENT_LOCKING)
1083                        {
1084                            tweedLockStart = now;
1085                        }
1086                        else if (te.Event == TRACE_EVENT_LOCKING_END)
1087                        {
1088                            if (tweedLockStart.HasValue)
1089                                AddRectangle(core, tweedLockStart.Value, now, Brushes.Maroon, "Waiting for Lock to be released");
1090                            tweedLockStart = null;
1091                        }
1092                        else
1093                        {
1094                            AddBlob(core, now, te);
1095                        }
1096                    } // tweed
1097                    else // An unknown type of event
1098                    {
1099                        if (optGeneric.IsChecked)
1100                        {
1101                            AddBlob(core, now, te);
1102                        }
1103                    }
1104                } // end foreach
1105
1106                // End of data for this core,flush running process
1107                if (running.HasValue && runningstart.HasValue)
1108                {
1109                    if (!procnames.TryGetValue(running.Value, out name))
1110                        if (!procnames.TryGetValue(running.Value | OldHighBits, out name))
1111                            procnames.TryGetValue(running.Value | NewHighBits, out name);
1112
1113                    if (!"monitor".Equals(name)) // test this way round in case name==null
1114                    {
1115                        AddRectangle(core, runningstart.Value, (long)this.TimeMax, BrushForName(name),
1116                        String.Format("{2}={0:x} from {1:n0} to ...",
1117                        running.Value, runningstart.Value - this.TimeMin,
1118                        string.IsNullOrEmpty(name) ? "?" : name));
1119                    }
1120                }
1121            } // end for core
1122
1123
1124            //Dictionary<ulong, KeyValuePair<int, long>> sent = new Dictionary<ulong, KeyValuePair<int, long>>();
1125
1126            Dictionary<ulong, ChannelAction> sent = new Dictionary<ulong, ChannelAction>();
1127            Dictionary<ulong, ChannelAction> rcvd = new Dictionary<ulong, ChannelAction>();
1128            ulong rxbit = 0x0100000000000000;
1129            channelactions.Sort();
1130            if (optChannel.IsChecked)
1131            {
1132                foreach (ChannelAction ca in channelactions)
1133                {
1134                    // In theory EA is send and EB is recv, but sometimes clocks are funny
1135                    ulong chan = ca.Channel & 0x00FFFFFFFFFFFFFF;
1136                    if ((ca.Channel & rxbit) != 0)
1137                    {
1138                        ChannelAction other;
1139                        if (sent.TryGetValue(chan, out other))
1140                        {
1141                            sent.Remove(chan);
1142                            // Forwards in time
1143                            if (heads)
1144                                AddArrow(other.Core, other.Time, ca.Core, ca.Time, other.Colour ?? Brushes.Orange,
1145                                    String.Format("Chan={0:x} Sent {1:n0} Rcvd {2:n0}",
1146                                    chan, other.Time - this.TimeMin, ca.Time - this.TimeMin));
1147                            else
1148                                AddLine(other.Core, other.Time, ca.Core, ca.Time, other.Colour ?? Brushes.Orange,
1149                                    String.Format("Chan={0:x} Sent {1:n0} Rcvd {2:n0}",
1150                                    chan, other.Time - this.TimeMin, ca.Time - this.TimeMin));
1151                        }
1152                        else
1153                            rcvd.Add(chan, ca);
1154                    }
1155                    else
1156                    {
1157                        ChannelAction other;
1158                        if (rcvd.TryGetValue(chan, out other))
1159                        {
1160                            rcvd.Remove(chan);
1161                            // Bacwards in time
1162                            if (heads)
1163                                AddArrow(other.Core, other.Time, ca.Core, ca.Time, ca.Colour ?? Brushes.OrangeRed,
1164                                    String.Format("Chan={0:x} Sent {1:n0} Rcvd {2:n0}",
1165                                    chan, ca.Time - this.TimeMin, other.Time - this.TimeMin));
1166                            else
1167                                AddLine(other.Core, other.Time, ca.Core, ca.Time, ca.Colour ?? Brushes.OrangeRed,
1168                                    String.Format("Chan={0:x} Sent {1:n0} Rcvd {2:n0}",
1169                                    chan, ca.Time - this.TimeMin, other.Time - this.TimeMin));
1170                        }
1171                        else
1172                            sent.Add(chan, ca);
1173                    }
1174                }
1175            }
1176
1177            DateTime t2 = DateTime.Now;
1178
1179            // Any left over?
1180            if (optGeneric.IsChecked)
1181            {
1182                foreach (KeyValuePair<ulong, ChannelAction> kvp in sent)
1183                {
1184                    AddDiamond(kvp.Value.Core, kvp.Value.Time, Brushes.DarkTurquoise, kvp.Key.ToString("x"));
1185                }
1186                foreach (KeyValuePair<ulong, ChannelAction> kvp in rcvd)
1187                {
1188                    AddDiamond(kvp.Value.Core, kvp.Value.Time, Brushes.SeaGreen, kvp.Key.ToString("x"));
1189                }
1190            }
1191            DateTime t3 = DateTime.Now;
1192
1193            // So they all have the right Z order
1194            ShowBackground();
1195            ShowTimeAxis();
1196
1197            if (this.optTooltips.IsChecked == false)
1198            {
1199                this.VisRects.EndRender();
1200                this.VisThinRectangles.EndRender();
1201                this.VisBlobs.EndRender();
1202                this.VisArrows.EndRender();
1203                mainCanvas_AddChild(this.VisHost);
1204            }
1205            else
1206            {
1207                foreach (UIElement uie in this.Rectangles)
1208                    mainCanvas_AddChild(uie);
1209                foreach (UIElement uie in this.ThinRectangles)
1210                    mainCanvas_AddChild(uie);
1211                foreach (UIElement uie in this.Blobs)
1212                    mainCanvas_AddChild(uie);
1213                foreach (UIElement uie in this.Arrows)
1214                    mainCanvas_AddChild(uie);
1215            }
1216            ShowCpuAxis();
1217
1218            DateTime t4 = DateTime.Now;
1219
1220            // Otherwise last Blob is clipped at its LEFT edge, doh!
1221            // XXX This still doesnt quite work when zoomed in
1222            mainCanvas.Width += 10;
1223            // Stretch it out
1224            if (mainCanvas.Width < this.dockPanel3.ActualWidth)
1225                mainCanvas.Width = this.dockPanel3.ActualWidth;
1226
1227            Console.WriteLine("Render {0} {1}", t3 - t2, t4 - t3);
1228
1229//            System.Threading.Thread.Sleep(20); // XXX RI TMP
1230
1231        } // Method RenderFromData
1232
1233
1234
1235        // -------------------------
1236
1237        public void SetZoom()
1238        {
1239            this.PixelsPerSecond = Math.Pow(2, Zoom.Value);
1240
1241            double xsize = this.TimeRange * PixelsPerTick;
1242            mainCanvas.Width = xsize;
1243            //double xscale = PIXELSPERSECOND / (App.state.LastTs - App.state.FirstTs);
1244            Console.WriteLine("Canvas: {0} {1} {2}", mainCanvas.ActualWidth, mainCanvas.Width, xsize);
1245
1246            // Scrollbar is in timestamp units ... it controls the timestamp value of the left
1247            // hand edge of the main canvas window so it's value ranges from the first timestamp
1248            // to the last timestamp minus the viewportsize.  The "viewport"
1249            // size tells the scrollbar how much of the range is visible.
1250            double visibleWidth = this.dockPanel3.ActualWidth;
1251            XScrollBar.Minimum = this.TimeMin;
1252            XScrollBar.ViewportSize = visibleWidth * TicksPerPixel;
1253            XScrollBar.Maximum = this.TimeMax - XScrollBar.ViewportSize;
1254            Console.WriteLine("ViewportSize {0}", XScrollBar.ViewportSize);
1255
1256            // The
1257            XScrollBar.LargeChange = XScrollBar.ViewportSize;
1258            XScrollBar.SmallChange = XScrollBar.ViewportSize / 10;
1259        } // SetZoom
1260
1261        public void SetScroll()
1262        {
1263            double xshift = (XScrollBar.Value - XScrollBar.Minimum) * PixelsPerTick;
1264            this.VisibleTimeMin = XScrollBar.Value;
1265            this.VisibleTimeMax = this.VisibleTimeMin + XScrollBar.ViewportSize;
1266            Console.WriteLine("Scroll: visible range {0:f0}-{1:f0}", VisibleTimeMin, VisibleTimeMax);
1267            mainCanvas.RenderTransform = new TranslateTransform(-xshift, 0);
1268        } // SetScroll
1269
1270        private void ConsiderRescale()
1271        {
1272            if (this.TimeRange / this.TicksPerPixel < this.dockPanel3.ActualWidth / 2)
1273            {
1274                double targetPixelsPerSecond = this.dockPanel3.ActualWidth
1275                    / (this.TimeRange / this.TicksPerSecond);
1276                this.Zoom.Value = Math.Floor(Math.Log(targetPixelsPerSecond, 2));
1277                SetZoom();
1278                SetScroll();
1279                ReRender();
1280            }
1281        } // ConsiderRescale
1282
1283        // Event handlers
1284
1285        private void FileDcb_Click(object sender, RoutedEventArgs e)
1286        {
1287            string filename;
1288            if (!Dialogs.OpenThese("bfl", "Barrelfish log files|*.bfl", out filename))
1289                return;
1290
1291            this.dcbstatic = new Dictionary<ulong, string>();
1292
1293            using (TextReader reader = new StreamReader(filename))
1294            {
1295                string line;
1296                while ((line = reader.ReadLine()) != null)
1297                {
1298                    if (string.IsNullOrEmpty(line) || line[0] == '#')
1299                        continue;
1300
1301                    string[] tokens = line.Split();
1302                    ulong dcb;
1303                    // bool ok = ulong.TryParse(s, NumberStyles.AllowHexSpecifier, null, out raw);
1304
1305                    if (tokens.Length == 3
1306                        && tokens[0] == "DCB:"
1307                        && tokens[1].StartsWith("0x")
1308                        && ulong.TryParse(tokens[1].Substring(2), NumberStyles.AllowHexSpecifier, null, out dcb))
1309                        this.dcbstatic.Add(dcb, tokens[2]);
1310                }
1311            }
1312            this.ReRender();
1313        } // FileDcb_Click
1314
1315        private void FileOpen_Click(object sender, RoutedEventArgs e)
1316        {
1317            this.worker.CancelAsync();
1318            // XXX Cancel background worker
1319            if (this.TraceFetcher != null)
1320                this.TraceFetcher.Dispose();
1321            this.TraceFetcher = null;
1322
1323            string filename;
1324            //if (!ViewEtl.Dialogs.OpenThese("txt", "Text files|*.txt", out filename))
1325            if (!Dialogs.OpenThese("bfl", "Barrelfish Log files|*.bfl", out filename))
1326                    return;
1327
1328            this.Title = this.Name + ": " + filename;
1329
1330            StreamReader reader = new StreamReader(filename);
1331            ReadDataFromStream(reader);
1332            reader.Close();
1333
1334            this.Filename = filename;
1335            this.ReRender();
1336            this.zoomOut();
1337        } // FileOpen_Click
1338
1339
1340        private void Option_Click(object sender, RoutedEventArgs e)
1341        {
1342            ReRender();
1343        }
1344
1345        private void Connect_Click(object sender, RoutedEventArgs e)
1346        {
1347            MenuItem item = sender as MenuItem;
1348            if (item == null)
1349                throw new NotImplementedException();
1350            string header = item.Header as string;
1351            if (string.IsNullOrEmpty(header))
1352                throw new NotImplementedException();
1353
1354            if (this.worker.IsBusy) return;
1355            this.Title = this.Name + ": connecting to " + header;
1356            this.Filename = header;
1357            this.worker.RunWorkerAsync(header);
1358        }
1359
1360
1361        private void Zoom_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
1362        {
1363            if (this.mainCanvas == null)
1364                return; // Still processing the XAML
1365            Console.WriteLine("{0} pixels/sec", Math.Pow(2, Zoom.Value));
1366            SetZoom();
1367            SetScroll();
1368            ReRender();
1369        }
1370
1371        private void XScrollBar_Scroll(object sender, System.Windows.Controls.Primitives.ScrollEventArgs e)
1372        {
1373            SetScroll();
1374            if (e.ScrollEventType != ScrollEventType.ThumbTrack)
1375            {
1376                ReRender();
1377            }
1378        }
1379
1380        private void zoomOut()
1381        {
1382            double targetPixelsPerSecond = this.dockPanel3.ActualWidth
1383                / (this.TimeRange / this.TicksPerSecond);
1384            double wish = Math.Floor(Math.Log(targetPixelsPerSecond, 2));
1385            Zoom.Value = Math.Max(Zoom.Minimum, wish);
1386            // Zoom_ValueChanged already called
1387        }
1388
1389        private void zoomOut_Click(object sender, RoutedEventArgs e)
1390        {
1391            zoomOut();
1392        }
1393
1394        private void Zoom_DragCompleted(object sender, DragCompletedEventArgs e)
1395        {
1396            SetZoom();
1397            SetScroll();
1398            ReRender();
1399        }
1400
1401        private void dockPanel3_SizeChanged(object sender, SizeChangedEventArgs e)
1402        {
1403            if (e.WidthChanged)
1404            {
1405                SetZoom();
1406                SetScroll();
1407            }
1408            else if (e.HeightChanged)
1409            {
1410                this.mainCanvas.Height = e.NewSize.Height;
1411            }
1412            ReRender();
1413        }
1414
1415
1416        void BackgroundRender()
1417        {
1418            ReRender();
1419            ConsiderRescale();
1420        }
1421
1422        // Functions for interacting with the background worker
1423
1424        void worker_DoWork(object sender, DoWorkEventArgs e)
1425        {
1426            Console.WriteLine("worker_DoWork entered");
1427
1428            if (this.worker.CancellationPending)
1429            {
1430                Console.WriteLine("worker_DoWork: cancelling...");
1431                e.Result = null;
1432                e.Cancel = true;
1433                return;
1434            }
1435
1436            string target = e.Argument as string;
1437
1438            if (target != null)
1439            {
1440                // Connecting to a new place
1441                if (this.TraceFetcher != null)
1442                    this.TraceFetcher.Dispose();
1443                try
1444                {
1445                    this.TraceFetcher = new TraceFetcher(target);
1446                    Console.WriteLine("tracefetcher was constructed");
1447                    if (this.worker.CancellationPending)
1448                    {
1449                        e.Result = null;
1450                        e.Cancel = true;
1451                        return;
1452                    }
1453                    this.worker.ReportProgress(1);
1454                }
1455                catch (Exception ex)
1456                {
1457                    if (this.worker.CancellationPending)
1458                    {
1459                        e.Result = null;
1460                        e.Cancel = true;
1461                        return;
1462                    }
1463                    e.Result = ex;
1464                    return;
1465                }
1466                this.TraceFetcher.Pipelining = this.Automatic;
1467            }
1468
1469            MemoryStream ms = this.TraceFetcher.Next();
1470            if (this.worker.CancellationPending)
1471                e.Cancel = true;
1472            else if (ms != null)
1473                e.Result = new StreamReader(ms);
1474            else if (this.TraceFetcher != null)
1475                e.Result = this.TraceFetcher.Error;
1476            else
1477                throw new NotImplementedException("This shouldnt happen");
1478
1479            Console.WriteLine("worker_DoWork exiting");
1480        } // worker_DoWork
1481
1482        void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
1483        {
1484            if (e.Cancelled) {
1485                Console.WriteLine("RunWorkerCompleted: worker cancelled!");
1486                this.RunCancel.Content = "Run";
1487                return;
1488            }
1489            StreamReader reader = e.Result as StreamReader;
1490            Exception ex;
1491            if (reader != null)
1492            {
1493                ReadDataFromStream(reader);
1494                reader.Close();
1495                // NOTA BENE: This is a *synchronous* Invoke, i.e. the BackgroundRender
1496                // will happen on the UI thread (and first any other UI) before this call
1497                // returns.  This includes e.g. "Disconnect" UI pending.  Therefore
1498                // think very carefully about the state machine!
1499                Dispatcher.Invoke(DispatcherPriority.Background,
1500                                  new Action(BackgroundRender));
1501
1502                // Start fetching the next one
1503                if (this.TraceFetcher != null && this.Automatic && !this.worker.IsBusy)
1504                    this.worker.RunWorkerAsync(null);
1505            }
1506            else if ((ex = e.Result as Exception) != null)
1507            {
1508                MessageBox.Show(ex.ToString(), ex.Message, MessageBoxButton.OK, MessageBoxImage.Error);
1509                this.Title = this.Name + ": connection closed";
1510                this.Automatic = false;
1511                this.RunCancel.Content = "Run";
1512                if (this.TraceFetcher != null)
1513                    this.TraceFetcher.Dispose();
1514                this.TraceFetcher = null;
1515                this.mainCanvas.Children.Clear();
1516            }
1517            // else XXX
1518
1519        }
1520
1521
1522        void worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
1523        {
1524            if (e.ProgressPercentage == 1)
1525                this.Title = this.Name + ": connected to " + this.Filename;
1526            Console.WriteLine("Progress changed");
1527        }
1528
1529
1530
1531        private void RunCancel_Click(object sender, RoutedEventArgs e)
1532        {
1533            if (this.TraceFetcher == null)
1534            {
1535                MessageBox.Show("Cannot fetch a trace when not connected", "Not connected", MessageBoxButton.OK, MessageBoxImage.Stop);
1536                return;
1537            }
1538
1539            this.Automatic = !this.Automatic;
1540            this.TraceFetcher.Pipelining = this.Automatic;
1541
1542            if (this.Automatic)
1543            {
1544                this.RunCancel.Content = "Stop";
1545                if (!this.worker.IsBusy)
1546                    this.worker.RunWorkerAsync(null);
1547            }
1548            else
1549            {
1550                this.RunCancel.Content = "Run";
1551                // XXX this.worker.Cancel();
1552                Console.WriteLine("User clicked Cancel");
1553                this.worker.CancelAsync();
1554            }
1555        } // RunCancel_Click
1556
1557        private void Single_Click(object sender, RoutedEventArgs e)
1558        {
1559            this.mainCanvas.Children.Clear();
1560            if (this.TraceFetcher == null)
1561            {
1562                MessageBox.Show("Cannot fetch a trace when not connected", "Not connected", MessageBoxButton.OK, MessageBoxImage.Stop);
1563                return;
1564            }
1565            if (!this.worker.IsBusy)
1566                this.worker.RunWorkerAsync(null);
1567        }
1568
1569        private void FileSave_Click(object sender, RoutedEventArgs e)
1570        {
1571            if (this.ttec == null)
1572                return;
1573
1574            string filename;
1575            if (!Dialogs.SaveThese("bfl", "Barrelfish Log files|*.bfl", out filename))
1576                return;
1577
1578            StreamWriter writer = new StreamWriter(filename);
1579            if (this.procnames != null)
1580                foreach (KeyValuePair<ulong, string> kvp in this.procnames)
1581                    writer.WriteLine("# DCB 0 {0} {1}", kvp.Key, kvp.Value);
1582            foreach (TemporalTraceEvent tte in this.ttec)
1583                writer.WriteLine(tte.ToString());
1584            writer.Close();
1585        } // FileSave_Click
1586
1587
1588        private void Disconnect_Click(object sender, RoutedEventArgs e)
1589        {
1590            this.Title = this.Name;
1591
1592            this.worker.CancelAsync();
1593            if (this.TraceFetcher != null)
1594                this.TraceFetcher.Dispose();
1595            this.TraceFetcher = null;
1596            this.ttec = null;
1597            this.procnames = null;
1598            this.Filename = null;
1599            this.ReRender();
1600        }
1601
1602        private void ViewKey_Click(object sender, RoutedEventArgs e)
1603        {
1604            Key x = new Key();
1605            x.Show();
1606        }
1607
1608        private void Cores_Click(object sender, RoutedEventArgs e)
1609        {
1610            this.Cores4.IsChecked = (sender == this.Cores4);
1611            this.Cores8.IsChecked = (sender == this.Cores8);
1612            this.Cores16.IsChecked = (sender == this.Cores16);
1613            this.Cores24.IsChecked = (sender == this.Cores24);
1614            this.Cores32.IsChecked = (sender == this.Cores32);
1615            this.Cores64.IsChecked = (sender == this.Cores64);
1616            if (sender == this.Cores4)
1617                this.NumCores = 4;
1618            else if (sender == this.Cores8)
1619                this.NumCores = 8;
1620            else if (sender == this.Cores16)
1621                this.NumCores = 16;
1622            else if (sender == this.Cores24)
1623                this.NumCores = 24;
1624            else if (sender == this.Cores32)
1625                this.NumCores = 32;
1626            else if (sender == this.Cores64)
1627                this.NumCores = 64;
1628            this.ReRender();
1629        }
1630    } // class Window1
1631
1632
1633
1634    public class TraceFetcher : IDisposable
1635    {
1636        // These must match the equivalent code in Barrelfish and Aquarium.
1637        /// <summary>
1638        /// The number of bytes of header containing the size of the trace
1639        /// </summary>
1640        const int HeaderSize = 8;
1641        /// <summary>
1642        /// The format string for converting an integer to a trace header
1643        /// </summary>
1644        const string HeaderFormatString = "00000000";
1645
1646
1647        public readonly string Target;
1648        public bool Pipelining;
1649        public Exception Error { get; private set; }
1650
1651        private readonly byte[] tosend;
1652        private NetworkStream stream;
1653        private bool sentRequest;
1654
1655        public TraceFetcher(string target)
1656        {
1657            int port = 666;
1658            string[] addrport = target.Split(':');
1659            if (addrport.Length == 2)
1660            {
1661                target = addrport[0];
1662                port = int.Parse(addrport[1]);
1663                Console.WriteLine("Connecting to {0} on non-default port {1}", target, port);
1664            }
1665
1666            this.Target = target;
1667            this.tosend = Encoding.ASCII.GetBytes("trace\n");
1668
1669            // The name could resolve to both v4 and v6 addressesw
1670            // but we know that barrelfish will only be listening on v4.
1671            // The test trace replay (testaquarium) also listens only on v4
1672            // so here we need to filter the addresses to avoid long (e.g.
1673            // 30 second) hangs when connecting to a testaquarium.
1674
1675            IPAddress[] addresses = Dns.GetHostAddresses(target);
1676            List<IPAddress> v4s = new List<IPAddress>(addresses.Length);
1677            for (int i = 0; i < addresses.Length; i++)
1678                if (addresses[i].AddressFamily == AddressFamily.InterNetwork)
1679                    v4s.Add(addresses[i]);
1680
1681            TcpClient client = new TcpClient(AddressFamily.InterNetwork);
1682            client.Connect(v4s.ToArray(), port);
1683            this.stream = client.GetStream();
1684        }
1685
1686        public void Dispose()
1687        {
1688            if (this.stream == null)
1689                return;
1690            this.stream.Close();
1691            this.stream = null;
1692        }
1693
1694        /// <summary>
1695        /// Returns MemoryStream of the next trace.  If there is an error
1696        /// returns null, disposes itself, and sets Error property to the exception
1697        /// </summary>
1698        /// <returns>MemoryStream or null</returns>
1699        public MemoryStream Next()
1700        {
1701            if (this.stream == null)
1702                throw new ObjectDisposedException("TraceFetcher");
1703
1704            try
1705            {
1706                if (this.sentRequest)
1707                    this.sentRequest = false;
1708                else
1709                    this.stream.Write(tosend, 0, tosend.Length);
1710
1711                byte[] header = Read(HeaderSize);
1712
1713                string lenstring = Encoding.ASCII.GetString(header);
1714                if (lenstring.Length != HeaderSize)
1715                    throw new FormatException("header changed size after conversion: " + lenstring);
1716                foreach (char c in lenstring)
1717                    if (c < '0' || c > '9')
1718                        throw new FormatException("header contains non digits: " + lenstring);
1719                int len;
1720                if (!int.TryParse(lenstring, out len))
1721                    throw new FormatException("Not a valid length: " + lenstring);
1722
1723                byte[] data = Read(len);
1724                MemoryStream ms = new MemoryStream(data);
1725                if (this.Pipelining)
1726                {
1727                    this.stream.Write(tosend, 0, tosend.Length);
1728                    this.sentRequest = true;
1729                }
1730
1731                return ms;
1732            }
1733            catch (Exception ex)
1734            {
1735                this.Error = ex;
1736                this.Dispose();
1737                return null;
1738            }
1739        } // Next
1740
1741
1742        /// <summary>
1743        /// Keeps reading until it gets all of the bytes requested or fails
1744        /// with an EndOfStreamException
1745        /// </summary>
1746        /// <param name="len">Number of bytes to read</param>
1747        /// <returns>The bytes read</returns>
1748        private byte[] Read(int len)
1749        {
1750            byte[] data = new byte[len];
1751            int position = 0;
1752            do
1753            {
1754                int got = stream.Read(data, position, data.Length - position);
1755                if (got == 0)
1756                    throw new EndOfStreamException();
1757                position += got;
1758            } while (position < data.Length);
1759            return data;
1760        }
1761    } // class TraceFetcher
1762
1763    #region WPF helper classes
1764
1765    public class VisualHost : FrameworkElement
1766    {
1767        private VisualCollection _children;
1768        public VisualHost()
1769        {
1770            _children = new VisualCollection(this);
1771        }
1772
1773        public void AddVisual(DrawingVisual vis)
1774        {
1775            _children.Add(vis);
1776        }
1777        // Provide a required override for the VisualChildrenCount property.
1778        protected override int VisualChildrenCount
1779        {
1780            get { return _children.Count; }
1781        }
1782        // Provide a required override for the GetVisualChild method.
1783        protected override Visual GetVisualChild(int index)
1784        {
1785            if (index < 0 || index > _children.Count)
1786            {
1787                throw new ArgumentOutOfRangeException();
1788            }
1789
1790            return _children[index];
1791        }
1792    } // class VisualHost
1793
1794
1795    public class MyDrawingVisual : DrawingVisual
1796    {
1797        public DrawingContext dc;
1798
1799        public MyDrawingVisual()
1800        {
1801        }
1802        public void BeginRender()
1803        {
1804            this.dc = this.RenderOpen();
1805        }
1806        public void EndRender()
1807        {
1808            this.dc.Close();
1809        }
1810
1811    } // class MyDrawingVisual
1812
1813
1814    public class Highlighting
1815    {
1816        private readonly List<Shape> oldshapes;
1817        private readonly List<TextBlock> oldblocks;
1818        private readonly List<Brush> oldstroke, oldfill, oldforeground;
1819
1820        private readonly SolidColorBrush brush;
1821
1822        public Highlighting(SolidColorBrush brush)
1823        {
1824            this.brush = brush.Clone();
1825            this.brush.Freeze();
1826            this.oldshapes = new List<Shape>();
1827            this.oldblocks = new List<TextBlock>();
1828            this.oldstroke = new List<Brush>();
1829            this.oldfill = new List<Brush>();
1830            this.oldforeground = new List<Brush>();
1831        }
1832
1833        public void Set(params FrameworkElement[] elements)
1834        {
1835            if (oldshapes.Count > 0 || oldblocks.Count > 0)
1836                Clear();
1837            if (elements == null || elements.Length == 0)
1838                return;
1839            Shape shape;
1840            TextBlock block;
1841            for (int i = 0; i < elements.Length; i++)
1842            {
1843                if ((shape = elements[i] as Shape) != null)
1844                {
1845                    oldshapes.Add(shape);
1846                    oldstroke.Add(shape.Stroke);
1847                    oldfill.Add(shape.Fill);
1848
1849                    shape.Stroke = brush;
1850                    if (shape.Fill != null)
1851                    {
1852                        SolidColorBrush inside = new SolidColorBrush(brush.Color);
1853                        inside.Opacity = shape.Fill.Opacity;
1854                        shape.Fill = inside;
1855                    }
1856                }
1857                else if ((block = elements[i] as TextBlock) != null)
1858                {
1859                    oldblocks.Add(block);
1860                    oldforeground.Add(block.Foreground);
1861                    block.Foreground = this.brush;
1862                }
1863            }
1864        }
1865
1866        public void Clear()
1867        {
1868            for (int i = 0; i < oldshapes.Count; i++)
1869            {
1870                oldshapes[i].Stroke = oldstroke[i];
1871                oldshapes[i].Fill = oldfill[i];
1872            }
1873            oldshapes.Clear();
1874            oldstroke.Clear();
1875            oldfill.Clear();
1876
1877            for (int i = 0; i < oldblocks.Count; i++)
1878                oldblocks[i].Foreground = oldforeground[i];
1879            oldforeground.Clear();
1880            oldblocks.Clear();
1881        }
1882    } // class Highlighting
1883
1884    #endregion
1885
1886} // namespace
1887