Skip to content
This repository was archived by the owner on Dec 16, 2022. It is now read-only.

Commit f3f4540

Browse files
author
Paul H. Liu
committed
Produce a wrapper to j2c function; better examples
1 parent ae7d857 commit f3f4540

File tree

1 file changed

+129
-18
lines changed

1 file changed

+129
-18
lines changed

test/j2c.jl

+129-18
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,9 @@ function getenv(var::String)
2626
bytestring(val)
2727
end
2828

29+
julia_root = getenv("JULIA_ROOT")
30+
31+
# Force inline a function
2932
function inline(function_name, signature)
3033
m = methods(function_name, signature)
3134
if length(m) < 1
@@ -38,15 +41,112 @@ function inline(function_name, signature)
3841
def.j2cflag = convert(Int32, 1)
3942
end
4043

44+
function typeOfOpr(x)
45+
if isa(x, Expr) x.typ
46+
elseif isa(x, SymbolNode) x.typ
47+
else typeof(x)
48+
end
49+
end
50+
51+
# Convert regular Julia types to make them appropriate for calling C code.
52+
function convert_to_ccall_typ(typ)
53+
# if there a better way to check for typ being an array DataType?
54+
if isa(typ, DataType) && typ.name == Array.name
55+
# If it is an Array type then convert to Ptr type.
56+
return (Ptr{eltype(typ)},ndims(typ))
57+
elseif is(typ, ())
58+
return (Void, 0)
59+
else
60+
# Else no conversion needed.
61+
return (typ,0)
62+
end
63+
end
64+
65+
# dims is array of arrays from converting the datatype signature
66+
# ret_dims is an array of dimensions for the reurn type
67+
function sig_dims_to_args(dims)
68+
# add an Int64 argument for each array dimension we have
69+
ret = DataType[]
70+
for i = 1:length(dims)
71+
for j = 1:dims[i]
72+
push!(ret, Int64)
73+
end
74+
end
75+
ret
76+
end
77+
78+
# Convert a whole function signature in a form of a tuple to something appropriate for calling C code.
79+
function convert_sig(sig)
80+
assert(isa(typeof(sig),Tuple)) # make sure we got a tuple
81+
new_tuple = Expr(:tuple) # declare the new tuple
82+
# fill in the new_tuple args/elements by converting the individual elements of the incoming signature
83+
new_tuple.args = [ convert_to_ccall_typ(sig[i])[1] for i = 1:length(sig) ]
84+
sig_ndims = [ convert_to_ccall_typ(sig[i])[2] for i = 1:length(sig) ]
85+
append!(new_tuple.args,sig_dims_to_args(sig_ndims))
86+
return (eval(new_tuple), sig_ndims)
87+
end
88+
4189
function offload(function_name, signature)
90+
# get information about code for the given function and signature
91+
ct = code_typed(function_name, signature)
92+
code = ct[1]
93+
# set j2cflag properly
4294
m = methods(function_name, signature)
4395
def = m[1].func.code
4496
def.j2cflag = convert(Int32, 2)
45-
end
97+
# Same the number of statements so we can get the last one.
98+
num_stmts = length(ct[1].args[3].args)
99+
# Get the return type of the function by looking at the last statement
100+
last_stmt = ct[1].args[3].args[num_stmts]
101+
if isa(last_stmt, Expr) && is(last_stmt.head, :return)
102+
typ = typeOfOpr(last_stmt.args[1])
103+
(ret_type,ret_dims) = convert_to_ccall_typ(typ)
104+
else
105+
error("Last statement is not a return: ", last_stmt)
106+
end
46107

