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