Skip to content

Commit ad1461e

Browse files
committed
Auto merge of #41575 - alexcrichton:android-qemu-server, r=TimNN
travis: Parallelize tests on Android Currently our slowest test suite on android, run-pass, takes over 5 times longer than the x86_64 component (~400 -> ~2200s). Typically QEMU emulation does indeed add overhead, but not 5x for this kind of workload. One of the slowest parts of the Android process is that *compilation* happens serially. Tests themselves need to run single-threaded on the emulator (due to how the test harness works) and this forces the compiles themselves to be single threaded. Now Travis gives us more than one core per machine, so it'd be much better if we could take advantage of them! The emulator itself is still fundamentally single-threaded, but we should see a nice speedup by sending binaries for it to run much more quickly. It turns out that we've already got all the toos to do this in-tree. The qemu-test-{server,client} that are in use for the ARM Linux testing are a perfect match for the Android emulator. This commit migrates the custom adb management code in compiletest/rustbuild to the same qemu-test-{server,client} implementation that ARM Linux uses. This allows us to lift the parallelism restriction on the compiletest test suites, namely run-pass. Consequently although we'll still basically run the tests themselves in single threaded mode we'll be able to compile all of them in parallel, keeping the pipeline much more full hopefully and using more cores for the work at hand. Additionally the architecture here should be a bit speedier as it should have less overhead than adb which is a whole new process on both the host and the emulator! Locally on an 8 core machine I've seen the run-pass test suite speed up from taking nearly an hour to only taking 5 minutes. I don't think we'll see quite a drastic speedup on Travis but I'm hoping this change can place the Android tests well below 2 hours instead of just above 2 hours. Because the client/server here are now repurposed for more than just QEMU, they've been renamed to `remote-test-{server,client}`. Note that this PR does not currently modify how debuginfo tests are executed on Android. While parallelizable it wouldn't be quite as easy, so that's left to another day. Thankfull that test suite is much smaller than the run-pass test suite.
2 parents 2971d49 + 7bc2cbf commit ad1461e

File tree

14 files changed

+243
-467
lines changed

14 files changed

+243
-467
lines changed

src/Cargo.lock

+8-8
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/Cargo.toml

+2-2
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@ members = [
1111
"tools/rustbook",
1212
"tools/tidy",
1313
"tools/build-manifest",
14-
"tools/qemu-test-client",
15-
"tools/qemu-test-server",
14+
"tools/remote-test-client",
15+
"tools/remote-test-server",
1616
]
1717

1818
# Curiously, compiletest will segfault if compiled with opt-level=3 on 64-bit

src/bootstrap/check.rs

+27-113
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ use {Build, Compiler, Mode};
2828
use dist;
2929
use util::{self, dylib_path, dylib_path_var, exe};
3030

31-
const ADB_TEST_DIR: &'static str = "/data/tmp";
31+
const ADB_TEST_DIR: &'static str = "/data/tmp/work";
3232

3333
/// The two modes of the test runner; tests or benchmarks.
3434
#[derive(Copy, Clone)]
@@ -243,10 +243,10 @@ pub fn compiletest(build: &Build,
243243
.arg("--llvm-cxxflags").arg("");
244244
}
245245

246-
if build.qemu_rootfs(target).is_some() {
247-
cmd.arg("--qemu-test-client")
246+
if build.remote_tested(target) {
247+
cmd.arg("--remote-test-client")
248248
.arg(build.tool(&Compiler::new(0, &build.config.build),
249-
"qemu-test-client"));
249+
"remote-test-client"));
250250
}
251251

