Update Wiki URL
[amule.git] / src / Statistics.cpp
blob2bb51070bd28ce6c45e834ea449d3b1e5115ec26
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 "Preferences.h" // Needed for thePrefs
42 #include "ListenSocket.h" // (tree, GetAverageConnections)
43 #include "ServerList.h" // Needed for CServerList (tree)
44 #include <cmath> // Needed for std::floor
45 #include "updownclient.h" // Needed for CUpDownClient
46 #else
47 #include "GetTickCount.h" // Needed for GetTickCount64()
48 #include "Preferences.h"
49 #include <ec/cpp/RemoteConnect.h> // Needed for CRemoteConnect
50 #endif
52 #include "amule.h" // Needed for theApp
53 #include <wx/intl.h>
54 #include "Logger.h"
56 #ifdef __BSD__
57 // glibc -> bsd libc
58 #define round rint
59 #else
60 #define round(x) floor(x+0.5)
61 #endif /* __BSD__ */
64 #ifndef CLIENT_GUI
66 /*----- CPreciseRateCounter -----*/
68 void CPreciseRateCounter::CalculateRate(uint64_t now)
70 wxMutexLocker lock(m_mutex);
72 m_total += m_tmp_sum;
73 m_byte_history.push_back(m_tmp_sum);
74 m_tick_history.push_back(now);
75 m_tmp_sum = 0;
77 uint64_t timespan = now - m_tick_history.front();
79 // Checking maximal timespan, but make sure not to remove
80 // the extra node in m_tick_history.
81 while (timespan > m_timespan && !m_byte_history.empty()) {
82 m_total -= m_byte_history.front();
83 m_byte_history.pop_front();
84 m_tick_history.pop_front();
85 timespan = now - m_tick_history.front();
88 // Count rate/average
89 if (m_count_average) {
90 if (!m_byte_history.empty()) {
91 m_rate = m_total / (double)m_byte_history.size();
93 } else {
94 if (timespan > 0) {
95 m_rate = m_total / (timespan / 1000.0);
99 if (m_rate > m_max_rate) {
100 m_max_rate = m_rate;
105 /*----- CStatTreeItemRateCounter -----*/
107 #ifndef AMULE_DAEMON
108 wxString CStatTreeItemRateCounter::GetDisplayString() const
110 return CFormat(wxGetTranslation(m_label)) % CastItoSpeed(m_show_maxrate ? (uint32)m_max_rate : (uint32)m_rate);
112 #endif
114 void CStatTreeItemRateCounter::AddECValues(CECTag* tag) const
116 CECTag value(EC_TAG_STAT_NODE_VALUE, m_show_maxrate ? (uint32)m_max_rate : (uint32)m_rate);
117 value.AddTag(CECTag(EC_TAG_STAT_VALUE_TYPE, (uint8)EC_VALUE_SPEED));
118 tag->AddTag(value);
122 /*----- CStatTreeItemPeakConnections -----*/
124 #ifndef AMULE_DAEMON
125 wxString CStatTreeItemPeakConnections::GetDisplayString() const
127 return CFormat(wxGetTranslation(m_label)) % theStats::GetPeakConnections();
129 #endif
131 void CStatTreeItemPeakConnections::AddECValues(CECTag* tag) const
133 tag->AddTag(CECTag(EC_TAG_STAT_NODE_VALUE, (uint64)theStats::GetPeakConnections()));
137 /*----- CStatistics -----*/
139 // Static variables
141 // Rate counters
142 CPreciseRateCounter* CStatistics::s_upOverheadRate;
143 CPreciseRateCounter* CStatistics::s_downOverheadRate;
144 CStatTreeItemRateCounter* CStatistics::s_uploadrate;
145 CStatTreeItemRateCounter* CStatistics::s_downloadrate;
147 #else /* CLIENT_GUI */
149 uint64 CStatistics::s_start_time;
150 uint64 CStatistics::s_statData[sdTotalItems];
152 #endif /* !CLIENT_GUI / CLIENT_GUI */
154 // Tree root
155 CStatTreeItemBase* CStatistics::s_statTree;
157 #ifndef CLIENT_GUI
158 // Uptime
159 CStatTreeItemTimer* CStatistics::s_uptime;
161 // Upload
162 CStatTreeItemUlDlCounter* CStatistics::s_sessionUpload;
163 CStatTreeItemPacketTotals* CStatistics::s_totalUpOverhead;
164 CStatTreeItemPackets* CStatistics::s_fileReqUpOverhead;
165 CStatTreeItemPackets* CStatistics::s_sourceXchgUpOverhead;
166 CStatTreeItemPackets* CStatistics::s_serverUpOverhead;
167 CStatTreeItemPackets* CStatistics::s_kadUpOverhead;
168 CStatTreeItemCounter* CStatistics::s_cryptUpOverhead;
169 CStatTreeItemNativeCounter* CStatistics::s_activeUploads;
170 CStatTreeItemNativeCounter* CStatistics::s_waitingUploads;
171 CStatTreeItemCounter* CStatistics::s_totalSuccUploads;
172 CStatTreeItemCounter* CStatistics::s_totalFailedUploads;
173 CStatTreeItemCounter* CStatistics::s_totalUploadTime;
175 // Download
176 CStatTreeItemUlDlCounter* CStatistics::s_sessionDownload;
177 CStatTreeItemPacketTotals* CStatistics::s_totalDownOverhead;
178 CStatTreeItemPackets* CStatistics::s_fileReqDownOverhead;
179 CStatTreeItemPackets* CStatistics::s_sourceXchgDownOverhead;
180 CStatTreeItemPackets* CStatistics::s_serverDownOverhead;
181 CStatTreeItemPackets* CStatistics::s_kadDownOverhead;
182 CStatTreeItemCounter* CStatistics::s_cryptDownOverhead;
183 CStatTreeItemCounter* CStatistics::s_foundSources;
184 CStatTreeItemNativeCounter* CStatistics::s_activeDownloads;
186 // Connection
187 CStatTreeItemReconnects* CStatistics::s_reconnects;
188 CStatTreeItemTimer* CStatistics::s_sinceFirstTransfer;
189 CStatTreeItemTimer* CStatistics::s_sinceConnected;
190 CStatTreeItemCounterMax* CStatistics::s_activeConnections;
191 CStatTreeItemMaxConnLimitReached* CStatistics::s_limitReached;
192 CStatTreeItemSimple* CStatistics::s_avgConnections;
194 // Clients
195 CStatTreeItemHiddenCounter* CStatistics::s_clients;
196 CStatTreeItemCounter* CStatistics::s_unknown;
197 //CStatTreeItem CStatistics::s_lowID;
198 //CStatTreeItem CStatistics::s_secIdentOnOff;
199 #ifdef __DEBUG__
200 CStatTreeItemNativeCounter* CStatistics::s_hasSocket;
201 #endif
202 CStatTreeItemNativeCounter* CStatistics::s_filtered;
203 CStatTreeItemNativeCounter* CStatistics::s_banned;
205 // Servers
206 CStatTreeItemSimple* CStatistics::s_workingServers;
207 CStatTreeItemSimple* CStatistics::s_failedServers;
208 CStatTreeItemNativeCounter* CStatistics::s_totalServers;
209 CStatTreeItemNativeCounter* CStatistics::s_deletedServers;
210 CStatTreeItemNativeCounter* CStatistics::s_filteredServers;
211 CStatTreeItemSimple* CStatistics::s_usersOnWorking;
212 CStatTreeItemSimple* CStatistics::s_filesOnWorking;
213 CStatTreeItemSimple* CStatistics::s_totalUsers;
214 CStatTreeItemSimple* CStatistics::s_totalFiles;
215 CStatTreeItemSimple* CStatistics::s_serverOccupation;
217 // Shared files
218 CStatTreeItemCounter* CStatistics::s_numberOfShared;
219 CStatTreeItemCounter* CStatistics::s_sizeOfShare;
221 // Kad
222 uint64_t CStatistics::s_kadNodesTotal;
223 uint16_t CStatistics::s_kadNodesCur;
225 // Totals
226 uint64_t CStatistics::s_totalSent;
227 uint64_t CStatistics::s_totalReceived;
229 bool CStatistics::s_statsNeedSave;
232 CStatistics::CStatistics()
233 : m_graphRunningAvgDown(thePrefs::GetStatsAverageMinutes() * 60 * 1000, true),
234 m_graphRunningAvgUp(thePrefs::GetStatsAverageMinutes() * 60 * 1000, true),
235 m_graphRunningAvgKad(thePrefs::GetStatsAverageMinutes() * 60 * 1000, true)
237 uint64 start_time = GetTickCount64();
239 // Init graphs
241 average_minutes = thePrefs::GetStatsAverageMinutes();
243 HR hr = {0.0, 0.0, 0.0, 0.0, 0.0, 0, 0, 0, 0, 0};
244 hrInit = hr;
245 nHistRanges = 7; // =ceil(log(max_update_delay)/log(2))
246 nPointsPerRange = GetPointsPerRange();
247 bitsHistClockMask = (1 << (nHistRanges-1)) - 1;
248 aposRecycle = new listPOS[nHistRanges];
249 listPOS *ppos = aposRecycle+nHistRanges-1;
250 for (int i=nHistRanges; i>0; --i) { // permanently allocated history list
251 listHR.push_back(hr);
252 *ppos-- = --listHR.end();
253 for (int j=nPointsPerRange; j>1; --j)
254 listHR.push_back(hr);
257 // Init rate counters outside the tree
259 s_upOverheadRate = new CPreciseRateCounter(5000);
260 s_downOverheadRate = new CPreciseRateCounter(5000);
262 // Init Tree
264 InitStatsTree();
265 s_uptime->SetStartTime(start_time);
267 // Load saved statistics
268 Load();
269 s_statsNeedSave = false;
273 CStatistics::~CStatistics()
275 // clearing listHR frees the memory occupied by the nodes
276 listHR.clear();
277 delete [] aposRecycle;
279 delete s_statTree;
281 // delete items not in the tree
282 delete s_totalUploadTime;
284 // delete rate counters outside the tree
285 delete s_upOverheadRate;
286 delete s_downOverheadRate;
290 uint64_t ReadUInt64FromCfg(wxConfigBase* cfg, const wxString& key)
292 wxString buffer;
294 cfg->Read(key, &buffer, wxT("0"));
296 uint64 tmp = 0;
297 for (unsigned int i = 0; i < buffer.Length(); ++i) {
298 if ((buffer[i] >= wxChar('0')) &&(buffer[i] <= wxChar('9'))) {
299 tmp = tmp * 10 + (buffer[i] - wxChar('0'));
300 } else {
301 tmp = 0;
302 break;
306 return tmp;
309 void CStatistics::Load()
311 CFile f;
313 s_totalSent = 0;
314 s_totalReceived = 0;
315 try {
316 CPath path(JoinPaths(theApp->ConfigDir, wxT("statistics.dat")));
317 if (path.FileExists() && f.Open(path)) {
318 uint8_t version = f.ReadUInt8();
319 if (version == 0) {
320 s_totalSent = f.ReadUInt64();
321 s_totalReceived = f.ReadUInt64();
324 } catch (const CSafeIOException& e) {
325 AddLogLineN(e.what());
328 // Load old values from config
329 bool cfgChanged = false;
330 wxConfigBase* cfg = wxConfigBase::Get();
331 if (cfg->HasEntry(wxT("/Statistics/TotalUploadedBytes"))) {
332 s_totalSent += ReadUInt64FromCfg(cfg, wxT("/Statistics/TotalUploadedBytes"));
333 cfg->DeleteEntry(wxT("/Statistics/TotalUploadedBytes"));
334 cfgChanged = true;
336 if (cfg->HasEntry(wxT("/Statistics/TotalDownloadedBytes"))) {
337 s_totalReceived += ReadUInt64FromCfg(cfg, wxT("/Statistics/TotalDownloadedBytes"));
338 cfg->DeleteEntry(wxT("/Statistics/TotalDownloadedBytes"));
339 cfgChanged = true;
341 if (cfgChanged) {
342 cfg->Flush();
343 s_statsNeedSave = s_totalSent > 0 || s_totalReceived > 0;
344 Save();
349 void CStatistics::Save()
351 if (s_statsNeedSave) {
352 CFile f;
354 if (f.Open(JoinPaths(theApp->ConfigDir, wxT("statistics.dat")), CFile::write)) {
355 f.WriteUInt8(0); /* version */
356 f.WriteUInt64(s_totalSent);
357 f.WriteUInt64(s_totalReceived);
359 s_statsNeedSave = false;
363 void CStatistics::CalculateRates()
365 uint64_t now = GetTickCount64();
366 s_downOverheadRate->CalculateRate(now);
367 s_upOverheadRate->CalculateRate(now);
368 s_downloadrate->CalculateRate(now);
369 s_uploadrate->CalculateRate(now);
374 /* ------------------------------- GRAPHS ---------------------------- */
377 History List
379 The basic idea here is that we want to keep as much history as we can without paying
380 a high price in terms of memory space. Because we keep the history for display purposes,
381 we can take advantage of the fact that when the period shown in the graphs is long
382 then each pixel represents a long period. So as the most recent history we keep one
383 window full of points at a resolution of 1 second, the next window full at 2 seconds,
384 the next at 4 seconds and so on, up to the maximum desired. This way there is always
385 at least one sample point per pixel for any update delay set by the user, and the
386 memory required grows with the *log* of the total time period covered.
387 The history is kept in a doubly-linked list, with the most recent snapshot at the tail.
388 The number of nodes in the list is fixed, and there are no calls to RemoveHead() and
389 AddTail() which would add overhead and contribute to memory fragmentation. Instead,
390 every second when a new point gets recorded, one of the existing nodes is recycled;
391 it is disjoined from its present place, put at the tail of the list, and then gets
392 filled with new data. [Emilio Sandoz]
393 This unfortunately does not work with stl classes, as none of them supports moving
394 a node to another place, so we have to erase and re-add nodes.
397 void CStatistics::RecordHistory()
398 { // First we query and compute some values, then we store them in the history list
400 // A few comments about the use of double and float in computations:
401 // Even on a hi-res screen our graphs will have 10 bits of resolution at most,
402 // so the 24 bits resolution of a float on 32 bit Intel processors is more than
403 // enough for all displayed values. Rate computations however, and especially
404 // running average computations, use differences (delta bytes/ delta time), and
405 // for long uptimes the difference between two timestamps can lose too much
406 // accuracy because the large mantissa causes less significant bits to be dropped
407 // (same for the difference between two cumulative byte counts). [We don't store
408 // these values as integers because they will be used in floating point calculations,
409 // and we want to perform the conversion only once). Therefore timestamps and
410 // Kbyte counts are stored in the history as doubles, while computed values use
411 // float (to save space and execution time).
414 Store values; first determine the node to be recycled (using the bits in iClock)
416 oldest records ----------------- listHR ------------------ youngest records
418 O-[Range 2^n sec]-O- ... -O-[Range 4 sec]-O-[Range 2 sec]-O-[Range 1 sec]-O
419 | | | | > every 2 secs -^
420 | | ... | >--------------- every 4 secs -^
421 | | >------------------------ recycle every 8 secs -^
422 | | ...
423 | >-the node at this position is recycled every 2^n secs -^
424 >-------------------(ditto for the oldest node at the head of the list) --^
426 aposRecycle[nHistRanges-1] ... aposRecycle[0] Tail
428 listPOS *ppos;
429 static int iClock;
430 int iClockPrev = iClock++;
431 int bits = (iClockPrev^iClock) & iClock; // identify the highest changed bit
432 if (bits <= bitsHistClockMask) {
433 ppos = aposRecycle;
434 while ((bits /= 2) != 0) // count to the highest bit that was just toggled to 1
435 ++ppos;
436 // recycle one node and jump over the next to move it to the next higher range
437 listHR.push_back(**ppos);
438 *ppos = ++listHR.erase(*ppos);
439 } else {
440 ppos = aposRecycle+nHistRanges-1;
441 // recycle the node at the head; there is no higher range to move nodes into
442 listHR.push_back(**ppos);
443 *ppos = listHR.erase(*ppos);
446 // now save the latest data point in this node
447 listPOS phr = --listHR.end();
448 phr->kBytesSent = GetSessionSentBytes() / 1024.0;
449 phr->kBytesReceived = GetSessionReceivedBytes() / 1024.0;
450 phr->kBpsUpCur = GetUploadRate() / 1024.0;
451 phr->kBpsDownCur = GetDownloadRate() / 1024.0;
452 phr->cntUploads = GetActiveUploadsCount();
453 phr->cntConnections = GetActiveConnections();
454 phr->cntDownloads = GetDownloadingSources();
455 phr->sTimestamp = GetUptimeMillis() / 1000.0;
457 s_kadNodesTotal += s_kadNodesCur;
458 phr->kadNodesTotal = s_kadNodesTotal;
459 phr->kadNodesCur = s_kadNodesCur;
463 unsigned CStatistics::GetHistory( // Assemble arrays of sample points for a graph
464 unsigned cntPoints, // number of sample points to assemble
465 double sStep, // time difference between sample points
466 double sFinal, // latest allowed timestamp
467 const std::vector<float *> &ppf,// an array of pointers to arrays of floats for the result
468 StatsGraphType which_graph) // the graph which will receive the points
470 if (sStep==0.0 || cntPoints==0) {
471 return(0);
474 float *pf1 = ppf[0];
475 float *pf2 = ppf[1];
476 float *pf3 = ppf[2];
477 unsigned cntFilled = 0;
478 listRPOS pos = listHR.rbegin();
480 // start of list should be an integer multiple of the sampling period for samples
481 // to be consistent when the graphs are resized horizontally
482 double sTarget;
483 if (sFinal >= 0.0) {
484 sTarget = sFinal;
485 } else {
486 sTarget = sStep==1.0 ?
487 pos->sTimestamp :
488 std::floor(pos->sTimestamp/sStep) * sStep;
491 HR **ahr = NULL, **pphr = NULL;
492 bool bRateGraph = (which_graph != GRAPH_CONN); // rate graph or connections graph?
493 if (bRateGraph) {
494 ahr = new HR* [cntPoints];
495 pphr = ahr;
498 while (pos != listHR.rend()) {
499 if (pos->sTimestamp > sTarget) {
500 ++pos;
501 continue;
503 if (bRateGraph) { // assemble an array of pointers for ComputeAverages
504 *pphr++ = &(*pos);
505 } else { // or build the arrays if possible
506 *pf1++ = (float)pos->cntUploads;
507 *pf2++ = (float)pos->cntConnections;
508 *pf3++ = (float)pos->cntDownloads;
510 if (++cntFilled == cntPoints) { // enough points
511 break;
513 if (pos->sTimestamp == 0.0) { // reached beginning of uptime
514 break;
516 if ((sTarget -= sStep) <= 0.0) { // don't overshoot the beginning
517 if (bRateGraph) {
518 *pphr++ = &hrInit;
519 } else {
520 *pf1++ = *pf2++ = *pf3++ = 0.0;
522 ++cntFilled;
523 break;
527 if (bRateGraph) {
528 if (cntFilled > 0) {
529 ComputeAverages(pphr, pos, cntFilled, sStep, ppf, which_graph);
531 delete[] ahr;
534 return cntFilled;
538 unsigned CStatistics::GetHistoryForWeb( // Assemble arrays of sample points for the webserver
539 unsigned cntPoints, // maximum number of sample points to assemble
540 double sStep, // time difference between sample points
541 double *sStart, // earliest allowed timestamp
542 uint32 **graphData) // a pointer to a pointer that will point to the graph data array
544 if (*sStart < 0.0) {
545 *sStart = 0.0;
547 if (sStep==0.0 || cntPoints==0)
548 return(0);
549 unsigned cntFilled = 0;
550 listRPOS pos = listHR.rbegin();
551 double LastTimeStamp = pos->sTimestamp;
552 double sTarget = LastTimeStamp;
554 HR **pphr = new HR *[cntPoints];
556 while (pos != listHR.rend()) {
557 if (pos->sTimestamp > sTarget) {
558 ++pos; // find next history record
559 continue;
561 pphr[cntFilled] = &(*pos);
562 if (++cntFilled == cntPoints) // enough points
563 break;
564 if (pos->sTimestamp <= *sStart) // reached beginning of requested time
565 break;
566 if ((sTarget -= sStep) <= 0.0) { // don't overshoot the beginning
567 pphr[cntFilled++] = NULL;
568 break;
572 if (cntFilled) {
573 *graphData = new uint32 [4 * cntFilled];
574 if (*graphData) {
575 for (unsigned int i = 0; i < cntFilled; i++) {
576 HR *phr = pphr[cntFilled - i - 1];
577 if (phr) {
578 (*graphData)[4 * i ] = ENDIAN_HTONL((uint32)(phr->kBpsDownCur * 1024.0));
579 (*graphData)[4 * i + 1] = ENDIAN_HTONL((uint32)(phr->kBpsUpCur * 1024.0));
580 (*graphData)[4 * i + 2] = ENDIAN_HTONL((uint32)phr->cntConnections);
581 (*graphData)[4 * i + 3] = ENDIAN_HTONL((uint32)phr->kadNodesCur);
582 } else {
583 (*graphData)[4 * i] = (*graphData)[4 * i + 1] = 0;
584 (*graphData)[4 * i + 2] = (*graphData)[4 * i + 3] = 0;
588 } else {
589 *graphData = NULL;
592 delete [] pphr;
594 *sStart = LastTimeStamp;
596 return cntFilled;
600 void CStatistics::ComputeAverages(
601 HR **pphr, // pointer to (end of) array of assembled history records
602 listRPOS pos, // position in history list from which to backtrack
603 unsigned cntFilled, // number of points in the sample data
604 double sStep, // time difference between two samples
605 const std::vector<float *> &ppf,// an array of pointers to arrays of floats with sample data
606 StatsGraphType which_graph) // the graph which will receive the points
608 double sTarget, kValueRun;
609 uint64 avgTime = average_minutes * 60;
610 unsigned nBtPoints = (unsigned)(avgTime / sStep);
612 CPreciseRateCounter* runningAvg = NULL;
613 switch (which_graph) {
614 case GRAPH_DOWN: runningAvg = &m_graphRunningAvgDown; break;
615 case GRAPH_UP: runningAvg = &m_graphRunningAvgUp; break;
616 case GRAPH_KAD: runningAvg = &m_graphRunningAvgKad; break;
617 default:
618 wxCHECK_RET(false, wxT("ComputeAverages called with unsupported graph type."));
621 runningAvg->m_timespan = avgTime * 1000;
622 runningAvg->m_tick_history.clear();
623 runningAvg->m_byte_history.clear();
624 runningAvg->m_total = 0;
625 runningAvg->m_tmp_sum = 0;
627 if (pos == listHR.rend()) {
628 sTarget = 0.0;
629 } else {
630 sTarget = std::max(0.0, pos->sTimestamp - sStep);
633 while (nBtPoints--) {
634 while (pos != listHR.rend() && pos->sTimestamp > sTarget) ++pos; // find next history record
635 if (pos != listHR.rend()) {
636 runningAvg->m_tick_history.push_front((uint64)(pos->sTimestamp * 1000.0));
638 uint32 value = 0;
639 switch (which_graph) {
640 case GRAPH_DOWN:
641 value = (uint32)(pos->kBpsDownCur * 1024.0);
642 break;
643 case GRAPH_UP:
644 value = (uint32)(pos->kBpsUpCur * 1024.0);
645 break;
646 case GRAPH_KAD:
647 value = (uint32)(pos->kadNodesCur * 1024.0);
648 break;
649 default:
650 wxCHECK_RET(false, wxT("ComputeAverages called with unsupported graph type."));
653 runningAvg->m_byte_history.push_front(value);
654 runningAvg->m_total += value;
655 } else {
656 break;
658 if ((sTarget -= sStep) < 0.0) {
659 break;
663 // now compute averages in returned arrays, starting with the earliest values
664 float *pf1 = ppf[0] + cntFilled - 1; // holds session avg
665 float *pf2 = ppf[1] + cntFilled - 1; // holds running avg
666 float *pf3 = ppf[2] + cntFilled - 1; // holds current rate
668 for (int cnt=cntFilled; cnt>0; cnt--, pf1--, pf2--, pf3--) {
669 HR *phr = *(--pphr);
670 if (which_graph == GRAPH_DOWN) {
671 kValueRun = phr->kBytesReceived;
672 *pf3 = phr->kBpsDownCur;
673 } else if (which_graph == GRAPH_UP) {
674 kValueRun = phr->kBytesSent;
675 *pf3 = phr->kBpsUpCur;
676 } else {
677 kValueRun = phr->kadNodesTotal;
678 *pf3 = phr->kadNodesCur;
681 *pf1 = kValueRun / phr->sTimestamp;
682 (*runningAvg) += (uint32)(*pf3 * 1024.0);
683 runningAvg->CalculateRate((uint64)(phr->sTimestamp * 1000.0));
684 *pf2 = (float)(runningAvg->GetRate() / 1024.0);
689 GraphUpdateInfo CStatistics::GetPointsForUpdate()
691 GraphUpdateInfo update;
692 listPOS phr = --listHR.end();
693 update.timestamp = (double) phr->sTimestamp;
695 m_graphRunningAvgDown += (uint32)(phr->kBpsDownCur * 1024.0);
696 m_graphRunningAvgUp += (uint32)(phr->kBpsUpCur * 1024.0);
697 // Note: kadNodesCur is multiplied by 1024 since the value is done
698 // in other places, so we simply follow suit here to avoid trouble.
699 m_graphRunningAvgKad += (uint32)(phr->kadNodesCur * 1024.0);
700 m_graphRunningAvgDown.CalculateRate((uint64)(phr->sTimestamp * 1000.0));
701 m_graphRunningAvgUp.CalculateRate((uint64)(phr->sTimestamp * 1000.0));
702 m_graphRunningAvgKad.CalculateRate((uint64)(phr->sTimestamp * 1000.0));
704 update.downloads[0] = phr->kBytesReceived / phr->sTimestamp;
705 update.downloads[1] = m_graphRunningAvgDown.GetRate() / 1024.0;
706 update.downloads[2] = phr->kBpsDownCur;
708 update.uploads[0] = phr->kBytesSent / phr->sTimestamp;
709 update.uploads[1] = m_graphRunningAvgUp.GetRate() / 1024.0;
710 update.uploads[2] = phr->kBpsUpCur;
712 update.connections[0] = (float)phr->cntUploads;
713 update.connections[1] = (float)phr->cntConnections;
714 update.connections[2] = (float)phr->cntDownloads;
716 update.kadnodes[0] = phr->kadNodesTotal / phr->sTimestamp;
717 update.kadnodes[1] = m_graphRunningAvgKad.GetRate() / 1024.0;
718 update.kadnodes[2] = phr->kadNodesCur;
720 return update;
724 /* ------------------------------- TREE ---------------------------- */
726 void CStatistics::InitStatsTree()
728 s_statTree = new CStatTreeItemBase(wxTRANSLATE("Statistics"));
730 CStatTreeItemBase* tmpRoot1;
731 CStatTreeItemBase* tmpRoot2;
733 s_uptime = static_cast<CStatTreeItemTimer*>(s_statTree->AddChild(new CStatTreeItemTimer(wxTRANSLATE("Uptime: %s"))));
735 tmpRoot1 = s_statTree->AddChild(new CStatTreeItemBase(wxTRANSLATE("Transfer"), stSortChildren));
737 tmpRoot2 = tmpRoot1->AddChild(new CStatTreeItemBase(wxTRANSLATE("Uploads")), 2);
738 s_sessionUpload = static_cast<CStatTreeItemUlDlCounter*>(tmpRoot2->AddChild(new CStatTreeItemUlDlCounter(wxTRANSLATE("Uploaded Data (Session (Total)): %s"), theStats::GetTotalSentBytes, stSortChildren | stSortByValue)));
739 // Children will be added on-the-fly
740 s_totalUpOverhead = static_cast<CStatTreeItemPacketTotals*>(tmpRoot2->AddChild(new CStatTreeItemPacketTotals(wxTRANSLATE("Total Overhead (Packets): %s"))));
741 s_fileReqUpOverhead = static_cast<CStatTreeItemPackets*>(tmpRoot2->AddChild(new CStatTreeItemPackets(wxTRANSLATE("File Request Overhead (Packets): %s"))));
742 s_totalUpOverhead->AddPacketCounter(s_fileReqUpOverhead);
743 s_sourceXchgUpOverhead = static_cast<CStatTreeItemPackets*>(tmpRoot2->AddChild(new CStatTreeItemPackets(wxTRANSLATE("Source Exchange Overhead (Packets): %s"))));
744 s_totalUpOverhead->AddPacketCounter(s_sourceXchgUpOverhead);
745 s_serverUpOverhead = static_cast<CStatTreeItemPackets*>(tmpRoot2->AddChild(new CStatTreeItemPackets(wxTRANSLATE("Server Overhead (Packets): %s"))));
746 s_totalUpOverhead->AddPacketCounter(s_serverUpOverhead);
747 s_kadUpOverhead = static_cast<CStatTreeItemPackets*>(tmpRoot2->AddChild(new CStatTreeItemPackets(wxTRANSLATE("Kad Overhead (Packets): %s"))));
748 s_totalUpOverhead->AddPacketCounter(s_kadUpOverhead);
749 s_cryptUpOverhead = static_cast<CStatTreeItemCounter*>(tmpRoot2->AddChild(new CStatTreeItemCounter(wxTRANSLATE("Crypt overhead (UDP): %s"))));
750 s_cryptUpOverhead->SetDisplayMode(dmBytes);
751 s_activeUploads = static_cast<CStatTreeItemNativeCounter*>(tmpRoot2->AddChild(new CStatTreeItemNativeCounter(wxTRANSLATE("Active Uploads: %s"))));
752 s_waitingUploads = static_cast<CStatTreeItemNativeCounter*>(tmpRoot2->AddChild(new CStatTreeItemNativeCounter(wxTRANSLATE("Waiting Uploads: %s"))));
753 s_totalSuccUploads = static_cast<CStatTreeItemCounter*>(tmpRoot2->AddChild(new CStatTreeItemCounter(wxTRANSLATE("Total successful upload sessions: %s"))));
754 s_totalFailedUploads = static_cast<CStatTreeItemCounter*>(tmpRoot2->AddChild(new CStatTreeItemCounter(wxTRANSLATE("Total failed upload sessions: %s"))));
755 s_totalUploadTime = new CStatTreeItemCounter(wxEmptyString);
756 tmpRoot2->AddChild(new CStatTreeItemAverage(wxTRANSLATE("Average upload time: %s"), s_totalUploadTime, s_totalSuccUploads, dmTime));
758 tmpRoot2 = tmpRoot1->AddChild(new CStatTreeItemBase(wxTRANSLATE("Downloads")), 1);
759 s_sessionDownload = static_cast<CStatTreeItemUlDlCounter*>(tmpRoot2->AddChild(new CStatTreeItemUlDlCounter(wxTRANSLATE("Downloaded Data (Session (Total)): %s"), theStats::GetTotalReceivedBytes, stSortChildren | stSortByValue)));
760 // Children will be added on-the-fly
761 s_totalDownOverhead = static_cast<CStatTreeItemPacketTotals*>(tmpRoot2->AddChild(new CStatTreeItemPacketTotals(wxTRANSLATE("Total Overhead (Packets): %s"))));
762 s_fileReqDownOverhead = static_cast<CStatTreeItemPackets*>(tmpRoot2->AddChild(new CStatTreeItemPackets(wxTRANSLATE("File Request Overhead (Packets): %s"))));
763 s_totalDownOverhead->AddPacketCounter(s_fileReqDownOverhead);
764 s_sourceXchgDownOverhead = static_cast<CStatTreeItemPackets*>(tmpRoot2->AddChild(new CStatTreeItemPackets(wxTRANSLATE("Source Exchange Overhead (Packets): %s"))));
765 s_totalDownOverhead->AddPacketCounter(s_sourceXchgDownOverhead);
766 s_serverDownOverhead = static_cast<CStatTreeItemPackets*>(tmpRoot2->AddChild(new CStatTreeItemPackets(wxTRANSLATE("Server Overhead (Packets): %s"))));
767 s_totalDownOverhead->AddPacketCounter(s_serverDownOverhead);
768 s_kadDownOverhead = static_cast<CStatTreeItemPackets*>(tmpRoot2->AddChild(new CStatTreeItemPackets(wxTRANSLATE("Kad Overhead (Packets): %s"))));
769 s_totalDownOverhead->AddPacketCounter(s_kadDownOverhead);
770 s_cryptDownOverhead = static_cast<CStatTreeItemCounter*>(tmpRoot2->AddChild(new CStatTreeItemCounter(wxTRANSLATE("Crypt overhead (UDP): %s"))));
771 s_cryptDownOverhead->SetDisplayMode(dmBytes);
772 s_foundSources = static_cast<CStatTreeItemCounter*>(tmpRoot2->AddChild(new CStatTreeItemCounter(wxTRANSLATE("Found Sources: %s"), stSortChildren | stSortByValue)));
773 s_activeDownloads = static_cast<CStatTreeItemNativeCounter*>(tmpRoot2->AddChild(new CStatTreeItemNativeCounter(wxTRANSLATE("Active Downloads (chunks): %s"))));
775 tmpRoot1->AddChild(new CStatTreeItemRatio(wxTRANSLATE("Session UL:DL Ratio (Total): %s"), s_sessionUpload, s_sessionDownload, theStats::GetTotalSentBytes, theStats::GetTotalReceivedBytes), 3);
777 tmpRoot1 = s_statTree->AddChild(new CStatTreeItemBase(wxTRANSLATE("Connection")));
778 tmpRoot1->AddChild(new CStatTreeItemAverageSpeed(wxTRANSLATE("Average download rate (Session): %s"), s_sessionDownload, s_uptime));
779 tmpRoot1->AddChild(new CStatTreeItemAverageSpeed(wxTRANSLATE("Average upload rate (Session): %s"), s_sessionUpload, s_uptime));
780 s_downloadrate = static_cast<CStatTreeItemRateCounter*>(tmpRoot1->AddChild(new CStatTreeItemRateCounter(wxTRANSLATE("Max download rate (Session): %s"), true, 30000)));
781 s_uploadrate = static_cast<CStatTreeItemRateCounter*>(tmpRoot1->AddChild(new CStatTreeItemRateCounter(wxTRANSLATE("Max upload rate (Session): %s"), true, 30000)));
782 s_reconnects = static_cast<CStatTreeItemReconnects*>(tmpRoot1->AddChild(new CStatTreeItemReconnects(wxTRANSLATE("Reconnects: %i"))));
783 s_sinceFirstTransfer = static_cast<CStatTreeItemTimer*>(tmpRoot1->AddChild(new CStatTreeItemTimer(wxTRANSLATE("Time Since First Transfer: %s"), stHideIfZero)));
784 s_sinceConnected = static_cast<CStatTreeItemTimer*>(tmpRoot1->AddChild(new CStatTreeItemTimer(wxTRANSLATE("Connected To Server Since: %s"))));
785 s_activeConnections = static_cast<CStatTreeItemCounterMax*>(tmpRoot1->AddChild(new CStatTreeItemCounterMax(wxTRANSLATE("Active Connections (estimate): %i"))));
786 s_limitReached = static_cast<CStatTreeItemMaxConnLimitReached*>(tmpRoot1->AddChild(new CStatTreeItemMaxConnLimitReached(wxTRANSLATE("Max Connection Limit Reached: %s"))));
787 s_avgConnections = static_cast<CStatTreeItemSimple*>(tmpRoot1->AddChild(new CStatTreeItemSimple(wxTRANSLATE("Average Connections (estimate): %g"))));
788 s_avgConnections->SetValue(0.0);
789 tmpRoot1->AddChild(new CStatTreeItemPeakConnections(wxTRANSLATE("Peak Connections (estimate): %i")));
791 s_clients = static_cast<CStatTreeItemHiddenCounter*>(s_statTree->AddChild(new CStatTreeItemHiddenCounter(wxTRANSLATE("Clients"), stSortChildren | stSortByValue)));
792 s_unknown = static_cast<CStatTreeItemCounter*>(s_clients->AddChild(new CStatTreeItemCounter(wxTRANSLATE("Unknown: %s")), 6));
793 //s_lowID = static_cast<CStatTreeItem*>(s_clients->AddChild(new CStatTreeItem(wxTRANSLATE("LowID: %u (%.2f%% Total %.2f%% Known)")), 5));
794 //s_secIdentOnOff = static_cast<CStatTreeItem*>(s_clients->AddChild(new CStatTreeItem(wxTRANSLATE("SecIdent On/Off: %u (%.2f%%) : %u (%.2f%%)")), 4));
795 #ifdef __DEBUG__
796 s_hasSocket = static_cast<CStatTreeItemNativeCounter*>(s_clients->AddChild(new CStatTreeItemNativeCounter(wxT("HasSocket: %s")), 3));
797 #endif
798 s_filtered = static_cast<CStatTreeItemNativeCounter*>(s_clients->AddChild(new CStatTreeItemNativeCounter(wxTRANSLATE("Filtered: %s")), 2));
799 s_banned = static_cast<CStatTreeItemNativeCounter*>(s_clients->AddChild(new CStatTreeItemNativeCounter(wxTRANSLATE("Banned: %s")), 1));
800 s_clients->AddChild(new CStatTreeItemTotalClients(wxTRANSLATE("Total: %i Known: %i"), s_clients, s_unknown), 0x80000000);
802 // TODO: Use counters?
803 tmpRoot1 = s_statTree->AddChild(new CStatTreeItemBase(wxTRANSLATE("Servers")));
804 s_workingServers = static_cast<CStatTreeItemSimple*>(tmpRoot1->AddChild(new CStatTreeItemSimple(wxTRANSLATE("Working Servers: %i"))));
805 s_failedServers = static_cast<CStatTreeItemSimple*>(tmpRoot1->AddChild(new CStatTreeItemSimple(wxTRANSLATE("Failed Servers: %i"))));
806 s_totalServers = static_cast<CStatTreeItemNativeCounter*>(tmpRoot1->AddChild(new CStatTreeItemNativeCounter(wxTRANSLATE("Total: %s"))));
807 s_deletedServers = static_cast<CStatTreeItemNativeCounter*>(tmpRoot1->AddChild(new CStatTreeItemNativeCounter(wxTRANSLATE("Deleted Servers: %s"))));
808 s_filteredServers = static_cast<CStatTreeItemNativeCounter*>(tmpRoot1->AddChild(new CStatTreeItemNativeCounter(wxTRANSLATE("Filtered Servers: %s"))));
809 s_usersOnWorking = static_cast<CStatTreeItemSimple*>(tmpRoot1->AddChild(new CStatTreeItemSimple(wxTRANSLATE("Users on Working Servers: %llu"))));
810 s_filesOnWorking = static_cast<CStatTreeItemSimple*>(tmpRoot1->AddChild(new CStatTreeItemSimple(wxTRANSLATE("Files on Working Servers: %llu"))));
811 s_totalUsers = static_cast<CStatTreeItemSimple*>(tmpRoot1->AddChild(new CStatTreeItemSimple(wxTRANSLATE("Total Users: %llu"))));
812 s_totalFiles = static_cast<CStatTreeItemSimple*>(tmpRoot1->AddChild(new CStatTreeItemSimple(wxTRANSLATE("Total Files: %llu"))));
813 s_serverOccupation = static_cast<CStatTreeItemSimple*>(tmpRoot1->AddChild(new CStatTreeItemSimple(wxTRANSLATE("Server Occupation: %.2f%%"))));
814 s_serverOccupation->SetValue(0.0);
816 tmpRoot1 = s_statTree->AddChild(new CStatTreeItemBase(wxTRANSLATE("Shared Files")));
817 s_numberOfShared = static_cast<CStatTreeItemCounter*>(tmpRoot1->AddChild(new CStatTreeItemCounter(wxTRANSLATE("Number of Shared Files: %s"))));
818 s_sizeOfShare = static_cast<CStatTreeItemCounter*>(tmpRoot1->AddChild(new CStatTreeItemCounter(wxTRANSLATE("Total size of Shared Files: %s"))));
819 s_sizeOfShare->SetDisplayMode(dmBytes);
820 tmpRoot1->AddChild(new CStatTreeItemAverage(wxTRANSLATE("Average file size: %s"), s_sizeOfShare, s_numberOfShared, dmBytes));
824 void CStatistics::UpdateStatsTree()
826 // get sort orders right
827 s_sessionUpload->ReSortChildren();
828 s_sessionDownload->ReSortChildren();
829 s_clients->ReSortChildren();
830 s_foundSources->ReSortChildren();
831 // TODO: sort OS_Info subtrees.
833 s_avgConnections->SetValue(theApp->listensocket->GetAverageConnections());
835 // get serverstats
836 // TODO: make these realtime, too
837 uint32 servfail;
838 uint32 servuser;
839 uint32 servfile;
840 uint32 servtuser;
841 uint32 servtfile;
842 float servocc;
843 theApp->serverlist->GetStatus(servfail, servuser, servfile, servtuser, servtfile, servocc);
844 s_workingServers->SetValue((uint64)((*s_totalServers)-servfail));
845 s_failedServers->SetValue((uint64)servfail);
846 s_usersOnWorking->SetValue((uint64)servuser);
847 s_filesOnWorking->SetValue((uint64)servfile);
848 s_totalUsers->SetValue((uint64)servtuser);
849 s_totalFiles->SetValue((uint64)servtfile);
850 s_serverOccupation->SetValue(servocc);
854 void CStatistics::AddSourceOrigin(unsigned origin)
856 CStatTreeItemCounter* counter = static_cast<CStatTreeItemCounter*>(s_foundSources->GetChildById(0x0100 + origin));
857 if (counter) {
858 ++(*counter);
859 } else {
860 counter = new CStatTreeItemCounter(OriginToText(origin) + wxT(": %s"), stHideIfZero | stShowPercent);
861 ++(*counter);
862 s_foundSources->AddChild(counter, 0x0100 + origin);
866 void CStatistics::RemoveSourceOrigin(unsigned origin)
868 CStatTreeItemCounter* counter = static_cast<CStatTreeItemCounter*>(s_foundSources->GetChildById(0x0100 + origin));
869 wxASSERT(counter);
870 --(*counter);
873 uint32 GetSoftID(uint8 SoftType)
875 // prevent appearing multiple tree entries with the same name
876 // this should be kept in sync with GetSoftName().
877 switch (SoftType) {
878 case SO_OLDEMULE:
879 return 0x0100 + SO_EMULE;
880 case SO_NEW_SHAREAZA:
881 case SO_NEW2_SHAREAZA:
882 return 0x0100 + SO_SHAREAZA;
883 case SO_NEW2_MLDONKEY:
884 return 0x0100 + SO_NEW_MLDONKEY;
885 default:
886 return 0x0100 + SoftType;
890 void CStatistics::AddDownloadFromSoft(uint8 SoftType, uint32 bytes)
892 AddReceivedBytes(bytes);
894 uint32 id = GetSoftID(SoftType);
896 if (s_sessionDownload->HasChildWithId(id)) {
897 (*static_cast<CStatTreeItemCounter*>(s_sessionDownload->GetChildById(id))) += bytes;
898 } else {
899 CStatTreeItemCounter* tmp = new CStatTreeItemCounter(GetSoftName(SoftType) + wxT(": %s"));
900 tmp->SetDisplayMode(dmBytes);
901 (*tmp) += bytes;
902 s_sessionDownload->AddChild(tmp, id);
906 void CStatistics::AddUploadToSoft(uint8 SoftType, uint32 bytes)
908 uint32 id = GetSoftID(SoftType);
910 if (s_sessionUpload->HasChildWithId(id)) {
911 (*static_cast<CStatTreeItemCounter*>(s_sessionUpload->GetChildById(id))) += bytes;
912 } else {
913 CStatTreeItemCounter* tmp = new CStatTreeItemCounter(GetSoftName(SoftType) + wxT(": %s"));
914 tmp->SetDisplayMode(dmBytes);
915 (*tmp) += bytes;
916 s_sessionUpload->AddChild(tmp, id);
920 inline bool SupportsOSInfo(unsigned clientSoft)
922 return (clientSoft == SO_AMULE) || (clientSoft == SO_HYDRANODE) || (clientSoft == SO_NEW2_MLDONKEY);
925 // Do some random black magic to strings to get a relatively unique number for them.
926 uint32 GetIdFromString(const wxString& str)
928 uint32 id = 0;
929 for (unsigned i = 0; i < str.Length(); ++i) {
930 unsigned old_id = id;
931 id += (uint32)str.GetChar(i);
932 id <<= 2;
933 id ^= old_id;
934 id -= old_id;
936 return (((id >> 1) + id) | 0x00000100) & 0x7fffffff;
939 void CStatistics::AddKnownClient(CUpDownClient *pClient)
941 ++(*s_clients);
943 uint32 clientSoft = pClient->GetClientSoft();
944 uint32 id = GetSoftID(clientSoft);
946 CStatTreeItemCounter *client;
948 if (s_clients->HasChildWithId(id)) {
949 client = static_cast<CStatTreeItemCounter*>(s_clients->GetChildById(id));
950 ++(*client);
951 } else {
952 uint32 flags = stSortChildren | stShowPercent | stHideIfZero;
953 if (!SupportsOSInfo(clientSoft)) {
954 flags |= stCapChildren;
956 client = new CStatTreeItemCounter(GetSoftName(clientSoft) + wxT(": %s"), flags);
957 ++(*client);
958 s_clients->AddChild(client, id);
959 if (SupportsOSInfo(clientSoft)) {
960 client->AddChild(new CStatTreeItemBase(wxTRANSLATE("Version"), stSortChildren | stCapChildren), 2);
961 client->AddChild(new CStatTreeItemBase(wxTRANSLATE("Operating System"), stSortChildren | stSortByValue), 1);
965 CStatTreeItemBase *versionRoot = SupportsOSInfo(clientSoft) ? client->GetChildById(2) : client;
966 uint32 clientVersion = pClient->GetVersion();
968 if (versionRoot->HasChildWithId(clientVersion)) {
969 CStatTreeItemCounter *version = static_cast<CStatTreeItemCounter*>(versionRoot->GetChildById(clientVersion));
970 ++(*version);
971 } else {
972 const wxString& versionStr = pClient->GetVersionString();
973 CStatTreeItemCounter *version = new CStatTreeItemCounter((versionStr.IsEmpty() ? wxString(wxTRANSLATE("Unknown")) : versionStr) + wxT(": %s"), stShowPercent | stHideIfZero);
974 ++(*version);
975 versionRoot->AddChild(version, clientVersion, SupportsOSInfo(clientSoft));
978 if (SupportsOSInfo(clientSoft)) {
979 const wxString& OSInfo = pClient->GetClientOSInfo();
980 uint32 OS_ID = OSInfo.IsEmpty() ? 0 : GetIdFromString(OSInfo);
981 CStatTreeItemBase* OSRoot = client->GetChildById(1);
982 CStatTreeItemCounter* OSNode = static_cast<CStatTreeItemCounter*>(OSRoot->GetChildById(OS_ID));
983 if (OSNode) {
984 ++(*OSNode);
985 } else {
986 OSNode = new CStatTreeItemCounter((OS_ID ? OSInfo : wxString(wxTRANSLATE("Not Received"))) + wxT(": %s"), stShowPercent | stHideIfZero);
987 ++(*OSNode);
988 OSRoot->AddChild(OSNode, OS_ID, true);
993 void CStatistics::RemoveKnownClient(uint32 clientSoft, uint32 clientVersion, const wxString& OSInfo)
995 --(*s_clients);
997 uint32 id = GetSoftID(clientSoft);
999 CStatTreeItemCounter *client = static_cast<CStatTreeItemCounter*>(s_clients->GetChildById(id));
1000 wxASSERT(client);
1001 --(*client);
1003 CStatTreeItemBase *versionRoot = SupportsOSInfo(clientSoft) ? client->GetChildById(2) : client;
1005 CStatTreeItemCounter *version = static_cast<CStatTreeItemCounter*>(versionRoot->GetChildById(clientVersion));
1006 wxASSERT(version);
1007 --(*version);
1009 if (SupportsOSInfo(clientSoft)) {
1010 uint32 OS_ID = OSInfo.IsEmpty() ? 0 : GetIdFromString(OSInfo);
1011 CStatTreeItemCounter* OSNode = static_cast<CStatTreeItemCounter*>(client->GetChildById(1)->GetChildById(OS_ID));
1012 wxASSERT(OSNode);
1013 --(*OSNode);
1017 #else /* CLIENT_GUI */
1019 CStatistics::CStatistics(CRemoteConnect &conn)
1020 : m_conn(conn)
1022 s_start_time = GetTickCount64();
1024 // Init Tree
1025 s_statTree = new CStatTreeItemBase(_("Statistics"), 0);
1027 // Clear stat data container
1028 for (int i = 0; i < sdTotalItems; ++i) {
1029 s_statData[i] = 0;
1034 CStatistics::~CStatistics()
1036 delete s_statTree;
1040 void CStatistics::UpdateStats(const CECPacket* stats)
1042 s_statData[sdUpload] = stats->GetTagByNameSafe(EC_TAG_STATS_UL_SPEED)->GetInt();
1043 s_statData[sdUpOverhead] = stats->GetTagByNameSafe(EC_TAG_STATS_UP_OVERHEAD)->GetInt();
1044 s_statData[sdDownload] = stats->GetTagByNameSafe(EC_TAG_STATS_DL_SPEED)->GetInt();
1045 s_statData[sdDownOverhead] = stats->GetTagByNameSafe(EC_TAG_STATS_DOWN_OVERHEAD)->GetInt();
1046 s_statData[sdWaitingClients] = stats->GetTagByNameSafe(EC_TAG_STATS_UL_QUEUE_LEN)->GetInt();
1047 s_statData[sdBannedClients] = stats->GetTagByNameSafe(EC_TAG_STATS_BANNED_COUNT)->GetInt();
1048 s_statData[sdED2KUsers] = stats->GetTagByNameSafe(EC_TAG_STATS_ED2K_USERS)->GetInt();
1049 s_statData[sdKadUsers] = stats->GetTagByNameSafe(EC_TAG_STATS_KAD_USERS)->GetInt();
1050 s_statData[sdED2KFiles] = stats->GetTagByNameSafe(EC_TAG_STATS_ED2K_FILES)->GetInt();
1051 s_statData[sdKadFiles] = stats->GetTagByNameSafe(EC_TAG_STATS_KAD_FILES)->GetInt();
1052 s_statData[sdKadFirewalledUDP] = stats->GetTagByNameSafe(EC_TAG_STATS_KAD_FIREWALLED_UDP)->GetInt();
1053 s_statData[sdKadIndexedSources] = stats->GetTagByNameSafe(EC_TAG_STATS_KAD_INDEXED_SOURCES)->GetInt();
1054 s_statData[sdKadIndexedKeywords] = stats->GetTagByNameSafe(EC_TAG_STATS_KAD_INDEXED_KEYWORDS)->GetInt();
1055 s_statData[sdKadIndexedNotes] = stats->GetTagByNameSafe(EC_TAG_STATS_KAD_INDEXED_NOTES)->GetInt();
1056 s_statData[sdKadIndexedLoad] = stats->GetTagByNameSafe(EC_TAG_STATS_KAD_INDEXED_LOAD)->GetInt();
1057 s_statData[sdKadIPAdress] = stats->GetTagByNameSafe(EC_TAG_STATS_KAD_IP_ADRESS)->GetInt();
1058 s_statData[sdKadNodes] = stats->GetTagByNameSafe(EC_TAG_STATS_KAD_NODES)->GetInt();
1059 s_statData[sdBuddyStatus] = stats->GetTagByNameSafe(EC_TAG_STATS_BUDDY_STATUS)->GetInt();
1060 s_statData[sdBuddyIP] = stats->GetTagByNameSafe(EC_TAG_STATS_BUDDY_IP)->GetInt();
1061 s_statData[sdBuddyPort] = stats->GetTagByNameSafe(EC_TAG_STATS_BUDDY_PORT)->GetInt();
1062 s_statData[sdKadInLanMode] = stats->GetTagByNameSafe(EC_TAG_STATS_KAD_IN_LAN_MODE)->GetInt();
1063 s_statData[sdTotalSentBytes] = stats->GetTagByNameSafe(EC_TAG_STATS_TOTAL_SENT_BYTES)->GetInt();
1064 s_statData[sdTotalReceivedBytes] = stats->GetTagByNameSafe(EC_TAG_STATS_TOTAL_RECEIVED_BYTES)->GetInt();
1065 s_statData[sdSharedFileCount] = stats->GetTagByNameSafe(EC_TAG_STATS_SHARED_FILE_COUNT)->GetInt();
1067 const CECTag * LoggerTag = stats->GetTagByName(EC_TAG_STATS_LOGGER_MESSAGE);
1068 if (LoggerTag) {
1069 for (CECTag::const_iterator it = LoggerTag->begin(); it != LoggerTag->end(); ++it) {
1070 theApp->AddRemoteLogLine(it->GetStringData());
1076 void CStatistics::UpdateStatsTree()
1080 void CStatistics::RebuildStatTreeRemote(const CECTag * tag)
1082 delete s_statTree;
1083 s_statTree = new CStatTreeItemBase(tag);
1087 uint64 CStatistics::GetUptimeMillis()
1089 return GetTickCount64() - s_start_time;
1093 uint64 CStatistics::GetUptimeSeconds()
1095 return (GetTickCount64() - s_start_time) / 1000;
1098 #endif /* !CLIENT_GUI */
1100 // File_checked_for_headers