mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-26 13:29:12 +00:00
valgrind test crate
This commit is contained in:
parent
32e3f01a28
commit
c97dbcfde1
11 changed files with 314 additions and 0 deletions
20
crates/valgrind/Cargo.toml
Normal file
20
crates/valgrind/Cargo.toml
Normal 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
22
crates/valgrind/build.rs
Normal 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
101
crates/valgrind/src/lib.rs
Normal 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
BIN
crates/valgrind/tests/rocLovesZig
Executable file
Binary file not shown.
8
crates/valgrind/tests/str_concat_1.roc
Normal file
8
crates/valgrind/tests/str_concat_1.roc
Normal 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"
|
BIN
crates/valgrind/zig-platform/dynhost
Executable file
BIN
crates/valgrind/zig-platform/dynhost
Executable file
Binary file not shown.
138
crates/valgrind/zig-platform/host.zig
Normal file
138
crates/valgrind/zig-platform/host.zig
Normal 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;
|
||||
}
|
BIN
crates/valgrind/zig-platform/libapp.so
Normal file
BIN
crates/valgrind/zig-platform/libapp.so
Normal file
Binary file not shown.
9
crates/valgrind/zig-platform/main.roc
Normal file
9
crates/valgrind/zig-platform/main.roc
Normal file
|
@ -0,0 +1,9 @@
|
|||
platform "echo-in-zig"
|
||||
requires {} { main : Str }
|
||||
exposes []
|
||||
packages {}
|
||||
imports []
|
||||
provides [mainForHost]
|
||||
|
||||
mainForHost : Str
|
||||
mainForHost = main
|
Loading…
Add table
Add a link
Reference in a new issue