-
Notifications
You must be signed in to change notification settings - Fork 48
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
Add option to snoop commands to control spawning separate process vs eval'ing in existing process #252
base: master
Are you sure you want to change the base?
Add option to snoop commands to control spawning separate process vs eval'ing in existing process #252
Changes from all commits
74371aa
25c2d6e
ecdb272
50c030a
e1795a1
24c8c47
995ffd2
c06d84e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
""" | ||
``` | ||
SnoopCompileCore.@snoop_all "output_filename" begin | ||
# Commands to execute | ||
end | ||
``` | ||
|
||
Runs provided commands *in the current process*, and records snoop compilation results for | ||
all phases of the compiler supported by SnoopCompile: Inference, LLVM Optimization, Codegen. | ||
|
||
Returns a tuple of four values: | ||
- `tinf`: Results from `@snoopi_deep` - See https://timholy.github.io/SnoopCompile.jl/stable/snoopi_deep/#Viewing-the-results | ||
- `"snoopl.csv"`: File 1 of results for `@snoopl` - See https://timholy.github.io/SnoopCompile.jl/stable/reference/#SnoopCompile.read_snoopl | ||
- `"snoopl.yaml"`: File 2 of results for `@snoopl` - See https://timholy.github.io/SnoopCompile.jl/stable/reference/#SnoopCompile.read_snoopl | ||
- `"snoopc.csv"`: Results file for `@snoopc` - See https://timholy.github.io/SnoopCompile.jl/stable/snoopc/ | ||
|
||
# Example | ||
```julia | ||
julia> tinf, snoopl_csv, snoopl_yaml, snoopc_csv = @snoop_all "foo" foo(1, 2, 3); | ||
``` | ||
""" | ||
macro snoop_all(fname_prefix, commands) | ||
snoopl_csv_f, snoopl_yaml_f, snoopc_csv_f = | ||
"$fname_prefix.snoopl.csv", "$fname_prefix.snoopl.yaml", "$fname_prefix.snoopc.csv" | ||
tinf = gensym(:tinf) | ||
esc(quote | ||
@snoopc pspawn=false $snoopc_csv_f begin | ||
@snoopl pspawn=false $snoopl_csv_f $snoopl_yaml_f begin | ||
global $tinf = @snoopi_deep begin | ||
@eval $commands | ||
end | ||
end | ||
end; | ||
$tinf, $snoopl_csv_f, $snoopl_yaml_f, $snoopc_csv_f | ||
end) | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,33 +4,50 @@ using Serialization | |
|
||
""" | ||
``` | ||
@snoopc "compiledata.csv" begin | ||
# Commands to execute, in a new process | ||
@snoopc [pspawn=true] [String["<julia_flags...>"]] "compiledata.csv" begin | ||
# Commands to execute, either in a new process if pspawn==true, or via eval if false. | ||
end | ||
``` | ||
causes the julia compiler to log all functions compiled in the course | ||
of executing the commands to the file "compiledata.csv". This file | ||
can be used for the input to `SnoopCompile.read`. | ||
|
||
Julia flags can optionally be passed as a string or an array of strings, which will be set | ||
on the newly spawned julia process if `pspawn=true`. If `pspawn=false`, setting | ||
`julia_flags` will be ignored. | ||
|
||
If `pspawn=false`, the commands will be run in the same julia process, via `eval()` in | ||
the current module. This will only report _new_ compilations, that haven't already been | ||
cached in the current julia process, which can be (carefully) used to prune down the | ||
results to only the code you are interested in. | ||
""" | ||
macro snoopc(flags, filename, commands) | ||
return :(snoopc($(esc(flags)), $(esc(filename)), $(QuoteNode(commands)))) | ||
macro snoopc(args...) | ||
@assert 4 >= length(args) >= 2 """Usage: @snoopl [args...] "snoopl.csv" "snoopl.yaml" commands""" | ||
flags, (filename, commands) = args[1:end-2], args[end-1:end] | ||
pspawn_expr, julia_flags = begin | ||
if length(flags) == 2 | ||
flags[1], flags[2] | ||
elseif flags[1].head == :(=) && flags[1].args[1] == :pspawn | ||
flags[1], String[] | ||
else | ||
:(pspawn=false), flags[1] | ||
end | ||
end | ||
return :(snoopc($(esc(julia_flags)), $(esc(filename)), $(QuoteNode(commands)), $__module__; $(esc(pspawn_expr)))) | ||
end | ||
macro snoopc(filename, commands) | ||
return :(snoopc(String[], $(esc(filename)), $(QuoteNode(commands)))) | ||
end | ||
|
||
function snoopc(flags, filename, commands) | ||
println("Launching new julia process to run commands...") | ||
# addprocs will run the unmodified version of julia, so we | ||
# launch it as a command. | ||
function snoopc(flags, filename, commands, _module=nothing; pspawn=true) | ||
if pspawn | ||
println("Launching new julia process to run commands...") | ||
end | ||
code_object = """ | ||
using Serialization | ||
while !eof(stdin) | ||
Core.eval(Main, deserialize(stdin)) | ||
end | ||
Core.eval(Main, deserialize(IOBuffer(read(stdin)))) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Any particular reason for this change? What if Is it possible that this is the change that causes the closed stream issue? It seems possible that Julia 1.0 is not being as careful as this code. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Alas, this is not responsible for the error -- this was my attempt to fix it, but it didn't help. I can happily revert these changes, yeah. |
||
""" | ||
process = open(`$(Base.julia_cmd()) $flags --eval $code_object`, stdout, write=true) | ||
serialize(process, quote | ||
record_and_run_quote = quote | ||
let io = open($filename, "w") | ||
ccall(:jl_dump_compiles, Nothing, (Ptr{Nothing},), io.handle) | ||
try | ||
|
@@ -40,9 +57,20 @@ function snoopc(flags, filename, commands) | |
close(io) | ||
end | ||
end | ||
exit() | ||
end) | ||
wait(process) | ||
println("done.") | ||
end | ||
|
||
if pspawn | ||
# addprocs will run the unmodified version of julia, so we | ||
# launch it as a command. | ||
process = open(`$(Base.julia_cmd()) $flags --eval $code_object`, stdout, write=true) | ||
serialize(process, quote | ||
$record_and_run_quote | ||
end) | ||
close(process) | ||
wait(process) | ||
println("done.") | ||
else | ||
Core.eval(_module, record_and_run_quote) | ||
end | ||
nothing | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
using Test | ||
|
||
using SnoopCompile | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can't be run as a standalone unless either you say |
||
|
||
f(x) = 2^x + 100 | ||
|
||
@testset "basic snoop_all" begin | ||
# First time not empty | ||
tinf, snoopl_csv, snoopl_yaml, snoopc_csv = | ||
SnoopCompileCore.@snoop_all "snoop_all-f" f(2) | ||
|
||
@test length(collect(flatten(tinf))) > 1 | ||
@test filesize(snoopl_csv) != 0 | ||
@test filesize(snoopl_yaml) != 0 | ||
@test filesize(snoopc_csv) != 0 | ||
|
||
rm(snoopl_csv) | ||
rm(snoopl_yaml) | ||
rm(snoopc_csv) | ||
|
||
# Second run is empty because f(x) is already compiled | ||
tinf, snoopl_csv, snoopl_yaml, snoopc_csv = | ||
SnoopCompileCore.@snoop_all "snoop_all-f" f(2) | ||
|
||
@test length(collect(flatten(tinf))) == 1 | ||
@test filesize(snoopl_csv) == 0 | ||
@test filesize(snoopl_yaml) == 0 | ||
@test filesize(snoopc_csv) == 0 | ||
|
||
rm(snoopl_csv) | ||
rm(snoopl_yaml) | ||
rm(snoopc_csv) | ||
end | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can't we just include this macro into
SnoopCompileCore/src/snoopl.jl
? It's the same condition for including it that we use for@snoopl
.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, good idea. I've just moved it into the same if-block. I guess it doesn't necessarily belong in
snoopl.jl
because it will snoop all three types of compilation, which is why I put it in its own file.Can you have another look and let me know if this looks okay? :)