pwrake 0.9.5 → 0.9.6

Sign up to get free protection for your applications and to get access to all the features.
@@ -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 = %w[id task command start end elap status]
58
+ a = HEADER_FOR_PROFILE
39
59
  if @gnu_time
40
- a.concat %w[realtime systime usrtime maxrss averss memsz
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").inspect
80
+ #t.utc.strftime("%F %T.%L")
81
+ t.strftime("%F %T.%L")
63
82
  end
64
83
 
65
- def profile(task, cmd, start_time, end_time, status)
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
- _puts [id, task && task.name.inspect,
73
- cmd.inspect,
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 @gnu_time
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