Coverage Report

Created: 2026-11-13 23:29

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/build/source/src/bin/cas_speed_check.rs
Line
Count
Source
1
// Copyright 2026 Trace Machina, Inc. All rights reserved.
2
//
3
// Licensed under the Functional Source License, Version 1.1, Apache 2.0 Future License (the "License");
4
// you may not use this file except in compliance with the License.
5
// You may obtain a copy of the License at
6
//
7
//    See LICENSE file for details
8
//
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
// See the License for the specific language governing permissions and
13
// limitations under the License.
14
15
use core::time::Duration;
16
use std::sync::Arc;
17
18
use clap::Parser;
19
use nativelink_error::{Error, ResultExt};
20
use nativelink_proto::build::bazel::remote::execution::v2::content_addressable_storage_client::ContentAddressableStorageClient;
21
use nativelink_proto::build::bazel::remote::execution::v2::{
22
    Digest, FindMissingBlobsRequest, digest_function,
23
};
24
use nativelink_util::spawn;
25
use nativelink_util::telemetry::init_tracing;
26
use nativelink_util::tls_utils::endpoint_from;
27
use rand::{Rng, RngCore};
28
use sha2::{Digest as _, Sha256};
29
use tokio::sync::Mutex;
30
use tokio::time::Instant;
31
use tonic::Request;
32
use tonic::transport::ClientTlsConfig;
33
use tracing::info;
34
35
#[derive(Parser, Debug)]
36
#[command(version, about)]
37
struct Args {
38
    #[arg(short, long)]
39
    endpoint: String,
40
41
    #[arg(short, long)]
42
    nativelink_key: Option<String>,
43
}
44
45
0
fn main() -> Result<(), Box<dyn core::error::Error>> {
46
0
    let args = Args::parse();
47
    #[expect(
48
        clippy::disallowed_methods,
49
        reason = "It's the top-level, so we need the function"
50
    )]
51
0
    tokio::runtime::Builder::new_multi_thread()
52
0
        .enable_all()
53
0
        .build()
54
0
        .unwrap()
55
0
        .block_on(async {
56
0
            init_tracing().await?;
57
0
            let timings = Arc::new(Mutex::new(Vec::new()));
58
0
            let spawns: Vec<_> = (0..200)
59
0
                .map(|_| {
60
0
                    let local_timings = timings.clone();
61
0
                    let local_endpoint = args.endpoint.clone();
62
0
                    let local_api_key = args.nativelink_key.clone();
63
0
                    spawn!("CAS requester", async move {
64
0
                        let tls_config = ClientTlsConfig::new().with_enabled_roots();
65
0
                        let endpoint = endpoint_from(&local_endpoint, Some(tls_config))?;
66
0
                        let channel = endpoint.connect().await.unwrap();
67
68
0
                        let mut client = ContentAddressableStorageClient::new(channel);
69
70
0
                        for _ in 0..100 {
71
0
                            let raw_data: String = rand::rng()
72
0
                                .sample_iter::<char, _>(rand::distr::StandardUniform)
73
0
                                .take(300)
74
0
                                .collect();
75
0
                            let hashed = Sha256::digest(raw_data.as_bytes());
76
0
                            let rand_hash = hex::encode(hashed);
77
0
                            let digest = Digest {
78
0
                                hash: rand_hash,
79
0
                                size_bytes: i64::from(rand::rng().next_u32()),
80
0
                            };
81
82
0
                            let mut request = Request::new(FindMissingBlobsRequest {
83
0
                                instance_name: String::new(),
84
0
                                blob_digests: vec![digest.clone()],
85
0
                                digest_function: digest_function::Value::Sha256.into(),
86
0
                            });
87
0
                            if let Some(ref api_key) = local_api_key {
88
0
                                request
89
0
                                    .metadata_mut()
90
0
                                    .insert("x-nativelink-api-key", api_key.parse().unwrap());
91
0
                            }
92
0
                            let start = Instant::now();
93
0
                            client
94
0
                                .find_missing_blobs(request)
95
0
                                .await
96
0
                                .err_tip(|| "in find_missing_blobs")?
97
0
                                .into_inner();
98
0
                            let duration = Instant::now().checked_duration_since(start).unwrap();
99
100
                            // info!("response duration={duration:?} res={:?}", res);
101
0
                            local_timings.lock().await.push(duration);
102
                        }
103
0
                        Ok::<(), Error>(())
104
0
                    })
105
0
                })
106
0
                .collect();
107
0
            for thread in spawns {
108
0
                let res = thread.await;
109
0
                res.err_tip(|| "with spawn")??;
110
            }
111
0
            let avg = Duration::from_secs_f64({
112
0
                let locked = timings.lock().await;
113
0
                locked.iter().map(Duration::as_secs_f64).sum::<f64>() / locked.len() as f64
114
            });
115
0
            info!(?avg, "avg");
116
0
            Ok::<(), Error>(())
117
0
        })?;
118
0
    Ok(())
119
0
}