1/*
2 * LegacyClonk
3 *
4 * Copyright (c) RedWolf Design
5 * Copyright (c) 2005, Sven2
6 * Copyright (c) 2017-2020, The LegacyClonk Team and contributors
7 *
8 * Distributed under the terms of the ISC license; see accompanying file
9 * "COPYING" for details.
10 *
11 * "Clonk" is a registered trademark of Matthes Bender, used with permission.
12 * See accompanying file "TRADEMARK" for details.
13 *
14 * To redistribute this file separately, substitute the full license texts
15 * for the above references.
16 */
17
18// network statistics and information dialogs
19
20#pragma once
21
22#include "C4Application.h"
23
24#include <StdBuf.h>
25
26// (int) value by time function
27class C4Graph
28{
29public:
30 typedef float ValueType;
31 typedef int TimeType;
32
33private:
34 StdStrBuf szTitle;
35 uint32_t dwColor;
36
37public:
38 C4Graph();
39 virtual ~C4Graph() {}
40
41 void SetTitle(const char *szNewTitle) { szTitle.Copy(pnData: szNewTitle); }
42 void SetColorDw(uint32_t dwClr) { dwColor = dwClr; }
43
44 // retrieve timeframe covered by backlog
45 virtual TimeType GetStartTime() const = 0; // inclusively
46 virtual TimeType GetEndTime() const = 0; // exclusively
47
48 // retrieve values within backlog timeframe - guarantueed to be working inside [GetStartTime(), GetEndTime()[
49 virtual ValueType GetValue(TimeType iAtTime) const = 0;
50 virtual ValueType GetMedianValue(TimeType iStartTime, TimeType iEndTime) const = 0; // median within [iStartTime, iEndTime[
51 virtual ValueType GetMinValue() const = 0;
52 virtual ValueType GetMaxValue() const = 0;
53
54 // base graph has always just one series (self)
55 virtual int GetSeriesCount() const = 0;
56 virtual const C4Graph *GetSeries(int iIndex) const = 0;
57
58 uint32_t GetColorDw() const { return dwColor; }
59 const char *GetTitle() const { return szTitle.getData(); }
60
61 // called before drawing procedure: Make sure graph values are up-to-date
62 virtual void Update() const {}
63
64 virtual void SetAverageTime(int iToTime) = 0;
65 virtual void SetMultiplier(ValueType fToVal) = 0;
66};
67
68// Standard graph: Assume constant time and one call each time frame
69class C4TableGraph : public C4Graph
70{
71private:
72 // recorded backlog
73 int iBackLogLength;
74 ValueType *pValues;
75 ValueType fMultiplier; // multiplicative factor used for all value returns
76 mutable ValueType *pAveragedValues; // equals pValues if no average is being calculated
77
78 // currently valid backlog timeframe
79 int iBackLogPos; // position of next entry to be written
80 bool fWrapped; // if true, the buffer has been cycled already
81
82 TimeType iInitialStartTime; // initial table start time; used to calc offset in buffer
83 TimeType iTime; // next timeframe to be recorded
84 mutable TimeType iAveragedTime; // last timeframe for which average has been calculated
85 StdStrBuf szDumpFile; // if set, the buffer is dumped to file regularly
86 TimeType iAvgRange; // range used for averaging
87
88public:
89 enum { DefaultBlockLength = 256 }; // default backlog
90
91 C4TableGraph(int iBackLogLength = DefaultBlockLength, TimeType iStartTime = 0);
92 ~C4TableGraph();
93
94 // flush dump; reset time, etc
95 void Reset(TimeType iToTime);
96
97 void SetDumpFile(StdStrBuf &szFile) { szDumpFile.Ref(Buf2: szFile); }
98
99 // retrieve timeframe covered by backlog
100 virtual TimeType GetStartTime() const override; // inclusively
101 virtual TimeType GetEndTime() const override; // exclusively
102
103 // retrieve values within backlog timeframe - guarantueed to be working inside [GetStartTime(), GetEndTime()[
104 virtual ValueType GetValue(TimeType iAtTime) const override; // retrieve averaged value!
105 ValueType GetAtValue(TimeType iAtTime) const; // retrieve not-averaged value
106 void SetAvgValue(TimeType iAtTime, ValueType iValue) const; // overwrite avg value at time - considered const because it modifies mutable only
107 virtual ValueType GetMedianValue(TimeType iStartTime, TimeType iEndTime) const override; // median within [iStartTime, iEndTime[
108 virtual ValueType GetMinValue() const override;
109 virtual ValueType GetMaxValue() const override;
110
111 // record a value for this frame; increases time by one
112 void RecordValue(ValueType iValue);
113
114 // write table to file
115 virtual bool DumpToFile(const StdStrBuf &rszFilename, bool fAppend) const;
116
117 // base graph has always just one series (self)
118 virtual int GetSeriesCount() const override { return 1; }
119 virtual const C4Graph *GetSeries(int iIndex) const override { return iIndex ? nullptr : this; }
120
121 virtual void SetAverageTime(int iToTime) override;
122 virtual void Update() const override; // make sure average times are correctly calculated
123
124 virtual void SetMultiplier(ValueType fToVal) override { fMultiplier = fToVal; }
125};
126
127// A graph collection; grouping similar graphs
128// Does not delete graph pointers
129class C4GraphCollection : public C4Graph, private std::vector<C4Graph *>
130{
131private:
132 // if 0, keep individual for each graph
133 int iCommonAvgTime;
134 ValueType fMultiplier;
135
136public:
137 C4GraphCollection() : iCommonAvgTime(0), fMultiplier(0) {}
138
139 // retrieve max timeframe covered by all graphs
140 virtual C4Graph::TimeType GetStartTime() const override;
141 virtual C4Graph::TimeType GetEndTime() const override;
142
143 // must be called on base series only!
144 virtual C4Graph::ValueType GetValue(C4Graph::TimeType iAtTime) const override { assert(0); return 0; }
145 virtual C4Graph::ValueType GetMedianValue(C4Graph::TimeType iStartTime, C4Graph::TimeType iEndTime) const override { assert(0); return 0; }
146
147 // get overall min/max for all series
148 virtual C4Graph::ValueType GetMinValue() const override;
149 virtual C4Graph::ValueType GetMaxValue() const override;
150
151 // retrieve child (or grandchild) graphs
152 virtual int GetSeriesCount() const override;
153 virtual const C4Graph *GetSeries(int iIndex) const override;
154
155 void AddGraph(C4Graph *pAdd) { push_back(x: pAdd); if (iCommonAvgTime) pAdd->SetAverageTime(iCommonAvgTime); if (fMultiplier) pAdd->SetMultiplier(fMultiplier); }
156 void RemoveGraph(const C4Graph *pRemove) { iterator i = std::find(first: begin(), last: end(), val: pRemove); if (i != end()) erase(position: i); }
157
158 // update all children
159 virtual void Update() const override;
160
161 // force values for all children
162 virtual void SetAverageTime(int iToTime) override;
163 virtual void SetMultiplier(ValueType fToVal) override;
164};
165
166// network stat collection wrapper
167class C4Network2Stats : private C4Sec1Callback
168{
169private:
170 C4Sec1TimerCallback<C4Network2Stats> *pSec1Timer;
171
172 // per-frame stats
173 C4TableGraph statObjCount;
174
175 // per-second stats
176 C4TableGraph statFPS;
177
178 // overall network i/o
179 C4TableGraph statNetI, statNetO;
180 C4GraphCollection graphNetIO;
181
182protected:
183 C4GraphCollection statPings; // for all clients
184
185 // per-controlframe stats
186 C4GraphCollection statControls;
187 C4GraphCollection statActions;
188
189 int SecondCounter; // seconds passed in measured time by network stats module
190 int ControlCounter; // control frames passed in measured time by network stats module
191
192 friend class C4Player;
193 friend class C4Network2Client;
194
195public:
196 C4Network2Stats();
197 virtual ~C4Network2Stats();
198
199 // periodic callbacks
200 void ExecuteFrame();
201 void ExecuteSecond();
202 void ExecuteControlFrame();
203
204 virtual void OnSec1Timer() override { ExecuteSecond(); }
205
206 C4Graph *GetGraphByName(const StdStrBuf &rszName, bool &rfIsTemp);
207};
208