From 5bd9159fa4bab1bc51d97ed2475e52e9eb349df6 Mon Sep 17 00:00:00 2001 From: "C.Brenhin Keller" Date: Thu, 20 Oct 2022 12:50:18 -0400 Subject: [PATCH] Update integration tests --- test/scripts/interop.jl | 16 ++ test/scripts/loopvec_matrix.jl | 9 +- test/scripts/loopvec_matrix_stack.jl | 49 ++++ test/scripts/loopvec_product.jl | 4 +- test/scripts/rand_matrix.jl | 8 +- test/scripts/randn_matrix.jl | 22 ++ test/scripts/times_table.jl | 9 +- test/scripts/withmallocarray.jl | 31 +++ test/testintegration.jl | 342 +++++++++++++++++++++------ 9 files changed, 402 insertions(+), 88 deletions(-) create mode 100644 test/scripts/interop.jl create mode 100644 test/scripts/loopvec_matrix_stack.jl create mode 100644 test/scripts/randn_matrix.jl create mode 100644 test/scripts/withmallocarray.jl diff --git a/test/scripts/interop.jl b/test/scripts/interop.jl new file mode 100644 index 0000000..b601e09 --- /dev/null +++ b/test/scripts/interop.jl @@ -0,0 +1,16 @@ +using StaticCompiler +using StaticTools + +function interop(argc, argv) + lib = StaticTools.dlopen(c"libm") + printf(lib) + sin = StaticTools.dlsym(lib, c"sin") + printf(sin) + x = @ptrcall sin(5.0::Float64)::Float64 + printf(x) + newline() + StaticTools.dlclose(lib) +end + +# Attempt to compile +path = compile_executable(interop, (Int64, Ptr{Ptr{UInt8}}), "./", cflags=`-ldl -lm`) diff --git a/test/scripts/loopvec_matrix.jl b/test/scripts/loopvec_matrix.jl index 5477dd3..7b19ce8 100644 --- a/test/scripts/loopvec_matrix.jl +++ b/test/scripts/loopvec_matrix.jl @@ -15,8 +15,8 @@ end function loopvec_matrix(argc::Int, argv::Ptr{Ptr{UInt8}}) argc == 3 || return printf(stderrp(), c"Incorrect number of command-line arguments\n") - rows = parse(Int64, argv, 2) # First command-line argument - cols = parse(Int64, argv, 3) # Second command-line argument + rows = argparse(Int64, argv, 2) # First command-line argument + cols = argparse(Int64, argv, 3) # Second command-line argument # LHS A = MallocArray{Float64}(undef, rows, cols) @@ -41,9 +41,8 @@ function loopvec_matrix(argc::Int, argv::Ptr{Ptr{UInt8}}) # Print to stdout printf(C) # Also print to file - fp = fopen(c"table.tsv",c"w") - printf(fp, C) - fclose(fp) + printdlm(c"table.tsv", C, '\t') + fwrite(c"table.b", C) # Clean up matrices free(A) free(B) diff --git a/test/scripts/loopvec_matrix_stack.jl b/test/scripts/loopvec_matrix_stack.jl new file mode 100644 index 0000000..5e0c90d --- /dev/null +++ b/test/scripts/loopvec_matrix_stack.jl @@ -0,0 +1,49 @@ +using StaticCompiler +using StaticTools +using LoopVectorization + +@inline function mul!(C::StackArray, A::StackArray, B::StackArray) + @turbo for n ∈ indices((C,B), 2), m ∈ indices((C,A), 1) + Cmn = zero(eltype(C)) + for k ∈ indices((A,B), (2,1)) + Cmn += A[m,k] * B[k,n] + end + C[m,n] = Cmn + end + return C +end + +function loopvec_matrix_stack() + rows = 10 + cols = 5 + + # LHS + A = StackArray{Float64}(undef, rows, cols) + @turbo for i ∈ axes(A, 1) + for j ∈ axes(A, 2) + A[i,j] = i*j + end + end + + # RHS + B = StackArray{Float64}(undef, cols, rows) + @turbo for i ∈ axes(B, 1) + for j ∈ axes(B, 2) + B[i,j] = i*j + end + end + + # # Matrix multiplication + C = StackArray{Float64}(undef, cols, cols) + mul!(C, B, A) + + # Print to stdout + printf(C) + # Also print to file + fp = fopen(c"table.tsv",c"w") + printf(fp, C) + fclose(fp) +end + +# Attempt to compile +path = compile_executable(loopvec_matrix_stack, (), "./") diff --git a/test/scripts/loopvec_product.jl b/test/scripts/loopvec_product.jl index bffa69c..8342450 100644 --- a/test/scripts/loopvec_product.jl +++ b/test/scripts/loopvec_product.jl @@ -4,8 +4,8 @@ using LoopVectorization function loopvec_product(argc::Int, argv::Ptr{Ptr{UInt8}}) argc == 3 || return printf(stderrp(), c"Incorrect number of command-line arguments\n") - rows = parse(Int64, argv, 2) # First command-line argument - cols = parse(Int64, argv, 3) # Second command-line argument + rows = argparse(Int64, argv, 2) # First command-line argument + cols = argparse(Int64, argv, 3) # Second command-line argument s = 0 @turbo for i=1:rows diff --git a/test/scripts/rand_matrix.jl b/test/scripts/rand_matrix.jl index ce9fe46..604e44a 100644 --- a/test/scripts/rand_matrix.jl +++ b/test/scripts/rand_matrix.jl @@ -3,9 +3,10 @@ using StaticTools function rand_matrix(argc::Int, argv::Ptr{Ptr{UInt8}}) argc == 3 || return printf(stderrp(), c"Incorrect number of command-line arguments\n") - rows = parse(Int64, argv, 2) # First command-line argument - cols = parse(Int64, argv, 3) # Second command-line argument + rows = argparse(Int64, argv, 2) # First command-line argument + cols = argparse(Int64, argv, 3) # Second command-line argument + # Manually fil matrix M = MallocArray{Float64}(undef, rows, cols) rng = static_rng() @inbounds for i=1:rows @@ -18,4 +19,5 @@ function rand_matrix(argc::Int, argv::Ptr{Ptr{UInt8}}) end # Attempt to compile -path = compile_executable(rand_matrix, (Int64, Ptr{Ptr{UInt8}}), "./") +# cflags=`-lm`: need to explicitly include libm math library on linux +path = compile_executable(rand_matrix, (Int64, Ptr{Ptr{UInt8}}), "./", cflags=`-lm`) diff --git a/test/scripts/randn_matrix.jl b/test/scripts/randn_matrix.jl new file mode 100644 index 0000000..065d466 --- /dev/null +++ b/test/scripts/randn_matrix.jl @@ -0,0 +1,22 @@ +using StaticCompiler +using StaticTools + +function randn_matrix(argc::Int, argv::Ptr{Ptr{UInt8}}) + argc == 3 || return printf(stderrp(), c"Incorrect number of command-line arguments\n") + rows = argparse(Int64, argv, 2) # First command-line argument + cols = argparse(Int64, argv, 3) # Second command-line argument + + M = MallocArray{Float64}(undef, rows, cols) + rng = MarsagliaPolar(static_rng()) + @inbounds for i=1:rows + for j=1:cols + M[i,j] = randn(rng) + end + end + printf(M) + free(M) +end + +# Attempt to compile +# cflags=`-lm`: need to explicitly include libm math library on linux +path = compile_executable(randn_matrix, (Int64, Ptr{Ptr{UInt8}}), "./", cflags=`-lm`) diff --git a/test/scripts/times_table.jl b/test/scripts/times_table.jl index 2dab393..7d295eb 100644 --- a/test/scripts/times_table.jl +++ b/test/scripts/times_table.jl @@ -3,8 +3,8 @@ using StaticTools function times_table(argc::Int, argv::Ptr{Ptr{UInt8}}) argc == 3 || return printf(stderrp(), c"Incorrect number of command-line arguments\n") - rows = parse(Int64, argv, 2) # First command-line argument - cols = parse(Int64, argv, 3) # Second command-line argument + rows = argparse(Int64, argv, 2) # First command-line argument + cols = argparse(Int64, argv, 3) # Second command-line argument M = MallocArray{Int64}(undef, rows, cols) @inbounds for i=1:rows @@ -15,9 +15,8 @@ function times_table(argc::Int, argv::Ptr{Ptr{UInt8}}) # Print to stdout printf(M) # Also print to file - fp = fopen(c"table.tsv",c"w") - printf(fp, M) - fclose(fp) + fwrite(c"table.b", M) + printdlm(c"table.tsv", M) # Clean up matrix free(M) end diff --git a/test/scripts/withmallocarray.jl b/test/scripts/withmallocarray.jl new file mode 100644 index 0000000..2930121 --- /dev/null +++ b/test/scripts/withmallocarray.jl @@ -0,0 +1,31 @@ +using StaticCompiler +using StaticTools + +function withmallocarray(argc::Int, argv::Ptr{Ptr{UInt8}}) + argc == 3 || return printf(stderrp(), c"Incorrect number of command-line arguments\n") + rows = argparse(Int64, argv, 2) # First command-line argument + cols = argparse(Int64, argv, 3) # Second command-line argument + + mzeros(rows, cols) do A + printf(A) + end + mones(Int, rows, cols) do A + printf(A) + end + mfill(3.141592, rows, cols) do A + printf(A) + end + + # Random number generation + rng = MarsagliaPolar() + mrand(rng, rows, cols) do A + printf(A) + end + mrandn(rng, rows, cols) do A + printf(A) + end +end + +# Attempt to compile +# cflags=`-lm`: need to explicitly include libm math library on linux +path = compile_executable(withmallocarray, (Int64, Ptr{Ptr{UInt8}}), "./", cflags=`-lm`) diff --git a/test/testintegration.jl b/test/testintegration.jl index 5fd783e..f54a808 100644 --- a/test/testintegration.jl +++ b/test/testintegration.jl @@ -1,82 +1,278 @@ @testset "Standalone Executable Integration" begin - + # Setup testpath = pwd() scratch = tempdir() cd(scratch) + jlpath = joinpath(Sys.BINDIR, Base.julia_exename()) # Get path to julia executable - # --- Times table, file IO, mallocarray - - # Compile... - # We have to start a new Julia process to get around the fact that Pkg.test - # disables `@inbounds`, but ironically we can use `--compile=min` to make that - # faster. - status = run(`julia --compile=min $testpath/scripts/times_table.jl`) - @test isa(status, Base.Process) - @test status.exitcode == 0 - - # Attempt to run - println("5x5 times table:") - status = run(`./times_table 5 5`) - @test isa(status, Base.Process) - @test status.exitcode == 0 - @test parsedlm(Int64, c"table.tsv", '\t') == (1:5)*(1:5)' - - # --- Random number generation - - # Compile... - status = run(`julia --compile=min $testpath/scripts/rand_matrix.jl`) - @test isa(status, Base.Process) - @test status.exitcode == 0 - - # Run... - println("5x5 random matrix:") - status = run(`./rand_matrix 5 5`) - @test isa(status, Base.Process) - @test status.exitcode == 0 - - # --- Test LoopVectorization integration - -@static if LoopVectorization.VectorizationBase.has_feature(Val{:x86_64_avx2}) - # Compile... - status = run(`julia --compile=min $testpath/scripts/loopvec_product.jl`) - @test isa(status, Base.Process) - @test status.exitcode == 0 - - # Run... - println("10x10 table sum:") - status = run(`./loopvec_product 10 10`) - @test isa(status, Base.Process) - @test status.exitcode == 0 - @test parsedlm(c"product.tsv",'\t')[] == 3025 -end + ## --- Times table, file IO, mallocarray + let + # Attempt to compile + # We have to start a new Julia process to get around the fact that Pkg.test + # disables `@inbounds`, but ironically we can use `--compile=min` to make that + # faster. + status = -1 + try + isfile("times_table") && rm("times_table") + status = run(`$jlpath --compile=min $testpath/scripts/times_table.jl`) + catch e + @warn "Could not compile $testpath/scripts/times_table.jl" + println(e) + end + @test isa(status, Base.Process) + @test isa(status, Base.Process) && status.exitcode == 0 + + # Attempt to run + println("5x5 times table:") + status = -1 + try + status = run(`./times_table 5 5`) + catch e + @warn "Could not run $(scratch)/times_table" + println(e) + end + @test isa(status, Base.Process) + @test isa(status, Base.Process) && status.exitcode == 0 + # Test ascii output + @test parsedlm(Int, c"table.tsv", '\t') == (1:5)*(1:5)' + # Test binary output + @test fread!(szeros(Int, 5,5), c"table.b") == (1:5)*(1:5)' + end + + ## --- "withmallocarray"-type do-block pattern + let + # Compile... + status = -1 + try + isfile("withmallocarray") && rm("withmallocarray") + status = run(`$jlpath --compile=min $testpath/scripts/withmallocarray.jl`) + catch e + @warn "Could not compile $testpath/scripts/withmallocarray.jl" + println(e) + end + @test isa(status, Base.Process) + @test isa(status, Base.Process) && status.exitcode == 0 + + # Run... + println("3x3 malloc arrays via do-block syntax:") + status = -1 + try + status = run(`./withmallocarray 3 3`) + catch e + @warn "Could not run $(scratch)/withmallocarray" + println(e) + end + @test isa(status, Base.Process) + @test isa(status, Base.Process) && status.exitcode == 0 + end + + ## --- Random number generation + let + # Compile... + status = -1 + try + isfile("rand_matrix") && rm("rand_matrix") + status = run(`$jlpath --compile=min $testpath/scripts/rand_matrix.jl`) + catch e + @warn "Could not compile $testpath/scripts/rand_matrix.jl" + println(e) + end + @test isa(status, Base.Process) + @test isa(status, Base.Process) && status.exitcode == 0 + + # Run... + println("5x5 uniform random matrix:") + status = -1 + try + status = run(`./rand_matrix 5 5`) + catch e + @warn "Could not run $(scratch)/rand_matrix" + println(e) + end + @test isa(status, Base.Process) + @test isa(status, Base.Process) && status.exitcode == 0 + end + + let + # Compile... + status = -1 + try + isfile("randn_matrix") && rm("randn_matrix") + status = run(`$jlpath --compile=min $testpath/scripts/randn_matrix.jl`) + catch e + @warn "Could not compile $testpath/scripts/randn_matrix.jl" + println(e) + end + @static if Sys.isbsd() + @test isa(status, Base.Process) + @test isa(status, Base.Process) && status.exitcode == 0 + end + + # Run... + println("5x5 Normal random matrix:") + status = -1 + try + status = run(`./randn_matrix 5 5`) + catch e + @warn "Could not run $(scratch)/randn_matrix" + println(e) + end + @static if Sys.isbsd() + @test isa(status, Base.Process) + @test isa(status, Base.Process) && status.exitcode == 0 + end + end + + ## --- Test LoopVectorization integration + @static if LoopVectorization.VectorizationBase.has_feature(Val{:x86_64_avx2}) + let + # Compile... + status = -1 + try + isfile("loopvec_product") && rm("loopvec_product") + status = run(`$jlpath --compile=min $testpath/scripts/loopvec_product.jl`) + catch e + @warn "Could not compile $testpath/scripts/loopvec_product.jl" + println(e) + end + @test isa(status, Base.Process) + @test isa(status, Base.Process) && status.exitcode == 0 + + # Run... + println("10x10 table sum:") + status = -1 + try + status = run(`./loopvec_product 10 10`) + catch e + @warn "Could not run $(scratch)/loopvec_product" + println(e) + end + @test isa(status, Base.Process) + @test isa(status, Base.Process) && status.exitcode == 0 + @test parsedlm(c"product.tsv",'\t')[] == 3025 + end + end + + let + # Compile... + status = -1 + try + isfile("loopvec_matrix") && rm("loopvec_matrix") + status = run(`$jlpath --compile=min $testpath/scripts/loopvec_matrix.jl`) + catch e + @warn "Could not compile $testpath/scripts/loopvec_matrix.jl" + println(e) + end + @test isa(status, Base.Process) + @test isa(status, Base.Process) && status.exitcode == 0 + + # Run... + println("10x5 matrix product:") + status = -1 + try + status = run(`./loopvec_matrix 10 5`) + catch e + @warn "Could not run $(scratch)/loopvec_matrix" + println(e) + end + @test isa(status, Base.Process) + @test isa(status, Base.Process) && status.exitcode == 0 + A = (1:10) * (1:5)' + # Check ascii output + @test parsedlm(c"table.tsv",'\t') == A' * A + # Check binary output + @test fread!(szeros(5,5), c"table.b") == A' * A + end + + let + # Compile... + status = -1 + try + isfile("loopvec_matrix_stack") && rm("loopvec_matrix_stack") + status = run(`$jlpath --compile=min $testpath/scripts/loopvec_matrix_stack.jl`) + catch e + @warn "Could not compile $testpath/scripts/loopvec_matrix_stack.jl" + println(e) + end + @test isa(status, Base.Process) + @test isa(status, Base.Process) && status.exitcode == 0 + + # Run... + println("10x5 matrix product:") + status = -1 + try + status = run(`./loopvec_matrix_stack`) + catch e + @warn "Could not run $(scratch)/loopvec_matrix_stack" + println(e) + end + @test isa(status, Base.Process) + @test isa(status, Base.Process) && status.exitcode == 0 + A = (1:10) * (1:5)' + @test parsedlm(c"table.tsv",'\t') == A' * A + end + + + ## --- Test string handling + + let + # Compile... + status = -1 + try + isfile("print_args") && rm("print_args") + status = run(`$jlpath --compile=min $testpath/scripts/print_args.jl`) + catch e + @warn "Could not compile $testpath/scripts/print_args.jl" + println(e) + end + @test isa(status, Base.Process) + @test isa(status, Base.Process) && status.exitcode == 0 + + # Run... + println("String indexing and handling:") + status = -1 + try + status = run(`./print_args foo bar`) + catch e + @warn "Could not run $(scratch)/print_args" + println(e) + end + @test isa(status, Base.Process) + @test isa(status, Base.Process) && status.exitcode == 0 + end + + ## --- Test interop + + @static if Sys.isbsd() + let + # Compile... + status = -1 + try + isfile("interop") && rm("interop") + status = run(`$jlpath --compile=min $testpath/scripts/interop.jl`) + catch e + @warn "Could not compile $testpath/scripts/interop.jl" + println(e) + end + @test isa(status, Base.Process) + @test isa(status, Base.Process) && status.exitcode == 0 + + # Run... + println("Interop:") + status = -1 + try + status = run(`./interop`) + catch e + @warn "Could not run $(scratch)/interop" + println(e) + end + @test isa(status, Base.Process) + @test isa(status, Base.Process) && status.exitcode == 0 + end + end + + ## --- Clean up - # Compile... - status = run(`julia --compile=min $testpath/scripts/loopvec_matrix.jl`) - @test isa(status, Base.Process) - @test status.exitcode == 0 - - # Run... - println("10x3 matrix product:") - status = run(`./loopvec_matrix 10 3`) - @test isa(status, Base.Process) - @test status.exitcode == 0 - A = (1:10) * (1:3)' - @test parsedlm(c"table.tsv",'\t') == A' * A - - # --- Test string handling - - # Compile... - status = run(`julia --compile=min $testpath/scripts/print_args.jl`) - @test isa(status, Base.Process) - @test status.exitcode == 0 - - # Run... - println("String indexing and handling:") - status = run(`./print_args foo bar`) - @test isa(status, Base.Process) - @test status.exitcode == 0 - - # --- Clean up cd(testpath) end