-
Notifications
You must be signed in to change notification settings - Fork 12
Favoring Group Of Torrents
This is one of the most frequently asked questions regarding to the usage of rTorrent
. It turned out that its realization is pretty simple: let's adjust upload rate dynamically for each group and other attributes of them.
This feature is so powerful that it will change the way you used to work with rTorrent
.
Contents
There are sites where seeding data back is pretty hard while it's easy for others, not to mention public torrents that can easily eat all of the upload slots and bandwidth. So we want to distinguish between 3 groups, a special group, the rest of private downloads and public downloads:
- special group: we want to favor this private group in every possible way
- this doesn't need any additional throttle group, it uses the global one
-
slowup
group: rest of the private downloads- it's not so important to provide the best circumstances for them, but we still want to seed them as long as we can
-
tardyup
group: public downloads if they're throttled (e.g. by moving intofullseed
they can be special)- it's not important at all to provide the best circumstances for them, but we still want to seed them as long as we can
Applying this to downloading is easier (we have to set d.priority
accordingly and it will take care about everything, apart from limiting the available download slots for a group) but not to seeding.
Let's take a look what we need for this:
- define
throttle.up
group namedslowup
and set an initial value for it that will contain all the unimportant private torrents (torrents that are assigned to this group) - define
throttle.up
group namedtardyup
and set an initial value for it that will contain all the throttled public torrents - torrents that don't belong to either of the throttle groups belong to the special group (using the global throttle)
- set
d.priority
to low for theslowup
andtardyup
throttle groups that will take care of the downloading part- leaving
d.priority
set to normal for special group, so any download can be set to high manually if it's required
- leaving
- lower the default
min_peers
,max_peers
andmax_uploads
values forslowup
andtardyup
throttle groups (note: these settings aren't saved along the session hence we have to modify them on the fly, if necessary) - add config entries to be able to specify limits for each group
- adjust the value for each throttle groups in
.rtorrent-config.rc
- adjust the value for each throttle groups in
- setup 2 watch directories to automate this assignment between torrents and groups
- we don't need a 3rd one: public torrents are handled automatically
- adjust the upload rate of
slowup
andtardyup
throttle groups on the fly, depending on the current upload rate of the special group and the current global upload rate - use 6 choke groups to limit the number of upload slots per group on the fly:
-
default_leech
anddefault_seed
for special group -
slowup_leech
andslowup_seed
for other private downloads -
tardyup_leech
andtardyup_seed
for public downloads - add config entries to be able to specify limits for each group
- adjust the value for each choke groups in
.rtorrent-config.rc
- adjust the value for each choke groups in
- use the above naming convention to auto-assign the different choke groups to the proper download with the corresponding throttle group all the time!
-
Since all we want to do is seeding (unfortunately we have to download before it :) ), we can also deal with the common problem of asynchronous connections (e.g. ADSL) where upload speed can be slowed down if download speed is close to maximum bandwidth:
- adjusts the global download rate dynamically to always leave enough bandwidth to the upload rate of special group
Note: this feature requires rTorrent-PS-CH 1.5.0-0.9.7
or newer!
Let's see the related settings at once first. These settings are used with 74/20 Mbps connection.
# Global upload and download rate in KiB, `0` for unlimited (`download_rate`, `upload_rate`)
throttle.global_down.max_rate.set_kb = 10000
throttle.global_up.max_rate.set_kb = 2500
# Maximum number of simultaneous downloads and uploads slots (global slots!) (`max_downloads_global`, `max_uploads_global`)
throttle.max_downloads.global.set = 300
throttle.max_uploads.global.set = 300
# Maximum and minimum number of peers to connect to per torrent while downloading (`min_peers`, `max_peers`) Default: `100` and `200` respectively
throttle.min_peers.normal.set = 99
throttle.max_peers.normal.set = 100
# Same as above but for seeding completed torrents (seeds per torrent), `-1` for same as downloading (`min_peers_seed`, `max_peers_seed`) Default: `-1` for both
throttle.min_peers.seed.set = -1
throttle.max_peers.seed.set = -1
# Maximum number of simultaneous downloads and uploads slots per torrent (`max_uploads`) Default: `50` for both
throttle.max_downloads.set = 50
throttle.max_uploads.set = 50
# Throttles rates for (groups of) downloads or IP ranges. (throttle_up) These throttles borrow bandwidth from
# the global throttle and thus are limited by it too.
# You can assign throttles to a stopped (!) download with Ctrl-T. The `NULL` throttle is a special unlimited
# throttle that bypasses the global throttle.
# Limits the upload rate to 600 kb/s for the `slowup` throttle group. We also use this property to distinguish
# `special` and `rest` group. This value will be auto-adjusted by a helper script in Favoring section.
throttle.up = slowup,600
throttle.up = tardyup,300
# initial `slowup` group values for the previous similar 3 settings that will be overridden by per torrent settings
# Favouring section. `cfg.slowup.d.peers_min` ~ `throttle.min_peers.normal` ,
# `cfg.slowup.d.peers_max` ~ `throttle.max_peers.normal` , `cfg.slowup.d.uploads_max` ~ `throttle.max_uploads`
method.insert = cfg.slowup.d.peers_min, value, 29
method.insert = cfg.slowup.d.peers_max, value, 50
method.insert = cfg.slowup.d.uploads_max, value, 15
## Variables for getting upload rate limit for throttle groups and max number of upload/download slots for choke groups
# Max, Min value of uprate limit throttle in KB and Max number of upload/download slots during leeching and seeding for slowup throttle group
method.insert = cfg.slowup.uprate.max, value, 1600
method.insert = cfg.slowup.uprate.min, value, 75
method.insert = cfg.slowup.slots.leech.max, value, 200
method.insert = cfg.slowup.slots.seed.max, value, 125
# Max, Min value of uprate limit throttle in KB and Max number of upload/download slots during leeching and seeding for tardyup throttle group
method.insert = cfg.tardyup.uprate.max, value, 1200
method.insert = cfg.tardyup.uprate.min, value, 25
method.insert = cfg.tardyup.slots.leech.max,value, 150
method.insert = cfg.tardyup.slots.seed.max, value, 75
## Variables for getting global downrate limit
# Max, Min value of global downrate in KB
method.insert = cfg.global.downrate.max, value, 9999
method.insert = cfg.global.downrate.min, value, 8000
# Threshold values for global and special group uprate in KB
method.insert = cfg.global.upall.threshold, value, 1600
method.insert = cfg.global.upmain.threshold,value, 1100
# Min value of uprate per upload slot (unchoked peers) in KB
method.insert = cfg.global.slot.uprate.min, value, 5
# Setting up choke groups that restricts the number of unchoked peers in a group
# Modify default choke groups for specail group
choke_group.up.heuristics.set = default_leech,upload_leech_experimental
choke_group.tracker.mode.set = default_leech,aggressive
choke_group.tracker.mode.set = default_seed,aggressive
# Set up choke groups for slowup group
choke_group.insert = slowup_leech
choke_group.insert = slowup_seed
choke_group.up.heuristics.set = slowup_leech,upload_leech
choke_group.up.heuristics.set = slowup_seed,upload_seed
choke_group.down.max.set = slowup_leech,(cat,(cfg.slowup.slots.leech.max))
choke_group.up.max.set = slowup_leech,(cat,(cfg.slowup.slots.leech.max))
choke_group.up.max.set = slowup_seed,(cat,(cfg.slowup.slots.seed.max))
# Set up choke groups for tardyup group
choke_group.insert = tardyup_leech
choke_group.insert = tardyup_seed
choke_group.up.heuristics.set = tardyup_leech,upload_leech
choke_group.up.heuristics.set = tardyup_seed,upload_seed
choke_group.down.max.set = tardyup_leech,(cat,(cfg.tardyup.slots.leech.max))
choke_group.up.max.set = tardyup_leech,(cat,(cfg.tardyup.slots.leech.max))
choke_group.up.max.set = tardyup_seed,(cat,(cfg.tardyup.slots.seed.max))
# Watch directories for new torrents (meta files). Also specifying the final directories (data_dir and meta_dir) for them, whether it belongs to special group, whether its data is deletable (in this order) by setting:
# - normal priority for the special group ; - low priority and slowup throttle for the 2nd group (rest of the torrents) ; - unsafe_data custom field for those we want to delete their data upon removal
# 'd.attribs.set' command receives 3 arguments: dirname,specialgroup,unsafe_data
branch = ((cfg.inotify.use)), ((directory.watch.added, (cat,(cfg.dir.meta_downl),rotating/), load.start, "d.attribs.set=rotating,1,1"))
branch = ((cfg.inotify.use)), ((directory.watch.added, (cat,(cfg.dir.meta_downl),unsafe/), load.start, "d.attribs.set=unsafe,,1"))
##### begin: Favoring special group of torrents over the rest #####
# helper method: Sets choke group to one of the default ones if there's no throttle or throttle is special one (NULL) otherwise sets it to one of the throttle name ones
method.insert = d.modify_choke_group, simple|private, "branch=((and,((d.throttle_name)),((not,((equal,((d.throttle_name)),((cat,NULL)))))))),((d.group.set,(cat,(d.throttle_name),_,(d.connection_current)))),((d.group.set,(cat,default_,(d.connection_current))))"
# helper method: Modifies the peers_min, peers_max, max_uploads values of a torrent for both downloading and uploading
method.insert = d.modify_slots, simple|private, "d.peers_min.set=(argument.0); d.peers_max.set=(argument.1); d.uploads_max.set=(argument.2)"
# Modifies the above properties for a torrent based on which group it belongs to
method.insert = d.modify_slots_both, simple, "branch=((not,(d.throttle_name))),((d.modify_slots,(throttle.min_peers.normal),(throttle.max_peers.normal),(throttle.max_uploads))),((d.modify_slots,(cfg.slowup.d.peers_min),(cfg.slowup.d.peers_max),(cfg.slowup.d.uploads_max)))"
# Modify both group values when a torrent is resumed (even after hashchecking or after rtorrent is restarted)
method.set_key = event.download.resumed, modify_slots_resumed_both, "d.modify_slots_both=; d.modify_choke_group="
method.set_key = event.download.finished, modify_finished_choke_group, "d.modify_choke_group="
method.set_key = event.download.partially_restarted, modify_partially_restarted_choke_group, "d.modify_choke_group="
# Gets current uprate in KB for special group
method.insert = get_uprate_main, simple, "math.max=0,(math.div,(math.sub,(throttle.global_up.rate),(throttle.up.rate,slowup),(throttle.up.rate,tardyup)),1024)"
# helper methods: get new uprate limit in KB (based on special group uprate) for slowup and tardyup throttle groups
method.insert = get_uprate_slowup, simple|private, "math.min=(cfg.slowup.uprate.max),(math.max,(cfg.slowup.uprate.min),(math.sub,(cfg.slowup.uprate.max),(get_uprate_main),(math.div,(throttle.up.rate,tardyup),1024)))"
method.insert = get_uprate_tardyup, simple|private, "math.min=(cfg.tardyup.uprate.max),(math.max,(cfg.tardyup.uprate.min),(math.sub,(cfg.tardyup.uprate.max),(get_uprate_main),(math.div,(throttle.up.rate,slowup),1024)))"
# Set new uprate limit for slowup and tardyup throttle groups in every 20 seconds
schedule2 = adjust_throttle_slowup, 14, 20, "throttle.up=slowup,(cat,(get_uprate_slowup))"
schedule2 = adjust_throttle_tardyup, 15, 20, "throttle.up=tardyup,(cat,(get_uprate_tardyup))"
# helper method: get new global downrate limit in KB (based on special group uprate and given threshold values)
method.insert = get_downrate_global, simple|private, "branch=(and,((greater,((math.div,(throttle.global_up.rate),1024)),((cfg.global.upall.threshold)))),((greater,((get_uprate_main)),((cfg.global.upmain.threshold))))),(cfg.global.downrate.min),(cfg.global.downrate.max)"
# Set new global downrate limit in every 60 seconds
schedule2 = adjust_throttle_global_down_max_rate, 54, 60, "throttle.global_down.max_rate.set_kb=(get_downrate_global)"
# helper methods: get new upload slots limit for slowup_seed and tardyup_seed choke groups (based on their current uprate and the given cfg values)
method.insert = get_slots_slowup, simple|private, "math.min=(cfg.slowup.slots.seed.max),(math.max,(math.div,(cfg.slowup.uprate.min),(cfg.global.slot.uprate.min)),(math.div,(throttle.up.rate,slowup),1024,(cfg.global.slot.uprate.min)))"
method.insert = get_slots_tardyup, simple|private, "math.min=(cfg.tardyup.slots.seed.max),(math.max,(math.div,(cfg.tardyup.uprate.min),(cfg.global.slot.uprate.min)),(math.div,(throttle.up.rate,tardyup),1024,(cfg.global.slot.uprate.min)))"
# Set new upload slots (unchoked peers) limit for slowup_seed and tardyup_seed choke groups in every 100 seconds
schedule2 = adjust_slots_slowup, 47, 100,"choke_group.up.max.set=slowup_seed,(cat,(get_slots_slowup))"
schedule2 = adjust_slots_tardyup, 48, 100,"choke_group.up.max.set=tardyup_seed,(cat,(get_slots_tardyup))"
##### end: Favoring special group of torrents over the rest #####
### begin: Other UI enhancements ###
# UI/STATUS: Display additional throttle up info in status bar (it needs rT-PS-CH)
branch=pyro.extended=,"branch=pyro.extended.ch=,\"ui.status.throttle.up.set = slowup,tardyup\""
### end: Other UI enhancements ###
Since we can do basic arithmetic operations in rTorrent-PS-CH 1.5.0-0.9.7
or newer, we don't need the previously used external script file.
They do 3 things:
- gets new uprate limit for
slowup
andtardyup
throttle in every 20 seconds (based upon the configured variables)- specify the top of the cap (
cfg.slowup.uprate.max
,cfg.tardyup.uprate.max
: highest allowable value in KiB, e.g.1600
and1200
) - specify the bottom of the cap (
cfg.slowup.uprate.min
,cfg.tardyup.uprate.min
: lowest allowable value in KiB, e.g.75
and25
)
- specify the top of the cap (
- gets new global downrate limit (based on special group uprate and the configured variables) in every 1 minute
- specify the top of the cap (
cfg.global.downrate.max
in KiB, e.g.9999
) for global downrate - specify the bottom of the cap (
cfg.global.downrate.min
in KiB, e.g.8000
) for global downrate - specify the global uprate limit (
cfg.global.upall.threshold
in KiB, e.g.1600
) that above this value it should lower global downrate - specify uprate limit for special group (
cfg.global.upmain.threshold
in KiB, e.g.1100
) that above this value it should lower global downrate
- specify the top of the cap (
- gets new upload slots limit for
slowup_seed
andtardyup_seed
choke groups (based on their current uprate and the configured variables) in every 100 seconds- specify the top of the cap (
cfg.slowup.slots.seed.max
,cfg.tardyup.slots.seed.max
: highest allowable value per group, e.g.125
and75
)
- specify the top of the cap (
Also specify the max amount of upload/download slots for both groups during leeching (cfg.slowup.slots.leech.max
, cfg.tardyup.slots.leech.max
: highest allowable value per group, e.g. 200
and 150
), these values won't be changed.
You have to edit the variables in .rtorrent-config.rc
according to your needs, it probably also needs some experimenting which values works best for your needs. These variables can be adjusted on-the-fly while rTorrent
is running.
- once you put a torrent into a watch directory all the necessary attributes are assigned to it
-
adjust_throttle_slowup
andadjust_throttle_tardyup
runs in every 20 seconds -
adjust_throttle_global_down_max_rate
runs in every 60 seconds -
adjust_slots_slowup
andadjust_slots_tardyup
runs in every 100 seconds
It doesn't use a complicated algorithm to always give back reliable result, e.g. for slowup throttle cfg.slowup.uprate.max - uprate_main - throttle.up.rate,tardyup
, but it works pretty efficiently:
- checks the current uprate of the other throttle group and uprate of main (special) group (with the help of the global uprate) then it raises or lowers the throttle limit according to the uprate of the main (special) and the other throttle group
- you should leave a considerable amount of gap around
20%
(500 KiB
, in this case) between the top of the cap (cfg.slowup.uprate.max
, e.g.1600
) and the max global upload rate (throttle.global_up.max_rate.set_kb
: the global upload limit , e.g.2500
) and the other top cap of the other throttle group (cfg.tardyup.uprate.max
, e.g.1200
) to be able to work efficiently: to leave bandwidth to the main (special) group between checks (within that 20 seconds interval)
This one even less sophisticated then the above one, it only sets one of the 2 defined cfg.global.downrate.max
, cfg.global.downrate.min
values for global downrate:
- whether global upload rate is bigger than the specified global uprate threshold (
cfg.global.upall.threshold
) and main (special) upload rate is bigger than the specified main uprate threshold (cfg.global.upmain.threshold
)
Remember, if you don't need this feature then comment out adjust_throttle_global_down_max_rate
scheduling in rTorrent
config.
This is really simple, it just checks for the current uprate of the given throttle group and divides it by the minimum rate a slot can have (cfg.global.slot.uprate.min
, e.g. 5
KiB).