valgrind test crate

This commit is contained in:
Folkert 2022-12-23 17:17:27 +01:00
parent 32e3f01a28
commit c97dbcfde1
No known key found for this signature in database
GPG key ID: 1F17F6FFD112B97C
11 changed files with 314 additions and 0 deletions

15
Cargo.lock generated
View file

@ -5280,6 +5280,21 @@ dependencies = [
"getrandom", "getrandom",
] ]
[[package]]
name = "valgrind"
version = "0.1.0"
dependencies = [
"bumpalo",
"cli_utils",
"roc_build",
"roc_cli",
"roc_load",
"roc_mono",
"roc_packaging",
"roc_reporting",
"target-lexicon",
]
[[package]] [[package]]
name = "valuable" name = "valuable"
version = "0.1.0" version = "0.1.0"

View file

@ -17,6 +17,7 @@ members = [
"crates/repl_wasm", "crates/repl_wasm",
"crates/repl_expect", "crates/repl_expect",
"crates/test_utils", "crates/test_utils",
"crates/valgrind",
"crates/tracing", "crates/tracing",
"crates/utils", "crates/utils",
"crates/docs", "crates/docs",

View file

@ -0,0 +1,20 @@
[package]
name = "valgrind"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
roc_cli = { path = "../cli" } # depend on CLI to prevent cyclic dependencies
cli_utils = { path = "../cli_utils" }
roc_build = { path = "../compiler/build" }
roc_mono = { path = "../compiler/mono" }
roc_load = { path = "../compiler/load" }
roc_reporting = { path = "../reporting" }
roc_packaging = { path = "../packaging" }
bumpalo.workspace = true
target-lexicon.workspace = true
[build-dependencies]
roc_cli = { path = "../cli" } # depend on CLI to prevent cyclic dependencies
cli_utils = { path = "../cli_utils" }

22
crates/valgrind/build.rs Normal file
View file

@ -0,0 +1,22 @@
fn main() {
// goal: build the platform, so tests can use `precompiled-platform=true`
// first, make sure the roc binary is up to data
// cli_utils::helpers::build_roc_bin_cached();
// next, we just compile one of our examples
let roc_path = std::path::Path::new("../../target/debug/roc");
let out = cli_utils::helpers::run_roc_with_stdin_and_env(
roc_path,
&["run", "tests/str_concat_1.roc"],
&[],
&[],
);
if !out.status.success() {
panic!(
"Building platform with `{:?}` failed!\n\n{}\n\n{}",
out.cmd_str, out.stdout, out.stderr
);
}
}

101
crates/valgrind/src/lib.rs Normal file
View file

@ -0,0 +1,101 @@
#![cfg(test)]
use std::{
ffi::OsStr,
path::{Path, PathBuf},
};
use roc_build::{
link::{LinkType, LinkingStrategy},
program::{CodeGenBackend, CodeGenOptions},
};
use roc_cli::build::{BuildOrdering, BuiltFile};
use roc_load::Threading;
use roc_mono::ir::OptLevel;
fn list_files(dir: &std::path::Path) -> std::vec::Vec<PathBuf> {
std::fs::read_dir(dir)
.unwrap()
.map(|f| PathBuf::from(f.unwrap().file_name()))
.collect::<std::vec::Vec<_>>()
}
fn run_example(app_module_path: impl AsRef<Path>) {
let app_module_path = app_module_path.as_ref();
let arena = bumpalo::Bump::new();
let triple = target_lexicon::Triple::host();
let code_gen_options = CodeGenOptions {
backend: CodeGenBackend::Llvm,
opt_level: OptLevel::Normal,
emit_debug_info: false,
};
let emit_timings = false;
let link_type = LinkType::Executable;
let linking_strategy = LinkingStrategy::Surgical;
let prebuilt_requested = true;
let wasm_dev_stack_bytes = None;
let roc_cache_dir = roc_packaging::cache::RocCacheDir::Disallowed;
let build_ordering = BuildOrdering::AlwaysBuild;
let res_binary_path = roc_cli::build::build_file(
&arena,
&triple,
PathBuf::from(app_module_path),
code_gen_options,
emit_timings,
link_type,
linking_strategy,
prebuilt_requested,
Threading::AtMost(2),
wasm_dev_stack_bytes,
roc_cache_dir,
build_ordering,
);
match res_binary_path {
Ok(BuiltFile {
binary_path,
problems,
total_time: _,
expect_metadata: _,
}) => {
if problems.exit_code() != 0 {
panic!("there are problems")
}
// If possible, report the generated executable name relative to the current dir.
let generated_filename = binary_path
.strip_prefix(std::env::current_dir().unwrap())
.unwrap_or(&binary_path)
.to_str()
.unwrap();
let (out, _raw_xml) =
cli_utils::helpers::run_with_valgrind([], &[generated_filename.to_string()]);
if !out.status.success() {
panic!(
"Running the application `{:?}` failed!\n\n{}\n\n{}",
out.cmd_str, out.stdout, out.stderr
);
}
}
Err(e) => panic!("{:?}", e),
}
}
#[test]
fn it_works() {
for dir_entry in std::fs::read_dir("tests").unwrap() {
let path = dir_entry.unwrap().path();
if path.extension() != Some(OsStr::new("roc")) {
continue;
}
run_example(path);
}
}

BIN
crates/valgrind/tests/rocLovesZig Executable file

Binary file not shown.

View file

@ -0,0 +1,8 @@
app "test"
packages { pf: "../zig-platform/main.roc" }
imports []
provides [main] to pf
main =
Str.withCapacity 42
|> Str.concat "foobar"

Binary file not shown.

View file

@ -0,0 +1,138 @@
const std = @import("std");
const builtin = @import("builtin");
const str = @import("str");
const RocStr = str.RocStr;
const testing = std.testing;
const expectEqual = testing.expectEqual;
const expect = testing.expect;
comptime {
// This is a workaround for https://github.com/ziglang/zig/issues/8218
// which is only necessary on macOS.
//
// Once that issue is fixed, we can undo the changes in
// 177cf12e0555147faa4d436e52fc15175c2c4ff0 and go back to passing
// -fcompiler-rt in link.rs instead of doing this. Note that this
// workaround is present in many host.zig files, so make sure to undo
// it everywhere!
if (builtin.os.tag == .macos) {
_ = @import("compiler_rt");
}
}
const Align = 2 * @alignOf(usize);
extern fn malloc(size: usize) callconv(.C) ?*align(Align) anyopaque;
extern fn realloc(c_ptr: [*]align(Align) u8, size: usize) callconv(.C) ?*anyopaque;
extern fn free(c_ptr: [*]align(Align) u8) callconv(.C) void;
extern fn memcpy(dst: [*]u8, src: [*]u8, size: usize) callconv(.C) void;
extern fn memset(dst: [*]u8, value: i32, size: usize) callconv(.C) void;
const DEBUG: bool = false;
export fn roc_alloc(size: usize, alignment: u32) callconv(.C) ?*anyopaque {
if (DEBUG) {
var ptr = malloc(size);
const stdout = std.io.getStdOut().writer();
stdout.print("alloc: {d} (alignment {d}, size {d})\n", .{ ptr, alignment, size }) catch unreachable;
return ptr;
} else {
return malloc(size);
}
}
export fn roc_realloc(c_ptr: *anyopaque, new_size: usize, old_size: usize, alignment: u32) callconv(.C) ?*anyopaque {
if (DEBUG) {
const stdout = std.io.getStdOut().writer();
stdout.print("realloc: {d} (alignment {d}, old_size {d})\n", .{ c_ptr, alignment, old_size }) catch unreachable;
}
return realloc(@alignCast(Align, @ptrCast([*]u8, c_ptr)), new_size);
}
export fn roc_dealloc(c_ptr: *anyopaque, alignment: u32) callconv(.C) void {
if (DEBUG) {
const stdout = std.io.getStdOut().writer();
stdout.print("dealloc: {d} (alignment {d})\n", .{ c_ptr, alignment }) catch unreachable;
}
free(@alignCast(Align, @ptrCast([*]u8, c_ptr)));
}
export fn roc_panic(c_ptr: *anyopaque, tag_id: u32) callconv(.C) void {
_ = tag_id;
const stderr = std.io.getStdErr().writer();
const msg = @ptrCast([*:0]const u8, c_ptr);
stderr.print("Application crashed with message\n\n {s}\n\nShutting down\n", .{msg}) catch unreachable;
std.process.exit(0);
}
export fn roc_memcpy(dst: [*]u8, src: [*]u8, size: usize) callconv(.C) void {
return memcpy(dst, src, size);
}
export fn roc_memset(dst: [*]u8, value: i32, size: usize) callconv(.C) void {
return memset(dst, value, size);
}
extern fn kill(pid: c_int, sig: c_int) c_int;
extern fn shm_open(name: *const i8, oflag: c_int, mode: c_uint) c_int;
extern fn mmap(addr: ?*anyopaque, length: c_uint, prot: c_int, flags: c_int, fd: c_int, offset: c_uint) *anyopaque;
extern fn getppid() c_int;
fn roc_getppid() callconv(.C) c_int {
return getppid();
}
fn roc_getppid_windows_stub() callconv(.C) c_int {
return 0;
}
fn roc_shm_open(name: *const i8, oflag: c_int, mode: c_uint) callconv(.C) c_int {
return shm_open(name, oflag, mode);
}
fn roc_mmap(addr: ?*anyopaque, length: c_uint, prot: c_int, flags: c_int, fd: c_int, offset: c_uint) callconv(.C) *anyopaque {
return mmap(addr, length, prot, flags, fd, offset);
}
comptime {
if (builtin.os.tag == .macos or builtin.os.tag == .linux) {
@export(roc_getppid, .{ .name = "roc_getppid", .linkage = .Strong });
@export(roc_mmap, .{ .name = "roc_mmap", .linkage = .Strong });
@export(roc_shm_open, .{ .name = "roc_shm_open", .linkage = .Strong });
}
if (builtin.os.tag == .windows) {
@export(roc_getppid_windows_stub, .{ .name = "roc_getppid", .linkage = .Strong });
}
}
const mem = std.mem;
const Allocator = mem.Allocator;
extern fn roc__mainForHost_1_exposed_generic(*RocStr) void;
const Unit = extern struct {};
pub fn main() u8 {
const stdout = std.io.getStdOut().writer();
const stderr = std.io.getStdErr().writer();
var timer = std.time.Timer.start() catch unreachable;
// actually call roc to populate the callresult
var callresult = RocStr.empty();
roc__mainForHost_1_exposed_generic(&callresult);
const nanos = timer.read();
const seconds = (@intToFloat(f64, nanos) / 1_000_000_000.0);
// stdout the result
stdout.print("{s}", .{callresult.asSlice()}) catch unreachable;
callresult.deinit();
stderr.print("runtime: {d:.3}ms\n", .{seconds * 1000}) catch unreachable;
return 0;
}

Binary file not shown.

View file

@ -0,0 +1,9 @@
platform "echo-in-zig"
requires {} { main : Str }
exposes []
packages {}
imports []
provides [mainForHost]
mainForHost : Str
mainForHost = main