torrust_tracker/console/
profiling.rs

1//! This binary is used for profiling with [valgrind](https://valgrind.org/)
2//! and [kcachegrind](https://kcachegrind.github.io/).
3//!
4//! # Requirements
5//!
6//! [valgrind](https://valgrind.org/) and [kcachegrind](https://kcachegrind.github.io/).
7//!
8//! On Ubuntu you can install them with:
9//!
10//! ```text
11//! sudo apt install valgrind kcachegrind
12//! ```
13//!
14//! > NOTICE: valgrind executes the program you wan to profile and waits until
15//! > it ends. Since the tracker is a service and does not end the profiling
16//! > binary accepts an arguments with the duration you want to run the tracker,
17//! > so that it terminates automatically after that period of time.
18//!
19//! # Run profiling
20//!
21//! To run the profiling you have to:
22//!
23//! 1. Build and run the tracker for profiling.
24//! 2. Run the aquatic UDP load test tool to start collecting data in the tracker.
25//!
26//! Build and run the tracker for profiling:
27//!
28//! ```text
29//! RUSTFLAGS='-g' cargo build --release --bin profiling \
30//!   && export TORRUST_TRACKER_CONFIG_TOML_PATH="./share/default/config/tracker.udp.benchmarking.toml" \
31//!   && valgrind \
32//!     --tool=callgrind \
33//!     --callgrind-out-file=callgrind.out \
34//!     --collect-jumps=yes \
35//!     --simulate-cache=yes \
36//!     ./target/release/profiling 60
37//! ```
38//!
39//! The output should be something like:
40//!
41//! ```text
42//! RUSTFLAGS='-g' cargo build --release --bin profiling \
43//!    && export TORRUST_TRACKER_CONFIG_TOML_PATH="./share/default/config/tracker.udp.benchmarking.toml" \
44//!    && valgrind \
45//!      --tool=callgrind \
46//!      --callgrind-out-file=callgrind.out \
47//!      --collect-jumps=yes \
48//!      --simulate-cache=yes \
49//!      ./target/release/profiling 60
50//!
51//!    Compiling torrust-tracker v3.0.0-alpha.12-develop (/home/developer/Documents/git/committer/me/github/torrust/torrust-tracker)
52//!     Finished `release` profile [optimized + debuginfo] target(s) in 1m 15s
53//! ==122801== Callgrind, a call-graph generating cache profiler
54//! ==122801== Copyright (C) 2002-2017, and GNU GPL'd, by Josef Weidendorfer et al.
55//! ==122801== Using Valgrind-3.19.0 and LibVEX; rerun with -h for copyright info
56//! ==122801== Command: ./target/release/profiling 60
57//! ==122801==
58//! --122801-- warning: L3 cache found, using its data for the LL simulation.
59//! ==122801== For interactive control, run 'callgrind_control -h'.
60//! Loading configuration file: `./share/default/config/tracker.udp.benchmarking.toml` ...
61//! Torrust successfully shutdown.
62//! ==122801==
63//! ==122801== Events    : Ir Dr Dw I1mr D1mr D1mw ILmr DLmr DLmw
64//! ==122801== Collected : 1160654816 278135882 247755311 24453652 12650490 16315690 10932 2481624 4832145
65//! ==122801==
66//! ==122801== I   refs:      1,160,654,816
67//! ==122801== I1  misses:       24,453,652
68//! ==122801== LLi misses:           10,932
69//! ==122801== I1  miss rate:          2.11%
70//! ==122801== LLi miss rate:          0.00%
71//! ==122801==
72//! ==122801== D   refs:        525,891,193  (278,135,882 rd + 247,755,311 wr)
73//! ==122801== D1  misses:       28,966,180  ( 12,650,490 rd +  16,315,690 wr)
74//! ==122801== LLd misses:        7,313,769  (  2,481,624 rd +   4,832,145 wr)
75//! ==122801== D1  miss rate:           5.5% (        4.5%   +         6.6%  )
76//! ==122801== LLd miss rate:           1.4% (        0.9%   +         2.0%  )
77//! ==122801==
78//! ==122801== LL refs:          53,419,832  ( 37,104,142 rd +  16,315,690 wr)
79//! ==122801== LL misses:         7,324,701  (  2,492,556 rd +   4,832,145 wr)
80//! ==122801== LL miss rate:            0.4% (        0.2%   +         2.0%  )
81//! ```
82//!
83//! > NOTICE: We are using an specific tracker configuration for profiling that
84//! > removes all features except the UDP tracker and sets the logging level to `error`.
85//!
86//! Build the aquatic UDP load test command:
87//!
88//! ```text
89//! cd /tmp
90//! git clone git@github.com:greatest-ape/aquatic.git
91//! cd aquatic
92//! cargo build --profile=release-debug -p aquatic_udp_load_test
93//! ./target/release-debug/aquatic_udp_load_test -p > "load-test-config.toml"
94//! ```
95//!
96//! Modify the "load-test-config.toml" file to change the UDP tracker port from
97//! `3000` to `6969`.
98//!
99//! Running the aquatic UDP load test command:
100//!
101//! ```text
102//! ./target/release-debug/aquatic_udp_load_test -c "load-test-config.toml"
103//! ```
104//!
105//! The output should be something like this:
106//!
107//! ```text
108//! Starting client with config: Config {
109//!     server_address: 127.0.0.1:6969,
110//!     log_level: Error,
111//!     workers: 1,
112//!     duration: 0,
113//!     summarize_last: 0,
114//!     extra_statistics: true,
115//!     network: NetworkConfig {
116//!         multiple_client_ipv4s: true,
117//!         sockets_per_worker: 4,
118//!         recv_buffer: 8000000,
119//!     },
120//!     requests: RequestConfig {
121//!         number_of_torrents: 1000000,
122//!         number_of_peers: 2000000,
123//!         scrape_max_torrents: 10,
124//!         announce_peers_wanted: 30,
125//!         weight_connect: 50,
126//!         weight_announce: 50,
127//!         weight_scrape: 1,
128//!         peer_seeder_probability: 0.75,
129//!     },
130//! }
131//!
132//! Requests out: 45097.51/second
133//! Responses in: 4212.70/second
134//!   - Connect responses:  2098.15
135//!   - Announce responses: 2074.95
136//!   - Scrape responses:   39.59
137//!   - Error responses:    0.00
138//! Peers per announce response: 0.00
139//! Announce responses per info hash:
140//!   - p10: 1
141//!   - p25: 1
142//!   - p50: 1
143//!   - p75: 2
144//!   - p90: 3
145//!   - p95: 4
146//!   - p99: 6
147//!   - p99.9: 8
148//!   - p100: 10
149//! ```
150//!
151//! After running the tracker for some seconds the tracker will automatically stop
152//! and `valgrind`will write the file `callgrind.out` with the data.
153//!
154//! You can now analyze the collected data with:
155//!
156//! ```text
157//! kcachegrind callgrind.out
158//! ```
159use std::env;
160use std::time::Duration;
161
162use tokio::time::sleep;
163
164use crate::{app, bootstrap};
165
166pub async fn run() {
167    // Parse command line arguments
168    let args: Vec<String> = env::args().collect();
169
170    // Ensure an argument for duration is provided
171    if args.len() != 2 {
172        eprintln!("Usage: {} <duration_in_seconds>", args[0]);
173        return;
174    }
175
176    // Parse duration argument
177    let Ok(duration_secs) = args[1].parse::<u64>() else {
178        eprintln!("Invalid duration provided");
179        return;
180    };
181
182    let (config, tracker) = bootstrap::app::setup();
183
184    let jobs = app::start(&config, tracker).await;
185
186    // Run the tracker for a fixed duration
187    let run_duration = sleep(Duration::from_secs(duration_secs));
188
189    tokio::select! {
190        () = run_duration => {
191            tracing::info!("Torrust timed shutdown..");
192        },
193        _ = tokio::signal::ctrl_c() => {
194            tracing::info!("Torrust shutting down via Ctrl+C ...");
195            // Await for all jobs to shutdown
196            futures::future::join_all(jobs).await;
197        }
198    }
199
200    println!("Torrust successfully shutdown.");
201}