Skip to content

Commit

Permalink
perf(rsjudge-runner): ⚡️ pass less data in ResourceUsage type
Browse files Browse the repository at this point in the history
  • Loading branch information
Jisu-Woniu committed Jun 7, 2024
1 parent d272d1e commit 8852a96
Show file tree
Hide file tree
Showing 4 changed files with 48 additions and 29 deletions.
20 changes: 16 additions & 4 deletions crates/rsjudge-runner/examples/rusage_test.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use std::{path::PathBuf, time::Duration};

use anyhow::bail;
use rsjudge_runner::utils::resources::{rusage::WaitForResourceUsage, RunWithResourceLimit};
use rsjudge_traits::resource::ResourceLimit;
use tokio::{process::Command, time::Instant};
Expand All @@ -14,30 +15,41 @@ async fn main() -> anyhow::Result<()> {
let spin_lock = examples.join("spin_lock");
eprintln!("Starting spin_lock with CPU time limit of 1s, wall time limit 2s:");
let start_time = Instant::now();
let _ = Command::new(spin_lock)
let Some((status, rusage)) = Command::new(spin_lock)
.spawn_with_resource_limit(ResourceLimit::new(
Some(Duration::from_secs(1)),
Some(Duration::from_secs(2)),
None,
None,
))?
.wait_for_resource_usage()
.await;
.await?
else {
bail!("Failed to get resource usage");
};

dbg!(start_time.elapsed());
dbg!(status);
dbg!(rusage.cpu_time());
let sleep = examples.join("sleep");
eprintln!("Starting sleep with CPU time limit of 1s, wall time limit 2s:");
let start_time = Instant::now();
let _ = Command::new(sleep)
let Some((status, rusage)) = Command::new(sleep)
.spawn_with_resource_limit(ResourceLimit::new(
Some(Duration::from_secs(1)),
Some(Duration::from_secs(2)),
None,
None,
))?
.wait_for_resource_usage()
.await;
.await
.map_err(|err| dbg!(err))?
else {
bail!("Failed to get resource usage");
};

dbg!(start_time.elapsed());
dbg!(status);
dbg!(rusage.cpu_time());
Ok(())
}
7 changes: 6 additions & 1 deletion crates/rsjudge-runner/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ use capctl::Cap;
use log::error;
use thiserror::Error;

use crate::utils::resources::rusage::ResourceUsage;

#[derive(Debug, Error)]
pub enum Error {
/// Capabilities required but not set.
Expand All @@ -21,7 +23,10 @@ pub enum Error {
Io(std::io::Error),

#[error("Time limit exceeded")]
TimeLimitExceeded,
TimeLimitExceeded(
#[cfg(debug_assertions)] Option<(ExitStatus, ResourceUsage)>,
#[cfg(not(debug_assertions))] (),
),

#[error("Child process has exited with status: {0:?}")]
ChildExited(ExitStatus),
Expand Down
2 changes: 1 addition & 1 deletion crates/rsjudge-runner/src/utils/resources/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,6 @@ mod tests {
dbg!(elapsed);

assert!(elapsed < Duration::from_secs_f32(1.52));
assert!(matches!(error, Error::TimeLimitExceeded));
assert!(matches!(error, Error::TimeLimitExceeded(_)));
}
}
48 changes: 25 additions & 23 deletions crates/rsjudge-runner/src/utils/resources/rusage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,43 +23,40 @@ use tokio_util::sync::CancellationToken;

use crate::{utils::resources::ChildWithTimeout, Error, Result};

/// Resource usage of a process.
///
/// Works like [`rusage`], but smaller to reduce the size of the struct.
#[derive(Debug, Clone, Copy)]
pub struct ResourceUsage(rusage);

impl AsRef<rusage> for ResourceUsage {
fn as_ref(&self) -> &rusage {
&self.0
}
}

impl AsMut<rusage> for ResourceUsage {
fn as_mut(&mut self) -> &mut rusage {
&mut self.0
}
pub struct ResourceUsage {
cpu_time: Duration,
ram_usage: u64,
}

impl From<rusage> for ResourceUsage {
fn from(rusage: rusage) -> Self {
Self(rusage)
Self {
cpu_time: Duration::new(
rusage.ru_utime.tv_sec as u64,
rusage.ru_utime.tv_usec as u32 * 1000,
) + Duration::new(
rusage.ru_stime.tv_sec as u64,
rusage.ru_stime.tv_usec as u32 * 1000,
),
ram_usage: rusage.ru_maxrss as u64,
}
}
}

impl ResourceUsage {
#[must_use]
pub fn cpu_time(&self) -> Duration {
Duration::new(
self.0.ru_utime.tv_sec as u64,
self.0.ru_utime.tv_usec as u32 * 1000,
) + Duration::new(
self.0.ru_stime.tv_sec as u64,
self.0.ru_stime.tv_usec as u32 * 1000,
)
self.cpu_time
}

/// Get the maximum RAM usage (resident set size) in bytes.
#[must_use]
pub fn ram_usage(&self) -> u64 {
self.0.ru_maxrss as u64
self.ram_usage
}
}
#[async_trait]
Expand Down Expand Up @@ -103,7 +100,7 @@ pub fn wait4<P: Into<Option<Pid>>>(
0 => None,
_pid => Some((
ExitStatusExt::from_raw(status),
ResourceUsage(unsafe { rusage.assume_init() }),
ResourceUsage::from(unsafe { rusage.assume_init() }),
)),
})
}
Expand Down Expand Up @@ -160,7 +157,12 @@ impl WaitForResourceUsage for ChildWithTimeout {
res = self.child.wait_for_resource_usage() => return res,
() = child_token.cancelled() => {
self.child.start_kill()?;
return Err(Error::TimeLimitExceeded);
return Err(Error::TimeLimitExceeded(
#[cfg(debug_assertions)]
self.child.wait_for_resource_usage().await?,
#[cfg(not(debug_assertions))]
(),
));
}
}
}
Expand Down

0 comments on commit 8852a96

Please sign in to comment.