diff --git a/src/base/bittorrent/private/statistics.h b/src/base/bittorrent/private/statistics.h index 64b4015fc..c012c409e 100644 --- a/src/base/bittorrent/private/statistics.h +++ b/src/base/bittorrent/private/statistics.h @@ -30,8 +30,8 @@ private: // Will overflow at 15.9 EiB quint64 m_alltimeUL; quint64 m_alltimeDL; - qint64 m_sessionUL; - qint64 m_sessionDL; + quint64 m_sessionUL; + quint64 m_sessionDL; mutable qint64 m_lastWrite; mutable bool m_dirty; diff --git a/src/base/bittorrent/session.cpp b/src/base/bittorrent/session.cpp index e4236bf81..2343fa225 100644 --- a/src/base/bittorrent/session.cpp +++ b/src/base/bittorrent/session.cpp @@ -64,6 +64,9 @@ #endif #include #include +#if LIBTORRENT_VERSION_NUM >= 10100 +#include +#endif #include #include @@ -440,6 +443,11 @@ Session::Session(QObject *parent) // initialize PortForwarder instance Net::PortForwarder::initInstance(m_nativeSession); +#if LIBTORRENT_VERSION_NUM >= 10100 + initMetrics(); + m_statsUpdateTimer.start(); +#endif + qDebug("* BitTorrent Session constructed"); } @@ -920,6 +928,75 @@ void Session::adjustLimits(libt::settings_pack &settingsPack) , maxActive > -1 ? maxActive + m_extraLimit : maxActive); } +void Session::initMetrics() +{ + m_metricIndices.net.hasIncomingConnections = libt::find_metric_idx("net.has_incoming_connections"); + Q_ASSERT(m_metricIndices.net.hasIncomingConnections >= 0); + + m_metricIndices.net.sentPayloadBytes = libt::find_metric_idx("net.sent_payload_bytes"); + Q_ASSERT(m_metricIndices.net.sentPayloadBytes >= 0); + + m_metricIndices.net.recvPayloadBytes = libt::find_metric_idx("net.recv_payload_bytes"); + Q_ASSERT(m_metricIndices.net.recvPayloadBytes >= 0); + + m_metricIndices.net.sentBytes = libt::find_metric_idx("net.sent_bytes"); + Q_ASSERT(m_metricIndices.net.sentBytes >= 0); + + m_metricIndices.net.recvBytes = libt::find_metric_idx("net.recv_bytes"); + Q_ASSERT(m_metricIndices.net.recvBytes >= 0); + + m_metricIndices.net.sentIPOverheadBytes = libt::find_metric_idx("net.sent_ip_overhead_bytes"); + Q_ASSERT(m_metricIndices.net.sentIPOverheadBytes >= 0); + + m_metricIndices.net.recvIPOverheadBytes = libt::find_metric_idx("net.recv_ip_overhead_bytes"); + Q_ASSERT(m_metricIndices.net.recvIPOverheadBytes >= 0); + + m_metricIndices.net.sentTrackerBytes = libt::find_metric_idx("net.sent_tracker_bytes"); + Q_ASSERT(m_metricIndices.net.sentTrackerBytes >= 0); + + m_metricIndices.net.recvTrackerBytes = libt::find_metric_idx("net.recv_tracker_bytes"); + Q_ASSERT(m_metricIndices.net.recvTrackerBytes >= 0); + + m_metricIndices.net.recvRedundantBytes = libt::find_metric_idx("net.recv_redundant_bytes"); + Q_ASSERT(m_metricIndices.net.recvRedundantBytes >= 0); + + m_metricIndices.net.recvFailedBytes = libt::find_metric_idx("net.recv_failed_bytes"); + Q_ASSERT(m_metricIndices.net.recvFailedBytes >= 0); + + m_metricIndices.peer.numPeersConnected = libt::find_metric_idx("peer.num_peers_connected"); + Q_ASSERT(m_metricIndices.peer.numPeersConnected >= 0); + + m_metricIndices.peer.numPeersDownDisk = libt::find_metric_idx("peer.num_peers_down_disk"); + Q_ASSERT(m_metricIndices.peer.numPeersDownDisk >= 0); + + m_metricIndices.peer.numPeersUpDisk = libt::find_metric_idx("peer.num_peers_up_disk"); + Q_ASSERT(m_metricIndices.peer.numPeersUpDisk >= 0); + + m_metricIndices.dht.dhtBytesIn = libt::find_metric_idx("dht.dht_bytes_in"); + Q_ASSERT(m_metricIndices.dht.dhtBytesIn >= 0); + + m_metricIndices.dht.dhtBytesOut = libt::find_metric_idx("dht.dht_bytes_out"); + Q_ASSERT(m_metricIndices.dht.dhtBytesOut >= 0); + + m_metricIndices.dht.dhtNodes = libt::find_metric_idx("dht.dht_nodes"); + Q_ASSERT(m_metricIndices.dht.dhtNodes >= 0); + + m_metricIndices.disk.diskBlocksInUse = libt::find_metric_idx("disk.disk_blocks_in_use"); + Q_ASSERT(m_metricIndices.disk.diskBlocksInUse >= 0); + + m_metricIndices.disk.numBlocksRead = libt::find_metric_idx("disk.num_blocks_read"); + Q_ASSERT(m_metricIndices.disk.numBlocksRead >= 0); + + m_metricIndices.disk.numBlocksCacheHits = libt::find_metric_idx("disk.num_blocks_cache_hits"); + Q_ASSERT(m_metricIndices.disk.numBlocksCacheHits >= 0); + + m_metricIndices.disk.queuedDiskJobs = libt::find_metric_idx("disk.queued_disk_jobs"); + Q_ASSERT(m_metricIndices.disk.queuedDiskJobs >= 0); + + m_metricIndices.disk.diskJobTime = libt::find_metric_idx("disk.disk_job_time"); + Q_ASSERT(m_metricIndices.disk.diskJobTime >= 0); +} + void Session::configure(libtorrent::settings_pack &settingsPack) { Logger* const logger = Logger::instance(); @@ -3196,6 +3273,9 @@ quint64 Session::getAlltimeUL() const void Session::refresh() { m_nativeSession->post_torrent_updates(); +#if LIBTORRENT_VERSION_NUM >= 10100 + m_nativeSession->post_session_stats(); +#endif } void Session::handleIPFilterParsed(int ruleCount) @@ -3304,6 +3384,11 @@ void Session::handleAlert(libt::alert *a) case libt::state_update_alert::alert_type: handleStateUpdateAlert(static_cast(a)); break; +#if LIBTORRENT_VERSION_NUM >= 10100 + case libt::session_stats_alert::alert_type: + handleSessionStatsAlert(static_cast(a)); + break; +#endif case libt::file_error_alert::alert_type: handleFileErrorAlert(static_cast(a)); break; @@ -3581,6 +3666,69 @@ void Session::handleExternalIPAlert(libt::external_ip_alert *p) Logger::instance()->addMessage(tr("External IP: %1", "e.g. External IP: 192.168.0.1").arg(p->external_address.to_string(ec).c_str()), Log::INFO); } +#if LIBTORRENT_VERSION_NUM >= 10100 +void Session::handleSessionStatsAlert(libt::session_stats_alert *p) +{ + qreal interval = m_statsUpdateTimer.restart() / 1000.; + + m_status.hasIncomingConnections = static_cast(p->values[m_metricIndices.net.hasIncomingConnections]); + + const auto ipOverheadDownload = p->values[m_metricIndices.net.recvIPOverheadBytes]; + const auto ipOverheadUpload = p->values[m_metricIndices.net.sentIPOverheadBytes]; + const auto totalDownload = p->values[m_metricIndices.net.recvBytes] + ipOverheadDownload; + const auto totalUpload = p->values[m_metricIndices.net.sentBytes] + ipOverheadUpload; + const auto totalPayloadDownload = p->values[m_metricIndices.net.recvPayloadBytes]; + const auto totalPayloadUpload = p->values[m_metricIndices.net.sentPayloadBytes]; + const auto trackerDownload = p->values[m_metricIndices.net.recvTrackerBytes]; + const auto trackerUpload = p->values[m_metricIndices.net.sentTrackerBytes]; + const auto dhtDownload = p->values[m_metricIndices.dht.dhtBytesIn]; + const auto dhtUpload = p->values[m_metricIndices.dht.dhtBytesOut]; + + auto calcRate = [interval](quint64 previous, quint64 current) + { + Q_ASSERT(current >= previous); + return static_cast((current - previous) / interval); + }; + + m_status.payloadDownloadRate = calcRate(m_status.totalPayloadDownload, totalPayloadDownload); + m_status.payloadUploadRate = calcRate(m_status.totalPayloadUpload, totalPayloadUpload); + m_status.downloadRate = calcRate(m_status.totalDownload, totalDownload); + m_status.uploadRate = calcRate(m_status.totalUpload, totalUpload); + m_status.ipOverheadDownloadRate = calcRate(m_status.ipOverheadDownload, ipOverheadDownload); + m_status.ipOverheadUploadRate = calcRate(m_status.ipOverheadUpload, ipOverheadUpload); + m_status.dhtDownloadRate = calcRate(m_status.dhtDownload, dhtDownload); + m_status.dhtUploadRate = calcRate(m_status.dhtUpload, dhtUpload); + m_status.trackerDownloadRate = calcRate(m_status.trackerDownload, trackerDownload); + m_status.trackerUploadRate = calcRate(m_status.trackerUpload, trackerUpload); + + m_status.totalDownload = totalDownload; + m_status.totalUpload = totalUpload; + m_status.totalPayloadDownload = totalPayloadDownload; + m_status.totalPayloadUpload = totalPayloadUpload; + m_status.ipOverheadDownload = ipOverheadDownload; + m_status.ipOverheadUpload = ipOverheadUpload; + m_status.trackerDownload = trackerDownload; + m_status.trackerUpload = trackerUpload; + m_status.dhtDownload = dhtDownload; + m_status.dhtUpload = dhtUpload; + m_status.totalWasted = p->values[m_metricIndices.net.recvRedundantBytes] + + p->values[m_metricIndices.net.recvFailedBytes]; + m_status.dhtNodes = p->values[m_metricIndices.dht.dhtNodes]; + m_status.diskReadQueue = p->values[m_metricIndices.peer.numPeersUpDisk]; + m_status.diskWriteQueue = p->values[m_metricIndices.peer.numPeersDownDisk]; + m_status.peersCount = p->values[m_metricIndices.peer.numPeersConnected]; + + const auto numBlocksRead = p->values[m_metricIndices.disk.numBlocksRead]; + m_cacheStatus.totalUsedBuffers = p->values[m_metricIndices.disk.diskBlocksInUse]; + m_cacheStatus.readRatio = numBlocksRead > 0 + ? static_cast(p->values[m_metricIndices.disk.numBlocksCacheHits]) / numBlocksRead + : -1; + m_cacheStatus.jobQueueLength = p->values[m_metricIndices.disk.queuedDiskJobs]; + m_cacheStatus.averageJobTime = p->values[m_metricIndices.disk.diskJobTime]; + + emit statsUpdated(); +} +#else void Session::updateStats() { libt::session_status ss = m_nativeSession->status(); @@ -3595,6 +3743,7 @@ void Session::updateStats() m_status.dhtUploadRate = ss.dht_upload_rate; m_status.trackerDownloadRate = ss.tracker_download_rate; m_status.trackerUploadRate = ss.tracker_upload_rate; + m_status.totalDownload = ss.total_download; m_status.totalUpload = ss.total_upload; m_status.totalPayloadDownload = ss.total_payload_download; @@ -3610,20 +3759,19 @@ void Session::updateStats() m_cacheStatus.readRatio = cs.blocks_read > 0 ? static_cast(cs.blocks_read_hit) / cs.blocks_read : -1; -#if LIBTORRENT_VERSION_NUM < 10100 m_cacheStatus.jobQueueLength = cs.job_queue_length; -#else - m_cacheStatus.jobQueueLength = cs.queued_jobs; -#endif m_cacheStatus.averageJobTime = cs.average_job_time; - m_cacheStatus.queuedBytes = cs.queued_bytes; + m_cacheStatus.queuedBytes = cs.queued_bytes; // it seems that it is constantly equal to zero emit statsUpdated(); } +#endif void Session::handleStateUpdateAlert(libt::state_update_alert *p) { +#if LIBTORRENT_VERSION_NUM < 10100 updateStats(); +#endif foreach (const libt::torrent_status &status, p->status) { TorrentHandle *const torrent = m_torrents.value(status.info_hash); diff --git a/src/base/bittorrent/session.h b/src/base/bittorrent/session.h index 6ed134056..352649c8c 100644 --- a/src/base/bittorrent/session.h +++ b/src/base/bittorrent/session.h @@ -33,6 +33,9 @@ #include #include +#if LIBTORRENT_VERSION_NUM >= 10100 +#include +#endif #include #include #include @@ -97,6 +100,9 @@ namespace libtorrent struct listen_succeeded_alert; struct listen_failed_alert; struct external_ip_alert; +#if LIBTORRENT_VERSION_NUM >= 10100 + struct session_stats_alert; +#endif } class QThread; @@ -144,6 +150,49 @@ namespace BitTorrent uint nbErrored = 0; }; +#if LIBTORRENT_VERSION_NUM >= 10100 + struct SessionMetricIndices + { + struct + { + int hasIncomingConnections = 0; + int sentPayloadBytes = 0; + int recvPayloadBytes = 0; + int sentBytes = 0; + int recvBytes = 0; + int sentIPOverheadBytes = 0; + int recvIPOverheadBytes = 0; + int sentTrackerBytes = 0; + int recvTrackerBytes = 0; + int recvRedundantBytes = 0; + int recvFailedBytes = 0; + } net; + + struct + { + int numPeersConnected = 0; + int numPeersUpDisk = 0; + int numPeersDownDisk = 0; + } peer; + + struct + { + int dhtBytesIn = 0; + int dhtBytesOut = 0; + int dhtNodes = 0; + } dht; + + struct + { + int diskBlocksInUse = 0; + int numBlocksRead = 0; + int numBlocksCacheHits = 0; + int queuedDiskJobs = 0; + int diskJobTime = 0; + } disk; + }; +#endif + class Session : public QObject { Q_OBJECT @@ -435,6 +484,7 @@ namespace BitTorrent #else void configure(libtorrent::settings_pack &settingsPack); void adjustLimits(libtorrent::settings_pack &settingsPack); + void initMetrics(); #endif void adjustLimits(); void processBannedIPs(libtorrent::ip_filter &filter); @@ -473,6 +523,9 @@ namespace BitTorrent void handleListenSucceededAlert(libtorrent::listen_succeeded_alert *p); void handleListenFailedAlert(libtorrent::listen_failed_alert *p); void handleExternalIPAlert(libtorrent::external_ip_alert *p); +#if LIBTORRENT_VERSION_NUM >= 10100 + void handleSessionStatsAlert(libtorrent::session_stats_alert *p); +#endif void createTorrentHandle(const libtorrent::torrent_handle &nativeHandle); @@ -480,11 +533,10 @@ namespace BitTorrent #if LIBTORRENT_VERSION_NUM < 10100 void dispatchAlerts(libtorrent::alert *alertPtr); + void updateStats(); #endif void getPendingAlerts(std::vector &out, ulong time = 0); - void updateStats(); - // BitTorrent libtorrent::session *m_nativeSession; @@ -598,6 +650,9 @@ namespace BitTorrent QMutex m_alertsMutex; QWaitCondition m_alertsWaitCondition; std::vector m_alerts; +#else + SessionMetricIndices m_metricIndices; + QElapsedTimer m_statsUpdateTimer; #endif SessionStatus m_status; diff --git a/src/base/bittorrent/sessionstatus.h b/src/base/bittorrent/sessionstatus.h index d899b8545..1426786ba 100644 --- a/src/base/bittorrent/sessionstatus.h +++ b/src/base/bittorrent/sessionstatus.h @@ -61,6 +61,12 @@ namespace BitTorrent quint64 totalUpload = 0; quint64 totalPayloadDownload = 0; quint64 totalPayloadUpload = 0; + quint64 ipOverheadUpload = 0; + quint64 ipOverheadDownload = 0; + quint64 dhtUpload = 0; + quint64 dhtDownload = 0; + quint64 trackerUpload = 0; + quint64 trackerDownload = 0; quint64 totalWasted = 0; quint64 diskReadQueue = 0; quint64 diskWriteQueue = 0; diff --git a/src/gui/statusbar.cpp b/src/gui/statusbar.cpp index f8d55ed73..2e523d6d6 100644 --- a/src/gui/statusbar.cpp +++ b/src/gui/statusbar.cpp @@ -191,7 +191,7 @@ void StatusBar::updateDHTNodesNumber() if (BitTorrent::Session::instance()->isDHTEnabled()) { m_DHTLbl->setVisible(true); m_DHTLbl->setText(tr("DHT: %1 nodes") - .arg(QString::number(BitTorrent::Session::instance()->status().dhtNodes))); + .arg(BitTorrent::Session::instance()->status().dhtNodes)); } else { m_DHTLbl->setVisible(false);