252252
// Running a C compiler on MSVC requires a few env vars to be set, to be
@@ -445,9 +445,7 @@ pub fn krate(build: &Build,
445445
dylib_path.insert(0, build.sysroot_libdir(&compiler, target));
446446
cargo.env(dylib_path_var(), env::join_paths(&dylib_path).unwrap());
447447

448-
if target.contains("android") ||
449-
target.contains("emscripten") ||
450-
build.qemu_rootfs(target).is_some() {
448+
if target.contains("emscripten") || build.remote_tested(target) {
451449
cargo.arg("--no-run");
452450
}
453451

@@ -459,75 +457,24 @@ pub fn krate(build: &Build,
459457

460458
let _time = util::timeit();
461459

462-
if target.contains("android") {
463-
build.run(&mut cargo);
464-
krate_android(build, &compiler, target, mode);
465-
} else if target.contains("emscripten") {
460+
if target.contains("emscripten") {
466461
build.run(&mut cargo);
467462
krate_emscripten(build, &compiler, target, mode);
468-
} else if build.qemu_rootfs(target).is_some() {
463+
} else if build.remote_tested(target) {
469464
build.run(&mut cargo);
470-
krate_qemu(build, &compiler, target, mode);
465+
krate_remote(build, &compiler, target, mode);
471466
} else {
472467
cargo.args(&build.flags.cmd.test_args());
473468
build.run(&mut cargo);
474469
}
475470
}
476471

477-
fn krate_android(build: &Build,
478-
compiler: &Compiler,
479-
target: &str,
480-
mode: Mode) {
481-
let mut tests = Vec::new();
482-
let out_dir = build.cargo_out(compiler, mode, target);
483-
find_tests(&out_dir, target, &mut tests);
484-
find_tests(&out_dir.join("deps"), target, &mut tests);
485-
486-
for test in tests {
487-
build.run(Command::new("adb").arg("push").arg(&test).arg(ADB_TEST_DIR));
488-
489-
let test_file_name = test.file_name().unwrap().to_string_lossy();
490-
let log = format!("{}/check-stage{}-T-{}-H-{}-{}.log",
491-
ADB_TEST_DIR,
492-
compiler.stage,
493-
target,
494-
compiler.host,
495-
test_file_name);
496-
let quiet = if build.config.quiet_tests { "--quiet" } else { "" };
497-
let program = format!("(cd {dir}; \
498-
LD_LIBRARY_PATH=./{target} ./{test} \
499-
--logfile {log} \
500-
{quiet} \
501-
{args})",
502-
dir = ADB_TEST_DIR,
503-
target = target,
504-
test = test_file_name,
505-
log = log,
506-
quiet = quiet,
507-
args = build.flags.cmd.test_args().join(" "));
508-
509-
let output = output(Command::new("adb").arg("shell").arg(&program));
510-
println!("{}", output);
511-
512-
t!(fs::create_dir_all(build.out.join("tmp")));
513-
build.run(Command::new("adb")
514-
.arg("pull")
515-
.arg(&log)
516-
.arg(build.out.join("tmp")));
517-
build.run(Command::new("adb").arg("shell").arg("rm").arg(&log));
518-
if !output.contains("result: ok") {
519-
panic!("some tests failed");
520-
}
521-
}
522-
}
523-
524472
fn krate_emscripten(build: &Build,
525473
compiler: &Compiler,
526474
target: &str,
527475
mode: Mode) {
528476
let mut tests = Vec::new();
529477
let out_dir = build.cargo_out(compiler, mode, target);
530-
find_tests(&out_dir, target, &mut tests);
531478
find_tests(&out_dir.join("deps"), target, &mut tests);
532479

533480
for test in tests {
@@ -543,17 +490,16 @@ fn krate_emscripten(build: &Build,
543490
}
544491
}
545492

546-
fn krate_qemu(build: &Build,
547-
compiler: &Compiler,
548-
target: &str,
549-
mode: Mode) {
493+
fn krate_remote(build: &Build,
494+
compiler: &Compiler,
495+
target: &str,
496+
mode: Mode) {
550497
let mut tests = Vec::new();
551498
let out_dir = build.cargo_out(compiler, mode, target);
552-
find_tests(&out_dir, target, &mut tests);
553499
find_tests(&out_dir.join("deps"), target, &mut tests);
554500

555501
let tool = build.tool(&Compiler::new(0, &build.config.build),
556-
"qemu-test-client");
502+
"remote-test-client");
557503
for test in tests {
558504
let mut cmd = Command::new(&tool);
559505
cmd.arg("run")
@@ -566,7 +512,6 @@ fn krate_qemu(build: &Build,
566512
}
567513
}
568514

569-
570515
fn find_tests(dir: &Path,
571516
target: &str,
572517
dst: &mut Vec<PathBuf>) {
@@ -585,59 +530,28 @@ fn find_tests(dir: &Path,
585530
}
586531

587532
pub fn emulator_copy_libs(build: &Build, compiler: &Compiler, target: &str) {
588-
if target.contains("android") {
589-
android_copy_libs(build, compiler, target)
590-
} else if let Some(s) = build.qemu_rootfs(target) {
591-
qemu_copy_libs(build, compiler, target, s)
592-
}
593-
}
594-
595-
fn android_copy_libs(build: &Build, compiler: &Compiler, target: &str) {
596-
println!("Android copy libs to emulator ({})", target);
597-
build.run(Command::new("adb").arg("wait-for-device"));
598-
build.run(Command::new("adb").arg("remount"));
599-
build.run(Command::new("adb").args(&["shell", "rm", "-r", ADB_TEST_DIR]));
600-
build.run(Command::new("adb").args(&["shell", "mkdir", ADB_TEST_DIR]));
601-
build.run(Command::new("adb")
602-
.arg("push")
603-
.arg(build.src.join("src/etc/adb_run_wrapper.sh"))
604-
.arg(ADB_TEST_DIR));
605-
606-
let target_dir = format!("{}/{}", ADB_TEST_DIR, target);
607-
build.run(Command::new("adb").args(&["shell", "mkdir", &target_dir]));
608-
609-
for f in t!(build.sysroot_libdir(compiler, target).read_dir()) {
610-
let f = t!(f);
611-
let name = f.file_name().into_string().unwrap();
612-
if util::is_dylib(&name) {
613-
build.run(Command::new("adb")
614-
.arg("push")
615-
.arg(f.path())
616-
.arg(&target_dir));
617-
}
533+
if !build.remote_tested(target) {
534+
return
618535
}
619-
}
620536

621-
fn qemu_copy_libs(build: &Build,
622-
compiler: &Compiler,
623-
target: &str,
624-
rootfs: &Path) {
625-
println!("QEMU copy libs to emulator ({})", target);
626-
assert!(target.starts_with("arm"), "only works with arm for now");
537+
println!("REMOTE copy libs to emulator ({})", target);
627538
t!(fs::create_dir_all(build.out.join("tmp")));
628539

629-
// Copy our freshly compiled test server over to the rootfs
630540
let server = build.cargo_out(compiler, Mode::Tool, target)
631-
.join(exe("qemu-test-server", target));
632-
t!(fs::copy(&server, rootfs.join("testd")));
541+
.join(exe("remote-test-server", target));
633542

634543
// Spawn the emulator and wait for it to come online
635544
let tool = build.tool(&Compiler::new(0, &build.config.build),
636-
"qemu-test-client");
637-
build.run(Command::new(&tool)
638-
.arg("spawn-emulator")
639-
.arg(rootfs)
640-
.arg(build.out.join("tmp")));
545+
"remote-test-client");
546+
let mut cmd = Command::new(&tool);
547+
cmd.arg("spawn-emulator")
548+
.arg(target)
549+
.arg(&server)
550+
.arg(build.out.join("tmp"));
551+
if let Some(rootfs) = build.qemu_rootfs(target) {
552+
cmd.arg(rootfs);
553+
}
554+
build.run(&mut cmd);
641555

642556
// Push all our dylibs to the emulator
643557
for f in t!(build.sysroot_libdir(compiler, target).read_dir()) {

src/bootstrap/lib.rs

+6
Original file line numberDiff line numberDiff line change
@@ -945,6 +945,12 @@ impl Build {
945945
.map(|p| &**p)
946946
}
947947

948+
/// Returns whether the target will be tested using the `remote-test-client`
949+
/// and `remote-test-server` binaries.
950+
fn remote_tested(&self, target: &str) -> bool {
951+
self.qemu_rootfs(target).is_some() || target.contains("android")
952+
}
953+
948954
/// Returns the root of the "rootfs" image that this target will be using,
949955
/// if one was configured.
950956
///

src/bootstrap/step.rs

+8-8
Original file line numberDiff line numberDiff line change
@@ -513,15 +513,15 @@ pub fn build_rules<'a>(build: &'a Build) -> Rules {
513513
rules.test("emulator-copy-libs", "path/to/nowhere")
514514
.dep(|s| s.name("libtest"))
515515
.dep(move |s| {
516-
if build.qemu_rootfs(s.target).is_some() {
517-
s.name("tool-qemu-test-client").target(s.host).stage(0)
516+
if build.remote_tested(s.target) {
517+
s.name("tool-remote-test-client").target(s.host).stage(0)
518518
} else {
519519
Step::noop()
520520
}
521521
})
522522
.dep(move |s| {
523-
if build.qemu_rootfs(s.target).is_some() {
524-
s.name("tool-qemu-test-server")
523+
if build.remote_tested(s.target) {
524+
s.name("tool-remote-test-server")
525525
} else {
526526
Step::noop()
527527
}
@@ -566,14 +566,14 @@ pub fn build_rules<'a>(build: &'a Build) -> Rules {
566566
.dep(|s| s.name("maybe-clean-tools"))
567567
.dep(|s| s.name("libstd-tool"))
568568
.run(move |s| compile::tool(build, s.stage, s.target, "build-manifest"));
569-
rules.build("tool-qemu-test-server", "src/tools/qemu-test-server")
569+
rules.build("tool-remote-test-server", "src/tools/remote-test-server")
570570
.dep(|s| s.name("maybe-clean-tools"))
571571
.dep(|s| s.name("libstd-tool"))
572-
.run(move |s| compile::tool(build, s.stage, s.target, "qemu-test-server"));
573-
rules.build("tool-qemu-test-client", "src/tools/qemu-test-client")
572+
.run(move |s| compile::tool(build, s.stage, s.target, "remote-test-server"));
573+
rules.build("tool-remote-test-client", "src/tools/remote-test-client")
574574
.dep(|s| s.name("maybe-clean-tools"))
575575
.dep(|s| s.name("libstd-tool"))
576-
.run(move |s| compile::tool(build, s.stage, s.target, "qemu-test-client"));
576+
.run(move |s| compile::tool(build, s.stage, s.target, "remote-test-client"));
577577
rules.build("tool-cargo", "cargo")
578578
.dep(|s| s.name("maybe-clean-tools"))
579579
.dep(|s| s.name("libstd-tool"))

src/etc/adb_run_wrapper.sh

-35
This file was deleted.

src/test/run-pass/vector-sort-panic-safe.rs

+12-1
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,11 @@
1313
#![feature(rand)]
1414
#![feature(const_fn)]
1515

16-
use std::sync::atomic::{AtomicUsize, Ordering};
1716
use std::__rand::{thread_rng, Rng};
17+
use std::panic;
18+
use std::sync::atomic::{AtomicUsize, Ordering};
1819
use std::thread;
20+
use std::cell::Cell;
1921

2022
const MAX_LEN: usize = 80;
2123

@@ -76,6 +78,7 @@ fn test(input: &[DropCounter]) {
7678
let mut panic_countdown = panic_countdown;
7779
v.sort_by(|a, b| {
7880
if panic_countdown == 0 {
81+
SILENCE_PANIC.with(|s| s.set(true));
7982
panic!();
8083
}
8184
panic_countdown -= 1;
@@ -94,7 +97,15 @@ fn test(input: &[DropCounter]) {
9497
}
9598
}
9699

100+
thread_local!(static SILENCE_PANIC: Cell<bool> = Cell::new(false));
101+
97102
fn main() {
103+
let prev = panic::take_hook();
104+
panic::set_hook(Box::new(move |info| {
105+
if !SILENCE_PANIC.with(|s| s.get()) {
106+
prev(info);
107+
}
108+
}));
98109
for len in (1..20).chain(70..MAX_LEN) {
99110
// Test on a random array.
100111
let mut rng = thread_rng();

src/tools/compiletest/src/common.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -185,8 +185,8 @@ pub struct Config {
185185
// Print one character per test instead of one line
186186
pub quiet: bool,
187187

188-
// where to find the qemu test client process, if we're using it
189-
pub qemu_test_client: Option<PathBuf>,
188+
// where to find the remote test client process, if we're using it
189+
pub remote_test_client: Option<PathBuf>,
190190

191191
// Configuration for various run-make tests frobbing things like C compilers
192192
// or querying about various LLVM component information.

0 commit comments

Comments
 (0)