pwrake 0.9.5 → 0.9.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/README.md +83 -4
- data/lib/pwrake/application.rb +34 -0
- data/lib/pwrake/file_utils.rb +43 -16
- data/lib/pwrake/gfarm_feature.rb +79 -40
- data/lib/pwrake/locality_aware_queue.rb +141 -111
- data/lib/pwrake/logger.rb +7 -1
- data/lib/pwrake/master.rb +21 -2
- data/lib/pwrake/option.rb +106 -56
- data/lib/pwrake/profiler.rb +44 -12
- data/lib/pwrake/report/parallelism.rb +262 -0
- data/lib/pwrake/report/report.rb +355 -0
- data/lib/pwrake/report/report_multi.rb +196 -0
- data/lib/pwrake/report/stat.rb +115 -0
- data/lib/pwrake/report.rb +6 -0
- data/lib/pwrake/shell.rb +30 -10
- data/lib/pwrake/task_algorithm.rb +174 -50
- data/lib/pwrake/task_queue.rb +130 -50
- data/lib/pwrake/version.rb +1 -1
- data/spec/004/Rakefile +1 -1
- data/spec/009/pwrake_conf.yaml +1 -0
- data/spec/011/Rakefile +15 -0
- data/spec/helper.rb +7 -3
- data/spec/pwrake_spec.rb +12 -0
- metadata +15 -9
data/lib/pwrake/profiler.rb
CHANGED
@@ -2,9 +2,19 @@ module Pwrake
|
|
2
2
|
|
3
3
|
class Profiler
|
4
4
|
|
5
|
+
HEADER_FOR_PROFILE =
|
6
|
+
%w[exec_id task_id task_name command
|
7
|
+
start_time end_time elap_time host status]
|
8
|
+
|
9
|
+
HEADER_FOR_GNU_TIME =
|
10
|
+
%w[realtime systime usrtime maxrss averss memsz
|
11
|
+
datasz stcksz textsz pagesz majflt minflt nswap ncswinv
|
12
|
+
ncswvol ninp nout msgrcv msgsnd signum]
|
13
|
+
|
5
14
|
def initialize
|
6
15
|
@lock = Mutex.new
|
7
16
|
@separator = ","
|
17
|
+
@re_escape = /\s#{Regexp.escape(@separator)}/
|
8
18
|
@gnu_time = false
|
9
19
|
@id = 0
|
10
20
|
@io = nil
|
@@ -12,20 +22,30 @@ module Pwrake
|
|
12
22
|
|
13
23
|
attr_accessor :separator, :gnu_time
|
14
24
|
|
15
|
-
def open(file,gnu_time)
|
25
|
+
def open(file,gnu_time=false,plot=false)
|
26
|
+
@file = file
|
16
27
|
@gnu_time = gnu_time
|
28
|
+
@plot = plot
|
17
29
|
@lock.synchronize do
|
18
30
|
@io.close if @io != nil
|
19
31
|
@io = File.open(file,"w")
|
20
32
|
end
|
21
33
|
_puts table_header
|
34
|
+
t = Time.now
|
35
|
+
profile(nil,'pwrake_profile_start',t,t)
|
22
36
|
end
|
23
37
|
|
24
38
|
def close
|
39
|
+
t = Time.now
|
40
|
+
profile(nil,'pwrake_profile_end',t,t)
|
25
41
|
@lock.synchronize do
|
26
42
|
@io.close if @io != nil
|
27
43
|
@io = nil
|
28
44
|
end
|
45
|
+
if @plot
|
46
|
+
require 'pwrake/report'
|
47
|
+
Parallelism.plot_parallelism(@file)
|
48
|
+
end
|
29
49
|
end
|
30
50
|
|
31
51
|
def _puts(s)
|
@@ -35,11 +55,9 @@ module Pwrake
|
|
35
55
|
end
|
36
56
|
|
37
57
|
def table_header
|
38
|
-
a =
|
58
|
+
a = HEADER_FOR_PROFILE
|
39
59
|
if @gnu_time
|
40
|
-
a
|
41
|
-
datasz stcksz textsz pagesz majflt minflt nswap ncswinv
|
42
|
-
ncswvol ninp nout msgrcv msgsnd signum]
|
60
|
+
a += HEADER_FOR_GNU_TIME
|
43
61
|
end
|
44
62
|
a.join(@separator)
|
45
63
|
end
|
@@ -56,27 +74,41 @@ module Pwrake
|
|
56
74
|
else
|
57
75
|
"#{cmd}\necho '#{terminator}':$? "
|
58
76
|
end
|
59
|
-
end
|
77
|
+
end #`
|
60
78
|
|
61
79
|
def format_time(t)
|
62
|
-
t.utc.strftime("%F %T.%L")
|
80
|
+
#t.utc.strftime("%F %T.%L")
|
81
|
+
t.strftime("%F %T.%L")
|
63
82
|
end
|
64
83
|
|
65
|
-
def
|
84
|
+
def self.format_time(t)
|
85
|
+
t.strftime("%F %T.%L")
|
86
|
+
end
|
87
|
+
|
88
|
+
def profile(task, cmd, start_time, end_time, host="", status="")
|
66
89
|
id = @lock.synchronize do
|
67
90
|
id = @id
|
68
91
|
@id += 1
|
69
92
|
id
|
70
93
|
end
|
71
94
|
if @io
|
72
|
-
|
73
|
-
|
95
|
+
if task.kind_of? Rake::Task
|
96
|
+
tname = task.name.inspect
|
97
|
+
task_id = task.task_id
|
98
|
+
else
|
99
|
+
tname = ""
|
100
|
+
task_id = ""
|
101
|
+
end
|
102
|
+
host = '"'+host+'"' if @re_escape =~ host
|
103
|
+
_puts [id, task_id, tname, cmd.inspect,
|
74
104
|
format_time(start_time),
|
75
105
|
format_time(end_time),
|
76
106
|
"%.3f" % (end_time-start_time),
|
77
|
-
status].join(@separator)
|
107
|
+
host, status].join(@separator)
|
78
108
|
end
|
79
|
-
if
|
109
|
+
if status==""
|
110
|
+
1
|
111
|
+
elsif @gnu_time
|
80
112
|
/^([^,]*),/ =~ status
|
81
113
|
Integer($1)
|
82
114
|
else
|
@@ -0,0 +1,262 @@
|
|
1
|
+
module Pwrake
|
2
|
+
|
3
|
+
module Parallelism
|
4
|
+
module_function
|
5
|
+
|
6
|
+
def count_start_end_from_csv(file)
|
7
|
+
a = []
|
8
|
+
start_time = nil
|
9
|
+
|
10
|
+
CSV.foreach(file,:headers=>true) do |row|
|
11
|
+
if row['command'] == 'pwrake_profile_start'
|
12
|
+
start_time = Time.parse(row['start_time'])
|
13
|
+
elsif row['command'] == 'pwrake_profile_end'
|
14
|
+
t = Time.parse(row['start_time']) - start_time
|
15
|
+
a << [t,0]
|
16
|
+
elsif start_time
|
17
|
+
t = Time.parse(row['start_time']) - start_time
|
18
|
+
a << [t,+1]
|
19
|
+
t = Time.parse(row['end_time']) - start_time
|
20
|
+
a << [t,-1]
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
a.sort{|x,y| x[0]<=>y[0]}
|
25
|
+
end
|
26
|
+
|
27
|
+
def exec_density(a)
|
28
|
+
reso = 0.1
|
29
|
+
delta = 1/reso
|
30
|
+
t_end = (a.last)[0]
|
31
|
+
n = (t_end/reso).to_i + 1
|
32
|
+
i = 0
|
33
|
+
t_next = reso
|
34
|
+
d = (n+1).times.map{|i| [reso*i,0]}
|
35
|
+
a.each do |x|
|
36
|
+
while d[i+1][0] <= x[0]
|
37
|
+
i += 1
|
38
|
+
end
|
39
|
+
if x[1] == 1
|
40
|
+
d[i][1] += delta
|
41
|
+
end
|
42
|
+
end
|
43
|
+
d
|
44
|
+
end
|
45
|
+
|
46
|
+
def plot_parallelism(file)
|
47
|
+
a = count_start_end_from_csv(file)
|
48
|
+
return if a.size < 4
|
49
|
+
|
50
|
+
density = exec_density(a)
|
51
|
+
|
52
|
+
base = file.sub(/\.csv$/,"")
|
53
|
+
fpara = base+"_para.dat"
|
54
|
+
|
55
|
+
n = a.size
|
56
|
+
i = 0
|
57
|
+
y = 0
|
58
|
+
y_max = 0
|
59
|
+
|
60
|
+
File.open(fpara,"w") do |f|
|
61
|
+
begin
|
62
|
+
t = 0
|
63
|
+
y_pre = 0
|
64
|
+
n.times do |i|
|
65
|
+
if a[i][0]-t > 0.001
|
66
|
+
f.printf "%.3f %d\n", t, y_pre
|
67
|
+
t = a[i][0]
|
68
|
+
f.printf "%.3f %d\n", t, y
|
69
|
+
end
|
70
|
+
y += a[i][1]
|
71
|
+
y_pre = y
|
72
|
+
y_max = y if y > y_max
|
73
|
+
end
|
74
|
+
rescue
|
75
|
+
p a[i]
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
t_end = (a.last)[0]
|
80
|
+
|
81
|
+
IO.popen("gnuplot","r+") do |f|
|
82
|
+
f.puts "
|
83
|
+
set terminal png
|
84
|
+
set output '#{base}.png'
|
85
|
+
#set rmargin 10
|
86
|
+
set title '#{base}'
|
87
|
+
set xlabel 'time (sec)'
|
88
|
+
set ylabel 'parallelism'
|
89
|
+
|
90
|
+
set arrow 1 from #{t_end},#{y_max*0.5} to #{t_end},0 linecolor rgb 'blue'
|
91
|
+
set label 1 at first #{t_end},#{y_max*0.5} right \"#{t_end}\\nsec\" textcolor rgb 'blue'
|
92
|
+
|
93
|
+
plot '#{fpara}' w l axis x1y1 title 'parallelism'
|
94
|
+
"
|
95
|
+
end
|
96
|
+
|
97
|
+
#puts "Parallelism plot: #{base}.png"
|
98
|
+
end
|
99
|
+
|
100
|
+
|
101
|
+
def plot_parallelism2(file)
|
102
|
+
a = count_start_end_from_csv(file)
|
103
|
+
return if a.size < 4
|
104
|
+
|
105
|
+
density = exec_density(a)
|
106
|
+
|
107
|
+
base = file.sub(/\.csv$/,"")
|
108
|
+
fpara = base+"_para.dat"
|
109
|
+
fdens = base+'_dens.dat'
|
110
|
+
fimg = base+'.png'
|
111
|
+
|
112
|
+
File.open(fdens,"w") do |f|
|
113
|
+
density.each do |t,d|
|
114
|
+
f.puts "#{t} #{d}"
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
n = a.size
|
119
|
+
i = 0
|
120
|
+
y = 0
|
121
|
+
y_max = 0
|
122
|
+
|
123
|
+
File.open(fpara,"w") do |f|
|
124
|
+
begin
|
125
|
+
t = 0
|
126
|
+
y_pre = 0
|
127
|
+
n.times do |i|
|
128
|
+
if a[i][0]-t > 0.001
|
129
|
+
f.printf "%.3f %d\n", t, y_pre
|
130
|
+
t = a[i][0]
|
131
|
+
f.printf "%.3f %d\n", t, y
|
132
|
+
end
|
133
|
+
y += a[i][1]
|
134
|
+
y_pre = y
|
135
|
+
y_max = y if y > y_max
|
136
|
+
end
|
137
|
+
rescue
|
138
|
+
p a[i]
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
t_end = (a.last)[0]
|
143
|
+
|
144
|
+
IO.popen("gnuplot","r+") do |f|
|
145
|
+
f.puts "
|
146
|
+
set terminal png
|
147
|
+
set output '#{fimg}'
|
148
|
+
#set rmargin 10
|
149
|
+
set title '#{base}'
|
150
|
+
set xlabel 'time (sec)'
|
151
|
+
set ylabel 'parallelism'
|
152
|
+
set y2tics
|
153
|
+
set ytics nomirror
|
154
|
+
set y2label 'exec/sec'
|
155
|
+
|
156
|
+
set arrow 1 from #{t_end},#{y_max*0.5} to #{t_end},0 linecolor rgb 'blue'
|
157
|
+
set label 1 \"#{t_end}\\nsec\" at first #{t_end},#{y_max*0.5} right front textcolor rgb 'blue'
|
158
|
+
|
159
|
+
plot '#{fpara}' w l axis x1y1 title 'parallelism', '#{fdens}' w l axis x1y2 title 'exec/sec'
|
160
|
+
"
|
161
|
+
end
|
162
|
+
|
163
|
+
#puts "Parallelism plot: #{fimg}"
|
164
|
+
fimg
|
165
|
+
end
|
166
|
+
|
167
|
+
def read_time_by_host_from_csv(csvtable)
|
168
|
+
a = {}
|
169
|
+
start_time = nil
|
170
|
+
|
171
|
+
csvtable.each do |row|
|
172
|
+
host = row['host']
|
173
|
+
if row['command'] == 'pwrake_profile_start'
|
174
|
+
start_time = Time.parse(row['start_time'])
|
175
|
+
elsif row['command'] == 'pwrake_profile_end'
|
176
|
+
t = Time.parse(row['start_time']) - start_time
|
177
|
+
a.each do |h,v|
|
178
|
+
v << [t,0]
|
179
|
+
end
|
180
|
+
elsif start_time
|
181
|
+
a[host] ||= []
|
182
|
+
t = Time.parse(row['start_time']) - start_time
|
183
|
+
a[host] << [t,+1]
|
184
|
+
t = Time.parse(row['end_time']) - start_time
|
185
|
+
a[host] << [t,-1]
|
186
|
+
end
|
187
|
+
end
|
188
|
+
a
|
189
|
+
end
|
190
|
+
|
191
|
+
def timeline_to_grid(a)
|
192
|
+
resolution = Rational(1,10)
|
193
|
+
|
194
|
+
a = a.sort{|x,y| x[0]<=>y[0]}
|
195
|
+
t_end = (a.last)[0]
|
196
|
+
|
197
|
+
ngrid = (t_end/resolution).floor
|
198
|
+
grid = [[0,0]]
|
199
|
+
|
200
|
+
j = 0
|
201
|
+
a.each do |x|
|
202
|
+
i = (x[0]/resolution).floor
|
203
|
+
while j < i
|
204
|
+
grid[j+1] = [j*resolution,grid[j][1]]
|
205
|
+
j += 1
|
206
|
+
end
|
207
|
+
grid[i][1] += x[1]
|
208
|
+
end
|
209
|
+
return grid
|
210
|
+
end
|
211
|
+
|
212
|
+
def plot_parallelizm_by_host(csvtable,base)
|
213
|
+
fpng = base+"_para_host.png"
|
214
|
+
data = read_time_by_host_from_csv(csvtable)
|
215
|
+
#return if data.size < 4
|
216
|
+
|
217
|
+
grid = []
|
218
|
+
hosts = data.keys.sort
|
219
|
+
hosts.each do |h|
|
220
|
+
a = timeline_to_grid(data[h])
|
221
|
+
grid << a
|
222
|
+
end
|
223
|
+
|
224
|
+
IO.popen("gnuplot","r+") do |f|
|
225
|
+
f.puts "
|
226
|
+
set terminal png
|
227
|
+
set output '#{fpng}'
|
228
|
+
#set rmargin 7
|
229
|
+
set lmargin 16
|
230
|
+
set pm3d map
|
231
|
+
set pm3d corners2color c1
|
232
|
+
set xlabel 'time (sec)'
|
233
|
+
set ytics nomirror
|
234
|
+
set ticslevel 0
|
235
|
+
set format y ''
|
236
|
+
"
|
237
|
+
hosts.each_with_index do |h,i|
|
238
|
+
if /^([^.]+)\./ =~ h
|
239
|
+
h = $1
|
240
|
+
end
|
241
|
+
f.puts "set ytics add ('#{h}' #{i+0.5})"
|
242
|
+
end
|
243
|
+
f.puts "splot '-' using 2:1:3 with pm3d title ''"
|
244
|
+
|
245
|
+
grid.each_with_index do |a,j|
|
246
|
+
a.each do |x|
|
247
|
+
f.printf "%g %g %d\n", j, x[0], x[1]
|
248
|
+
end
|
249
|
+
f.printf "\n"
|
250
|
+
end
|
251
|
+
j = grid.size
|
252
|
+
grid[j-1].each do |x|
|
253
|
+
f.printf "%g %g %d\n", j, x[0], x[1]
|
254
|
+
end
|
255
|
+
f.printf "e\n"
|
256
|
+
end
|
257
|
+
#puts "Parallelism by host: "+fpng
|
258
|
+
fpng
|
259
|
+
end
|
260
|
+
|
261
|
+
end
|
262
|
+
end
|