OpenClonk
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros
C4Network2Stats.cpp
Go to the documentation of this file.
1 /*
2  * OpenClonk, http://www.openclonk.org
3  *
4  * Copyright (c) 2005-2009, RedWolf Design GmbH, http://www.clonk.de/
5  * Copyright (c) 2010-2016, The OpenClonk Team and contributors
6  *
7  * Distributed under the terms of the ISC license; see accompanying file
8  * "COPYING" for details.
9  *
10  * "Clonk" is a registered trademark of Matthes Bender, used with permission.
11  * See accompanying file "TRADEMARK" for details.
12  *
13  * To redistribute this file separately, substitute the full license texts
14  * for the above references.
15  */
16 // network statistics and information dialogs
17 
18 #include "C4Include.h"
20 
21 #include "game/C4Game.h"
22 #include "player/C4Player.h"
23 #include "player/C4PlayerList.h"
24 #include "object/C4GameObjects.h"
25 #include "network/C4Network2.h"
26 #include "control/C4GameControl.h"
27 
29  : szTitle(LoadResStr("IDS_NET_GRAPH")), dwColor(0x7fff0000)
30 {
31 }
32 
33 C4TableGraph::C4TableGraph(int iBackLogLength, int iStartTime)
34  : iBackLogLength(iBackLogLength), pValues(nullptr), fMultiplier(1), pAveragedValues(nullptr), iBackLogPos(0), fWrapped(false)
35  , iInitialStartTime(iStartTime), iTime(iStartTime), iAveragedTime(iStartTime), iAvgRange(1)
36 {
37  // create value buffer
38  assert(iBackLogLength);
39  pValues = pAveragedValues = new ValueType[iBackLogLength];
40  *pValues = 0;
41 }
42 
44 {
45  // flush stuff
46  Reset(-1);
47  // free value buffer(s)
48  if (pValues != pAveragedValues) delete [] pAveragedValues;
49  delete [] pValues;
50 }
51 
52 void C4TableGraph::Reset(TimeType iToTime)
53 {
54  // flush buffer
55  if (!!szDumpFile) DumpToFile(szDumpFile, fWrapped);
56  // reset stuff
57  iInitialStartTime = iTime = iToTime;
58  fWrapped = false;
59  iBackLogPos = 0;
60  *pValues = 0;
61 }
62 
63 
64 // retrieve timeframe covered by backlog
66 {
67  // wrap? -> whole buffer used
68  if (fWrapped) return iTime - iBackLogLength;
69  // otherwise, just buffer to the start used
70  return iTime - iBackLogPos;
71 }
72 
74 {
75  // end time is current
76  return iTime;
77 }
78 
80 {
81  // must be inside buffer
82  assert(Inside(iAtTime, GetStartTime(), GetEndTime()-1));
83  // query it - can't be negative if inside start/end-time
84  return pAveragedValues[(iAtTime - iInitialStartTime) % iBackLogLength] * fMultiplier;
85 }
86 
88 {
89  // must be inside buffer
90  assert(Inside(iAtTime, GetStartTime(), GetEndTime()-1));
91  // query it - can't be negative if inside start/end-time
92  return pValues[(iAtTime - iInitialStartTime) % iBackLogLength];
93 }
94 
95 void C4TableGraph::SetAvgValue(TimeType iAtTime, ValueType iValue) const
96 {
97  // must be inside buffer
98  assert(Inside(iAtTime, GetStartTime(), GetEndTime()-1));
99  // set it - can't be negative if inside start/end-time
100  pAveragedValues[(iAtTime - iInitialStartTime) % iBackLogLength] = iValue;
101 }
102 
103 C4Graph::ValueType C4TableGraph::GetMedianValue(TimeType iStartTime, TimeType iEndTime) const
104 {
105  assert(iStartTime < iEndTime);
106  // safety: Never build median if no values are recorded
107  if (!iBackLogPos && !fWrapped) return 0;
108  // sum up and divide in the end - let's hope this will never be called for really large values that could overflow ValueType
109  ValueType iSum = GetValue(iStartTime), iNum=1;
110  for (; ++iStartTime < iEndTime; ++iNum) iSum += GetValue(iStartTime);
111  return iSum / iNum;
112 }
113 
115 {
116  int iPos0 = iBackLogPos ? iBackLogPos-1 : iBackLogPos;
117  ValueType iMinVal = pAveragedValues[iPos0];
118  int i = iPos0; ValueType *p = pAveragedValues;
119  while (i--) iMinVal = std::min(iMinVal, *p++);
120  if (fWrapped)
121  {
122  i = iBackLogLength - iPos0;
123  while (--i) iMinVal = std::min(iMinVal, *++p);
124  }
125  return iMinVal * fMultiplier;
126 }
127 
129 {
130  int iPos0 = iBackLogPos ? iBackLogPos-1 : iBackLogPos;
131  ValueType iMaxVal = pAveragedValues[iPos0];
132  int i = iPos0; ValueType *p = pAveragedValues;
133  while (i--) iMaxVal = std::max(iMaxVal, *p++);
134  if (fWrapped)
135  {
136  i = iBackLogLength - iPos0;
137  while (--i) iMaxVal = std::max(iMaxVal, *++p);
138  }
139  return iMaxVal * fMultiplier;
140 }
141 
143 {
144  // rec value
145  pValues[iBackLogPos] = iValue;
146  // calc time
147  ++iTime;
148  if (++iBackLogPos >= iBackLogLength)
149  {
150  // create dump before overwriting last buffer
151  if (!!szDumpFile) DumpToFile(szDumpFile, fWrapped);
152  // restart buffer
153  fWrapped = true;
154  iBackLogPos = 0;
155  }
156 }
157 
158 bool C4TableGraph::DumpToFile(const StdStrBuf &rszFilename, bool fAppend) const
159 {
160  assert(!!rszFilename);
161  // nothing to write?
162  if (!fWrapped && !iBackLogPos) return false;
163  // try append if desired; create if unsuccessful
164  CStdFile out;
165  if (fAppend) if (!out.Append(rszFilename.getData())) fAppend = false;
166  if (!fAppend)
167  {
168  if (!out.Create(rszFilename.getData())) return false;
169  // print header
170  out.WriteString("t\tv\n\r");
171  }
172  // write out current timeframe
173  int iEndTime = GetEndTime();
174  StdStrBuf buf;
175  for (int iWriteTime = GetStartTime(); iWriteTime < iEndTime; ++iWriteTime)
176  {
177  buf.Format("%d\t%d\n\r", (int) iWriteTime, (int) GetValue(iWriteTime));
178  out.WriteString(buf.getData());
179  }
180  return true;
181 }
182 
184 {
185  // set new time; resetting valid, averaged range
186  if (iAveragedTime == iToTime) return;
187  assert(iToTime > 0);
188  iAvgRange = iToTime;
189  iAveragedTime = iInitialStartTime;
190 }
191 
192 #define FORWARD_AVERAGE
193 #define FORWARD_AVERAGE_FACTOR 4
194 
196 {
197  // no averaging necessary?
198  if (pAveragedValues == pValues)
199  {
200  if (iAvgRange == 1) return;
201  // averaging necessary, but buffer not yet created: Create it!
202  pAveragedValues = new ValueType[iBackLogLength];
203  }
204  // up-to-date?
205  if (iAveragedTime == iTime) return;
206  assert(iAveragedTime < iTime); // must not have gone back!
207  // update it
208  int iStartTime = GetStartTime();
209 #ifdef FORWARD_AVERAGE
210  int iAvgFwRange = iAvgRange/FORWARD_AVERAGE_FACTOR;
211 #else
212  int iAvgFwRange = 0;
213 #endif
214  for (int iUpdateTime = std::max(iAveragedTime-iAvgFwRange-1, iStartTime); iUpdateTime < iTime; ++iUpdateTime)
215  {
216  ValueType iSum=0, iSumWeight=0, iWeight;
217  for (int iSumTime = std::max(iUpdateTime - iAvgRange, iStartTime); iSumTime < std::min(iUpdateTime + iAvgFwRange+1, iTime); ++iSumTime)
218  {
219  iWeight = (ValueType) iAvgRange - Abs(iUpdateTime - iSumTime) + 1;
220  iSum += GetAtValue(iSumTime) * iWeight;
221  iSumWeight += iWeight;
222  }
223  SetAvgValue(iUpdateTime, iSum / iSumWeight);
224  }
225  // now it's all up-to-date
226  iAveragedTime = iTime;
227 }
228 
229 // --------------------------------------------------
230 
232 {
233  const_iterator i = begin(); if (i == end()) return 0;
234  C4Graph::TimeType iTime = (*i)->GetStartTime();
235  while (++i != end()) iTime = std::min(iTime, (*i)->GetStartTime());
236  return iTime;
237 }
238 
240 {
241  const_iterator i = begin(); if (i == end()) return 0;
242  C4Graph::TimeType iTime = (*i)->GetEndTime();
243  while (++i != end()) iTime = std::max(iTime, (*i)->GetEndTime());
244  return iTime;
245 }
246 
248 {
249  const_iterator i = begin(); if (i == end()) return 0;
250  C4Graph::ValueType iVal = (*i)->GetMinValue();
251  while (++i != end()) iVal = std::min(iVal, (*i)->GetMinValue());
252  return iVal;
253 }
254 
256 {
257  const_iterator i = begin(); if (i == end()) return 0;
258  C4Graph::ValueType iVal = (*i)->GetMaxValue();
259  while (++i != end()) iVal = std::max(iVal, (*i)->GetMaxValue());
260  return iVal;
261 }
262 
264 {
265  int iCount = 0;
266  for (const_iterator i = begin(); i != end(); ++i) iCount += (*i)->GetSeriesCount();
267  return iCount;
268 }
269 
270 const C4Graph *C4GraphCollection::GetSeries(int iIndex) const
271 {
272  for (const_iterator i = begin(); i != end(); ++i)
273  {
274  int iCnt = (*i)->GetSeriesCount();
275  if (iIndex < iCnt) return (*i)->GetSeries(iIndex);
276  iIndex -= iCnt;
277  }
278  return nullptr;
279 }
280 
282 {
283  // update all child graphs
284  for (const_iterator i = begin(); i != end(); ++i) (*i)->Update();
285 }
286 
288 {
289  if ((iCommonAvgTime = iToTime))
290  for (iterator i = begin(); i != end(); ++i) (*i)->SetAverageTime(iToTime);
291 }
292 
294 {
295  if ((fMultiplier = fToVal))
296  for (iterator i = begin(); i != end(); ++i) (*i)->SetMultiplier(fToVal);
297 }
298 
299 
300 // --------------------------------------------------------------------------------
301 
303 {
304  // init callback timer
305  Application.Add(this);
306  SecondCounter = 0;
307  ControlCounter = 0;
308  // init graphs
309  statObjCount.SetTitle(LoadResStr("IDS_MSG_OBJCOUNT"));
310  statFPS.SetTitle(LoadResStr("IDS_MSG_FPS"));
311  statNetI.SetTitle(LoadResStr("IDS_NET_INPUT"));
312  statNetI.SetColorDw(0x00ff00);
313  statNetO.SetTitle(LoadResStr("IDS_NET_OUTPUT"));
314  statNetO.SetColorDw(0xff0000);
315  graphNetIO.AddGraph(&statNetI); graphNetIO.AddGraph(&statNetO);
316  statControls.SetTitle(LoadResStr("IDS_NET_CONTROL"));
318  statActions.SetTitle(LoadResStr("IDS_NET_APM"));
320  for (C4Player *pPlr = ::Players.First; pPlr; pPlr = pPlr->Next) pPlr->CreateGraphs();
321  C4Network2Client *pClient = nullptr;
322  while ((pClient = ::Network.Clients.GetNextClient(pClient))) pClient->CreateGraphs();
323 }
324 
326 {
327  for (C4Player *pPlr = ::Players.First; pPlr; pPlr = pPlr->Next) pPlr->ClearGraphs();
328  C4Network2Client *pClient = nullptr;
329  while ((pClient = ::Network.Clients.GetNextClient(pClient))) pClient->ClearGraphs();
330  Application.Remove(this);
331 }
332 
334 {
336 }
337 
339 {
343  // pings for all clients
344  C4Network2Client *pClient = nullptr;
345  while ((pClient = ::Network.Clients.GetNextClient(pClient))) if (pClient->getStatPing())
346  {
347  int iPing=0;
348  C4Network2IOConnection *pConn = pClient->getMsgConn();
349  if (pConn) iPing = pConn->getLag();
350  pClient->getStatPing()->RecordValue(C4Graph::ValueType(iPing));
351  }
352  ++SecondCounter;
353 }
354 
356 {
357  // control rate may have updated: always convert values to actions per minute
360  // register and reset control counts for all players
361  for (C4Player *pPlr = ::Players.First; pPlr; pPlr = pPlr->Next)
362  {
363  if (pPlr->pstatControls)
364  {
365  pPlr->pstatControls->RecordValue(C4Graph::ValueType(pPlr->ControlCount));
366  pPlr->ControlCount = 0;
367  }
368  if (pPlr->pstatActions)
369  {
370  pPlr->pstatActions->RecordValue(C4Graph::ValueType(pPlr->ActionCount));
371  pPlr->ActionCount = 0;
372  }
373  }
374  ++ControlCounter;
375 }
376 
377 C4Graph *C4Network2Stats::GetGraphByName(const StdStrBuf &rszName, bool &rfIsTemp)
378 {
379  // compare against default graph names
380  rfIsTemp = false;
381  if (SEqualNoCase(rszName.getData(), "oc")) return &statObjCount;
382  if (SEqualNoCase(rszName.getData(), "fps")) return &statFPS;
383  if (SEqualNoCase(rszName.getData(), "netio")) return &graphNetIO;
384  if (SEqualNoCase(rszName.getData(), "pings")) return &statPings;
385  if (SEqualNoCase(rszName.getData(), "control")) return &statControls;
386  if (SEqualNoCase(rszName.getData(), "apm")) return &statActions;
387  // no match
388  return nullptr;
389 }
390 
391 // MassGraph.SetDumpFile(StdStrBuf("C:\\test.txt"));
virtual ValueType GetMaxValue() const
const char * getData() const
Definition: StdBuf.h:450
virtual void Update() const
virtual void SetAverageTime(int iToTime)
C4GraphCollection statControls
C4Network2Client * GetNextClient(C4Network2Client *pClient)
C4Network2IO NetIO
Definition: C4Network2.h:110
C4Game Game
Definition: C4Globals.cpp:52
virtual C4Graph::ValueType GetMinValue() const
bool Create(const char *szFileName, bool fCompressed=false, bool fExecutable=false, bool fMemory=false)
Definition: CStdFile.cpp:53
C4Network2IOConnection * getMsgConn() const
virtual TimeType GetStartTime() const
bool SEqualNoCase(const char *szStr1, const char *szStr2, int iLen)
Definition: Standard.cpp:177
C4Graph * GetGraphByName(const StdStrBuf &rszName, bool &rfIsTemp)
C4Player * First
Definition: C4PlayerList.h:31
C4GraphCollection statPings
void Format(const char *szFmt,...) GNUC_FORMAT_ATTRIBUTE_O
Definition: StdBuf.cpp:181
virtual int GetSeriesCount() const
virtual void SetMultiplier(ValueType fToVal)
void Add(StdSchedulerProc *pProc)
virtual const C4Graph * GetSeries(int iIndex) const
const char * LoadResStr(const char *id)
Definition: C4Language.h:83
virtual ValueType GetMedianValue(TimeType iStartTime, TimeType iEndTime) const
virtual ~C4Network2Stats()
C4Network2 Network
Definition: C4Globals.cpp:53
virtual C4Graph::TimeType GetEndTime() const
virtual C4Graph::ValueType GetMaxValue() const
int iCnt
Definition: TstC4NetIO.cpp:35
virtual void Update() const
int32_t FPS
Definition: C4Game.h:113
C4GameControl Control
bool Append(const char *szFilename, bool text=false)
Definition: CStdFile.cpp:136
C4GraphCollection statActions
C4PlayerList Players
virtual ValueType GetValue(TimeType iAtTime) const
ValueType GetAtValue(TimeType iAtTime) const
#define FORWARD_AVERAGE_FACTOR
virtual bool DumpToFile(const StdStrBuf &rszFilename, bool fAppend) const
virtual C4Graph::TimeType GetStartTime() const
void Remove(StdSchedulerProc *pProc)
class C4TableGraph * getStatPing() const
int ObjectCount(C4ID id=C4ID::None) const
int getProtORate(C4Network2IOProtocol eProt) const
Definition: C4Network2IO.h:153
C4Network2ClientList Clients
Definition: C4Network2.h:116
virtual void SetAverageTime(int iToTime)
void RecordValue(ValueType iValue)
int getProtIRate(C4Network2IOProtocol eProt) const
Definition: C4Network2IO.h:152
float ValueType
virtual ValueType GetMinValue() const
C4Player * Next
Definition: C4Player.h:144
void SetAvgValue(TimeType iAtTime, ValueType iValue) const
void SetTitle(const char *szNewTitle)
T Abs(T val)
Definition: Standard.h:44
virtual TimeType GetEndTime() const
bool WriteString(const char *szStr)
Definition: CStdFile.cpp:268
void AddGraph(C4Graph *pAdd)
C4TableGraph(int iBackLogLength=DefaultBlockLength, TimeType iStartTime=0)
void Reset(TimeType iToTime)
bool Inside(T ival, U lbound, V rbound)
Definition: Standard.h:45
C4Application Application
Definition: C4Globals.cpp:44
int32_t ControlRate
Definition: C4GameControl.h:88
void SetColorDw(DWORD dwClr)
C4GameObjects Objects
Definition: C4Globals.cpp:48