Skip to content

Commit a3a4cba

Browse files
timholyKristofferC
authored andcommitted
Profile: add line number correction (Revise) (#34235)
This ensures that Profiling will report the current line number in interactively-modified code.
1 parent 6f7b736 commit a3a4cba

File tree

3 files changed

+47
-2
lines changed

3 files changed

+47
-2
lines changed

stdlib/Profile/src/Profile.jl

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -196,9 +196,16 @@ function retrieve()
196196
end
197197

198198
function getdict(data::Vector{UInt})
199+
# Lookup is expensive, so do it only once per ip.
200+
udata = unique(data)
199201
dict = LineInfoDict()
200-
for ip in data
201-
get!(() -> lookup(convert(Ptr{Cvoid}, ip)), dict, UInt64(ip))
202+
for ip in udata
203+
st = lookup(convert(Ptr{Cvoid}, ip))
204+
# To correct line numbers for moving code, put it in the form expected by
205+
# Base.update_stackframes_callback[]
206+
stn = map(x->(x, 1), st)
207+
try Base.invokelatest(Base.update_stackframes_callback[], stn) catch end
208+
dict[UInt64(ip)] = map(first, stn)
202209
end
203210
return dict
204211
end

stdlib/Profile/test/runtests.jl

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,3 +93,21 @@ end
9393
@test delay_ == 0.0005
9494
Profile.init(n=1_000_000, delay=def_delay)
9595
end
96+
97+
@testset "Line number correction" begin
98+
@profile busywait(1, 20)
99+
_, fdict0 = Profile.flatten(Profile.retrieve()...)
100+
Base.update_stackframes_callback[] = function(list)
101+
modify((sf, n)) = sf.func == :busywait ? (StackTraces.StackFrame(sf.func, sf.file, sf.line+2, sf.linfo, sf.from_c, sf.inlined, sf.pointer), n) : (sf, n)
102+
map!(modify, list, list)
103+
end
104+
_, fdictc = Profile.flatten(Profile.retrieve()...)
105+
Base.update_stackframes_callback[] = identity
106+
function getline(sfs)
107+
for sf in sfs
108+
sf.func == :busywait && return sf.line
109+
end
110+
nothing
111+
end
112+
@test getline(values(fdictc)) == getline(values(fdict0)) + 2
113+
end

test/errorshow.jl

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -596,6 +596,26 @@ end
596596
end
597597
end
598598

599+
@testset "Line number correction" begin
600+
getbt() = backtrace()
601+
bt = getbt()
602+
Base.update_stackframes_callback[] = function(list)
603+
modify((sf, n)) = sf.func == :getbt ? (StackTraces.StackFrame(sf.func, sf.file, sf.line+2, sf.linfo, sf.from_c, sf.inlined, sf.pointer), n) : (sf, n)
604+
map!(modify, list, list)
605+
end
606+
io = IOBuffer()
607+
Base.show_backtrace(io, bt)
608+
outputc = split(String(take!(io)), '\n')
609+
Base.update_stackframes_callback[] = identity
610+
Base.show_backtrace(io, bt)
611+
output0 = split(String(take!(io)), '\n')
612+
function getline(output)
613+
idx = findfirst(str->occursin("getbt", str), output)
614+
return parse(Int, match(r":(\d*)$", output[idx]).captures[1])
615+
end
616+
@test getline(outputc) == getline(output0) + 2
617+
end
618+
599619
# issue #30633
600620
@test_throws ArgumentError("invalid index: \"foo\" of type String") [1]["foo"]
601621
@test_throws ArgumentError("invalid index: nothing of type Nothing") [1][nothing]

0 commit comments

Comments
 (0)