From 687e7a1343083336f443fb4ca550ec81fb93d63c Mon Sep 17 00:00:00 2001 From: Nick Tiskov Date: Thu, 14 Nov 2013 23:56:13 +0400 Subject: [PATCH 1/2] Collect and save alltime UL/DL samples --- src/qtlibtorrent/qbtsession.cpp | 8 ++++++ src/qtlibtorrent/qbtsession.h | 2 ++ src/qtlibtorrent/torrentspeedmonitor.cpp | 35 +++++++++++++++++++++++- src/qtlibtorrent/torrentspeedmonitor.h | 10 +++++-- 4 files changed, 51 insertions(+), 4 deletions(-) diff --git a/src/qtlibtorrent/qbtsession.cpp b/src/qtlibtorrent/qbtsession.cpp index b42398fbb..808f54837 100755 --- a/src/qtlibtorrent/qbtsession.cpp +++ b/src/qtlibtorrent/qbtsession.cpp @@ -2778,6 +2778,14 @@ qlonglong QBtSession::getETA(const QString &hash) const return m_speedMonitor->getETA(hash); } +quint64 QBtSession::getAlltimeDL() const { + return m_speedMonitor->getAlltimeDL(); +} + +quint64 QBtSession::getAlltimeUL() const { + return m_speedMonitor->getAlltimeUL(); +} + void QBtSession::handleIPFilterParsed(int ruleCount) { addConsoleMessage(tr("Successfully parsed the provided IP filter: %1 rules were applied.", "%1 is a number").arg(ruleCount)); diff --git a/src/qtlibtorrent/qbtsession.h b/src/qtlibtorrent/qbtsession.h index e2b1fd30c..749b836b3 100755 --- a/src/qtlibtorrent/qbtsession.h +++ b/src/qtlibtorrent/qbtsession.h @@ -107,6 +107,8 @@ public: inline bool isLSDEnabled() const { return LSDEnabled; } inline bool isPexEnabled() const { return PeXEnabled; } inline bool isQueueingEnabled() const { return queueingEnabled; } + quint64 getAlltimeDL() const; + quint64 getAlltimeUL() const; public slots: QTorrentHandle addTorrent(QString path, bool fromScanDir = false, QString from_url = QString(), bool resumed = false); diff --git a/src/qtlibtorrent/torrentspeedmonitor.cpp b/src/qtlibtorrent/torrentspeedmonitor.cpp index 5b9d55cab..549949253 100644 --- a/src/qtlibtorrent/torrentspeedmonitor.cpp +++ b/src/qtlibtorrent/torrentspeedmonitor.cpp @@ -35,6 +35,7 @@ #include "qbtsession.h" #include "misc.h" #include "torrentspeedmonitor.h" +#include "qinisettings.h" using namespace libtorrent; @@ -64,12 +65,14 @@ TorrentSpeedMonitor::TorrentSpeedMonitor(QBtSession* session) : { connect(m_session, SIGNAL(deletedTorrent(QString)), SLOT(removeSamples(QString))); connect(m_session, SIGNAL(pausedTorrent(QTorrentHandle)), SLOT(removeSamples(QTorrentHandle))); + loadStats(); } TorrentSpeedMonitor::~TorrentSpeedMonitor() { m_abort = true; m_abortCond.wakeOne(); wait(); + saveStats(); } void TorrentSpeedMonitor::run() @@ -77,6 +80,7 @@ void TorrentSpeedMonitor::run() do { m_mutex.lock(); getSamples(); + saveStats(); m_abortCond.wait(&m_mutex, 1000); m_mutex.unlock(); } while(!m_abort); @@ -153,6 +157,16 @@ qlonglong TorrentSpeedMonitor::getETA(const QString &hash) const return (h.total_wanted() - h.total_wanted_done()) / speed_average.download; } +quint64 TorrentSpeedMonitor::getAlltimeDL() const { + QMutexLocker l(&m_mutex); + return alltimeDL; +} + +quint64 TorrentSpeedMonitor::getAlltimeUL() const { + QMutexLocker l(&m_mutex); + return alltimeUL; +} + void TorrentSpeedMonitor::getSamples() { const std::vector torrents = m_session->getSession()->get_torrents(); @@ -163,8 +177,27 @@ void TorrentSpeedMonitor::getSamples() try { torrent_status st = it->status(0x0); if (!st.paused) { - m_samples[misc::toQString(it->info_hash())].addSample(st.download_payload_rate, st.upload_payload_rate); + int up = st.upload_payload_rate; + int down = st.download_payload_rate; + m_samples[misc::toQString(it->info_hash())].addSample(down, up); + alltimeDL += down; + alltimeUL += up; } } catch(invalid_handle&) {} } } + +void TorrentSpeedMonitor::saveStats() const { + QIniSettings s; + QVariantHash v; + v.insert("AlltimeDL", alltimeDL); + v.insert("AlltimeUL", alltimeUL); + s.setValue("Stats/AllStats", v); +} + +void TorrentSpeedMonitor::loadStats() { + QIniSettings s; + QVariantHash v(s.value("Stats/AllStats", QVariantHash()).toHash()); + alltimeDL = v["AlltimeDL"].toULongLong(); + alltimeUL = v["AlltimeUL"].toULongLong(); +} diff --git a/src/qtlibtorrent/torrentspeedmonitor.h b/src/qtlibtorrent/torrentspeedmonitor.h index 4a29ac4e4..3a310a719 100644 --- a/src/qtlibtorrent/torrentspeedmonitor.h +++ b/src/qtlibtorrent/torrentspeedmonitor.h @@ -49,26 +49,30 @@ public: explicit TorrentSpeedMonitor(QBtSession* session); ~TorrentSpeedMonitor(); qlonglong getETA(const QString &hash) const; + quint64 getAlltimeDL() const; + quint64 getAlltimeUL() const; protected: void run(); private: void getSamples(); + void saveStats() const; + void loadStats(); private slots: void removeSamples(const QString& hash); void removeSamples(const QTorrentHandle& h); -private: - static const int sampling_interval = 1000; // 1s - private: bool m_abort; QWaitCondition m_abortCond; QHash m_samples; mutable QMutex m_mutex; QBtSession *m_session; + // Will overflow at 15.9 EiB + quint64 alltimeUL; + quint64 alltimeDL; }; #endif // TORRENTSPEEDMONITOR_H From f12b64d36a186fd7fe11360fdc5e0f870d75e071 Mon Sep 17 00:00:00 2001 From: Nick Tiskov Date: Sun, 17 Nov 2013 01:16:24 +0400 Subject: [PATCH 2/2] Add dialog to show statistics --- src/Icons/oxygen/office-chart-bar.png | Bin 0 -> 1874 bytes src/icons.qrc | 1 + src/mainwindow.cpp | 10 + src/mainwindow.h | 3 + src/mainwindow.ui | 6 + src/src.pro | 9 +- src/statsdialog.cpp | 109 +++++++++++ src/statsdialog.h | 58 ++++++ src/statsdialog.ui | 253 ++++++++++++++++++++++++++ 9 files changed, 446 insertions(+), 3 deletions(-) create mode 100644 src/Icons/oxygen/office-chart-bar.png create mode 100644 src/statsdialog.cpp create mode 100644 src/statsdialog.h create mode 100644 src/statsdialog.ui diff --git a/src/Icons/oxygen/office-chart-bar.png b/src/Icons/oxygen/office-chart-bar.png new file mode 100644 index 0000000000000000000000000000000000000000..dd8ae4e42755fe5c4c95d175640f8991871b2fc2 GIT binary patch literal 1874 zcmV-Y2d(&tP)e{sEOvKesa-weDDJtDTNB z#X40Sv4T}AOV+n0AsXBUt+o{`sAW^r5OrK|K}6iDf*=SkkU$a*plqVT%ggCGAz@Ml zr{jn8!g`y3Y{WZ&ML*DLwVY0;TaM4;f&&>D09ZVR z6fFKD%d%5~6huXG2&3tZu>(Kh49p6)|NrR#0+sPX7^L9m0D!@k;@e@s%OdcMAQ?t)wLf^& z)b4}!9v^tSWw`5=VGG)DEoO)k^c9DGd5RyTXt*K7x1Wzgcm)A07~BVhXi?yXf(La% zFEG3)jox&y_P)1!z}NS@U+(SemtBuv_{heKhPMK~w7ZI?v7BfegEE#Ejc=1(2<8~B z1Mgr5)Cgc!h+|$djblaAL`*b+lQJeC*8v~`7BS>kH#yp#LwolNpSSb5uhG*7Xlusy z#|V;XET4P%WJYoQBXjX>x4F31Efv+b@L5F(0;i)6M2$3rtMx25N96U4ZhKJ@mtWUr zDy-=+7S?u1g>{|UoJ;2gDPtTJ;r3l`rlRhSXNt3}PpNVA0-JZ;LBMs!t+AW!%}CDx zJnZa;$Grnk-p~uFznnQP@jB{Y^vD|#$IdYbdS>nR6Q|1WbVCOwakf7PdRybcyP!2} z`G|_Bv#&U+9X)X0)2lSPdX%eoyFitF#YuE&#LQTW^^VfrH=wk2z3_KG?H{OY=u*~g zJ7$$I_bVL;QZODVKnA!tqsTHzmJ(Y<{S)PJ&x-+v_o*M>(k~U%_%QioDzahsMdy{q zPPpypR;nI!DkrPjVEwKNhbZ!l8hs1}xBU;FAaHM=-}CsHTw2`$$(i=Q3_ME!qKDfF z=iv}uMgR*9$aA9EYCl!g4lV6{a(zpWzrM8xw0SrEYQZv@W@JrPnd59tJ5FAS|eGLe7 zb#oWoYVMMA&$hq{L$S?(xp9Vu1;8MHH8_NGO%lf}x#3Wy8&+&7gEZD0OKpyq?9ScCn;`FO zi$bysb+QEjpwEh}WnjJRfx-(euw8v9Z!5V6OZ59k>;T<}-p4zk1v~JCQRJA#s$9F} za048?=#lrIYk>kxwA6eWQuP^u4t&d6ojZ;`fIrSS6%x|PMgYj?d-SE417)pnu+k%M zJah*Zt8;CXo9Blg!r3^4+5=JOr^=IsqxVj94o2wYnGq z+y~@VAt9Y?v_?MUOEDBnIVjgRDcLrY$i3Qu@Y9eeAOH*2{aV8AuYrB%S_k%=Z1(4z zcECdY5&s6QX)+a=my++;Zoh{G96l1#$wq7BL%tM4v6w@qT$s~F^Ti8dRQRDZG=y{- zB7nFI10NNawDYK;pjNS7_V)jI-sLZ>@F)wkHdwDQe2iZ~)a-TpT7Nsyq!d-SWfIcK zMr-6lz7#{Tl!J1`CGWIiZieH9(c!0K06?$<$w6aYh+va;qRU`#PlT zxelKs75X-4jqe&Hf%!Bsr!Fz;5~T0F5fIYJMr-6lz7#{Tl!J23NZfG*I}n2%_}9@K zPQhA@R+lR9`WdTIjcL;oG98~MSX|Q+EKjB`%WPYeWU&)PJg1+zWSx2M)a99;>4WPo z(#b|^U8?Au;%#Cu|0J8z9s3FRueCA z+V41R`cXlzR*9@O9`}l5l(jld+8KdWC*eBz#FI`oS|cCwr5K8(93rQQXLXu%9Q0zX zR+EkZ-V5EnhrhYdoj@4;MZ|NFw~0d7Wdd#U>COIcons/oxygen/network-server.png Icons/oxygen/network-wired.png Icons/oxygen/object-locked.png + Icons/oxygen/office-chart-bar.png Icons/oxygen/preferences-desktop.png Icons/oxygen/preferences-other.png Icons/oxygen/preferences-system-network.png diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index fad5791d1..0c5c37057 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -123,6 +123,7 @@ MainWindow::MainWindow(QWidget *parent, const QStringList& torrentCmdLine) : QMa actionSet_global_download_limit->setIcon(QIcon(QString::fromUtf8(":/Icons/skin/download.png"))); actionCreate_torrent->setIcon(IconProvider::instance()->getIcon("document-edit")); actionAbout->setIcon(IconProvider::instance()->getIcon("help-about")); + actionStatistics->setIcon(IconProvider::instance()->getIcon("office-chart-bar")); actionBugReport->setIcon(IconProvider::instance()->getIcon("tools-report-bug")); actionDecreasePriority->setIcon(IconProvider::instance()->getIcon("go-down")); actionDelete->setIcon(IconProvider::instance()->getIcon("list-remove")); @@ -361,6 +362,8 @@ MainWindow::~MainWindow() { delete m_executionLog; if (aboutDlg) delete aboutDlg; + if (statsDlg) + delete statsDlg; if (options) delete options; if (downloadFromURLDialog) @@ -740,6 +743,13 @@ void MainWindow::on_actionAbout_triggered() { } } +void MainWindow::on_actionStatistics_triggered() { + if (statsDlg) + statsDlg->setFocus(); + else + statsDlg = new StatsDialog(this); +} + void MainWindow::showEvent(QShowEvent *e) { qDebug("** Show Event **"); diff --git a/src/mainwindow.h b/src/mainwindow.h index 4c79ae762..e27ed6c9b 100644 --- a/src/mainwindow.h +++ b/src/mainwindow.h @@ -36,6 +36,7 @@ #include #include "ui_mainwindow.h" #include "qtorrenthandle.h" +#include "statsdialog.h" class QBtSession; class downloadFromURL; @@ -93,6 +94,7 @@ protected slots: void dragEnterEvent(QDragEnterEvent *event); void toggleVisibility(QSystemTrayIcon::ActivationReason e = QSystemTrayIcon::Trigger); void on_actionAbout_triggered(); + void on_actionStatistics_triggered(); void on_actionCreate_torrent_triggered(); void on_actionWebsite_triggered() const; void on_actionBugReport_triggered() const; @@ -165,6 +167,7 @@ private: QPointer options; QPointer console; QPointer aboutDlg; + QPointer statsDlg; QPointer createTorrentDlg; QPointer downloadFromURLDialog; QPointer systrayIcon; diff --git a/src/mainwindow.ui b/src/mainwindow.ui index dc1a75221..aa7eaaaa3 100644 --- a/src/mainwindow.ui +++ b/src/mainwindow.ui @@ -72,6 +72,7 @@ + @@ -375,6 +376,11 @@ Minimize + + + Statistics + + diff --git a/src/src.pro b/src/src.pro index 38be01971..01f51f16d 100644 --- a/src/src.pro +++ b/src/src.pro @@ -149,7 +149,8 @@ nox { updownratiodlg.h \ loglistwidget.h \ addnewtorrentdialog.h \ - autoexpandabledialog.h + autoexpandabledialog.h \ + statsdialog.h SOURCES += mainwindow.cpp \ ico.cpp \ @@ -167,7 +168,8 @@ nox { updownratiodlg.cpp \ loglistwidget.cpp \ addnewtorrentdialog.cpp \ - autoexpandabledialog.cpp + autoexpandabledialog.cpp \ + statsdialog.cpp win32 { HEADERS += programupdater.h @@ -193,7 +195,8 @@ nox { torrentimportdlg.ui \ executionlog.ui \ addnewtorrentdialog.ui \ - autoexpandabledialog.ui + autoexpandabledialog.ui \ + statsdialog.ui } DESTDIR = . diff --git a/src/statsdialog.cpp b/src/statsdialog.cpp new file mode 100644 index 000000000..14459f6c4 --- /dev/null +++ b/src/statsdialog.cpp @@ -0,0 +1,109 @@ +/* + * Bittorrent Client using Qt4 and libtorrent. + * Copyright (C) 2013 Nick Tiskov + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * In addition, as a special exception, the copyright holders give permission to + * link this program with the OpenSSL project's "OpenSSL" library (or with + * modified versions of it that use the same license as the "OpenSSL" library), + * and distribute the linked executables. You must obey the GNU General Public + * License in all respects for all of the code used other than "OpenSSL". If you + * modify file(s), you may extend this exception to your version of the file(s), + * but you are not obligated to do so. If you do not wish to do so, delete this + * exception statement from your version. + * + * Contact : daymansmail@gmail.com + */ + +#include "statsdialog.h" +#include "ui_statsdialog.h" + +#include "misc.h" + +StatsDialog::StatsDialog(QWidget *parent) : QDialog(parent), ui(new Ui::StatsDialog) { + ui->setupUi(this); + setAttribute(Qt::WA_DeleteOnClose); + connect(ui->buttonOK, SIGNAL(clicked()), SLOT(close())); + session = QBtSession::instance(); + updateUI(); + t = new QTimer(this); + t->setInterval(1500); + connect(t, SIGNAL(timeout()), SLOT(updateUI())); + t->start(); + show(); +} + +StatsDialog::~StatsDialog() { + t->stop(); + delete t; + delete ui; +} + +void StatsDialog::updateUI() { + libtorrent::session* s = session->getSession(); + libtorrent::cache_status cache = s->get_cache_status(); + libtorrent::session_status ss = s->status(); + + // Alltime DL/UL + quint64 atd = session->getAlltimeDL(); + quint64 atu = session->getAlltimeUL(); + ui->labelAlltimeDL->setText(misc::friendlyUnit(atd)); + ui->labelAlltimeUL->setText(misc::friendlyUnit(atu)); + // Total waste (this session) + ui->labelWaste->setText(misc::friendlyUnit(ss.total_redundant_bytes + ss.total_failed_bytes)); + // Global ratio + ui->labelGlobalRatio->setText( + ( atd > 0 && atu > 0 ) ? + QString::number( (qreal)atu / (qreal)atd, 'f', 2) : + "-" + ); + // Cache hits + ui->labelCacheHits->setText( + ( cache.blocks_read > 0 && cache.blocks_read_hit > 0 ) ? + QString("%L1\%").arg(100. * (qreal)cache.blocks_read_hit / (qreal)cache.blocks_read, 0, 'f', 2) : + "-" + ); + // Buffers size + ui->labelTotalBuf->setText(misc::friendlyUnit(cache.total_used_buffers * 16 * 1024)); + // Disk overload (100%) equivalent + // From lt manual: disk_write_queue and disk_read_queue are the number of peers currently waiting on a disk write or disk read + // to complete before it receives or sends any more data on the socket. It'a a metric of how disk bound you are. + + // num_peers is not reliable (adds up peers, which didn't even overcome tcp handshake) + const std::vector torrents = session->getTorrents(); + std::vector::const_iterator iBegin = torrents.begin(); + std::vector::const_iterator iEnd = torrents.begin(); + quint32 peers = 0; + for ( ; iBegin < iEnd ; ++iBegin) + peers += (*iBegin).status().num_peers; + ui->labelWriteStarve->setText( + ( ss.disk_write_queue > 0 && peers > 0 ) ? + QString("%L1\%").arg(100. * (qreal)ss.disk_write_queue / (qreal)peers, 0, 'f', 2) : + QString("0\%") + ); + ui->labelReadStarve->setText( + ( ss.disk_read_queue > 0 && peers > 0 ) ? + QString("%L1\%").arg(100. * (qreal)ss.disk_read_queue / (qreal)peers, 0, 'f', 2) : + QString("0\%") + ); + // Disk queues + ui->labelQueuedJobs->setText(QString::number(cache.job_queue_length)); + ui->labelJobsTime->setText(QString::number(cache.average_job_time)); + ui->labelQueuedBytes->setText(misc::friendlyUnit(cache.queued_bytes)); + + // Total connected peers + ui->labelPeers->setText(QString::number(ss.num_peers)); +} diff --git a/src/statsdialog.h b/src/statsdialog.h new file mode 100644 index 000000000..004fde022 --- /dev/null +++ b/src/statsdialog.h @@ -0,0 +1,58 @@ +/* + * Bittorrent Client using Qt4 and libtorrent. + * Copyright (C) 2013 Nick Tiskov + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * In addition, as a special exception, the copyright holders give permission to + * link this program with the OpenSSL project's "OpenSSL" library (or with + * modified versions of it that use the same license as the "OpenSSL" library), + * and distribute the linked executables. You must obey the GNU General Public + * License in all respects for all of the code used other than "OpenSSL". If you + * modify file(s), you may extend this exception to your version of the file(s), + * but you are not obligated to do so. If you do not wish to do so, delete this + * exception statement from your version. + * + * Contact : daymansmail@gmail.com + */ + +#ifndef STATSDIALOG_H +#define STATSDIALOG_H + +#include +#include +#include "qbtsession.h" + +namespace Ui { + class StatsDialog; +} + +class StatsDialog : public QDialog { + Q_OBJECT + +public: + explicit StatsDialog(QWidget *parent = 0); + ~StatsDialog(); + +private slots: + void updateUI(); + +private: + Ui::StatsDialog *ui; + QBtSession* session; + QTimer* t; +}; + +#endif // STATSDIALOG_H diff --git a/src/statsdialog.ui b/src/statsdialog.ui new file mode 100644 index 000000000..7829b15dc --- /dev/null +++ b/src/statsdialog.ui @@ -0,0 +1,253 @@ + + + StatsDialog + + + + 0 + 0 + 273 + 395 + + + + Statistics + + + + + + User statistics + + + + + + Total peer connections: + + + + + + + Global ratio: + + + + + + + TextLabel + + + + + + + Alltime download: + + + + + + + TextLabel + + + + + + + TextLabel + + + + + + + Alltime upload: + + + + + + + TextLabel + + + + + + + Total waste (this session): + + + + + + + TextLabel + + + + + + + + + + Cache statistics + + + + + + Read cache Hits: + + + + + + + TextLabel + + + + + + + TextLabel + + + + + + + Total buffers size: + + + + + + + + + + Performance statistics + + + + + + TextLabel + + + + + + + TextLabel + + + + + + + TextLabel + + + + + + + TextLabel + + + + + + + Queued I/O jobs: + + + + + + + Write cache overload: + + + + + + + Average time in queue (ms): + + + + + + + Read cache overload: + + + + + + + Total queued size: + + + + + + + TextLabel + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + OK + + + + + + + + + +