Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

protype to compile julia scripts to exe #35

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
result.bin
fasta.txt
build
118 changes: 118 additions & 0 deletions build_julia.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
"""
Usage: build_julia relative/path/to/file.jl
Result: compiles an executable under the name build/file
"""

using Libdl
global gcc = "gcc"
gccworks = try
success(`$gcc -v`)
catch
error("GCC wasn't found. Please make sure that gcc is on the path and run again")
end
using Libdl
threadingOn() = ccall(:jl_threading_enabled, Cint, ()) != 0

shell_escape(str) = "'$(replace(str, "'" => "'\''"))'"
libDir() = dirname(abspath(Libdl.dlpath("libjulia")))
private_libDir() = abspath(Sys.BINDIR, Base.PRIVATE_LIBDIR)

includeDir() = abspath(Sys.BINDIR, Base.INCLUDEDIR, "julia")

function ldflags()
fl = "-L$(shell_escape(libDir()))"
if Sys.iswindows()
fl = fl * " -Wl,--stack,8388608"
elseif Sys.islinux()
fl = fl * " -Wl,--export-dynamic"
end
return fl
end

function ldlibs()
libname = "julia"
if Sys.isunix()
return "-Wl,-rpath,$(shell_escape(libDir())) -Wl,-rpath,$(shell_escape(private_libDir())) -l$libname"
else
return "-l$libname -lopenlibm"
end
end

function cflags()
return sprint() do io
print(io, "-std=gnu99")
include = shell_escape(includeDir())
print(io, " -I", include)
print(io, " -DJULIA_ENABLE_THREADING=1")
if Sys.isunix()
print(io, " -fPIC")
end
end
end

function allflags()
return "$(cflags()) $(ldflags()) $(ldlibs())"
end

function julia_flags(optimize, debug, cc_flags)
flags = Base.shell_split(allflags())
bitness_flag = Sys.ARCH == :aarch64 ? `` : Int == Int32 ? "-m32" : "-m64"
flags = `$flags $bitness_flag`
optimize == nothing || (flags = `$flags -O$optimize`)
debug == 2 && (flags = `$flags -g`)
cc_flags == nothing || isempty(cc_flags) || (flags = `$flags $cc_flags`)
flags
end
path = ARGS[1]

command = """
Base.reinit_stdio()
_bindir = ccall(:jl_get_julia_bindir, Any, ())::String
@eval(Sys, BINDIR = \$(_bindir))
@eval(Sys, STDLIB = joinpath(\$_bindir, "..", "share", "julia", "stdlib", string('v', (VERSION.major), '.', VERSION.minor)))
Base.init_load_path()
Base.init_depot_path()
using REPL
Base.REPL_MODULE_REF[] = REPL
include("$path")
"""
function default_sysimg_path(debug = false)
ext = "sys"
if Sys.isunix()
dirname(Libdl.dlpath(ext))
else
normpath(Sys.BINDIR, "..", "lib", "julia")
end
end
function build_shared(s_file, o_file)
# Prevent compiler from stripping all symbols from the shared lib.
if Sys.isapple()
o_file = `-Wl,-all_load $o_file`
else
o_file = `-Wl,--whole-archive $o_file -Wl,--no-whole-archive`
end
command = `gcc -shared -DJULIAC_PROGRAM_LIBNAME=\"$s_file\" -o $s_file $o_file $(julia_flags("3", false, ""))`
if Sys.isapple()
command = `$command -Wl,-install_name,@rpath/$s_file`
elseif Sys.iswindows()
command = `$command -Wl,--export-all-symbols`
end
run(command)
end
function build_exec(e_file, cprog, s_file)
command = `gcc -DJULIAC_PROGRAM_LIBNAME=\"$s_file\" -o $e_file $cprog $s_file $(julia_flags("3", false, ""))`
if Sys.isapple()
command = `$command -Wl,-rpath,@executable_path`
else
command = `$command -Wl,-rpath,\$ORIGIN`
end
run(command)
end
sys_so = joinpath(default_sysimg_path(false), "sys.so")
isdir("build") || mkdir("build")
syso = abspath(joinpath("build", "sys.so"))
sysa = abspath(joinpath("build", "sys.a"))
run(`julia -C native --output-o $sysa -J $sys_so -O3 -e "$command"`)
build_shared(syso, sysa)
exe_name = splitext(basename(path))[1]
build_exec(joinpath("build", exe_name), "program.c", syso)
182 changes: 182 additions & 0 deletions fannkuchredux/fannkuchredux-compile.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
# The Computer Language Benchmarks Game
# https://salsa.debian.org/benchmarksgame-team/benchmarksgame/

