nixl_sys/
xfer.rs

1// SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
2// SPDX-License-Identifier: Apache-2.0
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15
16use super::*;
17
18#[repr(C)]
19#[derive(Debug, Copy, Clone, PartialEq)]
20pub enum XferOp {
21    Read = 0,
22    Write = 1,
23}
24
25/// Methods used for estimating transfer costs
26#[repr(C)]
27#[derive(Debug, Copy, Clone, PartialEq)]
28pub enum CostMethod {
29    AnalyticalBackend = 0,
30    Unknown = 1,
31}
32
33impl From<u32> for CostMethod {
34    fn from(value: u32) -> Self {
35        match value {
36            0 => CostMethod::AnalyticalBackend,
37            _ => CostMethod::Unknown,
38        }
39    }
40}
41
42/// A handle to a transfer request
43pub struct XferRequest {
44    inner: NonNull<bindings::nixl_capi_xfer_req_s>,
45    agent: Arc<RwLock<AgentInner>>,
46}
47
48impl XferRequest {
49    pub(crate) fn new(
50        inner: NonNull<bindings::nixl_capi_xfer_req_s>,
51        agent: Arc<RwLock<AgentInner>>,
52    ) -> Self {
53        Self { inner, agent }
54    }
55
56    pub(crate) fn handle(&self) -> *mut bindings::nixl_capi_xfer_req_s {
57        self.inner.as_ptr()
58    }
59
60    /// Gets telemetry data for this transfer request
61    ///
62    /// # Returns
63    /// Transfer telemetry data containing timing and performance metrics
64    ///
65    /// # Errors
66    /// * `NoTelemetry`  - If telemetry is not enabled or transfer is not complete
67    /// * `InvalidParam` - If the request handle is invalid
68    /// * `BackendError` - If there was an error retrieving telemetry data
69    pub fn get_telemetry(&self) -> Result<XferTelemetry, NixlError> {
70        tracing::trace!("Getting transfer telemetry from request");
71        let mut telemetry = bindings::nixl_capi_xfer_telemetry_s {
72            start_time_us: 0,
73            post_duration_us: 0,
74            xfer_duration_us: 0,
75            total_bytes: 0,
76            desc_count: 0,
77        };
78
79        let status = unsafe {
80            nixl_capi_get_xfer_telemetry(
81                self.agent.write().unwrap().handle.as_ptr(),
82                self.handle(),
83                &mut telemetry,
84            )
85        };
86
87        match status {
88            NIXL_CAPI_SUCCESS => {
89                tracing::trace!("Successfully retrieved transfer telemetry from request");
90                Ok(XferTelemetry {
91                    start_time_us: telemetry.start_time_us,
92                    post_duration_us: telemetry.post_duration_us,
93                    xfer_duration_us: telemetry.xfer_duration_us,
94                    total_bytes: telemetry.total_bytes,
95                    desc_count: telemetry.desc_count,
96                })
97            },
98            NIXL_CAPI_IN_PROG => {
99                tracing::error!(error = "transfer_not_complete", "Transfer not complete");
100                Err(NixlError::NoTelemetry)
101            },
102            NIXL_CAPI_ERROR_NO_TELEMETRY => {
103                tracing::error!(error = "telemetry_not_enabled", "Telemetry not enabled");
104                Err(NixlError::NoTelemetry)
105            },
106            _ => {
107                tracing::error!(error = "backend_error", "Failed to get transfer telemetry from request");
108                Err(NixlError::BackendError)
109            }
110        }
111    }
112}
113
114// SAFETY: XferRequest can be sent between threads safely
115unsafe impl Send for XferRequest {}
116// SAFETY: XferRequest can be shared between threads safely
117unsafe impl Sync for XferRequest {}
118
119impl Drop for XferRequest {
120    fn drop(&mut self) {
121        unsafe {
122            bindings::nixl_capi_release_xfer_req(
123                self.agent.write().unwrap().handle.as_ptr(),
124                self.inner.as_ptr(),
125            );
126
127            bindings::nixl_capi_destroy_xfer_req(self.inner.as_ptr());
128        }
129    }
130}