-
Notifications
You must be signed in to change notification settings - Fork 187
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
faster pysym macro #84
Conversation
It would be good to try at least looking at |
before: julia> using PyCall
julia> macroexpand(quote f() = PyCall.@pysym abc end)
:(begin # none, line 1:
f() = begin # none, line 1:
begin # /Users/jameson/.julia/PyCall/src/PyCall.jl, line 66:
begin # /Users/jameson/.julia/PyCall/src/PyCall.jl, line 67:
global ##abc#60415 # line 68:
if (##abc#60415::PyCall.Ptr{PyCall.Void} PyCall.== PyCall.C_NULL) # line 69:
##abc#60415::PyCall.Ptr{PyCall.Void} = PyCall.dlsym(PyCall.libpython::PyCall.Ptr{PyCall.Void},abc)
end # line 71:
##abc#60415::PyCall.Ptr{PyCall.Void}
end
end
end
end)
julia> f() = PyCall.@pysym abc
f (generic function with 1 method)
julia> code_typed(f,())
1-element Array{Any,1}:
:($(Expr(:lambda, {}, {{},{},{}}, :(begin # none, line 1: # /Users/jameson/.julia/PyCall/src/PyCall.jl, line 66: # /Users/jameson/.julia/PyCall/src/PyCall.jl, line 67: # line 68:
unless top(box)(Uint,top(typeassert)(##abc#60632,Ptr{None})::Ptr{None})::Uint64 === top(box)(Uint,top(getfield)(PyCall,:C_NULL)::Ptr{None})::Uint64::Bool goto 0 # line 69:
top(typeassert)(##abc#60632,Ptr{None})::Ptr{None}
##abc#60632 = top(getfield)(PyCall,:dlsym)(top(typeassert)(top(getfield)(PyCall,:libpython)::Top,Ptr{None})::Ptr{None},abc)::Ptr{None}
0: # line 71:
return top(typeassert)(##abc#60632,Ptr{None})::Ptr{None}
end::Ptr{None})))) after: julia> using PyCall
julia> macroexpand(quote f() = PyCall.@pysym abc end)
:(begin # none, line 1:
f() = begin # none, line 1:
begin # /Users/jameson/.julia/PyCall/src/PyCall.jl, line 67:
let #517###60562::PyCall.Ptr{PyCall.Void} = ##abc#60561::PyCall.Ptr{PyCall.Void} # line 68:
if (#517###60562 PyCall.== PyCall.C_NULL) # line 69:
global ##abc#60561 = #517###60562 = PyCall.dlsym(PyCall.libpython::PyCall.Ptr{PyCall.Void},abc)
end # line 71:
#517###60562
end
end
end
end)
julia> f() = PyCall.@pysym abc
f (generic function with 1 method)
julia> code_typed(f,())
1-element Array{Any,1}:
:($(Expr(:lambda, {}, {{symbol("#s112"),symbol("#519###60780")},{{symbol("#s112"),Ptr{None},18},{symbol("#519###60780"),Ptr{None},2}},{}}, :(begin # none, line 1: # /Users/jameson/.julia/PyCall/src/PyCall.jl, line 67:
NewvarNode(symbol("#519###60780"))
#519###60780 = top(typeassert)(##abc#60779,Ptr{None})::Ptr{None} # line 68:
unless top(box)(Uint,#519###60780::Ptr{None})::Uint64 === top(box)(Uint,top(getfield)(PyCall,:C_NULL)::Ptr{None})::Uint64::Bool goto 0 # line 69:
#s112 = top(getfield)(PyCall,:dlsym)(top(typeassert)(top(getfield)(PyCall,:libpython)::Top,Ptr{None})::Ptr{None},abc)::Ptr{None}
#519###60780 = #s112::Ptr{None}
##abc#60779 = #s112::Ptr{None}
0: # line 71:
return #519###60780::Ptr{None}
end::Ptr{None})))) where before has the following patch applied so that diff --git a/src/PyCall.jl b/src/PyCall.jl
index 37185c1..69393c1 100644
--- a/src/PyCall.jl
+++ b/src/PyCall.jl
@@ -61,7 +61,8 @@ end
# Macro version of pysym to cache dlsym lookup (thanks to vtjnash)
macro pysym(func)
z = gensym(string(func))
- @eval global $z = C_NULL
+ eval(current_module(),:( global $z = C_NULL ))
+ z = esc(z)
quote begin
global $z
if $z::Ptr{Void} == C_NULL before: julia> code_llvm(f,())
define i8* @"julia_f;20308"() {
top:
%0 = alloca [4 x %jl_value_t*], align 8
%.sub = getelementptr inbounds [4 x %jl_value_t*]* %0, i64 0, i64 0
%1 = getelementptr [4 x %jl_value_t*]* %0, i64 0, i64 2, !dbg !1853
store %jl_value_t* inttoptr (i64 4 to %jl_value_t*), %jl_value_t** %.sub, align 8
%2 = load %jl_value_t*** @jl_pgcstack, align 8, !dbg !1853
%3 = getelementptr [4 x %jl_value_t*]* %0, i64 0, i64 1, !dbg !1853
%.c = bitcast %jl_value_t** %2 to %jl_value_t*, !dbg !1853
store %jl_value_t* %.c, %jl_value_t** %3, align 8, !dbg !1853
store %jl_value_t** %.sub, %jl_value_t*** @jl_pgcstack, align 8, !dbg !1853
store %jl_value_t* null, %jl_value_t** %1, align 8
%4 = getelementptr [4 x %jl_value_t*]* %0, i64 0, i64 3
store %jl_value_t* null, %jl_value_t** %4, align 8
%5 = load %jl_value_t** inttoptr (i64 140705317604896 to %jl_value_t**), align 32, !dbg !1854
%6 = getelementptr inbounds %jl_value_t* %5, i64 0, i32 0, !dbg !1854
%7 = load %jl_value_t** %6, align 8, !dbg !1854
%8 = icmp eq %jl_value_t* %7, inttoptr (i64 140705301408096 to %jl_value_t*), !dbg !1854
br i1 %8, label %pass, label %fail, !dbg !1854
fail: ; preds = %top
call void @jl_type_error_rt(i8* getelementptr inbounds ([2 x i8]* @_j_str92, i64 0, i64 0), i8* getelementptr inbounds ([11 x i8]* @_j_str2, i64 0, i64 0), %jl_value_t* inttoptr (i64 140705301408096 to %jl_value_t*), %jl_value_t* %5), !dbg !1854
unreachable
pass: ; preds = %top
%9 = load %jl_value_t** inttoptr (i64 140705336983088 to %jl_value_t**), align 16, !dbg !1854
%10 = icmp eq %jl_value_t* %9, null, !dbg !1854
br i1 %10, label %err, label %ok, !dbg !1854
err: ; preds = %pass
call void @jl_undefined_var_error(%jl_value_t* inttoptr (i64 4550321216 to %jl_value_t*)), !dbg !1854
unreachable
ok: ; preds = %pass
%11 = getelementptr inbounds %jl_value_t* %5, i64 1, i32 0, !dbg !1854
%12 = load %jl_value_t** %11, align 8, !dbg !1854
%13 = getelementptr inbounds %jl_value_t* %9, i64 1, i32 0, !dbg !1854
%14 = load %jl_value_t** %13, align 8, !dbg !1854
%15 = icmp eq %jl_value_t* %12, %14, !dbg !1854
br i1 %15, label %pass2, label %L, !dbg !1854
pass2: ; preds = %ok
%16 = load %jl_value_t** inttoptr (i64 140705366698864 to %jl_value_t**), align 16, !dbg !1855
%17 = icmp eq %jl_value_t* %16, null, !dbg !1855
br i1 %17, label %err3, label %ok4, !dbg !1855
err3: ; preds = %pass2
call void @jl_undefined_var_error(%jl_value_t* inttoptr (i64 4550613776 to %jl_value_t*)), !dbg !1855
unreachable
ok4: ; preds = %pass2
%18 = getelementptr inbounds %jl_value_t* %16, i64 0, i32 0, !dbg !1855
%19 = load %jl_value_t** %18, align 8, !dbg !1855
%20 = icmp eq %jl_value_t* %19, inttoptr (i64 140705301408096 to %jl_value_t*), !dbg !1855
br i1 %20, label %pass6, label %fail5, !dbg !1855
fail5: ; preds = %ok4
call void @jl_type_error_rt(i8* getelementptr inbounds ([2 x i8]* @_j_str92, i64 0, i64 0), i8* getelementptr inbounds ([11 x i8]* @_j_str2, i64 0, i64 0), %jl_value_t* inttoptr (i64 140705301408096 to %jl_value_t*), %jl_value_t* %16), !dbg !1855
unreachable
pass6: ; preds = %ok4
store %jl_value_t* %16, %jl_value_t** %1, align 8, !dbg !1855
%21 = load %jl_value_t** inttoptr (i64 140705503770672 to %jl_value_t**), align 16, !dbg !1855
%22 = icmp eq %jl_value_t* %21, null, !dbg !1855
br i1 %22, label %err7, label %ok8, !dbg !1855
err7: ; preds = %pass6
call void @jl_undefined_var_error(%jl_value_t* inttoptr (i64 4550662592 to %jl_value_t*)), !dbg !1855
unreachable
ok8: ; preds = %pass6
store %jl_value_t* %21, %jl_value_t** %4, align 8, !dbg !1855
%23 = call %jl_value_t* @jl_apply_generic(%jl_value_t* inttoptr (i64 140705328437888 to %jl_value_t*), %jl_value_t** %1, i32 2), !dbg !1855
call void @jl_checked_assignment(%jl_value_t* inttoptr (i64 140705317604888 to %jl_value_t*), %jl_value_t* %23), !dbg !1855
br label %L, !dbg !1855
L: ; preds = %ok, %ok8
%24 = load %jl_value_t** inttoptr (i64 140705317604896 to %jl_value_t**), align 32, !dbg !1856
%25 = getelementptr inbounds %jl_value_t* %24, i64 0, i32 0, !dbg !1856
%26 = load %jl_value_t** %25, align 8, !dbg !1856
%27 = icmp eq %jl_value_t* %26, inttoptr (i64 140705301408096 to %jl_value_t*), !dbg !1856
br i1 %27, label %pass10, label %fail9, !dbg !1856
fail9: ; preds = %L
call void @jl_type_error_rt(i8* getelementptr inbounds ([2 x i8]* @_j_str92, i64 0, i64 0), i8* getelementptr inbounds ([11 x i8]* @_j_str2, i64 0, i64 0), %jl_value_t* inttoptr (i64 140705301408096 to %jl_value_t*), %jl_value_t* %24), !dbg !1856
unreachable
pass10: ; preds = %L
%28 = getelementptr inbounds %jl_value_t* %24, i64 1, i32 0, !dbg !1856
%29 = load %jl_value_t** %28, align 8, !dbg !1856
%30 = bitcast %jl_value_t* %29 to i8*, !dbg !1856
%31 = load %jl_value_t** %3, align 8, !dbg !1856
%32 = getelementptr inbounds %jl_value_t* %31, i64 0, i32 0, !dbg !1856
store %jl_value_t** %32, %jl_value_t*** @jl_pgcstack, align 8, !dbg !1856
ret i8* %30, !dbg !1856
} after: julia> code_llvm(f,())
define i8* @"julia_f;20345"() {
top:
%0 = alloca [4 x %jl_value_t*], align 8
%.sub = getelementptr inbounds [4 x %jl_value_t*]* %0, i64 0, i64 0
%1 = getelementptr [4 x %jl_value_t*]* %0, i64 0, i64 2, !dbg !1965
store %jl_value_t* inttoptr (i64 4 to %jl_value_t*), %jl_value_t** %.sub, align 8
%2 = load %jl_value_t*** @jl_pgcstack, align 8, !dbg !1965
%3 = getelementptr [4 x %jl_value_t*]* %0, i64 0, i64 1, !dbg !1965
%.c = bitcast %jl_value_t** %2 to %jl_value_t*, !dbg !1965
store %jl_value_t* %.c, %jl_value_t** %3, align 8, !dbg !1965
store %jl_value_t** %.sub, %jl_value_t*** @jl_pgcstack, align 8, !dbg !1965
store %jl_value_t* null, %jl_value_t** %1, align 8
%4 = getelementptr [4 x %jl_value_t*]* %0, i64 0, i64 3
store %jl_value_t* null, %jl_value_t** %4, align 8
%5 = load %jl_value_t** inttoptr (i64 140437150467856 to %jl_value_t**), align 16, !dbg !1966
%6 = getelementptr inbounds %jl_value_t* %5, i64 0, i32 0, !dbg !1966
%7 = load %jl_value_t** %6, align 8, !dbg !1966
%8 = icmp eq %jl_value_t* %7, inttoptr (i64 140437117816160 to %jl_value_t*), !dbg !1966
br i1 %8, label %pass, label %fail, !dbg !1966
fail: ; preds = %top
call void @jl_type_error_rt(i8* getelementptr inbounds ([2 x i8]* @_j_str96, i64 0, i64 0), i8* getelementptr inbounds ([11 x i8]* @_j_str2, i64 0, i64 0), %jl_value_t* inttoptr (i64 140437117816160 to %jl_value_t*), %jl_value_t* %5), !dbg !1966
unreachable
pass: ; preds = %top
%9 = load %jl_value_t** inttoptr (i64 140437144057392 to %jl_value_t**), align 16, !dbg !1967
%10 = icmp eq %jl_value_t* %9, null, !dbg !1967
br i1 %10, label %err, label %ok, !dbg !1967
if: ; preds = %ok
%11 = load %jl_value_t** inttoptr (i64 140437206339968 to %jl_value_t**), align 128, !dbg !1968
%12 = icmp eq %jl_value_t* %11, null, !dbg !1968
br i1 %12, label %err1, label %ok2, !dbg !1968
err: ; preds = %pass
call void @jl_undefined_var_error(%jl_value_t* inttoptr (i64 4532941888 to %jl_value_t*)), !dbg !1967
unreachable
ok: ; preds = %pass
%13 = getelementptr inbounds %jl_value_t* %5, i64 1, i32 0, !dbg !1966
%14 = load %jl_value_t** %13, align 8, !dbg !1966
%15 = getelementptr inbounds %jl_value_t* %9, i64 1, i32 0, !dbg !1967
%16 = load %jl_value_t** %15, align 8, !dbg !1967
%17 = icmp eq %jl_value_t* %14, %16, !dbg !1967
br i1 %17, label %if, label %L, !dbg !1967
err1: ; preds = %if
call void @jl_undefined_var_error(%jl_value_t* inttoptr (i64 4533235432 to %jl_value_t*)), !dbg !1968
unreachable
ok2: ; preds = %if
%18 = getelementptr inbounds %jl_value_t* %11, i64 0, i32 0, !dbg !1968
%19 = load %jl_value_t** %18, align 8, !dbg !1968
%20 = icmp eq %jl_value_t* %19, inttoptr (i64 140437117816160 to %jl_value_t*), !dbg !1968
br i1 %20, label %pass4, label %fail3, !dbg !1968
fail3: ; preds = %ok2
call void @jl_type_error_rt(i8* getelementptr inbounds ([2 x i8]* @_j_str96, i64 0, i64 0), i8* getelementptr inbounds ([11 x i8]* @_j_str2, i64 0, i64 0), %jl_value_t* inttoptr (i64 140437117816160 to %jl_value_t*), %jl_value_t* %11), !dbg !1968
unreachable
pass4: ; preds = %ok2
store %jl_value_t* %11, %jl_value_t** %1, align 8, !dbg !1968
%21 = load %jl_value_t** inttoptr (i64 140437168830832 to %jl_value_t**), align 16, !dbg !1968
%22 = icmp eq %jl_value_t* %21, null, !dbg !1968
br i1 %22, label %err5, label %ok6, !dbg !1968
err5: ; preds = %pass4
call void @jl_undefined_var_error(%jl_value_t* inttoptr (i64 4533296200 to %jl_value_t*)), !dbg !1968
unreachable
ok6: ; preds = %pass4
store %jl_value_t* %21, %jl_value_t** %4, align 8, !dbg !1968
%23 = call %jl_value_t* @jl_apply_generic(%jl_value_t* inttoptr (i64 140437132619904 to %jl_value_t*), %jl_value_t** %1, i32 2), !dbg !1968
%24 = getelementptr inbounds %jl_value_t* %23, i64 1, i32 0, !dbg !1968
%25 = load %jl_value_t** %24, align 8, !dbg !1968
%26 = call %jl_value_t* @allocobj(i64 16), !dbg !1968
%27 = getelementptr inbounds %jl_value_t* %26, i64 0, i32 0, !dbg !1968
store %jl_value_t* inttoptr (i64 140437117816160 to %jl_value_t*), %jl_value_t** %27, align 8, !dbg !1968
%28 = getelementptr inbounds %jl_value_t* %26, i64 1, i32 0, !dbg !1968
store %jl_value_t* %25, %jl_value_t** %28, align 8, !dbg !1968
call void @jl_checked_assignment(%jl_value_t* inttoptr (i64 140437150467848 to %jl_value_t*), %jl_value_t* %26), !dbg !1968
br label %L, !dbg !1968
L: ; preds = %ok, %ok6
%"#519###60780.0.in" = phi %jl_value_t* [ %14, %ok ], [ %25, %ok6 ]
%"#519###60780.0" = bitcast %jl_value_t* %"#519###60780.0.in" to i8*, !dbg !1966
%29 = load %jl_value_t** %3, align 8, !dbg !1969
%30 = getelementptr inbounds %jl_value_t* %29, i64 0, i32 0, !dbg !1969
store %jl_value_t** %30, %jl_value_t*** @jl_pgcstack, align 8, !dbg !1969
ret i8* %"#519###60780.0", !dbg !1969
} before: julia> code_native(f,())
.section __TEXT,__text,regular,pure_instructions
Filename: none
Source line: 1
push RBP
mov RBP, RSP
sub RSP, 32
mov QWORD PTR [RBP - 32], 4
Source line: 1
movabs RAX, 4542164272
mov RCX, QWORD PTR [RAX]
mov QWORD PTR [RBP - 24], RCX
lea RCX, QWORD PTR [RBP - 32]
mov QWORD PTR [RAX], RCX
vxorps XMM0, XMM0, XMM0
vmovups XMMWORD PTR [RBP - 16], XMM0
movabs RAX, 140705317604896
Source line: 68
mov RCX, QWORD PTR [RAX]
movabs RAX, 140705301408096
cmp QWORD PTR [RCX], RAX
jne 288
movabs RAX, 140705336983088
mov RAX, QWORD PTR [RAX]
test RAX, RAX
je 200
mov RCX, QWORD PTR [RCX + 8]
cmp RCX, QWORD PTR [RAX + 8]
jne 127
movabs RAX, 140705366698864
Source line: 69
mov RCX, QWORD PTR [RAX]
test RCX, RCX
je 186
movabs RAX, 140705301408096
cmp QWORD PTR [RCX], RAX
jne 211
mov QWORD PTR [RBP - 16], RCX
movabs RAX, 140705503770672
mov RAX, QWORD PTR [RAX]
test RAX, RAX
je 163
Source line: 1
lea RSI, QWORD PTR [RBP - 16]
Source line: 69
mov QWORD PTR [RBP - 8], RAX
movabs RAX, 4526133600
movabs RDI, 140705328437888
mov EDX, 2
call RAX
movabs RCX, 4526172592
movabs RDI, 140705317604888
mov RSI, RAX
call RCX
movabs RAX, 140705317604896
Source line: 71
mov RCX, QWORD PTR [RAX]
movabs RAX, 140705301408096
cmp QWORD PTR [RCX], RAX
jne 93
mov RAX, QWORD PTR [RCX + 8]
mov RCX, QWORD PTR [RBP - 24]
movabs RDX, 4542164272
mov QWORD PTR [RDX], RCX
add RSP, 32
pop RBP
ret
Source line: 68
movabs RAX, 4526151168
movabs RDI, 4550321216
call RAX
Source line: 69
movabs RAX, 4526151168
movabs RDI, 4550613776
call RAX
movabs RAX, 4526151168
movabs RDI, 4550662592
call RAX
Source line: 68
movabs RAX, 4526150976
movabs RDI, 4578510036
movabs RSI, 4578508870
movabs RDX, 140705301408096
call RAX after: julia> code_native(f,())
.section __TEXT,__text,regular,pure_instructions
Filename: none
Source line: 1
push RBP
mov RBP, RSP
push RBX
sub RSP, 40
mov QWORD PTR [RBP - 40], 4
Source line: 1
movabs RAX, 4524784944
mov RCX, QWORD PTR [RAX]
mov QWORD PTR [RBP - 32], RCX
lea RCX, QWORD PTR [RBP - 40]
mov QWORD PTR [RAX], RCX
vxorps XMM0, XMM0, XMM0
vmovups XMMWORD PTR [RBP - 24], XMM0
movabs RAX, 140437150467856
Source line: 67
mov RCX, QWORD PTR [RAX]
movabs RAX, 140437117816160
cmp QWORD PTR [RCX], RAX
jne 272
movabs RAX, 140437144057392
Source line: 68
mov RAX, QWORD PTR [RAX]
test RAX, RAX
je 206
Source line: 67
mov RBX, QWORD PTR [RCX + 8]
cmp RBX, QWORD PTR [RAX + 8]
jne 165
movabs RAX, 140437206339968
Source line: 69
mov RCX, QWORD PTR [RAX]
test RCX, RCX
je 192
movabs RAX, 140437117816160
cmp QWORD PTR [RCX], RAX
jne 195
mov QWORD PTR [RBP - 24], RCX
movabs RAX, 140437168830832
mov RAX, QWORD PTR [RAX]
test RAX, RAX
je 211
Source line: 1
lea RSI, QWORD PTR [RBP - 24]
Source line: 69
mov QWORD PTR [RBP - 16], RAX
movabs RAX, 4508754272
movabs RDI, 140437132619904
mov EDX, 2
call RAX
mov RBX, QWORD PTR [RAX + 8]
movabs RAX, 4509159072
mov EDI, 16
call RAX
movabs RCX, 4508793264
movabs RDX, 140437117816160
mov QWORD PTR [RAX], RDX
mov QWORD PTR [RAX + 8], RBX
movabs RDI, 140437150467848
mov RSI, RAX
call RCX
Source line: 71
mov RAX, QWORD PTR [RBP - 32]
movabs RCX, 4524784944
mov QWORD PTR [RCX], RAX
mov RAX, RBX
add RSP, 40
pop RBX
pop RBP
ret
Source line: 68
movabs RAX, 4508771840
movabs RDI, 4532941888
call RAX
Source line: 69
movabs RAX, 4508771840
movabs RDI, 4533235432
call RAX
Source line: 67
movabs RAX, 4508771648
movabs RDI, 4561122548
movabs RSI, 4561121350
movabs RDX, 140437117816160
call RAX
Source line: 69
movabs RAX, 4508771840
movabs RDI, 4533296200
call RAX |
The codegen in both versions looks pretty insane to me, I suppose because of the lack of type-inference for globals (even with type assertions). |
true, the updated code checks for the previous version checks for |
this is just a theory, since I haven't done testing, but I think this may compile to a faster, simpler pysym macro, since it should avoid the repeated typeassert and pointer dereference