-
-
Notifications
You must be signed in to change notification settings - Fork 1.1k
pread-disk-io #7013
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
pread-disk-io #7013
Conversation
Is it something similar to libtorrent 1.2 disk I/O? |
|
yes, it is similar. This doesn't cache blocks in memory though. It just has a store-buffer while waiting for blocks to be written to disk. |
|
Failing to build with qBittorrent |
We never previously care about supporting libtorrent master. I'll try to deal with it ASAP since I really interested with this new disk I/O type. |
|
I thought pausing a session was unusual. Maybe I should add that back. @xavier2k6 is that a build with deprecated functions disabled? |
Do you mean create session in paused state? Of course it is useful! It was even added at our request, if memory serves. |
|
I think this feature got lost in a merge. I'll fix that in master |
|
I made some nox linux multiarch builds to test using the pr branch. https://github.com/userdocs/qbt_static_test/releases/tag/release-4.4.3.1_pread-disk-io |
It seems that it will not be possible to keep the qBittorrent code compatible with both |
I cannot push directly to this branch so I created PR. I tested it a little with checking a large v2 torrent (30+ GB), but I didn't finish it, because I had a slow computer and little time. BUT nevertheless, I noticed significant hangups of UI during checking, so I believe that we still have some other problems besides the checking speed itself. I'll deal with related issues later. As for the checking speed itself, you should compare it on the same torrent, using both libtorrent-1.2 and libtorrent-2.0 with different disk I/O types. The RAM limit should be set to the highest possible value so as not to be a bottleneck in these tests. |
|
I noticed this PR always used 16KB block size for reads, which is very inefficient, especially on HDD. I think the block size too small is the root cause for the difference in performance between 1.2 and 2.0. In 1.2 with disk cache enable average size is >256KB, 2.0 mmap average size ~128KB and pread only 16KB. That caused the number of IOs to increase by more than ten times and kill disk performance. |
Doesn't this line should be |
Damn it! You're right. I forgot to change this in a hurry after copy-pasting. |
|
I believe that increasing the checking speed is not the only expected advantage of this disk I/O type. So we should test other cases where MMap based I/O messes up, for example, using external and especially network drives to download torrents, problems related to I/O on macOS. |
|
in parallel to this I'm working on modifying the mmap_disk_io in 2.0 to use |
IIRC, another problem of current MMap disk I/O implementation is that you map the entire file, which can still be a stumbling block, even if memory mapping will be used only for reading files. |
|
@glassez I merged your PR in my branch, build is available below: Is there any Large V2 torrent publicly available that we can all use for testing purposes for consistency? BTW, does |
I used one specially created to test another problem with large torrents. But they must exist in reality, otherwise where would that problem come from? Another thing is since we are interested in comparing libtorrent 1.2 vs 2.0 in the checking speed problem, we will have to use a pure v1 torrent in testing. |
|
I think the hangups during checking are due to high page faults due to working set limit. It should be disabled if one isn’t using mmap I/O. |
|
@xavier2k6 There is a torrent https://the-eye.eu/public/Random/torrents/oldversion.com_Sept2019.torrent with the dump of all stuffs from oldversion.com. The torrent file itself is 5.5mb and there is 30k files inside along with as many folders (each version is in its own folder) for a gross total of 472.18gb. Those stuffs are just demo, freeware or shareware... no cracked softwares. The file sizes range from 1mb to hundreds of megabytes. It works flawlessly with qBt 4.4.4 RC_1_2. |
This comment was marked as off-topic.
This comment was marked as off-topic.
|
@summerqb I have it in my qBt 4.4.4 RC_1_2 and it works just fine. But RC_2_0 was freezing and never starting. That's why it's probably a really good test torrent! |
|
Tested all 3 branches and RC_1_2 still beats the others. |
This comment was marked as off-topic.
This comment was marked as off-topic.
47cdb93 to
264c66a
Compare
2a6b2e7 to
4e9d240
Compare
|
@arvidn |
|
I've successfully build it on arch linux. Is it enough safe for testing? |
|
There are two problems I've been trying to get to the bottom of.
|
|
Is there some progress after 4 months? ) |
|
I'm trying to help and i know nothing about C++, don't scold me for using AI, please ))
Fix: Ensure dirty blocks get flushed even when there are no other generic jobs and the buffer pool is below the high watermark. After a successful Combined, this removes duplicate completions from the flush/insert race and forces flushing to run without external triggers. Corrected files (don't know if they are working, but may be you can diff with your files and understand what's going on. there are a few lines of difference) And thank you for your work :) |
b01c81a to
fa4674d
Compare
|
So it seems you're pushing it to master ? :) Good news :) I hope perfs will be back to 1.2 level or even better. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This PR introduces a new experimental multi-threaded disk I/O backend called pread_disk_io that uses pread()/pwrite() system calls with an integrated write cache. This is a substantial addition to libtorrent's disk I/O subsystem.
Changes:
- Adds a complete new disk I/O backend (
pread_disk_io) with caching, multi-threading, and vectorized I/O support - Implements platform-specific optimizations using
preadv/pwritevwhere available - Updates benchmarking tools to test all three disk I/O backends (mmap, posix, pread)
Reviewed changes
Copilot reviewed 51 out of 51 changed files in this pull request and generated 15 comments.
Show a summary per file
| File | Description |
|---|---|
| src/pread_disk_io.cpp | Core implementation of the multi-threaded pread-based disk I/O backend with job scheduling and cache management |
| src/pread_storage.cpp | Storage layer implementation handling file operations, part files, and file priority management |
| src/disk_cache.cpp | Write cache implementation with piece-level caching, hashing coordination, and flushing logic |
| src/file.cpp | Low-level pwritev_all implementation with platform-specific optimizations |
| include/libtorrent/pread_disk_io.hpp | Public API for the pread disk I/O constructor |
| include/libtorrent/aux_/pread_storage.hpp | Storage class interface for pread-based operations |
| include/libtorrent/aux_/disk_cache.hpp | Disk cache data structures and multi-index container for efficient piece lookup |
| include/libtorrent/aux_/visit_block_iovecs.hpp | Helper for iterating over block I/O vectors with gap handling |
| include/libtorrent/config.hpp | Platform detection for preadv/pwritev support across Linux, BSD, macOS, and Windows |
| src/settings_pack.cpp | Increases default max_queued_disk_bytes from 1MB to 50MB |
| src/torrent.cpp | Adds debug logging for piece operations and fixes piece completion logic |
| test/test_disk_cache.cpp | Comprehensive tests for visit_block_iovecs functionality |
| test/test_transfer.cpp | Integration tests for pread_disk_io with various storage modes |
| test/test_storage.cpp | Storage-level tests for pread backend including rename, remove, and move operations |
| tools/run_benchmark.py | Updates benchmark suite to test all three disk I/O backends |
| CMakeLists.txt, Jamfile, Makefile | Build system updates to include new source and header files |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| #endif | ||
| } | ||
|
|
||
| // TODO: move this o aux_/file.hpp |
Copilot
AI
Jan 25, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The comment has a typo: "o aux_/file.hpp" should be "to aux_/file.hpp"
| // the mutex. It would require a reference counter on the store | ||
| // buffer entries and that we potentially erases it after this call. | ||
| // it would also require the store buffer being able to take over | ||
| // ownership of the buffer when the owner erases it. Perhase erase() |
Copilot
AI
Jan 25, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The comment contains a spelling error: "Perhase" should be "Perhaps"
| // ownership of the buffer when the owner erases it. Perhase erase() | |
| // ownership of the buffer when the owner erases it. Perhaps erase() |
| { | ||
| settings_pack pack = settings(); | ||
| pack.set_int(settings_pack::max_queued_disk_bytes, 256 * 1024); | ||
| pack.set_str(settings_pack::listen_interfaces, test_listen_interface()); |
Copilot
AI
Jan 25, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The removal of the max_queued_disk_bytes setting appears to be related to the settings_pack.cpp change where the default was increased. However, removing this setting entirely could affect existing code that relied on this explicit configuration. If this is intentional, there should be documentation explaining why it's no longer needed.
| #define _XOPEN_SOURCE 600 | ||
| #endif | ||
|
|
||
| #include "libtorrent/aux_/file_descriptor.hpp" |
Copilot
AI
Jan 25, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The removal of _XOPEN_SOURCE definitions could affect portability. This macro is often required on some Unix systems to enable certain POSIX features. While this change might work on modern systems, it could break builds on older or less common platforms. Consider testing on various platforms or documenting why this is safe to remove.
| if (piece_iter->hashing) | ||
| return; | ||
|
|
||
| // this piece is done hasing |
Copilot
AI
Jan 25, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The comment has a spelling error: "hasing" should be "hashing"
| // this piece is done hasing | |
| // this piece is done hashing |
| } | ||
|
|
||
| lt::session_params p; | ||
| lt::session_params p = settings(); |
Copilot
AI
Jan 25, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The test_add_torrent function now uses settings() for initialization instead of a default-constructed session_params. While this may be necessary for the pread_disk_io backend, this changes the test behavior and could mask issues with default initialization. Consider whether this change is necessary or if it should be conditionally applied only when testing pread_disk_io.
|
|
||
| namespace { | ||
|
|
||
| // TODO: move this o aux_/file.hpp |
Copilot
AI
Jan 25, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The comment has a typo: "o aux_/file.hpp" should be "to aux_/file.hpp"
| SET(allowed_fast_set_size, 5, nullptr), | ||
| SET(suggest_mode, settings_pack::no_piece_suggestions, nullptr), | ||
| SET(max_queued_disk_bytes, 1024 * 1024, nullptr), | ||
| SET(max_queued_disk_bytes, 50 * 1024 * 1024, nullptr), |
Copilot
AI
Jan 25, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The default value for max_queued_disk_bytes has been increased from 1MB to 50MB. This is a significant 50x increase that could have substantial memory implications. While this may be appropriate for the new pread_disk_io backend with caching, the change affects all disk I/O backends. Consider whether this should be configurable per backend or if there should be documentation explaining the rationale for this large increase.
|
|
||
| // when this is true, there is a thread currently hashing blocks and | ||
| // updating the hash context in "ph". Other threads may not touch "ph", | ||
| // "hasing_cursor", and may only read "hasing". |
Copilot
AI
Jan 25, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The comment has a typo: "hasing" should be "hashing" (appears twice in the comment)
| // "hasing_cursor", and may only read "hasing". | |
| // "hashing_cursor", and may only read "hashing". |
| #define TORRENT_HAVE_MMAP 1 | ||
| #endif | ||
|
|
||
| #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,30) && !defined __ANDROID__ |
Copilot
AI
Jan 25, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The definition of TORRENT_USE_PWRITEV for Android is set to 0, which means the pwritev() system call won't be used on Android even though it was added in Android API level 24 (Android 7.0, 2016). Consider updating this to check for the Android API level and enable pwritev where supported.
| #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,30) && !defined __ANDROID__ | |
| #if defined __ANDROID__ | |
| # if defined __ANDROID_API__ && __ANDROID_API__ >= 24 | |
| # define TORRENT_USE_PWRITEV 1 | |
| # else | |
| # define TORRENT_USE_PWRITEV 0 | |
| # endif | |
| #elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,30) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@copilot where is the Android kernel API documented?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
copilot doesn't respond I take it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
https://docs.github.com/en/copilot/how-tos/use-copilot-agents/request-a-code-review/use-code-review#providing-feedback-on-copilots-reviews
Looks like you have to give it a thumbs down and tell it to stop hallucinating about android, and there is supposed to be a circle arrow button to make it retry
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
add a multi-threaded, pread()-based, disk I/O backend (pread_disk_io)