NTP Analyzer  0.8.2
Analyze the operation of time servers
PeerGraph.cs
Go to the documentation of this file.
1 //
2 // Copyright (c) 2013-2017 Carsten Sonne Larsen <cs@innolan.net>
3 //
4 // Permission is hereby granted, free of charge, to any person obtaining a copy
5 // of this software and associated documentation files (the "Software"), to deal
6 // in the Software without restriction, including without limitation the rights
7 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 // copies of the Software, and to permit persons to whom the Software is
9 // furnished to do so, subject to the following conditions:
10 //
11 // The above copyright notice and this permission notice shall be included in
12 // all copies or substantial portions of the Software.
13 //
14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 // THE SOFTWARE.
21 
22 using System;
23 using System.Collections.Generic;
24 using System.Drawing;
25 using NPlot;
26 using Ntp.Analyzer.Data;
27 using Ntp.Analyzer.Data.Sql;
28 using Ntp.Analyzer.Interface;
29 using Ntp.Analyzer.Objects;
30 
31 namespace Ntp.Analyzer.Graph
32 {
33  public sealed class PeerGraph : DispersionGraph
34  {
35  public PeerGraph(IPeerGraphConfiguration configuration, Host host, Peer peer)
36  : base(configuration)
37  {
38  config = configuration;
39  this.host = host;
40  this.peer = peer;
41 
42  timedReading = new Dictionary<DateTime, HostReading>();
43  }
44 
45  private readonly List<double> balance = new List<double>();
46  private readonly IPeerGraphConfiguration config;
47  private readonly List<double> delay = new List<double>();
48  private readonly Host host;
49  private readonly Peer peer;
50  private readonly Dictionary<DateTime, HostReading> timedReading;
51 
52  protected override string YLabel => "Milliseconds";
53 
54  protected override void AddPlots()
55  {
56  base.AddPlots();
57 
58  if (config.Delay.HasValue)
59  {
60  var delayPlot = SetupPlot("Delay", Color.DarkOrange, Time, delay);
61  Surface.Add(delayPlot, PlotSurface2D.XAxisPosition.Bottom, PlotSurface2D.YAxisPosition.Left);
62  }
63 
64  if (config.Balance.HasValue)
65  {
66  var balancePlot = SetupPlot("Balanced offset", Color.DarkViolet, Time, balance);
67  Surface.Add(balancePlot, PlotSurface2D.XAxisPosition.Bottom, PlotSurface2D.YAxisPosition.Left);
68  }
69  }
70 
71  protected override void LoadData()
72  {
74  peerMapper.FilterHost = host;
75  peerMapper.FilterPeer = peer;
76  peerMapper.FilterTime = DateTime.UtcNow.Subtract(GraphTimeSpan);
77 
78  if (config.Balance.HasValue)
79  {
80  foreach (var reading in peerMapper)
81  {
82  Time.Add(config.GraphTime == DateTimeKind.Local ? reading.LocalTime : reading.UtcTime);
83 
84  if (config.Offset.HasValue) Offset.Add(reading.Offset*config.Offset.Value);
85  else Offset.Add(0.0);
86 
87  if (config.Jitter.HasValue) Jitter.Add(reading.Jitter*config.Jitter.Value);
88  else Jitter.Add(0.0);
89 
90  if (config.Delay.HasValue) delay.Add(reading.Delay*config.Delay.Value);
91  else delay.Add(0.0);
92 
93  balance.Add(0.0);
94  }
95  }
96  else
97  {
99  hostMapper.FilterHost = host;
100  hostMapper.FilterTime = DateTime.UtcNow.Subtract(GraphTimeSpan);
101 
102  // Prepare balance data
103  foreach (var hostReading in hostMapper)
104  {
105  var indexTime = config.GraphTime == DateTimeKind.Local
106  ? hostReading.RoundedLocalTime
107  : hostReading.RoundedUtcTime;
108 
109  if (!timedReading.ContainsKey(indexTime))
110  timedReading.Add(indexTime, hostReading);
111  }
112 
113  // Add
114  foreach (var reading in peerMapper)
115  {
116  Time.Add(config.GraphTime == DateTimeKind.Local ? reading.LocalTime : reading.UtcTime);
117 
118  if (config.Offset.HasValue) Offset.Add(reading.Offset*config.Offset.Value);
119  else Offset.Add(0.0);
120 
121  if (config.Jitter.HasValue) Jitter.Add(reading.Jitter*config.Jitter.Value);
122  else Jitter.Add(0.0);
123 
124  if (config.Delay.HasValue) delay.Add(reading.Delay*config.Delay.Value);
125  else delay.Add(0.0);
126 
127  var indexTime = config.GraphTime == DateTimeKind.Local
128  ? reading.RoundedLocalTime
129  : reading.RoundedUtcTime;
130 
131  if (timedReading.ContainsKey(indexTime))
132  balance.Add(reading.Offset - timedReading[indexTime].Offset);
133  else
134  balance.Add(0.0);
135  }
136  }
137 
138  if (config.FilterFactor.HasValue)
139  CleanSeries();
140  }
141 
142  protected override void PreRender()
143  {
144  base.PreRender();
145 
146  Surface.Title = config.GetTitle(peer);
147  }
148 
152  private void CleanSeries()
153  {
154  double totalOffset = 0.0;
155  double totalJitter = 0.0;
156  double totalDelay = 0.0;
157  double totalBalance = 0.0;
158 
159  // Calculate mean value
160  for (int i = 0; i < Time.Count; i++)
161  {
162  totalOffset += Math.Abs(Offset[i]);
163  totalJitter += Math.Abs(Jitter[i]);
164  totalDelay += Math.Abs(delay[i]);
165  totalBalance += Math.Abs(balance[i]);
166  }
167 
168  double avgOffset = totalOffset/Time.Count;
169  double avgJitter = totalJitter/Time.Count;
170  double avgDelay = totalDelay/Time.Count;
171  double avgBalance = totalBalance/Time.Count;
172 
173  var indexes = new List<int>();
174 
175  // Find invalid values
176  for (int i = 0; i < Time.Count; i++)
177  {
178  if (Math.Abs(Offset[i]) > avgOffset*config.FilterFactor ||
179  Math.Abs(Jitter[i]) > avgJitter*config.FilterFactor ||
180  Math.Abs(delay[i]) > avgDelay*config.FilterFactor ||
181  Math.Abs(balance[i]) > avgBalance*config.FilterFactor)
182  {
183  indexes.Add(i);
184  }
185  }
186 
187  // Remove invalid values
188  for (int i = indexes.Count - 1; i >= 0; i--)
189  {
190  Time.RemoveAt(indexes[i]);
191  Offset.RemoveAt(indexes[i]);
192  Jitter.RemoveAt(indexes[i]);
193  delay.RemoveAt(indexes[i]);
194  balance.RemoveAt(indexes[i]);
195  }
196  }
197  }
198 }
A dispersion graph contains an series of offsets and jitter values together with a time coordinate...
DateTime FilterTime
Gets or sets the time to use when extracting data. Only readings with a timestamp later than FilterTi...
HostReadingDatabaseMapper HostReadings
Gets the host reading mapper.
Definition: DataFace.cs:75
PeerReadingDatabaseMapper PeerReadings
Gets the peer reading mapper.
Definition: DataFace.cs:87
Peer FilterPeer
Gets or sets the peer to use when extracting data.
readonly IPeerGraphConfiguration config
Definition: PeerGraph.cs:46
override void AddPlots()
Definition: PeerGraph.cs:54
Singleton facade class used to access memory persistent data.
Definition: DataFace.cs:30
void CleanSeries()
Cleans the value series from values out side boundaries.
Definition: PeerGraph.cs:152
override void LoadData()
Definition: PeerGraph.cs:71
readonly Dictionary< DateTime, HostReading > timedReading
Definition: PeerGraph.cs:50
PeerGraph(IPeerGraphConfiguration configuration, Host host, Peer peer)
Definition: PeerGraph.cs:35
override void PreRender()
Definition: PeerGraph.cs:142
static DataFace Instance
Gets the Singleton instance.
Definition: DataFace.cs:51