Skip to content

Commit 55b5201

Browse files
committed
Get rustc-perf compiling on Windows
1 parent ecb5dfe commit 55b5201

File tree

6 files changed

+222
-67
lines changed

6 files changed

+222
-67
lines changed

Cargo.lock

Lines changed: 16 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

collector/Cargo.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,10 @@ jobserver = "0.1.21"
3030
crossbeam-utils = "0.7"
3131
snap = "1"
3232

33+
[target.'cfg(windows)'.dependencies]
34+
miow = "0.3"
35+
winapi = { version = "0.3", features = ["winerror"] }
36+
3337
[[bin]]
3438
name = "collector"
3539
path = "src/main.rs"

collector/src/read2.rs

Lines changed: 187 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -1,74 +1,201 @@
11
// This is copied from
22
// https://github.com/rust-lang/rust/blob/master/src/tools/compiletest/src/read2.rs
33
// and falls under the MIT or Apache 2.0 licenses.
4+
pub use self::imp::read2;
45

5-
use std::io;
6-
use std::io::prelude::*;
7-
use std::mem;
8-
use std::os::unix::prelude::*;
9-
use std::process::{ChildStderr, ChildStdout};
10-
11-
pub fn read2(
12-
mut out_pipe: ChildStdout,
13-
mut err_pipe: ChildStderr,
14-
data: &mut dyn FnMut(bool, &mut Vec<u8>, bool),
15-
) -> io::Result<()> {
16-
unsafe {
17-
libc::fcntl(out_pipe.as_raw_fd(), libc::F_SETFL, libc::O_NONBLOCK);
18-
libc::fcntl(err_pipe.as_raw_fd(), libc::F_SETFL, libc::O_NONBLOCK);
6+
#[cfg(not(any(unix, windows)))]
7+
mod imp {
8+
use std::io::{self, Read};
9+
use std::process::{ChildStderr, ChildStdout};
10+
11+
pub fn read2(
12+
out_pipe: ChildStdout,
13+
err_pipe: ChildStderr,
14+
data: &mut dyn FnMut(bool, &mut Vec<u8>, bool),
15+
) -> io::Result<()> {
16+
let mut buffer = Vec::new();
17+
out_pipe.read_to_end(&mut buffer)?;
18+
data(true, &mut buffer, true);
19+
buffer.clear();
20+
err_pipe.read_to_end(&mut buffer)?;
21+
data(false, &mut buffer, true);
22+
Ok(())
1923
}
24+
}
25+
26+
#[cfg(unix)]
27+
mod imp {
28+
use std::io;
29+
use std::io::prelude::*;
30+
use std::mem;
31+
use std::os::unix::prelude::*;
32+
use std::process::{ChildStderr, ChildStdout};
33+
34+
pub fn read2(
35+
mut out_pipe: ChildStdout,
36+
mut err_pipe: ChildStderr,
37+
data: &mut dyn FnMut(bool, &mut Vec<u8>, bool),
38+
) -> io::Result<()> {
39+
unsafe {
40+
libc::fcntl(out_pipe.as_raw_fd(), libc::F_SETFL, libc::O_NONBLOCK);
41+
libc::fcntl(err_pipe.as_raw_fd(), libc::F_SETFL, libc::O_NONBLOCK);
42+
}
43+
44+
let mut out_done = false;
45+
let mut err_done = false;
46+
let mut out = Vec::new();
47+
let mut err = Vec::new();
48+
49+
let mut fds: [libc::pollfd; 2] = unsafe { mem::zeroed() };
50+
fds[0].fd = out_pipe.as_raw_fd();
51+
fds[0].events = libc::POLLIN;
52+
fds[1].fd = err_pipe.as_raw_fd();
53+
fds[1].events = libc::POLLIN;
54+
let mut nfds = 2;
55+
let mut errfd = 1;
56+
57+
while nfds > 0 {
58+
// wait for either pipe to become readable using `select`
59+
let r = unsafe { libc::poll(fds.as_mut_ptr(), nfds, -1) };
60+
if r == -1 {
61+
let err = io::Error::last_os_error();
62+
if err.kind() == io::ErrorKind::Interrupted {
63+
continue;
64+
}
65+
return Err(err);
66+
}
2067

21-
let mut out_done = false;
22-
let mut err_done = false;
23-
let mut out = Vec::new();
24-
let mut err = Vec::new();
25-
26-
let mut fds: [libc::pollfd; 2] = unsafe { mem::zeroed() };
27-
fds[0].fd = out_pipe.as_raw_fd();
28-
fds[0].events = libc::POLLIN;
29-
fds[1].fd = err_pipe.as_raw_fd();
30-
fds[1].events = libc::POLLIN;
31-
let mut nfds = 2;
32-
let mut errfd = 1;
33-
34-
while nfds > 0 {
35-
// wait for either pipe to become readable using `select`
36-
let r = unsafe { libc::poll(fds.as_mut_ptr(), nfds, -1) };
37-
if r == -1 {
38-
let err = io::Error::last_os_error();
39-
if err.kind() == io::ErrorKind::Interrupted {
40-
continue;
68+
// Read as much as we can from each pipe, ignoring EWOULDBLOCK or
69+
// EAGAIN. If we hit EOF, then this will happen because the underlying
70+
// reader will return Ok(0), in which case we'll see `Ok` ourselves. In
71+
// this case we flip the other fd back into blocking mode and read
72+
// whatever's leftover on that file descriptor.
73+
let handle = |res: io::Result<_>| match res {
74+
Ok(_) => Ok(true),
75+
Err(e) => {
76+
if e.kind() == io::ErrorKind::WouldBlock {
77+
Ok(false)
78+
} else {
79+
Err(e)
80+
}
81+
}
82+
};
83+
if !err_done && fds[errfd].revents != 0 && handle(err_pipe.read_to_end(&mut err))? {
84+
err_done = true;
85+
nfds -= 1;
86+
}
87+
data(false, &mut err, err_done);
88+
if !out_done && fds[0].revents != 0 && handle(out_pipe.read_to_end(&mut out))? {
89+
out_done = true;
90+
fds[0].fd = err_pipe.as_raw_fd();
91+
errfd = 0;
92+
nfds -= 1;
4193
}
42-
return Err(err);
94+
data(true, &mut out, out_done);
4395
}
96+
Ok(())
97+
}
98+
}
99+
100+
#[cfg(windows)]
101+
mod imp {
102+
use std::io;
103+
use std::os::windows::prelude::*;
104+
use std::process::{ChildStderr, ChildStdout};
105+
use std::slice;
106+
107+
use miow::iocp::{CompletionPort, CompletionStatus};
108+
use miow::pipe::NamedPipe;
109+
use miow::Overlapped;
110+
use winapi::shared::winerror::ERROR_BROKEN_PIPE;
111+
112+
struct Pipe<'a> {
113+
dst: &'a mut Vec<u8>,
114+
overlapped: Overlapped,
115+
pipe: NamedPipe,
116+
done: bool,
117+
}
118+
119+
pub fn read2(
120+
out_pipe: ChildStdout,
121+
err_pipe: ChildStderr,
122+
data: &mut dyn FnMut(bool, &mut Vec<u8>, bool),
123+
) -> io::Result<()> {
124+
let mut out = Vec::new();
125+
let mut err = Vec::new();
126+
127+
let port = CompletionPort::new(1)?;
128+
port.add_handle(0, &out_pipe)?;
129+
port.add_handle(1, &err_pipe)?;
44130

45-
// Read as much as we can from each pipe, ignoring EWOULDBLOCK or
46-
// EAGAIN. If we hit EOF, then this will happen because the underlying
47-
// reader will return Ok(0), in which case we'll see `Ok` ourselves. In
48-
// this case we flip the other fd back into blocking mode and read
49-
// whatever's leftover on that file descriptor.
50-
let handle = |res: io::Result<_>| match res {
51-
Ok(_) => Ok(true),
52-
Err(e) => {
53-
if e.kind() == io::ErrorKind::WouldBlock {
54-
Ok(false)
55-
} else {
56-
Err(e)
131+
unsafe {
132+
let mut out_pipe = Pipe::new(out_pipe, &mut out);
133+
let mut err_pipe = Pipe::new(err_pipe, &mut err);
134+
135+
out_pipe.read()?;
136+
err_pipe.read()?;
137+
138+
let mut status = [CompletionStatus::zero(), CompletionStatus::zero()];
139+
140+
while !out_pipe.done || !err_pipe.done {
141+
for status in port.get_many(&mut status, None)? {
142+
if status.token() == 0 {
143+
out_pipe.complete(status);
144+
data(true, out_pipe.dst, out_pipe.done);
145+
out_pipe.read()?;
146+
} else {
147+
err_pipe.complete(status);
148+
data(false, err_pipe.dst, err_pipe.done);
149+
err_pipe.read()?;
150+
}
57151
}
58152
}
59-
};
60-
if !err_done && fds[errfd].revents != 0 && handle(err_pipe.read_to_end(&mut err))? {
61-
err_done = true;
62-
nfds -= 1;
153+
154+
Ok(())
63155
}
64-
data(false, &mut err, err_done);
65-
if !out_done && fds[0].revents != 0 && handle(out_pipe.read_to_end(&mut out))? {
66-
out_done = true;
67-
fds[0].fd = err_pipe.as_raw_fd();
68-
errfd = 0;
69-
nfds -= 1;
156+
}
157+
158+
impl<'a> Pipe<'a> {
159+
unsafe fn new<P: IntoRawHandle>(p: P, dst: &'a mut Vec<u8>) -> Pipe<'a> {
160+
Pipe {
161+
dst: dst,
162+
pipe: NamedPipe::from_raw_handle(p.into_raw_handle()),
163+
overlapped: Overlapped::zero(),
164+
done: false,
165+
}
166+
}
167+
168+
unsafe fn read(&mut self) -> io::Result<()> {
169+
let dst = slice_to_end(self.dst);
170+
match self.pipe.read_overlapped(dst, self.overlapped.raw()) {
171+
Ok(_) => Ok(()),
172+
Err(e) => {
173+
if e.raw_os_error() == Some(ERROR_BROKEN_PIPE as i32) {
174+
self.done = true;
175+
Ok(())
176+
} else {
177+
Err(e)
178+
}
179+
}
180+
}
181+
}
182+
183+
unsafe fn complete(&mut self, status: &CompletionStatus) {
184+
let prev = self.dst.len();
185+
self.dst.set_len(prev + status.bytes_transferred() as usize);
186+
if status.bytes_transferred() == 0 {
187+
self.done = true;
188+
}
70189
}
71-
data(true, &mut out, out_done);
72190
}
73-
Ok(())
74-
}
191+
192+
unsafe fn slice_to_end(v: &mut Vec<u8>) -> &mut [u8] {
193+
if v.capacity() == 0 {
194+
v.reserve(16);
195+
}
196+
if v.capacity() == v.len() {
197+
v.reserve(1);
198+
}
199+
slice::from_raw_parts_mut(v.as_mut_ptr().offset(v.len() as isize), v.capacity() - v.len())
200+
}
201+
}

collector/src/rustc-fake.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -305,6 +305,14 @@ fn bash_command(tool: OsString, args: Vec<OsString>, redirect: &str) -> Command
305305
cmd
306306
}
307307

308+
#[cfg(windows)]
309+
fn exec(cmd: &mut Command) {
310+
let cmd_d = format!("{:?}", cmd);
311+
if let Err(e) = cmd.status() {
312+
panic!("failed to execute `{}`: {}", cmd_d, e);
313+
}
314+
}
315+
308316
#[cfg(unix)]
309317
fn exec(cmd: &mut Command) -> ! {
310318
use std::os::unix::prelude::*;

site/Cargo.toml

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,6 @@ regex = "1"
2626
lazy_static = "1"
2727
reqwest = { version = "0.10", features = ["json", "blocking"] }
2828
toml = "0.5"
29-
jemallocator = "0.3"
30-
jemalloc-ctl = "0.3"
3129
rust_team_data = { git = "https://github.com/rust-lang/team" }
3230
parking_lot = "0.10"
3331
snap = "1"
@@ -46,6 +44,10 @@ inferno = { version="0.10", default-features = false }
4644
mime = "0.3"
4745
prometheus = "0.11"
4846

47+
[target.'cfg(unix)'.dependencies]
48+
jemallocator = "0.3"
49+
jemalloc-ctl = "0.3"
50+
4951
[dependencies.collector]
5052
path = "../collector"
5153

site/src/main.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,15 @@ use site::load;
1515
use std::env;
1616
use std::sync::Arc;
1717

18+
#[cfg(unix)]
1819
#[global_allocator]
1920
static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;
2021

2122
#[tokio::main]
2223
async fn main() {
2324
env_logger::init();
25+
26+
#[cfg(unix)]
2427
let _ = jemalloc_ctl::background_thread::write(true);
2528

2629
let data: Arc<RwLock<Option<Arc<load::InputData>>>> = Arc::new(RwLock::new(None));

0 commit comments

Comments
 (0)