2 // This file is part of the aMule Project.
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 )
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
35 #include <common/Format.h> // Needed for CFormat
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
46 #include "GetTickCount.h" // Needed for GetTickCount64()
47 #include <ec/cpp/RemoteConnect.h> // Needed for CRemoteConnect
50 #include "amule.h" // Needed for theApp
53 #include "Preferences.h" // Needed for thePrefs
59 #define round(x) floor(x+0.5)
65 /*----- CPreciseRateCounter -----*/
67 void CPreciseRateCounter::CalculateRate(uint64_t now
)
69 wxMutexLocker
lock(m_mutex
);
72 m_byte_history
.push_back(m_tmp_sum
);
73 m_tick_history
.push_back(now
);
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();
88 if (m_count_average
) {
89 if (!m_byte_history
.empty()) {
90 m_rate
= m_total
/ (double)m_byte_history
.size();
94 m_rate
= m_total
/ (timespan
/ 1000.0);
98 if (m_rate
> m_max_rate
) {
104 /*----- CStatTreeItemRateCounter -----*/
107 wxString
CStatTreeItemRateCounter::GetDisplayString() const
109 return CFormat(wxGetTranslation(m_label
)) % CastItoSpeed(m_show_maxrate
? (uint32
)m_max_rate
: (uint32
)m_rate
);
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
));
121 /*----- CStatTreeItemPeakConnections -----*/
124 wxString
CStatTreeItemPeakConnections::GetDisplayString() const
126 return CFormat(wxGetTranslation(m_label
)) % theStats::GetPeakConnections();
130 void CStatTreeItemPeakConnections::AddECValues(CECTag
* tag
) const
132 tag
->AddTag(CECTag(EC_TAG_STAT_NODE_VALUE
, (uint64
)theStats::GetPeakConnections()));
136 /*----- CStatistics -----*/
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 */
154 CStatTreeItemBase
* CStatistics::s_statTree
;
158 CStatTreeItemTimer
* CStatistics::s_uptime
;
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
;
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
;
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
;
194 CStatTreeItemHiddenCounter
* CStatistics::s_clients
;
195 CStatTreeItemCounter
* CStatistics::s_unknown
;
196 //CStatTreeItem CStatistics::s_lowID;
197 //CStatTreeItem CStatistics::s_secIdentOnOff;
199 CStatTreeItemNativeCounter
* CStatistics::s_hasSocket
;
201 CStatTreeItemNativeCounter
* CStatistics::s_filtered
;
202 CStatTreeItemNativeCounter
* CStatistics::s_banned
;
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
;
217 CStatTreeItemCounter
* CStatistics::s_numberOfShared
;
218 CStatTreeItemCounter
* CStatistics::s_sizeOfShare
;
221 uint64_t CStatistics::s_kadNodesTotal
;
222 uint16_t CStatistics::s_kadNodesCur
;
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();
240 average_minutes
= thePrefs::GetStatsAverageMinutes();
242 HR hr
= {0.0, 0.0, 0.0, 0.0, 0.0, 0, 0, 0, 0, 0};
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);
264 s_uptime
->SetStartTime(start_time
);
266 // Load saved statistics
268 s_statsNeedSave
= false;
272 CStatistics::~CStatistics()
274 // clearing listHR frees the memory occupied by the nodes
276 delete [] aposRecycle
;
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
)
293 cfg
->Read(key
, &buffer
, wxT("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'));
308 void CStatistics::Load()
315 CPath
path(JoinPaths(thePrefs::GetConfigDir(), wxT("statistics.dat")));
316 if (path
.FileExists() && f
.Open(path
)) {
317 uint8_t version
= f
.ReadUInt8();
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"));
335 if (cfg
->HasEntry(wxT("/Statistics/TotalDownloadedBytes"))) {
336 s_totalReceived
+= ReadUInt64FromCfg(cfg
, wxT("/Statistics/TotalDownloadedBytes"));
337 cfg
->DeleteEntry(wxT("/Statistics/TotalDownloadedBytes"));
342 s_statsNeedSave
= s_totalSent
> 0 || s_totalReceived
> 0;
348 void CStatistics::Save()
350 if (s_statsNeedSave
) {
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 ---------------------------- */
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 -^
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
429 int iClockPrev
= iClock
++;
430 int bits
= (iClockPrev
^iClock
) & iClock
; // identify the highest changed bit
431 if (bits
<= bitsHistClockMask
) {
433 while ((bits
/= 2) != 0) // count to the highest bit that was just toggled to 1
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
);
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) {
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
485 sTarget
= sStep
==1.0 ?
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?
493 ahr
= new HR
* [cntPoints
];
497 while (pos
!= listHR
.rend()) {
498 if (pos
->sTimestamp
> sTarget
) {
502 if (bRateGraph
) { // assemble an array of pointers for ComputeAverages
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
512 if (pos
->sTimestamp
== 0.0) { // reached beginning of uptime
515 if ((sTarget
-= sStep
) <= 0.0) { // don't overshoot the beginning
519 *pf1
++ = *pf2
++ = *pf3
++ = 0.0;
528 ComputeAverages(pphr
, pos
, cntFilled
, sStep
, ppf
, which_graph
);
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
546 if (sStep
==0.0 || cntPoints
==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
560 pphr
[cntFilled
] = &(*pos
);
561 if (++cntFilled
== cntPoints
) // enough points
563 if (pos
->sTimestamp
<= *sStart
) // reached beginning of requested time
565 if ((sTarget
-= sStep
) <= 0.0) { // don't overshoot the beginning
566 pphr
[cntFilled
++] = NULL
;
572 *graphData
= new uint32
[4 * cntFilled
];
574 for (unsigned int i
= 0; i
< cntFilled
; i
++) {
575 HR
*phr
= pphr
[cntFilled
- i
- 1];
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
);
582 (*graphData
)[4 * i
] = (*graphData
)[4 * i
+ 1] = 0;
583 (*graphData
)[4 * i
+ 2] = (*graphData
)[4 * i
+ 3] = 0;
593 *sStart
= LastTimeStamp
;
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;
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()) {
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));
638 switch (which_graph
) {
640 value
= (uint32
)(pos
->kBpsDownCur
* 1024.0);
643 value
= (uint32
)(pos
->kBpsUpCur
* 1024.0);
646 value
= (uint32
)(pos
->kadNodesCur
* 1024.0);
649 wxCHECK_RET(false, wxT("ComputeAverages called with unsupported graph type."));
652 runningAvg
->m_byte_history
.push_front(value
);
653 runningAvg
->m_total
+= value
;
657 if ((sTarget
-= sStep
) < 0.0) {
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
--) {
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
;
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
;
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));
795 s_hasSocket
= static_cast<CStatTreeItemNativeCounter
*>(s_clients
->AddChild(new CStatTreeItemNativeCounter(wxT("HasSocket: %s")), 3));
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());
835 // TODO: make these realtime, too
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
));
859 counter
= new CStatTreeItemCounter(OriginToText(origin
) + wxT(": %s"), stHideIfZero
| stShowPercent
);
861 s_foundSources
->AddChild(counter
, 0x0100 + origin
);
865 void CStatistics::RemoveSourceOrigin(unsigned origin
)
867 CStatTreeItemCounter
* counter
= static_cast<CStatTreeItemCounter
*>(s_foundSources
->GetChildById(0x0100 + origin
));
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().
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
;
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
;
898 CStatTreeItemCounter
* tmp
= new CStatTreeItemCounter(GetSoftName(SoftType
) + wxT(": %s"));
899 tmp
->SetDisplayMode(dmBytes
);
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
;
912 CStatTreeItemCounter
* tmp
= new CStatTreeItemCounter(GetSoftName(SoftType
) + wxT(": %s"));
913 tmp
->SetDisplayMode(dmBytes
);
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
)
928 for (unsigned i
= 0; i
< str
.Length(); ++i
) {
929 unsigned old_id
= id
;
930 id
+= (uint32
)str
.GetChar(i
);
935 return (((id
>> 1) + id
) | 0x00000100) & 0x7fffffff;
938 void CStatistics::AddKnownClient(CUpDownClient
*pClient
)
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
));
951 uint32 flags
= stSortChildren
| stShowPercent
| stHideIfZero
;
952 if (!SupportsOSInfo(clientSoft
)) {
953 flags
|= stCapChildren
;
955 client
= new CStatTreeItemCounter(GetSoftName(clientSoft
) + wxT(": %s"), flags
);
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
));
971 const wxString
& versionStr
= pClient
->GetVersionString();
972 CStatTreeItemCounter
*version
= new CStatTreeItemCounter((versionStr
.IsEmpty() ? wxString(wxTRANSLATE("Unknown")) : versionStr
) + wxT(": %s"), stShowPercent
| stHideIfZero
);
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
));
985 OSNode
= new CStatTreeItemCounter((OS_ID
? OSInfo
: wxString(wxTRANSLATE("Not Received"))) + wxT(": %s"), stShowPercent
| stHideIfZero
);
987 OSRoot
->AddChild(OSNode
, OS_ID
, true);
992 void CStatistics::RemoveKnownClient(uint32 clientSoft
, uint32 clientVersion
, const wxString
& OSInfo
)
996 uint32 id
= GetSoftID(clientSoft
);
998 CStatTreeItemCounter
*client
= static_cast<CStatTreeItemCounter
*>(s_clients
->GetChildById(id
));
1002 CStatTreeItemBase
*versionRoot
= SupportsOSInfo(clientSoft
) ? client
->GetChildById(2) : client
;
1004 CStatTreeItemCounter
*version
= static_cast<CStatTreeItemCounter
*>(versionRoot
->GetChildById(clientVersion
));
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
));
1016 #else /* CLIENT_GUI */
1018 CStatistics::CStatistics(CRemoteConnect
&conn
)
1021 s_start_time
= GetTickCount64();
1024 s_statTree
= new CStatTreeItemBase(_("Statistics"), 0);
1026 // Clear stat data container
1027 for (int i
= 0; i
< sdTotalItems
; ++i
) {
1033 CStatistics::~CStatistics()
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
);
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
)
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