@@ -15,11 +15,20 @@ import Dagger.TimespanLogging: Timespan
15
15
_name_to_color (name:: AbstractString , colors) =
16
16
colors[mod1 (hash (name), length (colors))]
17
17
_name_to_color (name:: AbstractString , :: Nothing ) = " black"
18
- _default_colors = [" red" , " orange" , " green" , " blue" , " purple" , " pink" , " silver" ]
18
+ tab20_colors = [
19
+ " #1f77b4" , " #aec7e8" , " #ff7f0e" , " #ffbb78" ,
20
+ " #2ca02c" , " #98df8a" , " #d62728" , " #ff9896" ,
21
+ " #9467bd" , " #c5b0d5" , " #8c564b" , " #c49c94" ,
22
+ " #e377c2" , " #f7b6d2" , " #7f7f7f" , " #c7c7c7" ,
23
+ " #bcbd22" , " #dbdb8d" , " #17becf" , " #9edae5"
24
+ ]
25
+ _default_colors = tab20_colors
19
26
20
- function logs_to_df (logs:: Dict ; colors= _default_colors, name_to_color= _name_to_color, color_by= :fn )
27
+ function logs_to_df (logs:: Dict , :: Val{:execution} ; colors= _default_colors, name_to_color= _name_to_color, color_by= :fn )
21
28
# Generate function names
22
29
fn_names = Dict {Int, String} ()
30
+ dtask_names = Dict {UInt, String} ()
31
+ uid_to_tid = Dict {UInt, Int} ()
23
32
for w in keys (logs)
24
33
for idx in 1 : length (logs[w][:core ])
25
34
category = logs[w][:core ][idx]. category:: Symbol
@@ -32,10 +41,33 @@ function logs_to_df(logs::Dict; colors=_default_colors, name_to_color=_name_to_c
32
41
@warn " Task names missing from logs"
33
42
fn_names[tid] = " unknown"
34
43
end
44
+ if haskey (logs[w], :taskuidtotid )
45
+ uid_tid = logs[w][:taskuidtotid ][idx]
46
+ if uid_tid != = nothing
47
+ uid, tid = uid_tid:: Pair{UInt,Int}
48
+ uid_to_tid[uid] = tid
49
+ end
50
+ end
51
+ elseif category == :data_annotation && kind == :start
52
+ id = logs[w][:id ][idx]:: NamedTuple
53
+ name = String (id. name)
54
+ obj = id. objectid:: Dagger.LoggedMutableObject
55
+ objid = obj. objid
56
+ if obj. kind == :task
57
+ dtask_names[objid] = name
58
+ end
35
59
end
36
60
end
37
61
end
38
62
63
+ # Process DTasks-to-Thunk mappings
64
+ for (uid, tid) in uid_to_tid
65
+ # Patch in custom name
66
+ if haskey (dtask_names, uid)
67
+ fn_names[tid] = dtask_names[uid]
68
+ end
69
+ end
70
+
39
71
# FIXME : Color eltype
40
72
df = DataFrame (proc= Processor[], proc_name= String[], fn_name= String[], tid= Int[], t_start= UInt64[], t_end= UInt64[], color= Any[])
41
73
Dagger. logs_event_pairs (logs) do w, start_idx, finish_idx
@@ -59,43 +91,42 @@ function logs_to_df(logs::Dict; colors=_default_colors, name_to_color=_name_to_c
59
91
end
60
92
return df
61
93
end
62
-
63
- # Implementation by Przemyslaw Szufel
64
- function Dagger. render_logs (logs:: Dict , :: Val{:plots_gantt_ps} )
65
- df = logs_to_df (logs)
66
-
67
- proc_names = sort! (unique (df. proc_name))
68
- proc_idx = Dict {String,Int} ()
69
- for name in proc_names
70
- proc_idx[name] = findfirst (== (name), proc_names)
71
- end
72
- proc_idxs = map (name-> proc_idx[name], proc_names)
73
- tvals = zeros (UInt64, length (proc_names))
74
- plt = bar (orientation= :h , yticks= (1 : length (proc_names), proc_names), linewidth= 0 ,yflip= true ,color= :green ,legend= nothing )
75
- xlabel! (plt, " Time in seconds" )
76
- dfc = deepcopy (df)
77
- while nrow (dfc) > 0
78
- rowslast = DataFrame ([g[findmax (g. t_end)[2 ],:] for g in groupby (dfc, :proc_name )])
79
- tvals .= .0
80
- for i in 1 : nrow (rowslast)
81
- tvals[proc_idx[rowslast. proc_name[i]]] = rowslast. t_end[i]
94
+ function logs_to_df (logs:: Dict , :: Val{:processor} ; colors= _default_colors, name_to_color= _name_to_color, kwargs... )
95
+ # Collect processor events
96
+ # FIXME : Color eltype
97
+ df = DataFrame (proc= Processor[], proc_name= String[], category= String[], t_start= UInt64[], t_end= UInt64[], color= Any[])
98
+ Dagger. logs_event_pairs (logs) do w, start_idx, finish_idx
99
+ category = logs[w][:core ][start_idx]. category
100
+ if category in (:compute , :storage_wait , :storage_safe_scan , :proc_run_fetch , :proc_steal_local )
101
+ proc = logs[w][:id ][start_idx]. processor:: Processor
102
+ proc_name = Dagger. short_name (proc)
103
+ t_start = logs[w][:core ][start_idx]. timestamp:: UInt64
104
+ t_end = logs[w][:core ][finish_idx]. timestamp:: UInt64
105
+ category_str = string (category)
106
+ color = name_to_color (category_str, colors)
107
+ push! (df, (;proc, proc_name, category= category_str, t_start, t_end, color))
82
108
end
83
- # setindex!.(Ref(tvals), rowslast.t_end, getindex.(proc_idx, rowslast.proc_name))
84
- bar! (plt, tvals[proc_idxs], orientation= :h , linewidth= 0.5 ,yflip= true ,color= :green )
85
- tvals .= .0
86
- for i in 1 : nrow (rowslast)
87
- tvals[proc_idx[rowslast. proc_name[i]]] = rowslast. t_start[i]
109
+ end
110
+ return df
111
+ end
112
+ function logs_to_df (logs:: Dict , :: Val{:scheduler} ; colors= _default_colors, name_to_color= _name_to_color, kwargs... )
113
+ # Collect scheduler events
114
+ # FIXME : Color eltype
115
+ df = DataFrame (category= String[], t_start= UInt64[], t_end= UInt64[], color= Any[])
116
+ Dagger. logs_event_pairs (logs) do w, start_idx, finish_idx
117
+ category = logs[w][:core ][start_idx]. category
118
+ if category in (:scheduler_init , :scheduler_exit , :init_proc , :remove_proc , :add_thunk , :handle_fault , :schedule , :fire , :enqueue , :take , :finish )
119
+ t_start = logs[w][:core ][start_idx]. timestamp:: UInt64
120
+ t_end = logs[w][:core ][finish_idx]. timestamp:: UInt64
121
+ category_str = string (category)
122
+ color = name_to_color (category_str, colors)
123
+ push! (df, (;category= category_str, t_start, t_end, color))
88
124
end
89
- # setindex!.(Ref(tvals), rowslast.t_start, proc_idx[rowslast.proc_name])
90
- bar! (plt, tvals[proc_idxs], orientation= :h , linewidth= 0.5 ,linecolor= :white ,yflip= true ,color= :white )
91
- annotate! .(Ref (plt),(rowslast. t_start .+ rowslast. t_end) ./ 2 , findfirst .( .== (rowslast. proc_name), Ref (proc_names)), text .(string .(rowslast. tid),9 ,rotation= 90 ))
92
- dfc = dfc[ .! (dfc. tid .∈ Ref (rowslast. tid) ), : ]
93
125
end
94
- # FIXME : theoretic_optimal = simulate_polling(df)[1] + minimum(df.t_start)
95
- theoretic_optimal = minimum (df. t_start)
96
- plot! (plt, [theoretic_optimal,theoretic_optimal], [0 , length (proc_names)+ 1 ],width= 3 ,color= :black ,style= :dot )
97
- return plt
126
+ return df
98
127
end
128
+ logs_to_df (logs:: Dict , :: Val{target} ; kwargs... ) where target =
129
+ throw (ArgumentError (" Invalid target: $(repr (target)) " ))
99
130
100
131
# Implementation adapted from:
101
132
# https://discourse.julialang.org/t/how-to-make-a-gantt-plot-with-plots-jl/95165/7
@@ -105,30 +136,54 @@ end
105
136
Render a Gantt chart of task execution in `logs` using Plots. `kwargs` are passed to `plot` directly.
106
137
"""
107
138
function Dagger. render_logs (logs:: Dict , :: Val{:plots_gantt} ;
139
+ target= :execution ,
108
140
colors= _default_colors, name_to_color= _name_to_color,
109
141
color_by= :fn , kwargs... )
110
- df = logs_to_df (logs; colors, name_to_color, color_by)
142
+ df = logs_to_df (logs, Val {target} (); colors, name_to_color, color_by)
143
+ y_elem = if target == :execution || target == :processor
144
+ :proc_name
145
+ elseif target == :scheduler
146
+ :category
147
+ end
148
+ ylabel = if target == :execution || target == :processor
149
+ " Processor"
150
+ elseif target == :scheduler
151
+ " Category"
152
+ end
153
+ sort! (df, y_elem)
154
+
155
+ global_t_start, global_t_end = extrema (logs[1 ][:core ][idx]. timestamp for idx in 1 : length (logs[1 ][:core ]))
111
156
112
157
rect (w, h, x, y) = Shape (x .+ [0 ,w,w,0 ], y .+ [0 ,0 ,h,h])
113
158
114
- t_init = minimum (df. t_start)
115
- t_start = (df. t_start .- t_init) ./ 1e9
116
- t_end = (df. t_end .- t_init) ./ 1e9
159
+ t_start = (df. t_start .- global_t_start) ./ 1e9
160
+ t_end = (df. t_end .- global_t_start) ./ 1e9
117
161
duration = t_end .- t_start
118
- u = unique (df . proc_name )
162
+ u = unique (getproperty (df, y_elem) )
119
163
dy = Dict (u .=> 1 : length (u))
120
- r = [rect (t1, 1 , t2, dy[t3]) for (t1,t2,t3) in zip (duration, t_start, df. proc_name)]
121
- labels = permutedims (df. fn_name)
122
- # Deduplicate labels
123
- for idx in 1 : length (labels)
124
- if findfirst (other_idx-> labels[other_idx]== labels[idx], 1 : length (labels)) < idx
125
- labels[idx] = " "
164
+ r = [rect (t1, 1 , t2, dy[t3]) for (t1,t2,t3) in zip (duration, t_start, getproperty (df, y_elem))]
165
+ if target == :execution
166
+ labels = permutedims (df. fn_name)
167
+ elseif target == :processor
168
+ labels = permutedims (df. category)
169
+ elseif target == :scheduler
170
+ labels = nothing
171
+ end
172
+
173
+ if labels != = nothing
174
+ # Deduplicate labels
175
+ for idx in 1 : length (labels)
176
+ if findfirst (other_idx-> labels[other_idx]== labels[idx], 1 : length (labels)) < idx
177
+ labels[idx] = " "
178
+ end
126
179
end
127
180
end
128
181
129
182
return plot (r; color= permutedims (df. color), labels,
130
183
yticks= (1.5 : (nrow (df) + 0.5 ), u),
131
- xlabel= " Time (seconds)" , ylabel= " Processor" ,
184
+ xlabel= " Time (seconds)" , ylabel,
185
+ xlim= (0.0 , (global_t_end - global_t_start) / 1e9 ),
186
+ legendalpha= 0 ,
132
187
kwargs... )
133
188
end
134
189
0 commit comments