# based on Oleg Mazurov's Java Implementation and Jeremy Zerfas' C implementation
# transliterated by Hamza Yusuf Çakır

global const preferred_num_blocks = 24

struct Fannkuch
n::Int64
blocksz::Int64
maxflips::Vector{Int32}
chksums::Vector{Int32}

function Fannkuch(n, nthreads)
nfact = factorial(n)

blocksz = nfact ÷ (nfact < preferred_num_blocks ? 1 : preferred_num_blocks)
maxflips = zeros(Int32, nthreads)
chksums = zeros(Int32, nthreads)

new(n, blocksz, maxflips, chksums)
end
end

struct Perm
p::Vector{Int8}
pp::Vector{Int8}
count::Vector{Int32}

function Perm(n)
p = zeros(Int8, n)
pp = zeros(Int8, n)
count = zeros(Int32, n)

new(p, pp, count)
end
end

Base.@propagate_inbounds @inline function first_permutation(perm::Perm, idx)
p = perm.p
pp = perm.pp

for i = 2:length(p)
p[i] = i - 1
end

for i = length(p):-1:2
ifact = factorial(i-1)
d = idx ÷ ifact
perm.count[i] = d
idx = idx % ifact

for j = 1:i
pp[j] = p[j]
end

for j = 1:i
p[j] = j+d <= i ? pp[j+d] : pp[j+d-i]
end
end
end

Base.@propagate_inbounds @inline function next_permutation(perm::Perm)
p = perm.p
count = perm.count

first = p[2]
p[2] = p[1]
p[1] = first

i = 2
while count[i] >= i - 1
count[i] = 0

next = p[1] = p[2]

for j = 1:i
p[j] = p[j+1]
end

i += 1
p[i] = first
first = next
end
count[i] += 1
nothing
end

Base.@propagate_inbounds @inline function count_flips(perm::Perm)
p = perm.p
pp = perm.pp

flips = Int32(1)

first = p[1] + 1

if p[first] != 0

unsafe_copyto!(pp, 2, p, 2, length(p) - 1)

while true
flips += one(flips)
new_first = pp[first]
pp[first] = first - 1

if first > 3
lo = 2; hi = first - 1
# see the note in Jeremy Zerfas' C implementation for
# this loop
for k = 0:13
t = pp[lo]
pp[lo] = pp[hi]
pp[hi] = t
(hi < lo + 3) && break
lo += 1
hi -= 1
end
end

first = new_first + 1
pp[first] == 0 && break
end
end

return flips
end

Base.@propagate_inbounds function run_task(f::Fannkuch, perm::Perm, idxmin, idxmax)
maxflips = Int32(0)
chksum = Int32(0)

i = idxmin
while true
if perm.p[1] != 0
flips = count_flips(perm)
maxflips = max(maxflips, flips)
chksum += iseven(i) ? flips : -flips
end
i != idxmax || break
i += 1
next_permutation(perm)
end

id = Threads.threadid()
f.maxflips[id] = max(f.maxflips[id], maxflips)
f.chksums[id] += chksum
nothing
end

function runf(f::Fannkuch)
factn = factorial(f.n)

Threads.@threads for idxmin = 0:f.blocksz:factn-1
perm = Perm(f.n)
@inbounds first_permutation(perm, idxmin)
idxmax = idxmin + f.blocksz - 1
@inbounds run_task(f, perm, idxmin, idxmax)
end
end

function fannkuchredux(n)
f = Fannkuch(n, Threads.nthreads())

runf(f)

# reduce results
chk = sum(f.chksums)
res = maximum(f.maxflips)

println(chk, "\nPfannkuchen(", n, ") = ", res)
end

Base.@ccallable function julia_main(args::Vector{String})::Cint
n = parse(Int, args[1])
fannkuchredux(n)
return 0
end

# call once to make sure everything gets compiled!
# this is in global scope, so won't be called when calling the executable
julia_main(["7"])
Loading