Skip to content

Commit 7ec746d

Browse files
committed
GraphVizExt/PlotsExt: Configurable and matching colors
1 parent eb9c651 commit 7ec746d

File tree

2 files changed

+57
-15
lines changed

2 files changed

+57
-15
lines changed

ext/GraphVizExt.jl

+10-4
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,11 @@ function pretty_time(t; digits=3)
2424
end
2525
end
2626

27+
_name_to_color(name::AbstractString, colors) =
28+
colors[mod1(hash(name), length(colors))]
29+
_name_to_color(name::AbstractString, ::Nothing) = "black"
30+
_default_colors = ["red", "orange", "green", "blue", "purple", "pink", "silver"]
31+
2732
"""
2833
Dagger.render_logs(logs::Dict, ::Val{:graphviz}; disconnected=false,
2934
color_by=:fn, layout_engine="dot",
@@ -42,7 +47,8 @@ Options:
4247
"""
4348
function Dagger.render_logs(logs::Dict, ::Val{:graphviz}; disconnected=false,
4449
color_by=:fn, layout_engine="dot",
45-
times::Bool=true, times_digits::Integer=3)
50+
times::Bool=true, times_digits::Integer=3,
51+
colors=_default_colors, name_to_color=_name_to_color)
4652
# Lookup all relevant task/argument dependencies and values in logs
4753
g = SimpleDiGraph()
4854
tid_to_vertex = Dict{Int,Int}()
@@ -108,12 +114,12 @@ function Dagger.render_logs(logs::Dict, ::Val{:graphviz}; disconnected=false,
108114
labels = task_names
109115
all_fns = unique(map(label->first(split(label, " ")), labels[con_vs]))
110116
all_procs = unique(task_procs)
111-
all_colors = ("red", "orange", "green", "blue", "purple", "pink", "silver")
117+
112118
if color_by == :fn
113-
_colors = [all_colors[mod1(i, length(all_colors))] for i in 1:length(all_fns)]
119+
_colors = [name_to_color(all_fns[i], colors) for i in 1:length(all_fns)]
114120
colors = Dict(v=>_colors[findfirst(fn->occursin(fn, labels[v]), all_fns)] for v in con_vs)
115121
elseif color_by == :proc
116-
_colors = [all_colors[mod1(i, length(all_colors))] for i in 1:length(all_procs)]
122+
_colors = [name_to_color(string(all_procs[i]), colors) for i in 1:length(all_procs)]
117123
colors = Dict(v=>_colors[findfirst(proc->proc==task_procs[v], all_procs)] for v in con_vs)
118124
else
119125
throw(ArgumentError("Unknown `color_by` value: $color_by\nAllowed: :fn, :proc"))

ext/PlotsExt.jl

+47-11
Original file line numberDiff line numberDiff line change
@@ -12,17 +12,52 @@ import Dagger
1212
import Dagger: DTask, Chunk, Processor
1313
import Dagger.TimespanLogging: Timespan
1414

15-
function logs_to_df(logs::Dict)
16-
df = DataFrame(proc=Processor[], proc_name=String[], tid=Int[], t_start=UInt64[], t_end=UInt64[])
15+
_name_to_color(name::AbstractString, colors) =
16+
colors[mod1(hash(name), length(colors))]
17+
_name_to_color(name::AbstractString, ::Nothing) = "black"
18+
_default_colors = ["red", "orange", "green", "blue", "purple", "pink", "silver"]
19+
20+
function logs_to_df(logs::Dict; colors=_default_colors, name_to_color=_name_to_color, color_by=:fn)
21+
if color_by == :fn
22+
# Generate function names
23+
fn_names = Dict{Int, String}()
24+
for w in keys(logs)
25+
for idx in 1:length(logs[w][:core])
26+
category = logs[w][:core][idx].category::Symbol
27+
kind = logs[w][:core][idx].kind::Symbol
28+
if category == :add_thunk && kind == :start
29+
tid = logs[w][:id][idx].thunk_id::Int
30+
if haskey(logs[w], :tasknames)
31+
fn_names[tid] = first(split(logs[w][:tasknames][idx]::String, ' '))
32+
else
33+
@warn "Task names missing from logs"
34+
fn_names[tid] = ""
35+
end
36+
end
37+
end
38+
end
39+
end
40+
41+
# FIXME: Color eltype
42+
df = DataFrame(proc=Processor[], proc_name=String[], tid=Int[], t_start=UInt64[], t_end=UInt64[], color=Any[])
1743
Dagger.logs_event_pairs(logs) do w, start_idx, finish_idx
1844
category = logs[w][:core][start_idx].category
1945
if category == :compute
20-
proc = logs[w][:id][start_idx].processor
46+
proc = logs[w][:id][start_idx].processor::Processor
2147
proc_name = Dagger.short_name(proc)
22-
tid = logs[w][:id][start_idx].thunk_id
23-
t_start = logs[w][:core][start_idx].timestamp
24-
t_end = logs[w][:core][finish_idx].timestamp
25-
push!(df, (;proc, proc_name, tid, t_start, t_end))
48+
tid = logs[w][:id][start_idx].thunk_id::Int
49+
fn_name = get(fn_names, tid, "unknown")
50+
t_start = logs[w][:core][start_idx].timestamp::UInt64
51+
t_end = logs[w][:core][finish_idx].timestamp::UInt64
52+
if color_by == :fn
53+
fn_name = fn_names[tid]
54+
color = name_to_color(fn_name, colors)
55+
elseif color_by == :proc
56+
color = name_to_color(proc_name, colors)
57+
else
58+
throw(ArgumentError("Invalid color_by value: $(repr(color_by))"))
59+
end
60+
push!(df, (;proc, proc_name, tid, t_start, t_end, color))
2661
end
2762
end
2863
return df
@@ -72,8 +107,10 @@ end
72107
73108
Render a Gantt chart of task execution in `logs` using Plots. `kwargs` are passed to `plot` directly.
74109
"""
75-
function Dagger.render_logs(logs::Dict, ::Val{:plots_gantt}; kwargs...)
76-
df = logs_to_df(logs)
110+
function Dagger.render_logs(logs::Dict, ::Val{:plots_gantt};
111+
colors=_default_colors, name_to_color=_name_to_color,
112+
color_by=:fn, kwargs...)
113+
df = logs_to_df(logs; colors, name_to_color, color_by)
77114

78115
rect(w, h, x, y) = Shape(x .+ [0,w,w,0], y .+ [0,0,h,h])
79116

@@ -85,8 +122,7 @@ function Dagger.render_logs(logs::Dict, ::Val{:plots_gantt}; kwargs...)
85122
dy = Dict(u .=> 1:length(u))
86123
r = [rect(t1, 1, t2, dy[t3]) for (t1,t2,t3) in zip(duration, t_start, df.proc_name)]
87124

88-
# FIXME: Colors
89-
return plot(r; #=c=permutedims(df.color),=# yticks=(1.5:(nrow(df) + 0.5), u), xlabel="Time (seconds)", ylabel="Processor", labels=false, kwargs...)
125+
return plot(r; color=permutedims(df.color), yticks=(1.5:(nrow(df) + 0.5), u), xlabel="Time (seconds)", ylabel="Processor", labels=false, kwargs...)
90126
end
91127

92128
end # module PlotsExt

0 commit comments

Comments
 (0)