/
getrusage.rs
123 lines (111 loc) · 3.9 KB
/
getrusage.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
use std::{
ffi::CString,
fs::File,
io::{Read, Seek, SeekFrom, Write},
os::unix::prelude::FromRawFd,
process::Command,
time::Duration,
};
use super::{Measurement, Resource};
use anyhow::{Context, Result};
use nix::{
libc,
sys::{
memfd::{memfd_create, MemFdCreateFlag},
resource::{getrusage, UsageWho},
wait::waitpid,
},
unistd::{fork, ForkResult},
};
#[derive(Default)]
pub struct GetRusage {
memfd: Option<File>,
}
impl Resource for GetRusage {
fn init(&mut self) -> Result<()> {
// create shared memory
let shared_memfile =
memfd_create(&CString::new("shared")?, MemFdCreateFlag::MFD_ALLOW_SEALING)?;
self.memfd = Some(unsafe { File::from_raw_fd(shared_memfile) });
Ok(())
}
fn cleanup(&self) -> Result<()> {
Ok(())
}
fn spawn(&mut self, cmd: &mut Command, _day: u8, _part: u8) -> Result<Measurement> {
match unsafe { fork()? } {
ForkResult::Parent { child, .. } => {
waitpid(child, None)?;
}
ForkResult::Child => {
fn go(cmd: &mut Command) -> Result<Measurement> {
let mut process = cmd.spawn()?;
process.wait()?;
let rusage = getrusage(UsageWho::RUSAGE_CHILDREN)?;
// println!("{:?}", getrusage(UsageWho::RUSAGE_CHILDREN)?);
let timeval = rusage.user_time() + rusage.system_time();
let time = Duration::from_secs(timeval.tv_sec().try_into()?)
+ Duration::from_micros(timeval.tv_usec().try_into()?);
let memory = rusage.max_rss() * 1024;
// println!("{:?} {}", time, memory);
Ok(Measurement {
time,
memory: Some(memory.try_into()?),
})
}
let output = match go(cmd) {
Ok(measurement) => {
// println!("{:?}", measurement);
format!(
"({},{})",
measurement.time.as_nanos(),
measurement.memory.unwrap()
)
}
Err(e) => {
format!("Error: {}", e)
}
};
let output = output.as_bytes();
self.memfd
.as_mut()
.unwrap()
.set_len(output.len().try_into().unwrap())
.unwrap();
self.memfd
.as_mut()
.unwrap()
.seek(SeekFrom::Start(0))
.unwrap();
self.memfd.as_mut().unwrap().write_all(output).unwrap();
self.memfd
.as_mut()
.unwrap()
.seek(SeekFrom::Start(0))
.unwrap();
// self.memfd.as_ref().unwrap().sync_all().unwrap();
unsafe { libc::_exit(0) };
}
}
let mut buffer = String::new();
self.memfd.as_ref().unwrap().read_to_string(&mut buffer)?;
if buffer.starts_with("Error:") {
Err(anyhow::anyhow!("{}", buffer))
} else {
let split: Vec<_> = buffer
.strip_prefix('(')
.context("buffer not prefixed with (")?
.strip_suffix(')')
.context("buffer not suffixed with )")?
.split(',')
.collect();
// println!("{} {:?}", buffer, split);
let time = Duration::from_nanos(split[0].parse()?);
let memory = split[1].parse()?;
Ok(Measurement {
time,
memory: Some(memory),
})
}
}
}