From d7a543089325ec39950f13a3fdbe664b8e320cc5 Mon Sep 17 00:00:00 2001 From: Leon Blakey Date: Thu, 12 Jun 2025 23:47:23 -0700 Subject: [PATCH 1/6] Improve resume queue load performance PR #22831. --------- Co-authored-by: Vladimir Golovnev --- .../bittorrent/bencoderesumedatastorage.cpp | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/src/base/bittorrent/bencoderesumedatastorage.cpp b/src/base/bittorrent/bencoderesumedatastorage.cpp index b217afcc6..87b349f14 100644 --- a/src/base/bittorrent/bencoderesumedatastorage.cpp +++ b/src/base/bittorrent/bencoderesumedatastorage.cpp @@ -189,8 +189,13 @@ void BitTorrent::BencodeResumeDataStorage::loadQueue(const Path &queueFilename) return; } + QHash registeredTorrentsIndexes; + registeredTorrentsIndexes.reserve(m_registeredTorrents.length()); + for (qsizetype i = 0; i < m_registeredTorrents.length(); ++i) + registeredTorrentsIndexes.insert(m_registeredTorrents.at(i), i); + const QRegularExpression hashPattern {u"^([A-Fa-f0-9]{40})$"_s}; - int start = 0; + qsizetype queuePos = 0; while (true) { const auto line = QString::fromLatin1(queueFile.readLine(lineMaxLength).trimmed()); @@ -201,11 +206,15 @@ void BitTorrent::BencodeResumeDataStorage::loadQueue(const Path &queueFilename) if (rxMatch.hasMatch()) { const auto torrentID = BitTorrent::TorrentID::fromString(rxMatch.captured(1)); - const int pos = m_registeredTorrents.indexOf(torrentID, start); + const qsizetype pos = registeredTorrentsIndexes.value(torrentID, -1); if (pos != -1) { - std::swap(m_registeredTorrents[start], m_registeredTorrents[pos]); - ++start; + if (pos != queuePos) + { + m_registeredTorrents.swapItemsAt(pos, queuePos); + registeredTorrentsIndexes.insert(m_registeredTorrents.at(pos), pos); + } + ++queuePos; } } } From 406a389d7cdecc61b97e24cd14b700ee46e888f3 Mon Sep 17 00:00:00 2001 From: Thomas Piccirello <8296030+Piccirello@users.noreply.github.com> Date: Sat, 14 Jun 2025 06:06:33 -0700 Subject: [PATCH 2/6] WebUI: Improve performance of re-sorting table rows This change drastically improves the performance of changing a table's sorted column. This performance is achieved through improved data structures, namely removing operations that repeatedly spliced an array. We also no longer iterate over a potentially large array. On a torrent with ~50,000 files, re-rendering after a sort improves from ~20 seconds to 2 seconds. PR #22827. --- src/webui/www/private/scripts/dynamicTable.js | 57 +++++++++++-------- 1 file changed, 32 insertions(+), 25 deletions(-) diff --git a/src/webui/www/private/scripts/dynamicTable.js b/src/webui/www/private/scripts/dynamicTable.js index b0fa1a02e..8f5034be9 100644 --- a/src/webui/www/private/scripts/dynamicTable.js +++ b/src/webui/www/private/scripts/dynamicTable.js @@ -858,42 +858,49 @@ window.qBittorrent.DynamicTable ??= (() => { } else { const trs = [...this.getTrs()]; + const trMap = new Map(trs.map(tr => [tr.rowId, tr])); for (let rowPos = 0; rowPos < rows.length; ++rowPos) { const rowId = rows[rowPos].rowId; - let tr_found = false; - for (let j = rowPos; j < trs.length; ++j) { - if (trs[j].rowId === rowId) { - tr_found = true; - if (rowPos === j) - break; - trs[j].inject(trs[rowPos], "before"); - const tmpTr = trs[j]; - trs.splice(j, 1); - trs.splice(rowPos, 0, tmpTr); - break; - } + const existingTr = trMap.get(rowId); + if (existingTr !== undefined) { + this.updateRow(existingTr, fullUpdate); } - if (tr_found) { // row already exists in the table - this.updateRow(trs[rowPos], fullUpdate); - } - else { // else create a new row in the table + else { const tr = this.createRowElement(rows[rowPos]); - // Insert - if (rowPos >= trs.length) { - tr.inject(this.tableBody); - trs.push(tr); - } - else { - tr.inject(trs[rowPos], "before"); - trs.splice(rowPos, 0, tr); - } + // TODO look into using DocumentFragment or appending all trs at once for add'l performance gains + // add to end of table - we'll move into the proper order later + this.tableBody.appendChild(tr); + trMap.set(rowId, tr); this.updateRow(tr, true); } } + // reorder table rows + let prevTr = null; + for (let rowPos = 0; rowPos < rows.length; ++rowPos) { + const { rowId } = rows[rowPos]; + const tr = trMap.get(rowId); + + const isInCorrectLocation = rowId === trs[rowPos]?.rowId; + if (!isInCorrectLocation) { + // move row into correct location + if (prevTr === null) { + // insert as first row in table + if (trs.length === 0) + this.tableBody.append(tr); + else + trs[0].before(tr); + } + else { + prevTr.after(tr); + } + } + prevTr = tr; + } + const rowPos = rows.length; while ((rowPos < trs.length) && (trs.length > 0)) From 9b66693cb83b307063560a4ce7859c84177711b4 Mon Sep 17 00:00:00 2001 From: xavier2k6 <42386382+xavier2k6@users.noreply.github.com> Date: Sat, 14 Jun 2025 14:17:19 +0100 Subject: [PATCH 3/6] GHA CI: Bump dependencies * Bumped `Qt` to `6.9.1` on macOS/Windows * Bumped `Qt` to `6.9.1` & `Boost` to `1.88.0` on `coverity-scan` PR #22839. --- .github/workflows/ci_macos.yaml | 2 +- .github/workflows/ci_windows.yaml | 2 +- .github/workflows/coverity-scan.yaml | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci_macos.yaml b/.github/workflows/ci_macos.yaml index 0d8b1b634..6e3de936c 100644 --- a/.github/workflows/ci_macos.yaml +++ b/.github/workflows/ci_macos.yaml @@ -20,7 +20,7 @@ jobs: matrix: libt_version: ["2.0.11", "1.2.20"] qbt_gui: ["GUI=ON", "GUI=OFF"] - qt_version: ["6.9.0"] + qt_version: ["6.9.1"] env: boost_path: "${{ github.workspace }}/../boost" diff --git a/.github/workflows/ci_windows.yaml b/.github/workflows/ci_windows.yaml index 040844d0d..7a9b0910d 100644 --- a/.github/workflows/ci_windows.yaml +++ b/.github/workflows/ci_windows.yaml @@ -106,7 +106,7 @@ jobs: - name: Install Qt uses: jurplel/install-qt-action@v4 with: - version: "6.9.0" + version: "6.9.1" arch: win64_msvc2022_64 archives: qtbase qtsvg qttools cache: true diff --git a/.github/workflows/coverity-scan.yaml b/.github/workflows/coverity-scan.yaml index 22c5a7082..dc561ac4a 100644 --- a/.github/workflows/coverity-scan.yaml +++ b/.github/workflows/coverity-scan.yaml @@ -16,7 +16,7 @@ jobs: matrix: libt_version: ["2.0.11"] qbt_gui: ["GUI=ON"] - qt_version: ["6.6.3"] + qt_version: ["6.9.1"] env: boost_path: "${{ github.workspace }}/../boost" @@ -39,7 +39,7 @@ jobs: - name: Install boost env: BOOST_MAJOR_VERSION: "1" - BOOST_MINOR_VERSION: "86" + BOOST_MINOR_VERSION: "88" BOOST_PATCH_VERSION: "0" run: | boost_url="https://archives.boost.io/release/${{ env.BOOST_MAJOR_VERSION }}.${{ env.BOOST_MINOR_VERSION }}.${{ env.BOOST_PATCH_VERSION }}/source/boost_${{ env.BOOST_MAJOR_VERSION }}_${{ env.BOOST_MINOR_VERSION }}_${{ env.BOOST_PATCH_VERSION }}.tar.gz" From 753c6629a3d5555283547b33346e50ee6a9f9095 Mon Sep 17 00:00:00 2001 From: Chocobo1 Date: Wed, 28 May 2025 23:17:58 +0800 Subject: [PATCH 4/6] WebUI: use `defer` when loading scripts So that the HTML layout can be rendered earlier. --- src/webui/www/private/addpeers.html | 4 +- src/webui/www/private/addtrackers.html | 4 +- src/webui/www/private/addwebseeds.html | 4 +- .../www/private/confirmfeeddeletion.html | 4 +- src/webui/www/private/confirmruleclear.html | 4 +- .../www/private/confirmruledeletion.html | 4 +- .../www/private/confirmtrackerdeletion.html | 4 +- src/webui/www/private/download.html | 50 ++-- src/webui/www/private/editfeedurl.html | 4 +- src/webui/www/private/edittracker.html | 4 +- src/webui/www/private/editwebseed.html | 4 +- src/webui/www/private/newcategory.html | 8 +- src/webui/www/private/newfeed.html | 4 +- src/webui/www/private/newfolder.html | 4 +- src/webui/www/private/newrule.html | 4 +- src/webui/www/private/newtag.html | 6 +- src/webui/www/private/rename.html | 4 +- src/webui/www/private/rename_feed.html | 4 +- src/webui/www/private/rename_file.html | 6 +- src/webui/www/private/rename_files.html | 10 +- src/webui/www/private/rename_rule.html | 4 +- src/webui/www/private/setlocation.html | 6 +- src/webui/www/private/shareratio.html | 4 +- src/webui/www/private/speedlimit.html | 224 +++++++++--------- src/webui/www/private/upload.html | 46 ++-- 25 files changed, 216 insertions(+), 208 deletions(-) diff --git a/src/webui/www/private/addpeers.html b/src/webui/www/private/addpeers.html index d8d176161..39510862f 100644 --- a/src/webui/www/private/addpeers.html +++ b/src/webui/www/private/addpeers.html @@ -5,8 +5,8 @@ QBT_TR(Add Peers)QBT_TR[CONTEXT=PeersAdditionDialog] - - + + - + + - + + - + + - + + - + + - + + - - - + + + + @@ -160,31 +160,33 @@ diff --git a/src/webui/www/private/editfeedurl.html b/src/webui/www/private/editfeedurl.html index 9d87b5176..c1bd69c9a 100644 --- a/src/webui/www/private/editfeedurl.html +++ b/src/webui/www/private/editfeedurl.html @@ -5,8 +5,8 @@ QBT_TR(Please type a RSS feed URL)QBT_TR[CONTEXT=RSSWidget] - - + + - + + - + + - - - + + + + - + + - + + - + + - - + + + - + + - + + - - + + + - - - - + + + + + - + + - - + + + - + + - + + @@ -19,140 +19,144 @@ - + diff --git a/src/webui/www/private/upload.html b/src/webui/www/private/upload.html index ab2410627..ff5340536 100644 --- a/src/webui/www/private/upload.html +++ b/src/webui/www/private/upload.html @@ -6,10 +6,10 @@ QBT_TR(Upload local torrent)QBT_TR[CONTEXT=HttpServer] - - - - + + + + @@ -157,28 +157,30 @@ From 5605e083475facebff958c193a265c101f23d2ff Mon Sep 17 00:00:00 2001 From: Chocobo1 Date: Mon, 16 Jun 2025 03:10:37 +0800 Subject: [PATCH 5/6] WebUI: move scripts into `` section For consistency reasons. --- src/webui/www/private/download.html | 63 +++++++++++++-------------- src/webui/www/private/speedlimit.html | 29 ++++++------ src/webui/www/private/upload.html | 57 ++++++++++++------------ 3 files changed, 73 insertions(+), 76 deletions(-) diff --git a/src/webui/www/private/download.html b/src/webui/www/private/download.html index dd037eff2..53921e64d 100644 --- a/src/webui/www/private/download.html +++ b/src/webui/www/private/download.html @@ -10,6 +10,37 @@ + @@ -156,38 +187,6 @@
- - diff --git a/src/webui/www/private/speedlimit.html b/src/webui/www/private/speedlimit.html index d4e3f9a6d..95434e188 100644 --- a/src/webui/www/private/speedlimit.html +++ b/src/webui/www/private/speedlimit.html @@ -7,21 +7,6 @@ - - - -
-
-
- - - QBT_TR(KiB/s)QBT_TR[CONTEXT=SpeedLimit] -
- -
- -
- + + + +
+
+
+ + + QBT_TR(KiB/s)QBT_TR[CONTEXT=SpeedLimit] +
+ +
+ +
diff --git a/src/webui/www/private/upload.html b/src/webui/www/private/upload.html index ff5340536..1a89cffe1 100644 --- a/src/webui/www/private/upload.html +++ b/src/webui/www/private/upload.html @@ -10,6 +10,34 @@ + @@ -153,35 +181,6 @@
- - From 380d9af34c02a1f5e5cab83a50f59fa65634cd42 Mon Sep 17 00:00:00 2001 From: Thomas Piccirello <8296030+Piccirello@users.noreply.github.com> Date: Mon, 16 Jun 2025 11:53:09 -0700 Subject: [PATCH 6/6] WebUI: Increase number of buffered virtual rows Negligible performance hit for increased UX. Currently when scrolling I frequently see blank rows. PR #22853. --- src/webui/www/private/scripts/dynamicTable.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/webui/www/private/scripts/dynamicTable.js b/src/webui/www/private/scripts/dynamicTable.js index 8f5034be9..bb4492a86 100644 --- a/src/webui/www/private/scripts/dynamicTable.js +++ b/src/webui/www/private/scripts/dynamicTable.js @@ -915,8 +915,8 @@ window.qBittorrent.DynamicTable ??= (() => { if (this.dynamicTableDiv.offsetHeight === 0) return; this.renderedHeight = this.dynamicTableDiv.offsetHeight; - // show extra 6 rows at top/bottom to reduce flickering - const extraRowCount = 6; + // show extra rows at top/bottom to reduce flickering + const extraRowCount = 20; // how many rows can be shown in the visible area const visibleRowCount = Math.ceil(this.renderedHeight / this.rowHeight) + (extraRowCount * 2); // start position of visible rows, offsetted by scrollTop