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 "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
47 #include "GetTickCount.h" // Needed for GetTickCount64()
48 #include "Preferences.h"
49 #include <ec/cpp/RemoteConnect.h> // Needed for CRemoteConnect
52 #include "amule.h" // Needed for theApp
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
.size() > 0) {
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
.size() > 0) {
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 CStatTreeItemNativeCounter
* 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 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()
314 if (f
.Open(JoinPaths(theApp
->ConfigDir
, wxT("statistics.dat")))) {
315 uint8_t version
= f
.ReadUInt8();
317 s_totalSent
= f
.ReadUInt64();
318 s_totalReceived
= f
.ReadUInt64();
322 // Load old values from config
323 bool cfgChanged
= false;
324 wxConfigBase
* cfg
= wxConfigBase::Get();
325 if (cfg
->HasEntry(wxT("/Statistics/TotalUploadedBytes"))) {
326 s_totalSent
+= ReadUInt64FromCfg(cfg
, wxT("/Statistics/TotalUploadedBytes"));
327 cfg
->DeleteEntry(wxT("/Statistics/TotalUploadedBytes"));
330 if (cfg
->HasEntry(wxT("/Statistics/TotalDownloadedBytes"))) {
331 s_totalReceived
+= ReadUInt64FromCfg(cfg
, wxT("/Statistics/TotalDownloadedBytes"));
332 cfg
->DeleteEntry(wxT("/Statistics/TotalDownloadedBytes"));
337 s_statsNeedSave
= s_totalSent
> 0 || s_totalReceived
> 0;
343 void CStatistics::Save()
345 if (s_statsNeedSave
) {
348 if (f
.Open(JoinPaths(theApp
->ConfigDir
, wxT("statistics.dat")), CFile::write
)) {
349 f
.WriteUInt8(0); /* version */
350 f
.WriteUInt64(s_totalSent
);
351 f
.WriteUInt64(s_totalReceived
);
353 s_statsNeedSave
= false;
357 void CStatistics::CalculateRates()
359 uint64_t now
= GetTickCount64();
360 s_downOverheadRate
->CalculateRate(now
);
361 s_upOverheadRate
->CalculateRate(now
);
362 s_downloadrate
->CalculateRate(now
);
363 s_uploadrate
->CalculateRate(now
);
368 /* ------------------------------- GRAPHS ---------------------------- */
373 The basic idea here is that we want to keep as much history as we can without paying
374 a high price in terms of memory space. Because we keep the history for display purposes,
375 we can take advantage of the fact that when the period shown in the graphs is long
376 then each pixel represents a long period. So as the most recent history we keep one
377 window full of points at a resolution of 1 second, the next window full at 2 seconds,
378 the next at 4 seconds and so on, up to the maximum desired. This way there is always
379 at least one sample point per pixel for any update delay set by the user, and the
380 memory required grows with the *log* of the total time period covered.
381 The history is kept in a doubly-linked list, with the most recent snapshot at the tail.
382 The number of nodes in the list is fixed, and there are no calls to RemoveHead() and
383 AddTail() which would add overhead and contribute to memory fragmentation. Instead,
384 every second when a new point gets recorded, one of the existing nodes is recycled;
385 it is disjoined from its present place, put at the tail of the list, and then gets
386 filled with new data. [Emilio Sandoz]
387 This unfortunately does not work with stl classes, as none of them supports moving
388 a node to another place, so we have to erase and re-add nodes.
391 void CStatistics::RecordHistory()
392 { // First we query and compute some values, then we store them in the history list
394 // A few comments about the use of double and float in computations:
395 // Even on a hi-res screen our graphs will have 10 bits of resolution at most,
396 // so the 24 bits resolution of a float on 32 bit Intel processors is more than
397 // enough for all displayed values. Rate computations however, and especially
398 // running average computations, use differences (delta bytes/ delta time), and
399 // for long uptimes the difference between two timestamps can lose too much
400 // accuracy because the large mantissa causes less significant bits to be dropped
401 // (same for the difference between two cumulative byte counts). [We don't store
402 // these values as integers because they will be used in floating point calculations,
403 // and we want to perform the conversion only once). Therefore timestamps and
404 // Kbyte counts are stored in the history as doubles, while computed values use
405 // float (to save space and execution time).
408 Store values; first determine the node to be recycled (using the bits in iClock)
410 oldest records ----------------- listHR ------------------ youngest records
412 O-[Range 2^n sec]-O- ... -O-[Range 4 sec]-O-[Range 2 sec]-O-[Range 1 sec]-O
413 | | | | > every 2 secs -^
414 | | ... | >--------------- every 4 secs -^
415 | | >------------------------ recycle every 8 secs -^
417 | >-the node at this position is recycled every 2^n secs -^
418 >-------------------(ditto for the oldest node at the head of the list) --^
420 aposRecycle[nHistRanges-1] ... aposRecycle[0] Tail
424 int iClockPrev
= iClock
++;
425 int bits
= (iClockPrev
^iClock
) & iClock
; // identify the highest changed bit
426 if (bits
<= bitsHistClockMask
) {
428 while ((bits
/= 2) != 0) // count to the highest bit that was just toggled to 1
430 // recycle one node and jump over the next to move it to the next higher range
431 listHR
.push_back(**ppos
);
432 *ppos
= ++listHR
.erase(*ppos
);
434 ppos
= aposRecycle
+nHistRanges
-1;
435 // recycle the node at the head; there is no higher range to move nodes into
436 listHR
.push_back(**ppos
);
437 *ppos
= listHR
.erase(*ppos
);
440 // now save the latest data point in this node
441 listPOS phr
= --listHR
.end();
442 phr
->kBytesSent
= GetSessionSentBytes() / 1024.0;
443 phr
->kBytesReceived
= GetSessionReceivedBytes() / 1024.0;
444 phr
->kBpsUpCur
= GetUploadRate() / 1024.0;
445 phr
->kBpsDownCur
= GetDownloadRate() / 1024.0;
446 phr
->cntUploads
= GetActiveUploadsCount();
447 phr
->cntConnections
= GetActiveConnections();
448 phr
->cntDownloads
= GetDownloadingSources();
449 phr
->sTimestamp
= GetUptimeMillis() / 1000.0;
451 s_kadNodesTotal
+= s_kadNodesCur
;
452 phr
->kadNodesTotal
= s_kadNodesTotal
;
453 phr
->kadNodesCur
= s_kadNodesCur
;
457 unsigned CStatistics::GetHistory( // Assemble arrays of sample points for a graph
458 unsigned cntPoints
, // number of sample points to assemble
459 double sStep
, // time difference between sample points
460 double sFinal
, // latest allowed timestamp
461 const std::vector
<float *> &ppf
,// an array of pointers to arrays of floats for the result
462 StatsGraphType which_graph
) // the graph which will receive the points
464 if (sStep
==0.0 || cntPoints
==0) {
471 unsigned cntFilled
= 0;
472 listRPOS pos
= listHR
.rbegin();
474 // start of list should be an integer multiple of the sampling period for samples
475 // to be consistent when the graphs are resized horizontally
480 sTarget
= sStep
==1.0 ?
482 std::floor(pos
->sTimestamp
/sStep
) * sStep
;
485 HR
**ahr
= NULL
, **pphr
= NULL
;
486 bool bRateGraph
= (which_graph
!= GRAPH_CONN
); // rate graph or connections graph?
488 ahr
= new HR
* [cntPoints
];
492 while (pos
!= listHR
.rend()) {
493 if (pos
->sTimestamp
> sTarget
) {
497 if (bRateGraph
) { // assemble an array of pointers for ComputeAverages
499 } else { // or build the arrays if possible
500 *pf1
++ = (float)pos
->cntUploads
;
501 *pf2
++ = (float)pos
->cntConnections
;
502 *pf3
++ = (float)pos
->cntDownloads
;
504 if (++cntFilled
== cntPoints
) { // enough points
507 if (pos
->sTimestamp
== 0.0) { // reached beginning of uptime
510 if ((sTarget
-= sStep
) <= 0.0) { // don't overshoot the beginning
514 *pf1
++ = *pf2
++ = *pf3
++ = 0.0;
523 ComputeAverages(pphr
, pos
, cntFilled
, sStep
, ppf
, which_graph
);
532 unsigned CStatistics::GetHistoryForWeb( // Assemble arrays of sample points for the webserver
533 unsigned cntPoints
, // maximum number of sample points to assemble
534 double sStep
, // time difference between sample points
535 double *sStart
, // earliest allowed timestamp
536 uint32
**graphData
) // a pointer to a pointer that will point to the graph data array
541 if (sStep
==0.0 || cntPoints
==0)
543 unsigned cntFilled
= 0;
544 listRPOS pos
= listHR
.rbegin();
545 double LastTimeStamp
= pos
->sTimestamp
;
546 double sTarget
= LastTimeStamp
;
548 HR
**pphr
= new HR
*[cntPoints
];
550 while (pos
!= listHR
.rend()) {
551 if (pos
->sTimestamp
> sTarget
) {
552 ++pos
; // find next history record
555 pphr
[cntFilled
] = &(*pos
);
556 if (++cntFilled
== cntPoints
) // enough points
558 if (pos
->sTimestamp
<= *sStart
) // reached beginning of requested time
560 if ((sTarget
-= sStep
) <= 0.0) { // don't overshoot the beginning
561 pphr
[cntFilled
++] = NULL
;
567 *graphData
= new uint32
[4 * cntFilled
];
569 for (unsigned int i
= 0; i
< cntFilled
; i
++) {
570 HR
*phr
= pphr
[cntFilled
- i
- 1];
572 (*graphData
)[4 * i
] = ENDIAN_HTONL((uint32
)(phr
->kBpsDownCur
* 1024.0));
573 (*graphData
)[4 * i
+ 1] = ENDIAN_HTONL((uint32
)(phr
->kBpsUpCur
* 1024.0));
574 (*graphData
)[4 * i
+ 2] = ENDIAN_HTONL((uint32
)phr
->cntConnections
);
575 (*graphData
)[4 * i
+ 3] = ENDIAN_HTONL((uint32
)phr
->kadNodesCur
);
577 (*graphData
)[4 * i
] = (*graphData
)[4 * i
+ 1] = 0;
578 (*graphData
)[4 * i
+ 2] = (*graphData
)[4 * i
+ 3] = 0;
588 *sStart
= LastTimeStamp
;
594 void CStatistics::ComputeAverages(
595 HR
**pphr
, // pointer to (end of) array of assembled history records
596 listRPOS pos
, // position in history list from which to backtrack
597 unsigned cntFilled
, // number of points in the sample data
598 double sStep
, // time difference between two samples
599 const std::vector
<float *> &ppf
,// an array of pointers to arrays of floats with sample data
600 StatsGraphType which_graph
) // the graph which will receive the points
602 double sTarget
, kValueRun
;
603 uint64 avgTime
= average_minutes
* 60;
604 unsigned nBtPoints
= (unsigned)(avgTime
/ sStep
);
606 CPreciseRateCounter
* runningAvg
= NULL
;
607 switch (which_graph
) {
608 case GRAPH_DOWN
: runningAvg
= &m_graphRunningAvgDown
; break;
609 case GRAPH_UP
: runningAvg
= &m_graphRunningAvgUp
; break;
610 case GRAPH_KAD
: runningAvg
= &m_graphRunningAvgKad
; break;
612 wxCHECK_RET(false, wxT("ComputeAverages called with unsupported graph type."));
615 runningAvg
->m_timespan
= avgTime
* 1000;
616 runningAvg
->m_tick_history
.clear();
617 runningAvg
->m_byte_history
.clear();
618 runningAvg
->m_total
= 0;
619 runningAvg
->m_tmp_sum
= 0;
621 if (pos
== listHR
.rend()) {
624 sTarget
= std::max(0.0, pos
->sTimestamp
- sStep
);
627 while (nBtPoints
--) {
628 while (pos
!= listHR
.rend() && pos
->sTimestamp
> sTarget
) ++pos
; // find next history record
629 if (pos
!= listHR
.rend()) {
630 runningAvg
->m_tick_history
.push_front((uint64
)(pos
->sTimestamp
* 1000.0));
633 switch (which_graph
) {
635 value
= (uint32
)(pos
->kBpsDownCur
* 1024.0);
638 value
= (uint32
)(pos
->kBpsUpCur
* 1024.0);
641 value
= (uint32
)(pos
->kadNodesCur
* 1024.0);
644 wxCHECK_RET(false, wxT("ComputeAverages called with unsupported graph type."));
647 runningAvg
->m_byte_history
.push_front(value
);
648 runningAvg
->m_total
+= value
;
652 if ((sTarget
-= sStep
) < 0.0) {
657 // now compute averages in returned arrays, starting with the earliest values
658 float *pf1
= ppf
[0] + cntFilled
- 1; // holds session avg
659 float *pf2
= ppf
[1] + cntFilled
- 1; // holds running avg
660 float *pf3
= ppf
[2] + cntFilled
- 1; // holds current rate
662 for (int cnt
=cntFilled
; cnt
>0; cnt
--, pf1
--, pf2
--, pf3
--) {
664 if (which_graph
== GRAPH_DOWN
) {
665 kValueRun
= phr
->kBytesReceived
;
666 *pf3
= phr
->kBpsDownCur
;
667 } else if (which_graph
== GRAPH_UP
) {
668 kValueRun
= phr
->kBytesSent
;
669 *pf3
= phr
->kBpsUpCur
;
671 kValueRun
= phr
->kadNodesTotal
;
672 *pf3
= phr
->kadNodesCur
;
675 *pf1
= kValueRun
/ phr
->sTimestamp
;
676 (*runningAvg
) += (uint32
)(*pf3
* 1024.0);
677 runningAvg
->CalculateRate((uint64
)(phr
->sTimestamp
* 1000.0));
678 *pf2
= (float)(runningAvg
->GetRate() / 1024.0);
683 GraphUpdateInfo
CStatistics::GetPointsForUpdate()
685 GraphUpdateInfo update
;
686 listPOS phr
= --listHR
.end();
687 update
.timestamp
= (double) phr
->sTimestamp
;
689 m_graphRunningAvgDown
+= (uint32
)(phr
->kBpsDownCur
* 1024.0);
690 m_graphRunningAvgUp
+= (uint32
)(phr
->kBpsUpCur
* 1024.0);
691 // Note: kadNodesCur is multiplied by 1024 since the value is done
692 // in other places, so we simply follow suit here to avoid trouble.
693 m_graphRunningAvgKad
+= (uint32
)(phr
->kadNodesCur
* 1024.0);
694 m_graphRunningAvgDown
.CalculateRate((uint64
)(phr
->sTimestamp
* 1000.0));
695 m_graphRunningAvgUp
.CalculateRate((uint64
)(phr
->sTimestamp
* 1000.0));
696 m_graphRunningAvgKad
.CalculateRate((uint64
)(phr
->sTimestamp
* 1000.0));
698 update
.downloads
[0] = phr
->kBytesReceived
/ phr
->sTimestamp
;
699 update
.downloads
[1] = m_graphRunningAvgDown
.GetRate() / 1024.0;
700 update
.downloads
[2] = phr
->kBpsDownCur
;
702 update
.uploads
[0] = phr
->kBytesSent
/ phr
->sTimestamp
;
703 update
.uploads
[1] = m_graphRunningAvgUp
.GetRate() / 1024.0;
704 update
.uploads
[2] = phr
->kBpsUpCur
;
706 update
.connections
[0] = (float)phr
->cntUploads
;
707 update
.connections
[1] = (float)phr
->cntConnections
;
708 update
.connections
[2] = (float)phr
->cntDownloads
;
710 update
.kadnodes
[0] = phr
->kadNodesTotal
/ phr
->sTimestamp
;
711 update
.kadnodes
[1] = m_graphRunningAvgKad
.GetRate() / 1024.0;
712 update
.kadnodes
[2] = phr
->kadNodesCur
;
718 /* ------------------------------- TREE ---------------------------- */
720 void CStatistics::InitStatsTree()
722 s_statTree
= new CStatTreeItemBase(wxTRANSLATE("Statistics"));
724 CStatTreeItemBase
* tmpRoot1
;
725 CStatTreeItemBase
* tmpRoot2
;
727 s_uptime
= (CStatTreeItemTimer
*)s_statTree
->AddChild(new CStatTreeItemTimer(wxTRANSLATE("Uptime: %s")));
729 tmpRoot1
= s_statTree
->AddChild(new CStatTreeItemBase(wxTRANSLATE("Transfer"), stSortChildren
));
731 tmpRoot2
= tmpRoot1
->AddChild(new CStatTreeItemBase(wxTRANSLATE("Uploads")), 2);
732 s_sessionUpload
= (CStatTreeItemUlDlCounter
*)tmpRoot2
->AddChild(new CStatTreeItemUlDlCounter(wxTRANSLATE("Uploaded Data (Session (Total)): %s"), theStats::GetTotalSentBytes
, stSortChildren
| stSortByValue
));
733 // Children will be added on-the-fly
734 s_totalUpOverhead
= (CStatTreeItemPacketTotals
*)tmpRoot2
->AddChild(new CStatTreeItemPacketTotals(wxTRANSLATE("Total Overhead (Packets): %s")));
735 s_fileReqUpOverhead
= (CStatTreeItemPackets
*)tmpRoot2
->AddChild(new CStatTreeItemPackets(wxTRANSLATE("File Request Overhead (Packets): %s")));
736 s_totalUpOverhead
->AddPacketCounter(s_fileReqUpOverhead
);
737 s_sourceXchgUpOverhead
= (CStatTreeItemPackets
*)tmpRoot2
->AddChild(new CStatTreeItemPackets(wxTRANSLATE("Source Exchange Overhead (Packets): %s")));
738 s_totalUpOverhead
->AddPacketCounter(s_sourceXchgUpOverhead
);
739 s_serverUpOverhead
= (CStatTreeItemPackets
*)tmpRoot2
->AddChild(new CStatTreeItemPackets(wxTRANSLATE("Server Overhead (Packets): %s")));
740 s_totalUpOverhead
->AddPacketCounter(s_serverUpOverhead
);
741 s_kadUpOverhead
= (CStatTreeItemPackets
*)tmpRoot2
->AddChild(new CStatTreeItemPackets(wxTRANSLATE("Kad Overhead (Packets): %s")));
742 s_totalUpOverhead
->AddPacketCounter(s_kadUpOverhead
);
743 s_cryptUpOverhead
= (CStatTreeItemCounter
*)tmpRoot2
->AddChild(new CStatTreeItemCounter(wxTRANSLATE("Crypt overhead (UDP): %s")));
744 s_cryptUpOverhead
->SetDisplayMode(dmBytes
);
745 s_activeUploads
= (CStatTreeItemNativeCounter
*)tmpRoot2
->AddChild(new CStatTreeItemNativeCounter(wxTRANSLATE("Active Uploads: %s")));
746 s_waitingUploads
= (CStatTreeItemNativeCounter
*)tmpRoot2
->AddChild(new CStatTreeItemNativeCounter(wxTRANSLATE("Waiting Uploads: %s")));
747 s_totalSuccUploads
= (CStatTreeItemCounter
*)tmpRoot2
->AddChild(new CStatTreeItemCounter(wxTRANSLATE("Total successful upload sessions: %s")));
748 s_totalFailedUploads
= (CStatTreeItemCounter
*)tmpRoot2
->AddChild(new CStatTreeItemCounter(wxTRANSLATE("Total failed upload sessions: %s")));
749 s_totalUploadTime
= new CStatTreeItemCounter(wxEmptyString
);
750 tmpRoot2
->AddChild(new CStatTreeItemAverage(wxTRANSLATE("Average upload time: %s"), s_totalUploadTime
, s_totalSuccUploads
, dmTime
));
752 tmpRoot2
= tmpRoot1
->AddChild(new CStatTreeItemBase(wxTRANSLATE("Downloads")), 1);
753 s_sessionDownload
= (CStatTreeItemUlDlCounter
*)tmpRoot2
->AddChild(new CStatTreeItemUlDlCounter(wxTRANSLATE("Downloaded Data (Session (Total)): %s"), theStats::GetTotalReceivedBytes
, stSortChildren
| stSortByValue
));
754 // Children will be added on-the-fly
755 s_totalDownOverhead
= (CStatTreeItemPacketTotals
*)tmpRoot2
->AddChild(new CStatTreeItemPacketTotals(wxTRANSLATE("Total Overhead (Packets): %s")));
756 s_fileReqDownOverhead
= (CStatTreeItemPackets
*)tmpRoot2
->AddChild(new CStatTreeItemPackets(wxTRANSLATE("File Request Overhead (Packets): %s")));
757 s_totalDownOverhead
->AddPacketCounter(s_fileReqDownOverhead
);
758 s_sourceXchgDownOverhead
= (CStatTreeItemPackets
*)tmpRoot2
->AddChild(new CStatTreeItemPackets(wxTRANSLATE("Source Exchange Overhead (Packets): %s")));
759 s_totalDownOverhead
->AddPacketCounter(s_sourceXchgDownOverhead
);
760 s_serverDownOverhead
= (CStatTreeItemPackets
*)tmpRoot2
->AddChild(new CStatTreeItemPackets(wxTRANSLATE("Server Overhead (Packets): %s")));
761 s_totalDownOverhead
->AddPacketCounter(s_serverDownOverhead
);
762 s_kadDownOverhead
= (CStatTreeItemPackets
*)tmpRoot2
->AddChild(new CStatTreeItemPackets(wxTRANSLATE("Kad Overhead (Packets): %s")));
763 s_totalDownOverhead
->AddPacketCounter(s_kadDownOverhead
);
764 s_cryptDownOverhead
= (CStatTreeItemCounter
*)tmpRoot2
->AddChild(new CStatTreeItemCounter(wxTRANSLATE("Crypt overhead (UDP): %s")));
765 s_cryptDownOverhead
->SetDisplayMode(dmBytes
);
766 s_foundSources
= (CStatTreeItemNativeCounter
*)tmpRoot2
->AddChild(new CStatTreeItemNativeCounter(wxTRANSLATE("Found Sources: %s"), stSortChildren
| stSortByValue
));
767 s_activeDownloads
= (CStatTreeItemNativeCounter
*)tmpRoot2
->AddChild(new CStatTreeItemNativeCounter(wxTRANSLATE("Active Downloads (chunks): %s")));
769 tmpRoot1
->AddChild(new CStatTreeItemRatio(wxTRANSLATE("Session UL:DL Ratio (Total): %s"), s_sessionUpload
, s_sessionDownload
, theStats::GetTotalSentBytes
, theStats::GetTotalReceivedBytes
), 3);
771 tmpRoot1
= s_statTree
->AddChild(new CStatTreeItemBase(wxTRANSLATE("Connection")));
772 tmpRoot1
->AddChild(new CStatTreeItemAverageSpeed(wxTRANSLATE("Average download rate (Session): %s"), s_sessionDownload
, s_uptime
));
773 tmpRoot1
->AddChild(new CStatTreeItemAverageSpeed(wxTRANSLATE("Average upload rate (Session): %s"), s_sessionUpload
, s_uptime
));
774 s_downloadrate
= (CStatTreeItemRateCounter
*)tmpRoot1
->AddChild(new CStatTreeItemRateCounter(wxTRANSLATE("Max download rate (Session): %s"), true, 30000));
775 s_uploadrate
= (CStatTreeItemRateCounter
*)tmpRoot1
->AddChild(new CStatTreeItemRateCounter(wxTRANSLATE("Max upload rate (Session): %s"), true, 30000));
776 s_reconnects
= (CStatTreeItemReconnects
*)tmpRoot1
->AddChild(new CStatTreeItemReconnects(wxTRANSLATE("Reconnects: %i")));
777 s_sinceFirstTransfer
= (CStatTreeItemTimer
*)tmpRoot1
->AddChild(new CStatTreeItemTimer(wxTRANSLATE("Time Since First Transfer: %s"), stHideIfZero
));
778 s_sinceConnected
= (CStatTreeItemTimer
*)tmpRoot1
->AddChild(new CStatTreeItemTimer(wxTRANSLATE("Connected To Server Since: %s")));
779 s_activeConnections
= (CStatTreeItemCounterMax
*)tmpRoot1
->AddChild(new CStatTreeItemCounterMax(wxTRANSLATE("Active Connections (estimate): %i")));
780 s_limitReached
= (CStatTreeItemMaxConnLimitReached
*)tmpRoot1
->AddChild(new CStatTreeItemMaxConnLimitReached(wxTRANSLATE("Max Connection Limit Reached: %s")));
781 s_avgConnections
= (CStatTreeItemSimple
*)tmpRoot1
->AddChild(new CStatTreeItemSimple(wxTRANSLATE("Average Connections (estimate): %g")));
782 s_avgConnections
->SetValue(0.0);
783 tmpRoot1
->AddChild(new CStatTreeItemPeakConnections(wxTRANSLATE("Peak Connections (estimate): %i")));
785 s_clients
= (CStatTreeItemHiddenCounter
*)s_statTree
->AddChild(new CStatTreeItemHiddenCounter(wxTRANSLATE("Clients"), stSortChildren
| stSortByValue
));
786 s_unknown
= (CStatTreeItemCounter
*)s_clients
->AddChild(new CStatTreeItemCounter(wxTRANSLATE("Unknown: %s")), 6);
787 //s_lowID = (CStatTreeItem*)s_clients->AddChild(new CStatTreeItem(wxTRANSLATE("LowID: %u (%.2f%% Total %.2f%% Known)")), 5);
788 //s_secIdentOnOff = (CStatTreeItem*)s_clients->AddChild(new CStatTreeItem(wxTRANSLATE("SecIdent On/Off: %u (%.2f%%) : %u (%.2f%%)")), 4);
790 s_hasSocket
= (CStatTreeItemNativeCounter
*)s_clients
->AddChild(new CStatTreeItemNativeCounter(wxT("HasSocket: %s")), 3);
792 s_filtered
= (CStatTreeItemNativeCounter
*)s_clients
->AddChild(new CStatTreeItemNativeCounter(wxTRANSLATE("Filtered: %s")), 2);
793 s_banned
= (CStatTreeItemNativeCounter
*)s_clients
->AddChild(new CStatTreeItemNativeCounter(wxTRANSLATE("Banned: %s")), 1);
794 s_clients
->AddChild(new CStatTreeItemTotalClients(wxTRANSLATE("Total: %i Known: %i"), s_clients
, s_unknown
), 0x80000000);
796 // TODO: Use counters?
797 tmpRoot1
= s_statTree
->AddChild(new CStatTreeItemBase(wxTRANSLATE("Servers")));
798 s_workingServers
= (CStatTreeItemSimple
*)tmpRoot1
->AddChild(new CStatTreeItemSimple(wxTRANSLATE("Working Servers: %i")));
799 s_failedServers
= (CStatTreeItemSimple
*)tmpRoot1
->AddChild(new CStatTreeItemSimple(wxTRANSLATE("Failed Servers: %i")));
800 s_totalServers
= (CStatTreeItemNativeCounter
*)tmpRoot1
->AddChild(new CStatTreeItemNativeCounter(wxTRANSLATE("Total: %s")));
801 s_deletedServers
= (CStatTreeItemNativeCounter
*)tmpRoot1
->AddChild(new CStatTreeItemNativeCounter(wxTRANSLATE("Deleted Servers: %s")));
802 s_filteredServers
= (CStatTreeItemNativeCounter
*)tmpRoot1
->AddChild(new CStatTreeItemNativeCounter(wxTRANSLATE("Filtered Servers: %s")));
803 s_usersOnWorking
= (CStatTreeItemSimple
*)tmpRoot1
->AddChild(new CStatTreeItemSimple(wxTRANSLATE("Users on Working Servers: %llu")));
804 s_filesOnWorking
= (CStatTreeItemSimple
*)tmpRoot1
->AddChild(new CStatTreeItemSimple(wxTRANSLATE("Files on Working Servers: %llu")));
805 s_totalUsers
= (CStatTreeItemSimple
*)tmpRoot1
->AddChild(new CStatTreeItemSimple(wxTRANSLATE("Total Users: %llu")));
806 s_totalFiles
= (CStatTreeItemSimple
*)tmpRoot1
->AddChild(new CStatTreeItemSimple(wxTRANSLATE("Total Files: %llu")));
807 s_serverOccupation
= (CStatTreeItemSimple
*)tmpRoot1
->AddChild(new CStatTreeItemSimple(wxTRANSLATE("Server Occupation: %.2f%%")));
808 s_serverOccupation
->SetValue(0.0);
810 tmpRoot1
= s_statTree
->AddChild(new CStatTreeItemBase(wxTRANSLATE("Shared Files")));
811 s_numberOfShared
= (CStatTreeItemCounter
*)tmpRoot1
->AddChild(new CStatTreeItemCounter(wxTRANSLATE("Number of Shared Files: %s")));
812 s_sizeOfShare
= (CStatTreeItemCounter
*)tmpRoot1
->AddChild(new CStatTreeItemCounter(wxTRANSLATE("Total size of Shared Files: %s")));
813 s_sizeOfShare
->SetDisplayMode(dmBytes
);
814 tmpRoot1
->AddChild(new CStatTreeItemAverage(wxTRANSLATE("Average file size: %s"), s_sizeOfShare
, s_numberOfShared
, dmBytes
));
818 void CStatistics::UpdateStatsTree()
820 // get sort orders right
821 s_sessionUpload
->ReSortChildren();
822 s_sessionDownload
->ReSortChildren();
823 s_clients
->ReSortChildren();
824 s_foundSources
->ReSortChildren();
825 // TODO: sort OS_Info subtrees.
827 s_avgConnections
->SetValue(theApp
->listensocket
->GetAverageConnections());
830 // TODO: make these realtime, too
837 theApp
->serverlist
->GetStatus(servfail
, servuser
, servfile
, servtuser
, servtfile
, servocc
);
838 s_workingServers
->SetValue((uint64
)((*s_totalServers
)-servfail
));
839 s_failedServers
->SetValue((uint64
)servfail
);
840 s_usersOnWorking
->SetValue((uint64
)servuser
);
841 s_filesOnWorking
->SetValue((uint64
)servfile
);
842 s_totalUsers
->SetValue((uint64
)servtuser
);
843 s_totalFiles
->SetValue((uint64
)servtfile
);
844 s_serverOccupation
->SetValue(servocc
);
848 void CStatistics::AddSourceOrigin(unsigned origin
)
850 CStatTreeItemNativeCounter
* counter
= (CStatTreeItemNativeCounter
*)s_foundSources
->GetChildById(0x0100 + origin
);
854 counter
= new CStatTreeItemNativeCounter(OriginToText(origin
) + wxT(": %s"), stHideIfZero
| stShowPercent
);
856 s_foundSources
->AddChild(counter
, 0x0100 + origin
);
860 void CStatistics::RemoveSourceOrigin(unsigned origin
)
862 CStatTreeItemNativeCounter
* counter
= (CStatTreeItemNativeCounter
*)s_foundSources
->GetChildById(0x0100 + origin
);
867 uint32
GetSoftID(uint8 SoftType
)
869 // prevent appearing multiple tree entries with the same name
870 // this should be kept in sync with GetSoftName().
873 return 0x0100 + SO_EMULE
;
874 case SO_NEW_SHAREAZA
:
875 case SO_NEW2_SHAREAZA
:
876 return 0x0100 + SO_SHAREAZA
;
877 case SO_NEW2_MLDONKEY
:
878 return 0x0100 + SO_NEW_MLDONKEY
;
880 return 0x0100 + SoftType
;
884 void CStatistics::AddDownloadFromSoft(uint8 SoftType
, uint32 bytes
)
886 AddReceivedBytes(bytes
);
888 uint32 id
= GetSoftID(SoftType
);
890 if (s_sessionDownload
->HasChildWithId(id
)) {
891 (*((CStatTreeItemCounter
*)s_sessionDownload
->GetChildById(id
))) += bytes
;
893 CStatTreeItemCounter
* tmp
= new CStatTreeItemCounter(GetSoftName(SoftType
) + wxT(": %s"));
894 tmp
->SetDisplayMode(dmBytes
);
896 s_sessionDownload
->AddChild(tmp
, id
);
900 void CStatistics::AddUploadToSoft(uint8 SoftType
, uint32 bytes
)
902 uint32 id
= GetSoftID(SoftType
);
904 if (s_sessionUpload
->HasChildWithId(id
)) {
905 (*((CStatTreeItemCounter
*)s_sessionUpload
->GetChildById(id
))) += bytes
;
907 CStatTreeItemCounter
* tmp
= new CStatTreeItemCounter(GetSoftName(SoftType
) + wxT(": %s"));
908 tmp
->SetDisplayMode(dmBytes
);
910 s_sessionUpload
->AddChild(tmp
, id
);
914 inline bool SupportsOSInfo(unsigned clientSoft
)
916 return (clientSoft
== SO_AMULE
) || (clientSoft
== SO_HYDRANODE
) || (clientSoft
== SO_NEW2_MLDONKEY
);
919 // Do some random black magic to strings to get a relatively unique number for them.
920 uint32
GetIdFromString(const wxString
& str
)
923 for (unsigned i
= 0; i
< str
.Length(); ++i
) {
924 unsigned old_id
= id
;
925 id
+= (uint32
)str
.GetChar(i
);
930 return (((id
>> 1) + id
) | 0x00000100) & 0x7fffffff;
933 void CStatistics::AddKnownClient(CUpDownClient
*pClient
)
937 uint32 clientSoft
= pClient
->GetClientSoft();
938 uint32 id
= GetSoftID(clientSoft
);
940 CStatTreeItemCounter
*client
;
942 if (s_clients
->HasChildWithId(id
)) {
943 client
= (CStatTreeItemCounter
*)s_clients
->GetChildById(id
);
946 uint32 flags
= stSortChildren
| stShowPercent
| stHideIfZero
;
947 if (!SupportsOSInfo(clientSoft
)) {
948 flags
|= stCapChildren
;
950 client
= new CStatTreeItemCounter(GetSoftName(clientSoft
) + wxT(": %s"), flags
);
952 s_clients
->AddChild(client
, id
);
953 if (SupportsOSInfo(clientSoft
)) {
954 client
->AddChild(new CStatTreeItemBase(wxTRANSLATE("Version"), stSortChildren
| stCapChildren
), 2);
955 client
->AddChild(new CStatTreeItemBase(wxTRANSLATE("Operating System"), stSortChildren
| stSortByValue
), 1);
959 CStatTreeItemBase
*versionRoot
= SupportsOSInfo(clientSoft
) ? client
->GetChildById(2) : client
;
960 uint32 clientVersion
= pClient
->GetVersion();
962 if (versionRoot
->HasChildWithId(clientVersion
)) {
963 CStatTreeItemCounter
*version
= (CStatTreeItemCounter
*)versionRoot
->GetChildById(clientVersion
);
966 const wxString
& versionStr
= pClient
->GetVersionString();
967 CStatTreeItemCounter
*version
= new CStatTreeItemCounter((versionStr
.IsEmpty() ? wxString(wxTRANSLATE("Unknown")) : versionStr
) + wxT(": %s"), stShowPercent
| stHideIfZero
);
969 versionRoot
->AddChild(version
, clientVersion
, SupportsOSInfo(clientSoft
));
972 if (SupportsOSInfo(clientSoft
)) {
973 const wxString
& OSInfo
= pClient
->GetClientOSInfo();
974 uint32 OS_ID
= OSInfo
.IsEmpty() ? 0 : GetIdFromString(OSInfo
);
975 CStatTreeItemBase
* OSRoot
= client
->GetChildById(1);
976 CStatTreeItemCounter
* OSNode
= (CStatTreeItemCounter
*)OSRoot
->GetChildById(OS_ID
);
980 OSNode
= new CStatTreeItemCounter((OS_ID
? OSInfo
: wxString(wxTRANSLATE("Not Received"))) + wxT(": %s"), stShowPercent
| stHideIfZero
);
982 OSRoot
->AddChild(OSNode
, OS_ID
, true);
987 void CStatistics::RemoveKnownClient(uint32 clientSoft
, uint32 clientVersion
, const wxString
& OSInfo
)
991 uint32 id
= GetSoftID(clientSoft
);
993 CStatTreeItemCounter
*client
= (CStatTreeItemCounter
*)s_clients
->GetChildById(id
);
997 CStatTreeItemBase
*versionRoot
= SupportsOSInfo(clientSoft
) ? client
->GetChildById(2) : client
;
999 CStatTreeItemCounter
*version
= (CStatTreeItemCounter
*)versionRoot
->GetChildById(clientVersion
);
1003 if (SupportsOSInfo(clientSoft
)) {
1004 uint32 OS_ID
= OSInfo
.IsEmpty() ? 0 : GetIdFromString(OSInfo
);
1005 CStatTreeItemCounter
* OSNode
= (CStatTreeItemCounter
*)client
->GetChildById(1)->GetChildById(OS_ID
);
1011 #else /* CLIENT_GUI */
1013 CStatistics::CStatistics(CRemoteConnect
&conn
)
1017 s_start_time
= GetTickCount64();
1020 s_statTree
= new CStatTreeItemBase(_("Statistics"), 0);
1022 // Clear stat data container
1023 for (int i
= 0; i
< sdTotalItems
; ++i
) {
1029 CStatistics::~CStatistics()
1035 void CStatistics::UpdateStats(const CECPacket
* stats
)
1037 s_statData
[sdUpload
] = stats
->GetTagByNameSafe(EC_TAG_STATS_UL_SPEED
)->GetInt();
1038 s_statData
[sdUpOverhead
] = stats
->GetTagByNameSafe(EC_TAG_STATS_UP_OVERHEAD
)->GetInt();
1039 s_statData
[sdDownload
] = stats
->GetTagByNameSafe(EC_TAG_STATS_DL_SPEED
)->GetInt();
1040 s_statData
[sdDownOverhead
] = stats
->GetTagByNameSafe(EC_TAG_STATS_DOWN_OVERHEAD
)->GetInt();
1041 s_statData
[sdWaitingClients
] = stats
->GetTagByNameSafe(EC_TAG_STATS_UL_QUEUE_LEN
)->GetInt();
1042 s_statData
[sdBannedClients
] = stats
->GetTagByNameSafe(EC_TAG_STATS_BANNED_COUNT
)->GetInt();
1043 s_statData
[sdED2KUsers
] = stats
->GetTagByNameSafe(EC_TAG_STATS_ED2K_USERS
)->GetInt();
1044 s_statData
[sdKadUsers
] = stats
->GetTagByNameSafe(EC_TAG_STATS_KAD_USERS
)->GetInt();
1045 s_statData
[sdED2KFiles
] = stats
->GetTagByNameSafe(EC_TAG_STATS_ED2K_FILES
)->GetInt();
1046 s_statData
[sdKadFiles
] = stats
->GetTagByNameSafe(EC_TAG_STATS_KAD_FILES
)->GetInt();
1047 s_statData
[sdKadFirewalledUDP
] = stats
->GetTagByNameSafe(EC_TAG_STATS_KAD_FIREWALLED_UDP
)->GetInt();
1048 s_statData
[sdKadIndexedSources
] = stats
->GetTagByNameSafe(EC_TAG_STATS_KAD_INDEXED_SOURCES
)->GetInt();
1049 s_statData
[sdKadIndexedKeywords
] = stats
->GetTagByNameSafe(EC_TAG_STATS_KAD_INDEXED_KEYWORDS
)->GetInt();
1050 s_statData
[sdKadIndexedNotes
] = stats
->GetTagByNameSafe(EC_TAG_STATS_KAD_INDEXED_NOTES
)->GetInt();
1051 s_statData
[sdKadIndexedLoad
] = stats
->GetTagByNameSafe(EC_TAG_STATS_KAD_INDEXED_LOAD
)->GetInt();
1052 s_statData
[sdKadIPAdress
] = stats
->GetTagByNameSafe(EC_TAG_STATS_KAD_IP_ADRESS
)->GetInt();
1053 s_statData
[sdBuddyStatus
] = stats
->GetTagByNameSafe(EC_TAG_STATS_BUDDY_STATUS
)->GetInt();
1054 s_statData
[sdBuddyIP
] = stats
->GetTagByNameSafe(EC_TAG_STATS_BUDDY_IP
)->GetInt();
1055 s_statData
[sdBuddyPort
] = stats
->GetTagByNameSafe(EC_TAG_STATS_BUDDY_PORT
)->GetInt();
1056 s_statData
[sdKadInLanMode
] = stats
->GetTagByNameSafe(EC_TAG_STATS_KAD_IN_LAN_MODE
)->GetInt();
1057 s_statData
[sdTotalSentBytes
] = stats
->GetTagByNameSafe(EC_TAG_STATS_TOTAL_SENT_BYTES
)->GetInt();
1058 s_statData
[sdTotalReceivedBytes
] = stats
->GetTagByNameSafe(EC_TAG_STATS_TOTAL_RECEIVED_BYTES
)->GetInt();
1059 s_statData
[sdSharedFileCount
] = stats
->GetTagByNameSafe(EC_TAG_STATS_SHARED_FILE_COUNT
)->GetInt();
1061 const CECTag
* LoggerTag
= stats
->GetTagByName(EC_TAG_STATS_LOGGER_MESSAGE
);
1063 for (CECTag::const_iterator it
= LoggerTag
->begin(); it
!= LoggerTag
->end(); it
++) {
1064 theApp
->AddRemoteLogLine(it
->GetStringData());
1070 void CStatistics::UpdateStatsTree()
1075 void CStatistics::RebuildStatTreeRemote(const CECTag
* tag
)
1078 s_statTree
= new CStatTreeItemBase(tag
);
1082 uint64
CStatistics::GetUptimeMillis()
1084 return GetTickCount64() - s_start_time
;
1088 uint64
CStatistics::GetUptimeSeconds()
1090 return (GetTickCount64() - s_start_time
) / 1000;
1093 #endif /* !CLIENT_GUI */
1095 // File_checked_for_headers