Skip to content

Improve upload throughput on fast connections#435

Closed
got3nks wants to merge 2 commits intoamule-project:masterfrom
got3nks:pr/upload-throughput
Closed

Improve upload throughput on fast connections#435
got3nks wants to merge 2 commits intoamule-project:masterfrom
got3nks:pr/upload-throughput

Conversation

@got3nks
Copy link
Copy Markdown
Contributor

@got3nks got3nks commented Apr 4, 2026

Summary

The upload throttler uses hardcoded constants designed for ADSL-era connections (~128 KiB/s) that create artificial bottlenecks on modern fast connections. This patch dynamically scales parameters based on the configured upload rate while preserving identical behavior for slow connections (< 256 KiB/s).

  • Scale minFragSize/doubleSendSize dynamically with data rate for fast connections, removing the fixed 1300/2600 byte caps that limited per-slot data per throttler pass
  • Scale bandwidth banking tolerance to ~20ms worth of bandwidth, enabling efficient burst transmission instead of the fixed (slots * 512 + 1) byte cap
  • Increase per-client payload buffer from 100 KiB to 8 MiB to prevent socket starvation at high per-slot speeds
  • Increase packet chunk size from 10 KiB to 128 KiB in both standard and compressed packet paths, reducing per-packet header overhead
  • Set TCP send/receive buffers to 512 KiB after successful connect, allowing the kernel to batch more data per read/write

Backward compatibility

All changes are fully backward compatible:

  • Connections below 256 KiB/s use the original constants unchanged
  • The two-pass fairness algorithm is preserved
  • No wire protocol changes — works with all stock eMule/aMule clients
  • Larger packets (128 KiB) are well within MAX_PACKET_SIZE (2 MB)
  • Socket buffer sizes are local OS settings invisible to remote peers

Test results

Tested on a 1 Gbps dedicated server running aMule in Docker:

  • Before: ~450 KB/s per upload slot (stock aMule)
  • After: up to 8 MB/s per upload slot (18x improvement)
  • Aggregate upload throughput with 25+ concurrent slots: ~12-22 MB/s
  • Memory usage: 130-180 MiB under load (fluctuates with number of active upload slots)

Note: peak results were achieved in combination with #436 (uint16 → uint32 speed limits), which removes the 524 Mbps configuration cap. This PR alone still provides significant improvement on connections up to that limit.

Recommended configuration for fast connections

When using MaxUpload=0 (unlimited), aMule dynamically calculates the number of upload slots based on the current upload rate. This can result in a slow ramp-up where only a few slots are active initially. For best results on fast connections, set an explicit MaxUpload value rather than relying on unlimited mode:

This ensures the full number of upload slots are available immediately.

Files changed

File Changes
src/UploadBandwidthThrottler.cpp Fragment size scaling + bandwidth banking
src/UploadClient.cpp Per-client buffer + packet chunk size
src/LibSocketAsio.cpp TCP send/receive buffers after connect

got3nks added 2 commits April 4, 2026 12:03
The upload throttler was designed for ADSL-era connections (~128 KiB/s)
and uses conservative constants that create artificial bottlenecks on
modern fast connections. This patch dynamically scales parameters based
on the configured upload rate while preserving identical behavior for
slow connections (< 256 KiB/s).

Changes:

UploadBandwidthThrottler.cpp:
- Scale minFragSize/doubleSendSize dynamically with data rate for fast
  connections (> 256 KiB/s), removing the fixed 1300/2600 byte caps
  that limited per-slot data per throttler pass
- Scale bandwidth banking tolerance to ~20ms worth of bandwidth,
  enabling efficient burst transmission instead of the fixed
  (slots * 512 + 1) byte cap

UploadClient.cpp:
- Increase per-client payload buffer from 100 KiB to 8 MiB to prevent
  socket starvation at high per-slot speeds
- Increase packet chunk size from 10 KiB to 128 KiB in both standard
  and compressed packet paths, reducing per-packet header overhead and
  socket queue churn

LibSocketAsio.cpp:
- Set TCP send buffer to 512 KiB (up from OS default of ~16-64 KiB)
  after successful connect, allowing the kernel to batch more data per
  write and reducing context switches under high throughput

All changes are backward compatible:
- Connections below 256 KiB/s use the original constants unchanged
- The two-pass fairness algorithm is preserved
- No wire protocol changes; works with all stock eMule/aMule clients
- Larger packets (128 KiB) are well within MAX_PACKET_SIZE (2 MB)
- Socket buffer size is a local OS setting invisible to remote peers

Tested on a 1 Gbps server: per-slot upload speed increased from
~450 KB/s to 6 MB/s (13x improvement) on the same hardware and
connection.
Set SO_RCVBUF to 512 KiB after connect, matching the send buffer.
This improves download throughput by allowing the kernel to buffer
more incoming data before the application reads it.
@got3nks
Copy link
Copy Markdown
Contributor Author

got3nks commented Apr 13, 2026

Superseded by #444 — a cleaner, minimal version with just the two most impactful changes (adaptive payload buffer + adaptive chunk size), no throttler or socket layer modifications.

@got3nks got3nks closed this Apr 13, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant