debian: fix build-deps for focal
[amule.git] / src / Statistics.cpp
blob66355823553e2b49592946caff006d272bc74c6a
1 //
2 // This file is part of the aMule Project.
3 //
4 // Copyright (c) 2003-2011 aMule Team ( admin@amule.org / http://www.amule.org )
5 // Copyright (c) 2002-2011 Merkur ( devs@emule-project.net / http://www.emule-project.net )
6 // Copyright (c) 2005-2011 Dévai Tamás ( gonosztopi@amule.org )
7 //
8 // Any parts of this program derived from the xMule, lMule or eMule project,
9 // or contributed by third-party developers are copyrighted by their
10 // respective authors.
12 // This program is free software; you can redistribute it and/or modify
13 // it under the terms of the GNU General Public License as published by
14 // the Free Software Foundation; either version 2 of the License, or
15 // (at your option) any later version.
17 // This program is distributed in the hope that it will be useful,
18 // but WITHOUT ANY WARRANTY; without even the implied warranty of
19 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 // GNU General Public License for more details.
22 // You should have received a copy of the GNU General Public License
23 // along with this program; if not, write to the Free Software
24 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
27 #include "Statistics.h" // Interface declarations
29 #include <protocol/ed2k/ClientSoftware.h>
31 #include <ec/cpp/ECTag.h> // Needed for CECTag
33 #ifndef CLIENT_GUI
34 #ifndef AMULE_DAEMON
35 #include <common/Format.h> // Needed for CFormat
36 #endif
37 #include "CFile.h" // Needed for CFile access
38 #include <common/Path.h> // Needed for JoinPaths
39 #include <wx/config.h> // Needed for wxConfig
40 #include "DataToText.h" // Needed for GetSoftName()
41 #include "ListenSocket.h" // (tree, GetAverageConnections)
42 #include "ServerList.h" // Needed for CServerList (tree)
43 #include <cmath> // Needed for std::floor
44 #include "updownclient.h" // Needed for CUpDownClient
45 #else
46 #include "GetTickCount.h" // Needed for GetTickCount64()
47 #include <ec/cpp/RemoteConnect.h> // Needed for CRemoteConnect
48 #endif
50 #include "amule.h" // Needed for theApp
51 #include <wx/intl.h>
52 #include "Logger.h"
53 #include "Preferences.h" // Needed for thePrefs
55 #ifdef __BSD__
56 // glibc -> bsd libc
57 #define round rint
58 #else
59 #define round(x) floor(x+0.5)
60 #endif /* __BSD__ */
63 #ifndef CLIENT_GUI
65 /*----- CPreciseRateCounter -----*/
67 void CPreciseRateCounter::CalculateRate(uint64_t now)
69 wxMutexLocker lock(m_mutex);
71 m_total += m_tmp_sum;
72 m_byte_history.push_back(m_tmp_sum);
73 m_tick_history.push_back(now);
74 m_tmp_sum = 0;
76 uint64_t timespan = now - m_tick_history.front();
78 // Checking maximal timespan, but make sure not to remove
79 // the extra node in m_tick_history.
80 while (timespan > m_timespan && !m_byte_history.empty()) {
81 m_total -= m_byte_history.front();
82 m_byte_history.pop_front();
83 m_tick_history.pop_front();
84 timespan = now - m_tick_history.front();
87 // Count rate/average
88 if (m_count_average) {
89 if (!m_byte_history.empty()) {
90 m_rate = m_total / (double)m_byte_history.size();
92 } else {
93 if (timespan > 0) {
94 m_rate = m_total / (timespan / 1000.0);
98 if (m_rate > m_max_rate) {
99 m_max_rate = m_rate;
104 /*----- CStatTreeItemRateCounter -----*/
106 #ifndef AMULE_DAEMON
107 wxString CStatTreeItemRateCounter::GetDisplayString() const
109 return CFormat(wxGetTranslation(m_label)) % CastItoSpeed(m_show_maxrate ? (uint32)m_max_rate : (uint32)m_rate);
111 #endif
113 void CStatTreeItemRateCounter::AddECValues(CECTag* tag) const
115 CECTag value(EC_TAG_STAT_NODE_VALUE, m_show_maxrate ? (uint32)m_max_rate : (uint32)m_rate);
116 value.AddTag(CECTag(EC_TAG_STAT_VALUE_TYPE, (uint8)EC_VALUE_SPEED));
117 tag->AddTag(value);
121 /*----- CStatTreeItemPeakConnections -----*/
123 #ifndef AMULE_DAEMON
124 wxString CStatTreeItemPeakConnections::GetDisplayString() const
126 return CFormat(wxGetTranslation(m_label)) % theStats::GetPeakConnections();
128 #endif
130 void CStatTreeItemPeakConnections::AddECValues(CECTag* tag) const
132 tag->AddTag(CECTag(EC_TAG_STAT_NODE_VALUE, (uint64)theStats::GetPeakConnections()));
136 /*----- CStatistics -----*/
138 // Static variables
140 // Rate counters
141 CPreciseRateCounter* CStatistics::s_upOverheadRate;
142 CPreciseRateCounter* CStatistics::s_downOverheadRate;
143 CStatTreeItemRateCounter* CStatistics::s_uploadrate;
144 CStatTreeItemRateCounter* CStatistics::s_downloadrate;
146 #else /* CLIENT_GUI */
148 uint64 CStatistics::s_start_time;
149 uint64 CStatistics::s_statData[sdTotalItems];
151 #endif /* !CLIENT_GUI / CLIENT_GUI */
153 // Tree root
154 CStatTreeItemBase* CStatistics::s_statTree;
156 #ifndef CLIENT_GUI
157 // Uptime
158 CStatTreeItemTimer* CStatistics::s_uptime;
160 // Upload
161 CStatTreeItemUlDlCounter* CStatistics::s_sessionUpload;
162 CStatTreeItemPacketTotals* CStatistics::s_totalUpOverhead;
163 CStatTreeItemPackets* CStatistics::s_fileReqUpOverhead;
164 CStatTreeItemPackets* CStatistics::s_sourceXchgUpOverhead;
165 CStatTreeItemPackets* CStatistics::s_serverUpOverhead;
166 CStatTreeItemPackets* CStatistics::s_kadUpOverhead;
167 CStatTreeItemCounter* CStatistics::s_cryptUpOverhead;
168 CStatTreeItemNativeCounter* CStatistics::s_activeUploads;
169 CStatTreeItemNativeCounter* CStatistics::s_waitingUploads;
170 CStatTreeItemCounter* CStatistics::s_totalSuccUploads;
171 CStatTreeItemCounter* CStatistics::s_totalFailedUploads;
172 CStatTreeItemCounter* CStatistics::s_totalUploadTime;
174 // Download
175 CStatTreeItemUlDlCounter* CStatistics::s_sessionDownload;
176 CStatTreeItemPacketTotals* CStatistics::s_totalDownOverhead;
177 CStatTreeItemPackets* CStatistics::s_fileReqDownOverhead;
178 CStatTreeItemPackets* CStatistics::s_sourceXchgDownOverhead;
179 CStatTreeItemPackets* CStatistics::s_serverDownOverhead;
180 CStatTreeItemPackets* CStatistics::s_kadDownOverhead;
181 CStatTreeItemCounter* CStatistics::s_cryptDownOverhead;
182 CStatTreeItemCounter* CStatistics::s_foundSources;
183 CStatTreeItemNativeCounter* CStatistics::s_activeDownloads;
185 // Connection
186 CStatTreeItemReconnects* CStatistics::s_reconnects;
187 CStatTreeItemTimer* CStatistics::s_sinceFirstTransfer;
188 CStatTreeItemTimer* CStatistics::s_sinceConnected;
189 CStatTreeItemCounterMax* CStatistics::s_activeConnections;
190 CStatTreeItemMaxConnLimitReached* CStatistics::s_limitReached;
191 CStatTreeItemSimple* CStatistics::s_avgConnections;
193 // Clients
194 CStatTreeItemHiddenCounter* CStatistics::s_clients;
195 CStatTreeItemCounter* CStatistics::s_unknown;
196 //CStatTreeItem CStatistics::s_lowID;
197 //CStatTreeItem CStatistics::s_secIdentOnOff;
198 #ifdef __DEBUG__
199 CStatTreeItemNativeCounter* CStatistics::s_hasSocket;
200 #endif
201 CStatTreeItemNativeCounter* CStatistics::s_filtered;
202 CStatTreeItemNativeCounter* CStatistics::s_banned;
204 // Servers
205 CStatTreeItemSimple* CStatistics::s_workingServers;
206 CStatTreeItemSimple* CStatistics::s_failedServers;
207 CStatTreeItemNativeCounter* CStatistics::s_totalServers;
208 CStatTreeItemNativeCounter* CStatistics::s_deletedServers;
209 CStatTreeItemNativeCounter* CStatistics::s_filteredServers;
210 CStatTreeItemSimple* CStatistics::s_usersOnWorking;
211 CStatTreeItemSimple* CStatistics::s_filesOnWorking;
212 CStatTreeItemSimple* CStatistics::s_totalUsers;
213 CStatTreeItemSimple* CStatistics::s_totalFiles;
214 CStatTreeItemSimple* CStatistics::s_serverOccupation;
216 // Shared files
217 CStatTreeItemCounter* CStatistics::s_numberOfShared;
218 CStatTreeItemCounter* CStatistics::s_sizeOfShare;
220 // Kad
221 uint64_t CStatistics::s_kadNodesTotal;
222 uint16_t CStatistics::s_kadNodesCur;
224 // Totals
225 uint64_t CStatistics::s_totalSent;
226 uint64_t CStatistics::s_totalReceived;
228 bool CStatistics::s_statsNeedSave;
231 CStatistics::CStatistics()
232 : m_graphRunningAvgDown(thePrefs::GetStatsAverageMinutes() * 60 * 1000, true),
233 m_graphRunningAvgUp(thePrefs::GetStatsAverageMinutes() * 60 * 1000, true),
234 m_graphRunningAvgKad(thePrefs::GetStatsAverageMinutes() * 60 * 1000, true)
236 uint64 start_time = GetTickCount64();
238 // Init graphs
240 average_minutes = thePrefs::GetStatsAverageMinutes();
242 HR hr = {0.0, 0.0, 0.0, 0.0, 0.0, 0, 0, 0, 0, 0};
243 hrInit = hr;
244 nHistRanges = 7; // =ceil(log(max_update_delay)/log(2))
245 nPointsPerRange = GetPointsPerRange();
246 bitsHistClockMask = (1 << (nHistRanges-1)) - 1;
247 aposRecycle = new listPOS[nHistRanges];
248 listPOS *ppos = aposRecycle+nHistRanges-1;
249 for (int i=nHistRanges; i>0; --i) { // permanently allocated history list
250 listHR.push_back(hr);
251 *ppos-- = --listHR.end();
252 for (int j=nPointsPerRange; j>1; --j)
253 listHR.push_back(hr);
256 // Init rate counters outside the tree
258 s_upOverheadRate = new CPreciseRateCounter(5000);
259 s_downOverheadRate = new CPreciseRateCounter(5000);
261 // Init Tree
263 InitStatsTree();
264 s_uptime->SetStartTime(start_time);
266 // Load saved statistics
267 Load();
268 s_statsNeedSave = false;
272 CStatistics::~CStatistics()
274 // clearing listHR frees the memory occupied by the nodes
275 listHR.clear();
276 delete [] aposRecycle;
278 delete s_statTree;
280 // delete items not in the tree
281 delete s_totalUploadTime;
283 // delete rate counters outside the tree
284 delete s_upOverheadRate;
285 delete s_downOverheadRate;
289 static uint64_t ReadUInt64FromCfg(wxConfigBase* cfg, const wxString& key)
291 wxString buffer;
293 cfg->Read(key, &buffer, wxT("0"));
295 uint64 tmp = 0;
296 for (unsigned int i = 0; i < buffer.Length(); ++i) {
297 if ((buffer[i] >= wxChar('0')) &&(buffer[i] <= wxChar('9'))) {
298 tmp = tmp * 10 + (buffer[i] - wxChar('0'));
299 } else {
300 tmp = 0;
301 break;
305 return tmp;
308 void CStatistics::Load()
310 CFile f;
312 s_totalSent = 0;
313 s_totalReceived = 0;
314 try {
315 CPath path(JoinPaths(thePrefs::GetConfigDir(), wxT("statistics.dat")));
316 if (path.FileExists() && f.Open(path)) {
317 uint8_t version = f.ReadUInt8();
318 if (version == 0) {
319 s_totalSent = f.ReadUInt64();
320 s_totalReceived = f.ReadUInt64();
323 } catch (const CSafeIOException& e) {
324 AddLogLineN(e.what());
327 // Load old values from config
328 bool cfgChanged = false;
329 wxConfigBase* cfg = wxConfigBase::Get();
330 if (cfg->HasEntry(wxT("/Statistics/TotalUploadedBytes"))) {
331 s_totalSent += ReadUInt64FromCfg(cfg, wxT("/Statistics/TotalUploadedBytes"));
332 cfg->DeleteEntry(wxT("/Statistics/TotalUploadedBytes"));
333 cfgChanged = true;
335 if (cfg->HasEntry(wxT("/Statistics/TotalDownloadedBytes"))) {
336 s_totalReceived += ReadUInt64FromCfg(cfg, wxT("/Statistics/TotalDownloadedBytes"));
337 cfg->DeleteEntry(wxT("/Statistics/TotalDownloadedBytes"));
338 cfgChanged = true;
340 if (cfgChanged) {
341 cfg->Flush();
342 s_statsNeedSave = s_totalSent > 0 || s_totalReceived > 0;
343 Save();
348 void CStatistics::Save()
350 if (s_statsNeedSave) {
351 CFile f;
353 if (f.Open(JoinPaths(thePrefs::GetConfigDir(), wxT("statistics.dat")), CFile::write)) {
354 f.WriteUInt8(0); /* version */
355 f.WriteUInt64(s_totalSent);
356 f.WriteUInt64(s_totalReceived);
358 s_statsNeedSave = false;
362 void CStatistics::CalculateRates()
364 uint64_t now = GetTickCount64();
365 s_downOverheadRate->CalculateRate(now);
366 s_upOverheadRate->CalculateRate(now);
367 s_downloadrate->CalculateRate(now);
368 s_uploadrate->CalculateRate(now);
373 /* ------------------------------- GRAPHS ---------------------------- */
376 History List
378 The basic idea here is that we want to keep as much history as we can without paying
379 a high price in terms of memory space. Because we keep the history for display purposes,
380 we can take advantage of the fact that when the period shown in the graphs is long
381 then each pixel represents a long period. So as the most recent history we keep one
382 window full of points at a resolution of 1 second, the next window full at 2 seconds,
383 the next at 4 seconds and so on, up to the maximum desired. This way there is always
384 at least one sample point per pixel for any update delay set by the user, and the
385 memory required grows with the *log* of the total time period covered.
386 The history is kept in a doubly-linked list, with the most recent snapshot at the tail.
387 The number of nodes in the list is fixed, and there are no calls to RemoveHead() and
388 AddTail() which would add overhead and contribute to memory fragmentation. Instead,
389 every second when a new point gets recorded, one of the existing nodes is recycled;
390 it is disjoined from its present place, put at the tail of the list, and then gets
391 filled with new data. [Emilio Sandoz]
392 This unfortunately does not work with stl classes, as none of them supports moving
393 a node to another place, so we have to erase and re-add nodes.
396 void CStatistics::RecordHistory()
397 { // First we query and compute some values, then we store them in the history list
399 // A few comments about the use of double and float in computations:
400 // Even on a hi-res screen our graphs will have 10 bits of resolution at most,
401 // so the 24 bits resolution of a float on 32 bit Intel processors is more than
402 // enough for all displayed values. Rate computations however, and especially
403 // running average computations, use differences (delta bytes/ delta time), and
404 // for long uptimes the difference between two timestamps can lose too much
405 // accuracy because the large mantissa causes less significant bits to be dropped
406 // (same for the difference between two cumulative byte counts). [We don't store
407 // these values as integers because they will be used in floating point calculations,
408 // and we want to perform the conversion only once). Therefore timestamps and
409 // Kbyte counts are stored in the history as doubles, while computed values use
410 // float (to save space and execution time).
413 Store values; first determine the node to be recycled (using the bits in iClock)
415 oldest records ----------------- listHR ------------------ youngest records
417 O-[Range 2^n sec]-O- ... -O-[Range 4 sec]-O-[Range 2 sec]-O-[Range 1 sec]-O
418 | | | | > every 2 secs -^
419 | | ... | >--------------- every 4 secs -^
420 | | >------------------------ recycle every 8 secs -^
421 | | ...
422 | >-the node at this position is recycled every 2^n secs -^
423 >-------------------(ditto for the oldest node at the head of the list) --^
425 aposRecycle[nHistRanges-1] ... aposRecycle[0] Tail
427 listPOS *ppos;
428 static int iClock;
429 int iClockPrev = iClock++;
430 int bits = (iClockPrev^iClock) & iClock; // identify the highest changed bit
431 if (bits <= bitsHistClockMask) {
432 ppos = aposRecycle;
433 while ((bits /= 2) != 0) // count to the highest bit that was just toggled to 1
434 ++ppos;
435 // recycle one node and jump over the next to move it to the next higher range
436 listHR.push_back(**ppos);
437 *ppos = ++listHR.erase(*ppos);
438 } else {
439 ppos = aposRecycle+nHistRanges-1;
440 // recycle the node at the head; there is no higher range to move nodes into
441 listHR.push_back(**ppos);
442 *ppos = listHR.erase(*ppos);
445 // now save the latest data point in this node
446 listPOS phr = --listHR.end();
447 phr->kBytesSent = GetSessionSentBytes() / 1024.0;
448 phr->kBytesReceived = GetSessionReceivedBytes() / 1024.0;
449 phr->kBpsUpCur = GetUploadRate() / 1024.0;
450 phr->kBpsDownCur = GetDownloadRate() / 1024.0;
451 phr->cntUploads = GetActiveUploadsCount();
452 phr->cntConnections = GetActiveConnections();
453 phr->cntDownloads = GetDownloadingSources();
454 phr->sTimestamp = GetUptimeMillis() / 1000.0;
456 s_kadNodesTotal += s_kadNodesCur;
457 phr->kadNodesTotal = s_kadNodesTotal;
458 phr->kadNodesCur = s_kadNodesCur;
462 unsigned CStatistics::GetHistory( // Assemble arrays of sample points for a graph
463 unsigned cntPoints, // number of sample points to assemble
464 double sStep, // time difference between sample points
465 double sFinal, // latest allowed timestamp
466 const std::vector<float *> &ppf,// an array of pointers to arrays of floats for the result
467 StatsGraphType which_graph) // the graph which will receive the points
469 if (sStep==0.0 || cntPoints==0) {
470 return(0);
473 float *pf1 = ppf[0];
474 float *pf2 = ppf[1];
475 float *pf3 = ppf[2];
476 unsigned cntFilled = 0;
477 listRPOS pos = listHR.rbegin();
479 // start of list should be an integer multiple of the sampling period for samples
480 // to be consistent when the graphs are resized horizontally
481 double sTarget;
482 if (sFinal >= 0.0) {
483 sTarget = sFinal;
484 } else {
485 sTarget = sStep==1.0 ?
486 pos->sTimestamp :
487 std::floor(pos->sTimestamp/sStep) * sStep;
490 HR **ahr = NULL, **pphr = NULL;
491 bool bRateGraph = (which_graph != GRAPH_CONN); // rate graph or connections graph?
492 if (bRateGraph) {
493 ahr = new HR* [cntPoints];
494 pphr = ahr;
497 while (pos != listHR.rend()) {
498 if (pos->sTimestamp > sTarget) {
499 ++pos;
500 continue;
502 if (bRateGraph) { // assemble an array of pointers for ComputeAverages
503 *pphr++ = &(*pos);
504 } else { // or build the arrays if possible
505 *pf1++ = (float)pos->cntUploads;
506 *pf2++ = (float)pos->cntConnections;
507 *pf3++ = (float)pos->cntDownloads;
509 if (++cntFilled == cntPoints) { // enough points
510 break;
512 if (pos->sTimestamp == 0.0) { // reached beginning of uptime
513 break;
515 if ((sTarget -= sStep) <= 0.0) { // don't overshoot the beginning
516 if (bRateGraph) {
517 *pphr++ = &hrInit;
518 } else {
519 *pf1++ = *pf2++ = *pf3++ = 0.0;
521 ++cntFilled;
522 break;
526 if (bRateGraph) {
527 if (cntFilled > 0) {
528 ComputeAverages(pphr, pos, cntFilled, sStep, ppf, which_graph);
530 delete[] ahr;
533 return cntFilled;
537 unsigned CStatistics::GetHistoryForWeb( // Assemble arrays of sample points for the webserver
538 unsigned cntPoints, // maximum number of sample points to assemble
539 double sStep, // time difference between sample points
540 double *sStart, // earliest allowed timestamp
541 uint32 **graphData) // a pointer to a pointer that will point to the graph data array
543 if (*sStart < 0.0) {
544 *sStart = 0.0;
546 if (sStep==0.0 || cntPoints==0)
547 return(0);
548 unsigned cntFilled = 0;
549 listRPOS pos = listHR.rbegin();
550 double LastTimeStamp = pos->sTimestamp;
551 double sTarget = LastTimeStamp;
553 HR **pphr = new HR *[cntPoints];
555 while (pos != listHR.rend()) {
556 if (pos->sTimestamp > sTarget) {
557 ++pos; // find next history record
558 continue;
560 pphr[cntFilled] = &(*pos);
561 if (++cntFilled == cntPoints) // enough points
562 break;
563 if (pos->sTimestamp <= *sStart) // reached beginning of requested time
564 break;
565 if ((sTarget -= sStep) <= 0.0) { // don't overshoot the beginning
566 pphr[cntFilled++] = NULL;
567 break;
571 if (cntFilled) {
572 *graphData = new uint32 [4 * cntFilled];
573 if (*graphData) {
574 for (unsigned int i = 0; i < cntFilled; i++) {
575 HR *phr = pphr[cntFilled - i - 1];
576 if (phr) {
577 (*graphData)[4 * i ] = ENDIAN_HTONL((uint32)(phr->kBpsDownCur * 1024.0));
578 (*graphData)[4 * i + 1] = ENDIAN_HTONL((uint32)(phr->kBpsUpCur * 1024.0));
579 (*graphData)[4 * i + 2] = ENDIAN_HTONL((uint32)phr->cntConnections);
580 (*graphData)[4 * i + 3] = ENDIAN_HTONL((uint32)phr->kadNodesCur);
581 } else {
582 (*graphData)[4 * i] = (*graphData)[4 * i + 1] = 0;
583 (*graphData)[4 * i + 2] = (*graphData)[4 * i + 3] = 0;
587 } else {
588 *graphData = NULL;
591 delete [] pphr;
593 *sStart = LastTimeStamp;
595 return cntFilled;
599 void CStatistics::ComputeAverages(
600 HR **pphr, // pointer to (end of) array of assembled history records
601 listRPOS pos, // position in history list from which to backtrack
602 unsigned cntFilled, // number of points in the sample data
603 double sStep, // time difference between two samples
604 const std::vector<float *> &ppf,// an array of pointers to arrays of floats with sample data
605 StatsGraphType which_graph) // the graph which will receive the points
607 double sTarget, kValueRun;
608 uint64 avgTime = average_minutes * 60;
609 unsigned nBtPoints = (unsigned)(avgTime / sStep);
611 CPreciseRateCounter* runningAvg = NULL;
612 switch (which_graph) {
613 case GRAPH_DOWN: runningAvg = &m_graphRunningAvgDown; break;
614 case GRAPH_UP: runningAvg = &m_graphRunningAvgUp; break;
615 case GRAPH_KAD: runningAvg = &m_graphRunningAvgKad; break;
616 default:
617 wxCHECK_RET(false, wxT("ComputeAverages called with unsupported graph type."));
620 runningAvg->m_timespan = avgTime * 1000;
621 runningAvg->m_tick_history.clear();
622 runningAvg->m_byte_history.clear();
623 runningAvg->m_total = 0;
624 runningAvg->m_tmp_sum = 0;
626 if (pos == listHR.rend()) {
627 sTarget = 0.0;
628 } else {
629 sTarget = std::max(0.0, pos->sTimestamp - sStep);
632 while (nBtPoints--) {
633 while (pos != listHR.rend() && pos->sTimestamp > sTarget) ++pos; // find next history record
634 if (pos != listHR.rend()) {
635 runningAvg->m_tick_history.push_front((uint64)(pos->sTimestamp * 1000.0));
637 uint32 value = 0;
638 switch (which_graph) {
639 case GRAPH_DOWN:
640 value = (uint32)(pos->kBpsDownCur * 1024.0);
641 break;
642 case GRAPH_UP:
643 value = (uint32)(pos->kBpsUpCur * 1024.0);
644 break;
645 case GRAPH_KAD:
646 value = (uint32)(pos->kadNodesCur * 1024.0);
647 break;
648 default:
649 wxCHECK_RET(false, wxT("ComputeAverages called with unsupported graph type."));
652 runningAvg->m_byte_history.push_front(value);
653 runningAvg->m_total += value;
654 } else {
655 break;
657 if ((sTarget -= sStep) < 0.0) {
658 break;
662 // now compute averages in returned arrays, starting with the earliest values
663 float *pf1 = ppf[0] + cntFilled - 1; // holds session avg
664 float *pf2 = ppf[1] + cntFilled - 1; // holds running avg
665 float *pf3 = ppf[2] + cntFilled - 1; // holds current rate
667 for (int cnt=cntFilled; cnt>0; cnt--, pf1--, pf2--, pf3--) {
668 HR *phr = *(--pphr);
669 if (which_graph == GRAPH_DOWN) {
670 kValueRun = phr->kBytesReceived;
671 *pf3 = phr->kBpsDownCur;
672 } else if (which_graph == GRAPH_UP) {
673 kValueRun = phr->kBytesSent;
674 *pf3 = phr->kBpsUpCur;
675 } else {
676 kValueRun = phr->kadNodesTotal;
677 *pf3 = phr->kadNodesCur;
680 *pf1 = kValueRun / phr->sTimestamp;
681 (*runningAvg) += (uint32)(*pf3 * 1024.0);
682 runningAvg->CalculateRate((uint64)(phr->sTimestamp * 1000.0));
683 *pf2 = (float)(runningAvg->GetRate() / 1024.0);
688 GraphUpdateInfo CStatistics::GetPointsForUpdate()
690 GraphUpdateInfo update;
691 listPOS phr = --listHR.end();
692 update.timestamp = (double) phr->sTimestamp;
694 m_graphRunningAvgDown += (uint32)(phr->kBpsDownCur * 1024.0);
695 m_graphRunningAvgUp += (uint32)(phr->kBpsUpCur * 1024.0);
696 // Note: kadNodesCur is multiplied by 1024 since the value is done
697 // in other places, so we simply follow suit here to avoid trouble.
698 m_graphRunningAvgKad += (uint32)(phr->kadNodesCur * 1024.0);
699 m_graphRunningAvgDown.CalculateRate((uint64)(phr->sTimestamp * 1000.0));
700 m_graphRunningAvgUp.CalculateRate((uint64)(phr->sTimestamp * 1000.0));
701 m_graphRunningAvgKad.CalculateRate((uint64)(phr->sTimestamp * 1000.0));
703 update.downloads[0] = phr->kBytesReceived / phr->sTimestamp;
704 update.downloads[1] = m_graphRunningAvgDown.GetRate() / 1024.0;
705 update.downloads[2] = phr->kBpsDownCur;
707 update.uploads[0] = phr->kBytesSent / phr->sTimestamp;
708 update.uploads[1] = m_graphRunningAvgUp.GetRate() / 1024.0;
709 update.uploads[2] = phr->kBpsUpCur;
711 update.connections[0] = (float)phr->cntUploads;
712 update.connections[1] = (float)phr->cntConnections;
713 update.connections[2] = (float)phr->cntDownloads;
715 update.kadnodes[0] = phr->kadNodesTotal / phr->sTimestamp;
716 update.kadnodes[1] = m_graphRunningAvgKad.GetRate() / 1024.0;
717 update.kadnodes[2] = phr->kadNodesCur;
719 return update;
723 /* ------------------------------- TREE ---------------------------- */
725 void CStatistics::InitStatsTree()
727 s_statTree = new CStatTreeItemBase(wxTRANSLATE("Statistics"));
729 CStatTreeItemBase* tmpRoot1;
730 CStatTreeItemBase* tmpRoot2;
732 s_uptime = static_cast<CStatTreeItemTimer*>(s_statTree->AddChild(new CStatTreeItemTimer(wxTRANSLATE("Uptime: %s"))));
734 tmpRoot1 = s_statTree->AddChild(new CStatTreeItemBase(wxTRANSLATE("Transfer"), stSortChildren));
736 tmpRoot2 = tmpRoot1->AddChild(new CStatTreeItemBase(wxTRANSLATE("Uploads")), 2);
737 s_sessionUpload = static_cast<CStatTreeItemUlDlCounter*>(tmpRoot2->AddChild(new CStatTreeItemUlDlCounter(wxTRANSLATE("Uploaded Data (Session (Total)): %s"), theStats::GetTotalSentBytes, stSortChildren | stSortByValue)));
738 // Children will be added on-the-fly
739 s_totalUpOverhead = static_cast<CStatTreeItemPacketTotals*>(tmpRoot2->AddChild(new CStatTreeItemPacketTotals(wxTRANSLATE("Total Overhead (Packets): %s"))));
740 s_fileReqUpOverhead = static_cast<CStatTreeItemPackets*>(tmpRoot2->AddChild(new CStatTreeItemPackets(wxTRANSLATE("File Request Overhead (Packets): %s"))));
741 s_totalUpOverhead->AddPacketCounter(s_fileReqUpOverhead);
742 s_sourceXchgUpOverhead = static_cast<CStatTreeItemPackets*>(tmpRoot2->AddChild(new CStatTreeItemPackets(wxTRANSLATE("Source Exchange Overhead (Packets): %s"))));
743 s_totalUpOverhead->AddPacketCounter(s_sourceXchgUpOverhead);
744 s_serverUpOverhead = static_cast<CStatTreeItemPackets*>(tmpRoot2->AddChild(new CStatTreeItemPackets(wxTRANSLATE("Server Overhead (Packets): %s"))));
745 s_totalUpOverhead->AddPacketCounter(s_serverUpOverhead);
746 s_kadUpOverhead = static_cast<CStatTreeItemPackets*>(tmpRoot2->AddChild(new CStatTreeItemPackets(wxTRANSLATE("Kad Overhead (Packets): %s"))));
747 s_totalUpOverhead->AddPacketCounter(s_kadUpOverhead);
748 s_cryptUpOverhead = static_cast<CStatTreeItemCounter*>(tmpRoot2->AddChild(new CStatTreeItemCounter(wxTRANSLATE("Crypt overhead (UDP): %s"))));
749 s_cryptUpOverhead->SetDisplayMode(dmBytes);
750 s_activeUploads = static_cast<CStatTreeItemNativeCounter*>(tmpRoot2->AddChild(new CStatTreeItemNativeCounter(wxTRANSLATE("Active Uploads: %s"))));
751 s_waitingUploads = static_cast<CStatTreeItemNativeCounter*>(tmpRoot2->AddChild(new CStatTreeItemNativeCounter(wxTRANSLATE("Waiting Uploads: %s"))));
752 s_totalSuccUploads = static_cast<CStatTreeItemCounter*>(tmpRoot2->AddChild(new CStatTreeItemCounter(wxTRANSLATE("Total successful upload sessions: %s"))));
753 s_totalFailedUploads = static_cast<CStatTreeItemCounter*>(tmpRoot2->AddChild(new CStatTreeItemCounter(wxTRANSLATE("Total failed upload sessions: %s"))));
754 s_totalUploadTime = new CStatTreeItemCounter(wxEmptyString);
755 tmpRoot2->AddChild(new CStatTreeItemAverage(wxTRANSLATE("Average upload time: %s"), s_totalUploadTime, s_totalSuccUploads, dmTime));
757 tmpRoot2 = tmpRoot1->AddChild(new CStatTreeItemBase(wxTRANSLATE("Downloads")), 1);
758 s_sessionDownload = static_cast<CStatTreeItemUlDlCounter*>(tmpRoot2->AddChild(new CStatTreeItemUlDlCounter(wxTRANSLATE("Downloaded Data (Session (Total)): %s"), theStats::GetTotalReceivedBytes, stSortChildren | stSortByValue)));
759 // Children will be added on-the-fly
760 s_totalDownOverhead = static_cast<CStatTreeItemPacketTotals*>(tmpRoot2->AddChild(new CStatTreeItemPacketTotals(wxTRANSLATE("Total Overhead (Packets): %s"))));
761 s_fileReqDownOverhead = static_cast<CStatTreeItemPackets*>(tmpRoot2->AddChild(new CStatTreeItemPackets(wxTRANSLATE("File Request Overhead (Packets): %s"))));
762 s_totalDownOverhead->AddPacketCounter(s_fileReqDownOverhead);
763 s_sourceXchgDownOverhead = static_cast<CStatTreeItemPackets*>(tmpRoot2->AddChild(new CStatTreeItemPackets(wxTRANSLATE("Source Exchange Overhead (Packets): %s"))));
764 s_totalDownOverhead->AddPacketCounter(s_sourceXchgDownOverhead);
765 s_serverDownOverhead = static_cast<CStatTreeItemPackets*>(tmpRoot2->AddChild(new CStatTreeItemPackets(wxTRANSLATE("Server Overhead (Packets): %s"))));
766 s_totalDownOverhead->AddPacketCounter(s_serverDownOverhead);
767 s_kadDownOverhead = static_cast<CStatTreeItemPackets*>(tmpRoot2->AddChild(new CStatTreeItemPackets(wxTRANSLATE("Kad Overhead (Packets): %s"))));
768 s_totalDownOverhead->AddPacketCounter(s_kadDownOverhead);
769 s_cryptDownOverhead = static_cast<CStatTreeItemCounter*>(tmpRoot2->AddChild(new CStatTreeItemCounter(wxTRANSLATE("Crypt overhead (UDP): %s"))));
770 s_cryptDownOverhead->SetDisplayMode(dmBytes);
771 s_foundSources = static_cast<CStatTreeItemCounter*>(tmpRoot2->AddChild(new CStatTreeItemCounter(wxTRANSLATE("Found Sources: %s"), stSortChildren | stSortByValue)));
772 s_activeDownloads = static_cast<CStatTreeItemNativeCounter*>(tmpRoot2->AddChild(new CStatTreeItemNativeCounter(wxTRANSLATE("Active Downloads (chunks): %s"))));
774 tmpRoot1->AddChild(new CStatTreeItemRatio(wxTRANSLATE("Session UL:DL Ratio (Total): %s"), s_sessionUpload, s_sessionDownload, theStats::GetTotalSentBytes, theStats::GetTotalReceivedBytes), 3);
776 tmpRoot1 = s_statTree->AddChild(new CStatTreeItemBase(wxTRANSLATE("Connection")));
777 tmpRoot1->AddChild(new CStatTreeItemAverageSpeed(wxTRANSLATE("Average download rate (Session): %s"), s_sessionDownload, s_uptime));
778 tmpRoot1->AddChild(new CStatTreeItemAverageSpeed(wxTRANSLATE("Average upload rate (Session): %s"), s_sessionUpload, s_uptime));
779 s_downloadrate = static_cast<CStatTreeItemRateCounter*>(tmpRoot1->AddChild(new CStatTreeItemRateCounter(wxTRANSLATE("Max download rate (Session): %s"), true, 30000)));
780 s_uploadrate = static_cast<CStatTreeItemRateCounter*>(tmpRoot1->AddChild(new CStatTreeItemRateCounter(wxTRANSLATE("Max upload rate (Session): %s"), true, 30000)));
781 s_reconnects = static_cast<CStatTreeItemReconnects*>(tmpRoot1->AddChild(new CStatTreeItemReconnects(wxTRANSLATE("Reconnects: %i"))));
782 s_sinceFirstTransfer = static_cast<CStatTreeItemTimer*>(tmpRoot1->AddChild(new CStatTreeItemTimer(wxTRANSLATE("Time Since First Transfer: %s"), stHideIfZero)));
783 s_sinceConnected = static_cast<CStatTreeItemTimer*>(tmpRoot1->AddChild(new CStatTreeItemTimer(wxTRANSLATE("Connected To Server Since: %s"))));
784 s_activeConnections = static_cast<CStatTreeItemCounterMax*>(tmpRoot1->AddChild(new CStatTreeItemCounterMax(wxTRANSLATE("Active Connections (estimate): %i"))));
785 s_limitReached = static_cast<CStatTreeItemMaxConnLimitReached*>(tmpRoot1->AddChild(new CStatTreeItemMaxConnLimitReached(wxTRANSLATE("Max Connection Limit Reached: %s"))));
786 s_avgConnections = static_cast<CStatTreeItemSimple*>(tmpRoot1->AddChild(new CStatTreeItemSimple(wxTRANSLATE("Average Connections (estimate): %g"))));
787 s_avgConnections->SetValue(0.0);
788 tmpRoot1->AddChild(new CStatTreeItemPeakConnections(wxTRANSLATE("Peak Connections (estimate): %i")));
790 s_clients = static_cast<CStatTreeItemHiddenCounter*>(s_statTree->AddChild(new CStatTreeItemHiddenCounter(wxTRANSLATE("Clients"), stSortChildren | stSortByValue)));
791 s_unknown = static_cast<CStatTreeItemCounter*>(s_clients->AddChild(new CStatTreeItemCounter(wxTRANSLATE("Unknown: %s")), 6));
792 //s_lowID = static_cast<CStatTreeItem*>(s_clients->AddChild(new CStatTreeItem(wxTRANSLATE("LowID: %u (%.2f%% Total %.2f%% Known)")), 5));
793 //s_secIdentOnOff = static_cast<CStatTreeItem*>(s_clients->AddChild(new CStatTreeItem(wxTRANSLATE("SecIdent On/Off: %u (%.2f%%) : %u (%.2f%%)")), 4));
794 #ifdef __DEBUG__
795 s_hasSocket = static_cast<CStatTreeItemNativeCounter*>(s_clients->AddChild(new CStatTreeItemNativeCounter(wxT("HasSocket: %s")), 3));
796 #endif
797 s_filtered = static_cast<CStatTreeItemNativeCounter*>(s_clients->AddChild(new CStatTreeItemNativeCounter(wxTRANSLATE("Filtered: %s")), 2));
798 s_banned = static_cast<CStatTreeItemNativeCounter*>(s_clients->AddChild(new CStatTreeItemNativeCounter(wxTRANSLATE("Banned: %s")), 1));
799 s_clients->AddChild(new CStatTreeItemTotalClients(wxTRANSLATE("Total: %i Known: %i"), s_clients, s_unknown), 0x80000000);
801 // TODO: Use counters?
802 tmpRoot1 = s_statTree->AddChild(new CStatTreeItemBase(wxTRANSLATE("Servers")));
803 s_workingServers = static_cast<CStatTreeItemSimple*>(tmpRoot1->AddChild(new CStatTreeItemSimple(wxTRANSLATE("Working Servers: %i"))));
804 s_failedServers = static_cast<CStatTreeItemSimple*>(tmpRoot1->AddChild(new CStatTreeItemSimple(wxTRANSLATE("Failed Servers: %i"))));
805 s_totalServers = static_cast<CStatTreeItemNativeCounter*>(tmpRoot1->AddChild(new CStatTreeItemNativeCounter(wxTRANSLATE("Total: %s"))));
806 s_deletedServers = static_cast<CStatTreeItemNativeCounter*>(tmpRoot1->AddChild(new CStatTreeItemNativeCounter(wxTRANSLATE("Deleted Servers: %s"))));
807 s_filteredServers = static_cast<CStatTreeItemNativeCounter*>(tmpRoot1->AddChild(new CStatTreeItemNativeCounter(wxTRANSLATE("Filtered Servers: %s"))));
808 s_usersOnWorking = static_cast<CStatTreeItemSimple*>(tmpRoot1->AddChild(new CStatTreeItemSimple(wxTRANSLATE("Users on Working Servers: %llu"))));
809 s_filesOnWorking = static_cast<CStatTreeItemSimple*>(tmpRoot1->AddChild(new CStatTreeItemSimple(wxTRANSLATE("Files on Working Servers: %llu"))));
810 s_totalUsers = static_cast<CStatTreeItemSimple*>(tmpRoot1->AddChild(new CStatTreeItemSimple(wxTRANSLATE("Total Users: %llu"))));
811 s_totalFiles = static_cast<CStatTreeItemSimple*>(tmpRoot1->AddChild(new CStatTreeItemSimple(wxTRANSLATE("Total Files: %llu"))));
812 s_serverOccupation = static_cast<CStatTreeItemSimple*>(tmpRoot1->AddChild(new CStatTreeItemSimple(wxTRANSLATE("Server Occupation: %.2f%%"))));
813 s_serverOccupation->SetValue(0.0);
815 tmpRoot1 = s_statTree->AddChild(new CStatTreeItemBase(wxTRANSLATE("Shared Files")));
816 s_numberOfShared = static_cast<CStatTreeItemCounter*>(tmpRoot1->AddChild(new CStatTreeItemCounter(wxTRANSLATE("Number of Shared Files: %s"))));
817 s_sizeOfShare = static_cast<CStatTreeItemCounter*>(tmpRoot1->AddChild(new CStatTreeItemCounter(wxTRANSLATE("Total size of Shared Files: %s"))));
818 s_sizeOfShare->SetDisplayMode(dmBytes);
819 tmpRoot1->AddChild(new CStatTreeItemAverage(wxTRANSLATE("Average file size: %s"), s_sizeOfShare, s_numberOfShared, dmBytes));
823 void CStatistics::UpdateStatsTree()
825 // get sort orders right
826 s_sessionUpload->ReSortChildren();
827 s_sessionDownload->ReSortChildren();
828 s_clients->ReSortChildren();
829 s_foundSources->ReSortChildren();
830 // TODO: sort OS_Info subtrees.
832 s_avgConnections->SetValue(theApp->listensocket->GetAverageConnections());
834 // get serverstats
835 // TODO: make these realtime, too
836 uint32 servfail;
837 uint32 servuser;
838 uint32 servfile;
839 uint32 servtuser;
840 uint32 servtfile;
841 float servocc;
842 theApp->serverlist->GetStatus(servfail, servuser, servfile, servtuser, servtfile, servocc);
843 s_workingServers->SetValue((uint64)((*s_totalServers)-servfail));
844 s_failedServers->SetValue((uint64)servfail);
845 s_usersOnWorking->SetValue((uint64)servuser);
846 s_filesOnWorking->SetValue((uint64)servfile);
847 s_totalUsers->SetValue((uint64)servtuser);
848 s_totalFiles->SetValue((uint64)servtfile);
849 s_serverOccupation->SetValue(servocc);
853 void CStatistics::AddSourceOrigin(unsigned origin)
855 CStatTreeItemCounter* counter = static_cast<CStatTreeItemCounter*>(s_foundSources->GetChildById(0x0100 + origin));
856 if (counter) {
857 ++(*counter);
858 } else {
859 counter = new CStatTreeItemCounter(OriginToText(origin) + wxT(": %s"), stHideIfZero | stShowPercent);
860 ++(*counter);
861 s_foundSources->AddChild(counter, 0x0100 + origin);
865 void CStatistics::RemoveSourceOrigin(unsigned origin)
867 CStatTreeItemCounter* counter = static_cast<CStatTreeItemCounter*>(s_foundSources->GetChildById(0x0100 + origin));
868 wxASSERT(counter);
869 --(*counter);
872 static uint32 GetSoftID(uint8 SoftType)
874 // prevent appearing multiple tree entries with the same name
875 // this should be kept in sync with GetSoftName().
876 switch (SoftType) {
877 case SO_OLDEMULE:
878 return 0x0100 + SO_EMULE;
879 case SO_NEW_SHAREAZA:
880 case SO_NEW2_SHAREAZA:
881 return 0x0100 + SO_SHAREAZA;
882 case SO_NEW2_MLDONKEY:
883 return 0x0100 + SO_NEW_MLDONKEY;
884 default:
885 return 0x0100 + SoftType;
889 void CStatistics::AddDownloadFromSoft(uint8 SoftType, uint32 bytes)
891 AddReceivedBytes(bytes);
893 uint32 id = GetSoftID(SoftType);
895 if (s_sessionDownload->HasChildWithId(id)) {
896 (*static_cast<CStatTreeItemCounter*>(s_sessionDownload->GetChildById(id))) += bytes;
897 } else {
898 CStatTreeItemCounter* tmp = new CStatTreeItemCounter(GetSoftName(SoftType) + wxT(": %s"));
899 tmp->SetDisplayMode(dmBytes);
900 (*tmp) += bytes;
901 s_sessionDownload->AddChild(tmp, id);
905 void CStatistics::AddUploadToSoft(uint8 SoftType, uint32 bytes)
907 uint32 id = GetSoftID(SoftType);
909 if (s_sessionUpload->HasChildWithId(id)) {
910 (*static_cast<CStatTreeItemCounter*>(s_sessionUpload->GetChildById(id))) += bytes;
911 } else {
912 CStatTreeItemCounter* tmp = new CStatTreeItemCounter(GetSoftName(SoftType) + wxT(": %s"));
913 tmp->SetDisplayMode(dmBytes);
914 (*tmp) += bytes;
915 s_sessionUpload->AddChild(tmp, id);
919 inline bool SupportsOSInfo(unsigned clientSoft)
921 return (clientSoft == SO_AMULE) || (clientSoft == SO_HYDRANODE) || (clientSoft == SO_NEW2_MLDONKEY);
924 // Do some random black magic to strings to get a relatively unique number for them.
925 static uint32 GetIdFromString(const wxString& str)
927 uint32 id = 0;
928 for (unsigned i = 0; i < str.Length(); ++i) {
929 unsigned old_id = id;
930 id += (uint32)str.GetChar(i);
931 id <<= 2;
932 id ^= old_id;
933 id -= old_id;
935 return (((id >> 1) + id) | 0x00000100) & 0x7fffffff;
938 void CStatistics::AddKnownClient(CUpDownClient *pClient)
940 ++(*s_clients);
942 uint32 clientSoft = pClient->GetClientSoft();
943 uint32 id = GetSoftID(clientSoft);
945 CStatTreeItemCounter *client;
947 if (s_clients->HasChildWithId(id)) {
948 client = static_cast<CStatTreeItemCounter*>(s_clients->GetChildById(id));
949 ++(*client);
950 } else {
951 uint32 flags = stSortChildren | stShowPercent | stHideIfZero;
952 if (!SupportsOSInfo(clientSoft)) {
953 flags |= stCapChildren;
955 client = new CStatTreeItemCounter(GetSoftName(clientSoft) + wxT(": %s"), flags);
956 ++(*client);
957 s_clients->AddChild(client, id);
958 if (SupportsOSInfo(clientSoft)) {
959 client->AddChild(new CStatTreeItemBase(wxTRANSLATE("Version"), stSortChildren | stCapChildren), 2);
960 client->AddChild(new CStatTreeItemBase(wxTRANSLATE("Operating System"), stSortChildren | stSortByValue), 1);
964 CStatTreeItemBase *versionRoot = SupportsOSInfo(clientSoft) ? client->GetChildById(2) : client;
965 uint32 clientVersion = pClient->GetVersion();
967 if (versionRoot->HasChildWithId(clientVersion)) {
968 CStatTreeItemCounter *version = static_cast<CStatTreeItemCounter*>(versionRoot->GetChildById(clientVersion));
969 ++(*version);
970 } else {
971 const wxString& versionStr = pClient->GetVersionString();
972 CStatTreeItemCounter *version = new CStatTreeItemCounter((versionStr.IsEmpty() ? wxString(wxTRANSLATE("Unknown")) : versionStr) + wxT(": %s"), stShowPercent | stHideIfZero);
973 ++(*version);
974 versionRoot->AddChild(version, clientVersion, SupportsOSInfo(clientSoft));
977 if (SupportsOSInfo(clientSoft)) {
978 const wxString& OSInfo = pClient->GetClientOSInfo();
979 uint32 OS_ID = OSInfo.IsEmpty() ? 0 : GetIdFromString(OSInfo);
980 CStatTreeItemBase* OSRoot = client->GetChildById(1);
981 CStatTreeItemCounter* OSNode = static_cast<CStatTreeItemCounter*>(OSRoot->GetChildById(OS_ID));
982 if (OSNode) {
983 ++(*OSNode);
984 } else {
985 OSNode = new CStatTreeItemCounter((OS_ID ? OSInfo : wxString(wxTRANSLATE("Not Received"))) + wxT(": %s"), stShowPercent | stHideIfZero);
986 ++(*OSNode);
987 OSRoot->AddChild(OSNode, OS_ID, true);
992 void CStatistics::RemoveKnownClient(uint32 clientSoft, uint32 clientVersion, const wxString& OSInfo)
994 --(*s_clients);
996 uint32 id = GetSoftID(clientSoft);
998 CStatTreeItemCounter *client = static_cast<CStatTreeItemCounter*>(s_clients->GetChildById(id));
999 wxASSERT(client);
1000 --(*client);
1002 CStatTreeItemBase *versionRoot = SupportsOSInfo(clientSoft) ? client->GetChildById(2) : client;
1004 CStatTreeItemCounter *version = static_cast<CStatTreeItemCounter*>(versionRoot->GetChildById(clientVersion));
1005 wxASSERT(version);
1006 --(*version);
1008 if (SupportsOSInfo(clientSoft)) {
1009 uint32 OS_ID = OSInfo.IsEmpty() ? 0 : GetIdFromString(OSInfo);
1010 CStatTreeItemCounter* OSNode = static_cast<CStatTreeItemCounter*>(client->GetChildById(1)->GetChildById(OS_ID));
1011 wxASSERT(OSNode);
1012 --(*OSNode);
1016 #else /* CLIENT_GUI */
1018 CStatistics::CStatistics(CRemoteConnect &conn)
1019 : m_conn(conn)
1021 s_start_time = GetTickCount64();
1023 // Init Tree
1024 s_statTree = new CStatTreeItemBase(_("Statistics"), 0);
1026 // Clear stat data container
1027 for (int i = 0; i < sdTotalItems; ++i) {
1028 s_statData[i] = 0;
1033 CStatistics::~CStatistics()
1035 delete s_statTree;
1039 void CStatistics::UpdateStats(const CECPacket* stats)
1041 s_statData[sdUpload] = stats->GetTagByNameSafe(EC_TAG_STATS_UL_SPEED)->GetInt();
1042 s_statData[sdUpOverhead] = stats->GetTagByNameSafe(EC_TAG_STATS_UP_OVERHEAD)->GetInt();
1043 s_statData[sdDownload] = stats->GetTagByNameSafe(EC_TAG_STATS_DL_SPEED)->GetInt();
1044 s_statData[sdDownOverhead] = stats->GetTagByNameSafe(EC_TAG_STATS_DOWN_OVERHEAD)->GetInt();
1045 s_statData[sdWaitingClients] = stats->GetTagByNameSafe(EC_TAG_STATS_UL_QUEUE_LEN)->GetInt();
1046 s_statData[sdBannedClients] = stats->GetTagByNameSafe(EC_TAG_STATS_BANNED_COUNT)->GetInt();
1047 s_statData[sdED2KUsers] = stats->GetTagByNameSafe(EC_TAG_STATS_ED2K_USERS)->GetInt();
1048 s_statData[sdKadUsers] = stats->GetTagByNameSafe(EC_TAG_STATS_KAD_USERS)->GetInt();
1049 s_statData[sdED2KFiles] = stats->GetTagByNameSafe(EC_TAG_STATS_ED2K_FILES)->GetInt();
1050 s_statData[sdKadFiles] = stats->GetTagByNameSafe(EC_TAG_STATS_KAD_FILES)->GetInt();
1051 s_statData[sdKadFirewalledUDP] = stats->GetTagByNameSafe(EC_TAG_STATS_KAD_FIREWALLED_UDP)->GetInt();
1052 s_statData[sdKadIndexedSources] = stats->GetTagByNameSafe(EC_TAG_STATS_KAD_INDEXED_SOURCES)->GetInt();
1053 s_statData[sdKadIndexedKeywords] = stats->GetTagByNameSafe(EC_TAG_STATS_KAD_INDEXED_KEYWORDS)->GetInt();
1054 s_statData[sdKadIndexedNotes] = stats->GetTagByNameSafe(EC_TAG_STATS_KAD_INDEXED_NOTES)->GetInt();
1055 s_statData[sdKadIndexedLoad] = stats->GetTagByNameSafe(EC_TAG_STATS_KAD_INDEXED_LOAD)->GetInt();
1056 s_statData[sdKadIPAdress] = stats->GetTagByNameSafe(EC_TAG_STATS_KAD_IP_ADRESS)->GetInt();
1057 s_statData[sdKadNodes] = stats->GetTagByNameSafe(EC_TAG_STATS_KAD_NODES)->GetInt();
1058 s_statData[sdBuddyStatus] = stats->GetTagByNameSafe(EC_TAG_STATS_BUDDY_STATUS)->GetInt();
1059 s_statData[sdBuddyIP] = stats->GetTagByNameSafe(EC_TAG_STATS_BUDDY_IP)->GetInt();
1060 s_statData[sdBuddyPort] = stats->GetTagByNameSafe(EC_TAG_STATS_BUDDY_PORT)->GetInt();
1061 s_statData[sdKadInLanMode] = stats->GetTagByNameSafe(EC_TAG_STATS_KAD_IN_LAN_MODE)->GetInt();
1062 s_statData[sdTotalSentBytes] = stats->GetTagByNameSafe(EC_TAG_STATS_TOTAL_SENT_BYTES)->GetInt();
1063 s_statData[sdTotalReceivedBytes] = stats->GetTagByNameSafe(EC_TAG_STATS_TOTAL_RECEIVED_BYTES)->GetInt();
1064 s_statData[sdSharedFileCount] = stats->GetTagByNameSafe(EC_TAG_STATS_SHARED_FILE_COUNT)->GetInt();
1066 const CECTag * LoggerTag = stats->GetTagByName(EC_TAG_STATS_LOGGER_MESSAGE);
1067 if (LoggerTag) {
1068 for (CECTag::const_iterator it = LoggerTag->begin(); it != LoggerTag->end(); ++it) {
1069 theApp->AddRemoteLogLine(it->GetStringData());
1075 void CStatistics::UpdateStatsTree()
1079 void CStatistics::RebuildStatTreeRemote(const CECTag * tag)
1081 delete s_statTree;
1082 s_statTree = new CStatTreeItemBase(tag);
1086 uint64 CStatistics::GetUptimeMillis()
1088 return GetTickCount64() - s_start_time;
1092 uint64 CStatistics::GetUptimeSeconds()
1094 return (GetTickCount64() - s_start_time) / 1000;
1097 #endif /* !CLIENT_GUI */
1099 // File_checked_for_headers