diff --git a/.travis.yml b/.travis.yml index abc5220..b52f862 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,8 +2,8 @@ language: julia os: - linux julia: - - 0.5 - - 0.6 + - 0.7 + - 1.0 - nightly notifications: email: false diff --git a/REQUIRE b/REQUIRE index a4c0f68..d0177bd 100644 --- a/REQUIRE +++ b/REQUIRE @@ -1,4 +1,4 @@ -julia 0.5 +julia 0.7 Gtk GtkReactive 0.0.3 Cairo 0.5.1 diff --git a/src/ProfileView.jl b/src/ProfileView.jl index 7466e63..8946bfe 100644 --- a/src/ProfileView.jl +++ b/src/ProfileView.jl @@ -2,9 +2,10 @@ __precompile__() module ProfileView +using Profile using Colors -import Base: contains, isequal, show, mimewritable +import Base: isequal, show include("tree.jl") include("pvtree.jl") @@ -14,13 +15,13 @@ using .PVTree include("svgwriter.jl") -immutable TagData +struct TagData ip::UInt status::Int end const TAGNONE = TagData(UInt(0), -1) -type ProfileData +mutable struct ProfileData img lidict imgtags @@ -33,32 +34,32 @@ const gccolor = colorant"red" const colors = distinguishable_colors(13, [bkg,fontcolor,gccolor], lchoices=Float64[65, 70, 75, 80], cchoices=Float64[0, 50, 60, 70], - hchoices=linspace(0, 330, 24))[4:end] + hchoices=range(0, stop=330, length=24))[4:end] function have_display() - !is_unix() && return true - is_apple() && return true + !Sys.isunix() && return true + Sys.isapple() && return true return haskey(ENV, "DISPLAY") end function __init__() - push!(LOAD_PATH, splitdir(@__FILE__)[1]) + push!(LOAD_PATH, @__DIR__) if (isdefined(Main, :IJulia) && !isdefined(Main, :PROFILEVIEW_USEGTK)) || !have_display() - eval(Expr(:import, :ProfileViewSVG)) + @eval import ProfileViewSVG @eval begin view(data = Profile.fetch(); C = false, lidict = nothing, colorgc = true, fontsize = 12, combine = true, pruned = []) = ProfileViewSVG.view(data; C=C, lidict=lidict, colorgc=colorgc, fontsize=fontsize, combine=combine, pruned=pruned) end else - eval(Expr(:import, :ProfileViewGtk)) + @eval import ProfileViewGtk @eval begin view(data = Profile.fetch(); C = false, lidict = nothing, colorgc = true, fontsize = 12, combine = true, pruned = []) = ProfileViewGtk.view(data; C=C, lidict=lidict, colorgc=colorgc, fontsize=fontsize, combine=combine, pruned=pruned) - closeall() = ProfileViewGtk.closeall() @doc """ closeall() Closes all windows opened by ProfileView. -""" -> closeall +""" + closeall() = ProfileViewGtk.closeall() end end pop!(LOAD_PATH) @@ -70,7 +71,7 @@ function prepare(data; C = false, lidict = nothing, colorgc = true, combine = tr end function prepare_data(data, lidict) - bt, counts = Profile.tree_aggregate(data) + bt, counts = tree_aggregate(data) if isempty(counts) Profile.warning_empty() error("Nothing to view") @@ -97,7 +98,7 @@ function prepare_data(data, lidict) # Do code address lookups on all unique instruction pointers uip = unique(vcat(bt...)) if lidict == nothing - lkup = Vector{StackFrame}[Profile.lookup(ip) for ip in uip] + lkup = Vector{StackTraces.StackFrame}[Profile.lookup(ip) for ip in uip] lidict = Dict(zip(uip, lkup)) else lkup = [lidict[ip] for ip in uip] @@ -105,7 +106,7 @@ function prepare_data(data, lidict) bt, uip, counts, lidict, lkup end -prepare_data(::Void, ::Void) = nothing, nothing, nothing, nothing, nothing +prepare_data(::Nothing, ::Nothing) = nothing, nothing, nothing, nothing, nothing function prepare_image(bt, uip, counts, lidict, lkup, C, colorgc, combine, pruned) @@ -170,7 +171,7 @@ function svgwrite(filename::AbstractString; kwargs...) end -mimewritable(::MIME"image/svg+xml", pd::ProfileData) = true +Base.showable(::MIME"image/svg+xml", pd::ProfileData) = true function show(f::IO, ::MIME"image/svg+xml", pd::ProfileData) img = pd.img @@ -267,7 +268,7 @@ function buildtags!(rowtags, parent, level) end t = rowtags[level] for c in parent - t[c.data.hspan] = TagData(c.data.ip, c.data.status) + t[c.data.hspan] .= Ref(TagData(c.data.ip, c.data.status)) buildtags!(rowtags, c, level+1) end end @@ -318,10 +319,10 @@ end function fillrow!(img, j, rng::UnitRange{Int}, colorindex, colorlen, regcolor, gccolor, status) if status > 0 - img[rng,j] = gccolor + img[rng,j] .= gccolor return colorindex else - img[rng,j] = regcolor + img[rng,j] .= regcolor return mod1(colorindex+1, colorlen) end end @@ -407,4 +408,27 @@ function pushpruned!(pruned_ips, pruned, lidict) end end +## A tree representation +# Identify and counts repetitions of all unique backtraces +function tree_aggregate(data::Vector{UInt64}) + iz = findall(iszero, data) # find the breaks between backtraces + treecount = Dict{Vector{UInt64},Int}() + istart = 1 + for iend in iz + tmp = data[iend - 1 : -1 : istart] + treecount[tmp] = get(treecount, tmp, 0) + 1 + istart = iend + 1 + end + bt = Vector{Vector{UInt64}}(undef, 0) + counts = Vector{Int}(undef, 0) + for (k, v) in treecount + if !isempty(k) + push!(bt, k) + push!(counts, v) + end + end + return (bt, counts) +end + + end diff --git a/src/ProfileViewGtk.jl b/src/ProfileViewGtk.jl index 227c8a5..a90b31e 100644 --- a/src/ProfileViewGtk.jl +++ b/src/ProfileViewGtk.jl @@ -8,13 +8,13 @@ using Graphics using Gtk.GConstants.GdkModifierType: SHIFT, CONTROL, MOD1 -type ZoomCanvas +mutable struct ZoomCanvas bb::BoundingBox # in user-coordinates c::Canvas end function __init__() - eval(Expr(:import, :ProfileView)) + @eval import ProfileView end function closeall() @@ -24,13 +24,13 @@ function closeall() nothing end -const window_wrefs = WeakKeyDict{Gtk.GtkWindowLeaf,Void}() +const window_wrefs = WeakKeyDict{Gtk.GtkWindowLeaf,Nothing}() function view(data = Profile.fetch(); lidict=nothing, kwargs...) bt, uip, counts, lidict, lkup = ProfileView.prepare_data(data, lidict) # Display in a window c = canvas(UserUnit) - setproperty!(widget(c), :expand, true) + set_gtk_property!(widget(c), :expand, true) f = Frame(c) tb = Toolbar() bx = Box(:v) @@ -40,8 +40,8 @@ function view(data = Profile.fetch(); lidict=nothing, kwargs...) tb_save_as = ToolButton("gtk-save-as") push!(tb, tb_open) push!(tb, tb_save_as) - signal_connect(open_cb, tb_open, "clicked", Void, (), false, (widget(c),kwargs)) - signal_connect(save_as_cb, tb_save_as, "clicked", Void, (), false, (widget(c),data,lidict,kwargs)) + signal_connect(open_cb, tb_open, "clicked", Nothing, (), false, (widget(c),kwargs)) + signal_connect(save_as_cb, tb_save_as, "clicked", Nothing, (), false, (widget(c),data,lidict,kwargs)) win = Window(bx, "Profile") GtkReactive.gc_preserve(win, c) # Register the window with closeall @@ -57,17 +57,17 @@ function view(data = Profile.fetch(); lidict=nothing, kwargs...) # Ctrl-w and Ctrl-q destroy the window signal_connect(win, "key-press-event") do w, evt if evt.state == CONTROL && (evt.keyval == UInt('q') || evt.keyval == UInt('w')) - @schedule destroy(w) + @async destroy(w) nothing end end - showall(win) + Gtk.showall(win) end function viewprof(c, bt, uip, counts, lidict, lkup; C = false, colorgc = true, fontsize = 12, combine = true, pruned=[]) img, lidict, imgtags = ProfileView.prepare_image(bt, uip, counts, lidict, lkup, C, colorgc, combine, pruned) - img24 = UInt32[reinterpret(UInt32, convert(RGB24, img[i,j])) for i = 1:size(img,1), j = size(img,2):-1:1]' + img24 = Matrix(UInt32[reinterpret(UInt32, convert(RGB24, img[i,j])) for i = 1:size(img,1), j = size(img,2):-1:1]') fv = XY(0.0..size(img24,2), 0.0..size(img24,1)) zr = Signal(ZoomRegion(fv, fv)) sigrb = init_zoom_rubberband(c, zr) diff --git a/src/ProfileViewSVG.jl b/src/ProfileViewSVG.jl index e8c8e07..cb9b498 100644 --- a/src/ProfileViewSVG.jl +++ b/src/ProfileViewSVG.jl @@ -3,7 +3,7 @@ __precompile__() module ProfileViewSVG function __init__() - eval(Expr(:import, :ProfileView)) + @eval import ProfileView end function view(data = Profile.fetch(); C = false, lidict = nothing, colorgc = true, fontsize = 12, combine = true, pruned = true) diff --git a/src/pvtree.jl b/src/pvtree.jl index 7a60cae..d48b257 100644 --- a/src/pvtree.jl +++ b/src/pvtree.jl @@ -5,7 +5,7 @@ using ..Tree export PVData, buildgraph!, prunegraph! # ProfileView data we need attached to each node of the graph: -type PVData +mutable struct PVData ip::UInt # the instruction pointer hspan::UnitRange{Int} # horizontal span (used as the x-axis in display) status::Int # nonzero for special handling, (e.g., gc events) @@ -37,9 +37,9 @@ function buildgraph!(parent::Node, bt::Vector{Vector{UInt}}, counts::Vector{Int} end end ngroups = length(dorder) - group = Vector{Vector{Int}}(ngroups) # indices in bt that have the same sortorder - n = Array{Int}(ngroups) # aggregated counts for this group - order = Array{Int}(ngroups) + group = Vector{Vector{Int}}(undef, ngroups) # indices in bt that have the same sortorder + n = Array{Int}(undef, ngroups) # aggregated counts for this group + order = Array{Int}(undef, ngroups) i = 1 for (key, v) in dorder order[i] = key diff --git a/src/svgwriter.jl b/src/svgwriter.jl index e6e115d..fed5f0d 100644 --- a/src/svgwriter.jl +++ b/src/svgwriter.jl @@ -1,5 +1,5 @@ -const snapsvgjs = joinpath(dirname(@__FILE__), "..", "templates", "snap.svg-min.js") -const viewerjs = joinpath(dirname(@__FILE__), "viewer.js") +const snapsvgjs = joinpath(@__DIR__, "..", "templates", "snap.svg-min.js") +const viewerjs = joinpath(@__DIR__, "viewer.js") function escape_script(js::AbstractString) return replace(js, "]]", "] ]") diff --git a/src/tree.jl b/src/tree.jl index ea8da73..d1f23ae 100644 --- a/src/tree.jl +++ b/src/tree.jl @@ -1,6 +1,6 @@ module Tree -import Base: start, done, next, show +import Base: iterate, show export Node, addchild, @@ -16,14 +16,14 @@ export Node, # Any missing links (e.g., "c" does not have a sibling) link back to itself (c.sibling == c) # With this organization, no arrays need to be allocated. -type Node{T} +mutable struct Node{T} data::T parent::Node{T} child::Node{T} sibling::Node{T} # Constructor for the root of the tree - function (::Type{Node{T}}){T}(data::T) + function Node{T}(data) where T n = new{T}(data) n.parent = n n.child = n @@ -31,15 +31,15 @@ type Node{T} n end # Constructor for all others - function (::Type{Node{T}}){T}(data::T, parent::Node) + function Node{T}(data, parent::Node) where T n = new{T}(data, parent) n.child = n n.sibling = n n end end -Node{T}(data::T) = Node{T}(data) -Node{T}(data::T, parent::Node{T}) = Node{T}(data, parent) +Node(data::T) where {T} = Node{T}(data) +Node(data, parent::Node{T}) where {T} = Node{T}(data, parent) function lastsibling(sib::Node) newsib = sib.sibling @@ -50,7 +50,7 @@ function lastsibling(sib::Node) sib end -function addsibling{T}(oldersib::Node{T}, data::T) +function addsibling(oldersib::Node{T}, data) where T if oldersib.sibling != oldersib error("Truncation of sibling list") end @@ -59,7 +59,7 @@ function addsibling{T}(oldersib::Node{T}, data::T) youngersib end -function addchild{T}(parent::Node{T}, data::T) +function addchild(parent::Node{T}, data) where T newc = Node(data, parent) prevc = parent.child if prevc == parent @@ -80,9 +80,10 @@ show(io::IO, n::Node) = print(io, n.data) # for c in parent # # do something # end -start(n::Node) = n.child -done(n::Node, state::Node) = n == state -next(n::Node, state::Node) = state, state == state.sibling ? n : state.sibling +function iterate(n::Node, state = n.child) + n == state && return nothing + return state, state == state.sibling ? n : state.sibling +end function showedges(io::IO, parent::Node, printfunc = identity) str = printfunc(parent.data) diff --git a/test/test.jl b/test/test.jl index efc9b5a..222d9fc 100644 --- a/test/test.jl +++ b/test/test.jl @@ -1,13 +1,13 @@ +using Profile using ProfileView function profile_test(n) for i = 1:n A = randn(100,100,20) m = maximum(A) - Afft = fft(A) - Am = mapslices(sum, A, 2) + Am = mapslices(sum, A, dims = 2) B = A[:,:,5] - Bsort = mapslices(sort, B, 1) + Bsort = mapslices(sort, B, dims = 1) b = rand(100) C = B.*b end diff --git a/test/tree.jl b/test/tree.jl index c84f70e..5d1e40d 100644 --- a/test/tree.jl +++ b/test/tree.jl @@ -3,7 +3,7 @@ root = Tree.Node(0) @assert Tree.isleaf(root) nchildren = 0 for c in root - nchildren += 1 + global nchildren += 1 end @assert nchildren == 0 c1 = Tree.addchild(root, 1) @@ -17,7 +17,7 @@ c22 = Tree.addchild(c2, 5) nchildren = 0 for c in root @assert !Tree.isroot(c) - nchildren += 1 + global nchildren += 1 end @assert nchildren == 3 @assert Tree.isleaf(c1) @@ -30,5 +30,6 @@ end children2 = [c21,c22] i = 0 for c in c2 + global i @assert c == children2[i+=1] end