47-
julia_root = getenv("JULIA_ROOT")
48-
libname = string(julia_root, "/j2c/libout.so.1.0")
49-
println(libname)
108+
proxy_name = string(function_name,"_j2c_proxy")
109+
proxy_sym = symbol(proxy_name)
110+
j2c_name = string(function_name,"_")
111+
dyn_lib = string(julia_root, "/j2c/libout.so.1.0")
112+
113+
# Convert Arrays in signature to Ptr and add extra arguments for array dimensions
114+
(modified_sig, sig_dims) = convert_sig(signature)
115+
116+
# Create a set of expressions to pass as arguments to specify the array dimension sizes.
117+
extra_args = Any[]
118+
for(i = 1:length(sig_dims))
119+
for(j = 1:sig_dims[i])
120+
push!(extra_args, quote size($(code.args[1][i]),$(j)) end)
121+
end
122+
end
123+
124+
# Are we returning an array?
125+
if (ret_dims > 0)
126+
tuple_sig_expr = Expr(:tuple,modified_sig...,Cint,Ptr{Cint})
127+
func = @eval function ($proxy_sym)($(code.args[1]...))
128+
ret_out_dims = zeros(Cint,$ret_dims)
129+
result = ccall(($j2c_name, $dyn_lib), $ret_type, $tuple_sig_expr,
130+
$(code.args[1]...), $(extra_args...), $ret_dims, ret_out_dims)
131+
if(prod(ret_out_dims) == 0)
132+
throw(string("j2c code did not fill in at least one dimension for proxy ", $proxy_name))
133+
end
134+
rod64 = convert(Array{Int64,1},ret_out_dims)
135+
# Convert the result we get back from a pointer to an array.
136+
# The total size is the prod of the dimensions in ret_out_dims.
137+
# "true" says that Julia owns the returned memory and can free it with regular GC.
138+
# After getting array the right size we then reshape it again using ret_out_dims.
139+
reshape(pointer_to_array(result,prod(ret_out_dims),true),tuple(rod64...))
140+
end
141+
else
142+
tuple_sig_expr = Expr(:tuple,Cint,modified_sig...)
143+
func = @eval function ($proxy_sym)($(code.args[1]...))
144+
ccall(($j2c_name, $dyn_lib), $ret_type, $tuple_sig_expr,
145+
$(code.args[1]...), $(extra_args...))
146+
end
147+
end
148+
return func
149+
end
50150

51151
function sumOfThree(N::Int)
52152
a=[ (i*N+j)*11.0 for i=1:N, j=1:N]
@@ -56,21 +156,32 @@ function sumOfThree(N::Int)
56156
return d
57157
end
58158

59-
offload(sumOfThree, (Int,))
60-
# warm up, will trigger j2c compilation, but will not run
61-
sumOfThree(1)
62-
63-
@eval function j2c_sumOfThree(N::Int)
64-
ret_out_dims = zeros(Cint, 2)
65-
result = ccall((:sumOfThree_, $(libname)), Ptr{Float64}, (Int, Int, Int, Ptr{Cint},), -1, N, 1, ret_out_dims)
66-
rod64 = convert(Array{Int,1}, ret_out_dims)
67-
reshape(pointer_to_array(result,prod(ret_out_dims),true),tuple(rod64...))
159+
function powOfTwo(a::Array{Float64,2})
160+
return a .* a
68161
end
69162

70-
for sizea = 1:1 #100
71-
N = sizea * 1000
163+
# Here is a sample of calling j2c functions directly.
164+
# libname = string(julia_root, "/j2c/libout.so.1.0")
165+
# println(libname)
166+
# @eval function j2c_sumOfThree(N::Int)
167+
# ret_out_dims = zeros(Cint, 2)
168+
# result = ccall((:sumOfThree_, $(libname)), Ptr{Float64}, (Int, Int, Ptr{Cint},), N, 1, ret_out_dims)
169+
# rod64 = convert(Array{Int,1}, ret_out_dims)
170+
# reshape(pointer_to_array(result,prod(ret_out_dims),true),tuple(rod64...))
171+
# end
172+
173+
# Alternatively, we may use the offload function to automatically
174+
# generate the above wrapper.
175+
j2c_sumOfThree = offload(sumOfThree, (Int,))
176+
j2c_powOfTwo = offload(powOfTwo, (Array{Float64,2},))
177+
178+
# Warm up, will trigger j2c compilation
179+
powOfTwo(sumOfThree(1))
180+
181+
for sizea = 1:10 #100
182+
N = sizea * 100
72183
println("\n****Matrix size: ", N, "*", N)
73-
d=j2c_sumOfThree(N)
74-
println("sum=", sum(d))
184+
a=j2c_sumOfThree(N)
185+
b=j2c_powOfTwo(a)
186+
println("checksum =", sum(a), " ", sum(b))
75187
end
76-

0 commit comments

Comments
 (0)