// // PeerGraph.cs // // Author: // Carsten Sonne Larsen // // Copyright (c) 2013 Carsten Sonne Larsen // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. using System; using System.Collections.Generic; using System.Drawing; using System.Linq; using NPlot; using Ntp.Analyzer.Data; using Ntp.Analyzer.Objects; using Ntp.Analyzer.Config.Graph; using Ntp.Analyzer.Graph.Interface; using Ntp.Analyzer.Data.Static; namespace Ntp.Analyzer.Graph { public sealed class PeerGraph : DispersionGraph { private readonly List balance = new List (); private readonly IPeerGraphConfiguration config; private readonly List delay = new List (); private readonly Host host; private readonly Peer peer; private readonly Dictionary timedReading; public PeerGraph (IPeerGraphConfiguration configuratation, Host host, Peer peer) : base(configuratation) { config = configuratation; this.host = host; this.peer = peer; timedReading = new Dictionary (); } protected override string YLabel { get { return "Milliseconds"; } } protected override void LoadData () { FilteredMapper peerMapper = DataFace.Instance.PeerReadings; peerMapper.FilterHost = host; peerMapper.FilterPeer = peer; peerMapper.FilterTime = DateTime.Now.Subtract (GraphTimeSpan); if (config.Balance == 0.0) { foreach (PeerReading reading in peerMapper) { Time.Add (reading.Time); Offset.Add (reading.Offset * config.Offset); Jitter.Add (reading.Jitter * config.Jitter); delay.Add (reading.Delay * config.Delay); balance.Add (0); } } else { FilteredMapper hostMapper = DataFace.Instance.HostReadings; hostMapper.FilterHost = host; hostMapper.FilterTime = DateTime.Now.Subtract (GraphTimeSpan); // Prepare balance data foreach (HostReading hostReading in hostMapper) { if (!timedReading.ContainsKey (hostReading.RoundedTime)) timedReading.Add (hostReading.RoundedTime, hostReading); } // Add foreach (PeerReading reading in peerMapper) { Time.Add (reading.RoundedTime); Offset.Add (reading.Offset * config.Offset); Jitter.Add (reading.Jitter * config.Jitter); delay.Add (reading.Delay * config.Delay); if (timedReading.ContainsKey (reading.RoundedTime)) { balance.Add (reading.Offset - timedReading [reading.RoundedTime].Offset * 1000); } else { balance.Add (0); } } } if (config.FilterFactor != 0.0) CleanSeries (); } protected override void AddPlots () { base.AddPlots (); if (config.Delay != 0.0) { LinePlot delayPlot = SetupPlot ("Delay", Color.DarkOrange, Time, delay); Surface.Add (delayPlot, PlotSurface2D.XAxisPosition.Bottom, PlotSurface2D.YAxisPosition.Left); } if (config.Balance != 0.0) { LinePlot balancePlot = SetupPlot ("Balanced offset", Color.DarkViolet, Time, balance); Surface.Add (balancePlot, PlotSurface2D.XAxisPosition.Bottom, PlotSurface2D.YAxisPosition.Left); } } protected override void PreRender () { base.PreRender (); Surface.Title = config.GetTitle (peer); } /// /// Cleans the value series from values out side boundaries. /// private void CleanSeries () { double totalOffset = 0.0; double totalJitter = 0.0; double totalDelay = 0.0; double totalBalance = 0.0; // Calculate mean value for (int i = 0; i < Time.Count; i++) { totalOffset += Math.Abs (Offset [i]); totalJitter += Math.Abs (Jitter [i]); totalDelay += Math.Abs (delay [i]); totalBalance += Math.Abs (balance [i]); } double avgOffset = totalOffset / Time.Count; double avgJitter = totalJitter / Time.Count; double avgDelay = totalDelay / Time.Count; double avgBalance = totalBalance / Time.Count; List indexes = new List (); // Find invalid values for (int i = 0; i < Time.Count; i++) { if (Math.Abs (Offset [i]) > avgOffset * config.FilterFactor || Math.Abs (Jitter [i]) > avgJitter * config.FilterFactor || Math.Abs (delay [i]) > avgDelay * config.FilterFactor || Math.Abs (balance [i]) > avgBalance * config.FilterFactor) { indexes.Add (i); } } // Remove invalid values for (int i = indexes.Count - 1; i >= 0; i--) { Time.RemoveAt (indexes [i]); Offset.RemoveAt (indexes [i]); Jitter.RemoveAt (indexes [i]); delay.RemoveAt (indexes [i]); balance.RemoveAt (indexes [i]); } } } }