-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
5 changed files
with
178 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,2 @@ | ||
julia 0.4 | ||
Compat |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,150 @@ | ||
__precompile__() | ||
|
||
module DebuggingUtilities | ||
|
||
# package code goes here | ||
using Compat | ||
|
||
export @showln, test_showline, time_showline | ||
|
||
""" | ||
DebuggingUtilities contains a few tools that may help debug julia code. The | ||
exported tools are: | ||
- `@showln`: a macro for displaying variables and corresponding function, file, and line number information | ||
- `test_showline`: a function that displays progress as it executes a file | ||
- `time_showline`: a function that displays execution time for each expression in a file | ||
""" | ||
DebuggingUtilities | ||
|
||
## @showln | ||
|
||
btvalid(lkup) = !isempty(lkup) | ||
btfrom_c(lkup) = lkup[length(lkup)-1] | ||
|
||
if VERSION < v"0.5.0-dev" | ||
function print_btinfo(io, lkup) | ||
funcname, file, line = lkup | ||
print(io, "in ", funcname, " at ", file, ", line ", line) | ||
end | ||
else | ||
function print_btinfo(io, lkup) | ||
funcname = lkup[1] | ||
print(io, "in ", funcname) | ||
for i = 2:2:length(lkup)-3 | ||
print(io, " at ", lkup[i], ":", lkup[i+1]) | ||
end | ||
end | ||
end | ||
|
||
function show_backtrace1(io, bt) | ||
for t in bt | ||
lkup = ccall(:jl_lookup_code_address, Any, (Ptr{Void}, Int32), t, 0) | ||
if btvalid(lkup) && !btfrom_c(lkup) | ||
funcname = lkup[1] | ||
if funcname != :backtrace | ||
print_btinfo(io, lkup) | ||
break | ||
end | ||
end | ||
end | ||
end | ||
|
||
const showlnio = Ref{IO}(STDOUT) | ||
|
||
""" | ||
`@showln x` prints "x = val", where `val` is the value of `x`, along | ||
with information about the function, file, and line number at which | ||
this statement was executed. For example: | ||
function foo() | ||
x = 5 | ||
@showln x | ||
x = 7 | ||
@showln x | ||
nothing | ||
end | ||
might produce output like | ||
x = 5 | ||
(in foo at ./error.jl:26 at /tmp/showln_test.jl:52) | ||
x = 7 | ||
(in foo at ./error.jl:26 at /tmp/showln_test.jl:54) | ||
This macro causes a backtrace to be taken, and looking up the | ||
corresponding code information is relatively expensive, so using | ||
`@showln` can have a substantial performance cost. | ||
The indentation of the line is proportional to the length of the | ||
backtrace, and consequently is an indication of recursion depth. | ||
Line numbers are not typically correct on julia-0.4. | ||
""" | ||
macro showln(exs...) | ||
blk = Expr(:block) | ||
for ex in exs | ||
push!(blk.args, :(println(showlnio[], " "^indent, sprint(Base.show_unquoted,$(Expr(:quote, ex)),indent)*" = ", repr(begin value=$(esc(ex)) end)))) | ||
end | ||
if !isempty(exs); push!(blk.args, :value); end | ||
quote | ||
local bt = backtrace() | ||
local indent = length(bt) # to mark recursion | ||
$blk | ||
print(showlnio[], " "^indent*"(") | ||
show_backtrace1(showlnio[], bt) | ||
println(showlnio[], ")") | ||
end | ||
end | ||
|
||
""" | ||
`test_showline(filename)` is equivalent to `include(filename)`, except | ||
that it also displays the expression and file-offset (in characters) for | ||
each expression it executes. This can be useful for debugging errors, | ||
especially those that cause a segfault. | ||
""" | ||
function test_showline(filename) | ||
str = @compat readstring(filename) | ||
eval(Main, parse("using Base.Test")) | ||
idx = 1 | ||
while idx < length(str) | ||
ex, idx = parse(str, idx) | ||
try | ||
println(idx, ": ", ex) | ||
end | ||
eval(Main,ex) | ||
end | ||
println("done") | ||
end | ||
|
||
""" | ||
`time_showline(filename)` is equivalent to `include(filename)`, except | ||
that it also analyzes the time expended on each expression within the | ||
file. Once finished, it displays the file-offset (in characters), | ||
elapsed time, and expression in order of increasing duration. This | ||
can help you identify bottlenecks in execution. | ||
This is less useful now that julia has package precompilation, but can | ||
still be handy on occasion. | ||
""" | ||
function time_showline(filename) | ||
str = @compat readstring(filename) | ||
idx = 1 | ||
exprs = Array(Any, 0) | ||
t = Array(Float64, 0) | ||
pos = Array(Int, 0) | ||
while idx < length(str) | ||
ex, idx = parse(str, idx) | ||
push!(exprs, ex) | ||
push!(t, (tic(); eval(Main,ex); toq())) | ||
push!(pos, idx) | ||
end | ||
perm = sortperm(t) | ||
for p in perm | ||
print(pos[p], " ", t[p], ": ") | ||
str = string(exprs[p]) | ||
println(split(str, '\n')[1]) | ||
end | ||
println("done") | ||
end | ||
|
||
end # module |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
# The next line is a deliberate error | ||
sqrt(-3) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
x = 5 | ||
sqrt(x) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,30 @@ | ||
using DebuggingUtilities | ||
using Base.Test | ||
|
||
# write your own tests here | ||
@test 1 == 1 | ||
io = IOBuffer() | ||
DebuggingUtilities.showlnio[] = io | ||
|
||
function foo() | ||
x = 5 | ||
@showln x | ||
x = 7 | ||
@showln x | ||
nothing | ||
end | ||
|
||
foo() | ||
|
||
str = chomp(takebuf_string(io)) | ||
target = ("x = 5", "(in foo at", "x = 7", "(in foo at") | ||
for (i,ln) in enumerate(split(str, '\n')) | ||
ln = lstrip(ln) | ||
@test startswith(ln, target[i]) | ||
end | ||
|
||
DebuggingUtilities.showlnio[] = STDOUT | ||
nothing | ||
|
||
# Just make sure these run | ||
test_showline("noerror.jl") | ||
@test_throws DomainError test_showline("error.jl") | ||
time_showline("noerror.jl") |
dbb621b
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.
Why not just use
@__LINE__
in@showln
?dbb621b
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.
Because I forgot it existed.
dbb621b
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.
This actually dates from julia-0.3, if not earlier.
dbb621b
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.
Hmm,
@__LINE__
seems to capture the line number of the macro. File contents:Testing:
Since you know a thing or two about backtraces, any ideas? It looks like
@__LINE__
is implemented injulia-parser.scm
.dbb621b
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.
You're correct. It's magic and gets expanded upon parsing.
dbb621b
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.
Presumably this is solvable with a "wait to expand
@__LINE__
until macro expansion is done" step, but I'll let @JeffBezanson decide whether he thinks that's worth it.dbb621b
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.
Or rather, @ihnorton (ihnorton/julia@eee075c).