pwrake 0.9.9.2 → 2.0.0

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.
Files changed (78) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +2 -0
  3. data/CHANGES_V2.md +90 -0
  4. data/{LICENSE.txt → MIT-LICENSE} +2 -3
  5. data/README +12 -0
  6. data/README.md +75 -52
  7. data/bin/gfwhere-pipe +23 -12
  8. data/bin/pwrake +22 -29
  9. data/bin/pwrake_branch +24 -0
  10. data/lib/pwrake/branch.rb +22 -0
  11. data/lib/pwrake/branch/branch.rb +213 -0
  12. data/lib/pwrake/branch/branch_application.rb +53 -0
  13. data/lib/pwrake/branch/fiber_queue.rb +36 -0
  14. data/lib/pwrake/branch/file_utils.rb +101 -0
  15. data/lib/pwrake/branch/shell.rb +231 -0
  16. data/lib/pwrake/{profiler.rb → branch/shell_profiler.rb} +28 -27
  17. data/lib/pwrake/branch/worker_communicator.rb +104 -0
  18. data/lib/pwrake/{gfarm_feature.rb → gfarm/gfarm_path.rb} +2 -100
  19. data/lib/pwrake/gfarm/gfarm_postprocess.rb +53 -0
  20. data/lib/pwrake/iomux/channel.rb +70 -0
  21. data/lib/pwrake/iomux/handler.rb +124 -0
  22. data/lib/pwrake/iomux/handler_set.rb +35 -0
  23. data/lib/pwrake/iomux/runner.rb +62 -0
  24. data/lib/pwrake/logger.rb +3 -150
  25. data/lib/pwrake/master.rb +30 -137
  26. data/lib/pwrake/master/fiber_pool.rb +69 -0
  27. data/lib/pwrake/master/idle_cores.rb +30 -0
  28. data/lib/pwrake/master/master.rb +345 -0
  29. data/lib/pwrake/master/master_application.rb +150 -0
  30. data/lib/pwrake/master/postprocess.rb +16 -0
  31. data/lib/pwrake/{graphviz.rb → misc/graphviz.rb} +0 -0
  32. data/lib/pwrake/{mcgp.rb → misc/mcgp.rb} +63 -42
  33. data/lib/pwrake/option/host_map.rb +158 -0
  34. data/lib/pwrake/option/option.rb +357 -0
  35. data/lib/pwrake/option/option_filesystem.rb +112 -0
  36. data/lib/pwrake/queue/locality_aware_queue.rb +158 -0
  37. data/lib/pwrake/queue/no_action_queue.rb +67 -0
  38. data/lib/pwrake/queue/queue_array.rb +366 -0
  39. data/lib/pwrake/queue/task_queue.rb +164 -0
  40. data/lib/pwrake/report.rb +1 -0
  41. data/lib/pwrake/report/parallelism.rb +9 -3
  42. data/lib/pwrake/report/report.rb +50 -103
  43. data/lib/pwrake/report/task_stat.rb +83 -0
  44. data/lib/pwrake/task/task_algorithm.rb +107 -0
  45. data/lib/pwrake/task/task_manager.rb +32 -0
  46. data/lib/pwrake/task/task_property.rb +98 -0
  47. data/lib/pwrake/task/task_rank.rb +48 -0
  48. data/lib/pwrake/task/task_wrapper.rb +296 -0
  49. data/lib/pwrake/version.rb +1 -1
  50. data/lib/pwrake/worker/executor.rb +169 -0
  51. data/lib/pwrake/worker/gfarm_directory.rb +90 -0
  52. data/lib/pwrake/worker/invoker.rb +199 -0
  53. data/lib/pwrake/worker/load.rb +14 -0
  54. data/lib/pwrake/worker/log_executor.rb +73 -0
  55. data/lib/pwrake/worker/shared_directory.rb +74 -0
  56. data/lib/pwrake/worker/worker_main.rb +14 -0
  57. data/lib/pwrake/worker/writer.rb +59 -0
  58. data/setup.rb +1212 -1502
  59. data/spec/003/Rakefile +2 -2
  60. data/spec/008/Rakefile +2 -1
  61. data/spec/009/Rakefile +1 -1
  62. data/spec/009/pwrake_conf.yaml +1 -3
  63. data/spec/hosts +0 -2
  64. data/spec/pwrake_spec.rb +9 -8
  65. metadata +50 -21
  66. data/lib/pwrake.rb +0 -19
  67. data/lib/pwrake/application.rb +0 -232
  68. data/lib/pwrake/counter.rb +0 -54
  69. data/lib/pwrake/file_utils.rb +0 -98
  70. data/lib/pwrake/gfwhere_pool.rb +0 -109
  71. data/lib/pwrake/host_list.rb +0 -88
  72. data/lib/pwrake/locality_aware_queue.rb +0 -413
  73. data/lib/pwrake/option.rb +0 -400
  74. data/lib/pwrake/rake_modify.rb +0 -14
  75. data/lib/pwrake/shell.rb +0 -186
  76. data/lib/pwrake/task_algorithm.rb +0 -475
  77. data/lib/pwrake/task_queue.rb +0 -633
  78. data/lib/pwrake/timer.rb +0 -22
@@ -1,400 +0,0 @@
1
- module Pwrake
2
-
3
- START_TIME = Time.now
4
-
5
- module Option
6
-
7
- DEFAULT_CONFFILES = ["pwrake_conf.yaml","PwrakeConf.yaml"]
8
-
9
- def format_time_pid(v)
10
- START_TIME.strftime(v).sub("%$","%05d"%Process.pid)
11
- end
12
-
13
- def parse_opt(s)
14
- case s
15
- when /^(false|nil|off)$/i
16
- false
17
- when /^(true|on)$/i
18
- true
19
- else
20
- s
21
- end
22
- end
23
-
24
- def option_data
25
- [
26
- 'DRYRUN',
27
- 'IGNORE_SYSTEM',
28
- 'IGNORE_DEPRECATE',
29
- 'LOAD_SYSTEM',
30
- 'NOSEARCH',
31
- 'RAKELIB',
32
- 'SHOW_PREREQS',
33
- 'SILENT',
34
- 'TRACE',
35
- 'TRACE_RULES',
36
-
37
- 'FILESYSTEM',
38
- 'SSH_OPTION',
39
- 'PASS_ENV',
40
- 'GNU_TIME',
41
- 'DEBUG',
42
- 'PLOT_PARALLELISM',
43
- 'HALT_QUEUE_WHILE_SEARCH',
44
- 'SHOW_CONF',
45
- 'FAILED_TARGET', # rename(default), delete, leave
46
- 'QUEUE_PRIORITY', # RANK(default), FIFO, LIFO, DFS
47
- 'NOACTION_QUEUE_PRIORITY', # FIFO(default), LIFO, RAND
48
- 'NUM_NOACTION_THREADS', # default=4 when gfarm, else 1
49
- 'STEAL_WAIT',
50
- 'STEAL_WAIT_MAX',
51
- 'GRAPH_PARTITION',
52
- 'PLOT_PARTITION',
53
-
54
- ['HOSTFILE','HOSTS'],
55
- ['LOGFILE','LOG',
56
- proc{|v|
57
- if v
58
- # turn trace option on
59
- Rake.application.options.trace = true
60
- if v == "" || !v.kind_of?(String)
61
- v = "Pwrake%Y%m%d-%H%M%S_%$.log"
62
- end
63
- format_time_pid(v)
64
- end
65
- }],
66
- ['TASKLOG',
67
- proc{|v|
68
- if v
69
- if v == "" || !v.kind_of?(String)
70
- v = "Pwrake%Y%m%d-%H%M%S_%$.task"
71
- end
72
- format_time_pid(v)
73
- end
74
- }],
75
- ['PROFILE',
76
- proc{|v|
77
- if v
78
- if v == "" || !v.kind_of?(String)
79
- v = "Pwrake%Y%m%d-%H%M%S_%$.csv"
80
- end
81
- format_time_pid(v)
82
- end
83
- }],
84
- ['GC_PROFILE',
85
- proc{|v|
86
- if v
87
- if v == "" || !v.kind_of?(String)
88
- v = "Pwrake%Y%m%d-%H%M%S_%$.gcprof"
89
- end
90
- format_time_pid(v)
91
- end
92
- }],
93
- ['NUM_THREADS', proc{|v| v && v.to_i}],
94
- ['THREAD_CREATE_INTERVAL', proc{|v| (v || 0.010).to_f}],
95
- ['DISABLE_AFFINITY', proc{|v| v || ENV['AFFINITY']=='off'}],
96
- ['DISABLE_STEAL', proc{|v| v || ENV['STEAL']=='off'}],
97
- ['GFARM_BASEDIR', proc{|v| v || '/tmp'}],
98
- ['GFARM_PREFIX', proc{|v| v || "pwrake_#{ENV['USER']}"}],
99
- ['GFARM_SUBDIR', proc{|v| v || '/'}],
100
- ['MAX_GFWHERE_WORKER', proc{|v| (v || 8).to_i}],
101
- ['MASTER_HOSTNAME', proc{|v| (v || begin;`hostname -f`;rescue;end || '').chomp}],
102
- ['WORK_DIR',proc{|v|
103
- v ||= '$HOME/%CWD_RELATIVE_TO_HOME'
104
- v.sub('%CWD_RELATIVE_TO_HOME',cwd_relative_to_home)
105
- }],
106
- ]
107
- end
108
-
109
-
110
- # ----- init -----
111
-
112
- def init_option
113
- init_options
114
- init_pass_env
115
- init_logger
116
- Log.info "Options:"
117
- @opts.each do |k,v|
118
- Log.info " #{k} = #{v.inspect}"
119
- end
120
- if @opts['SHOW_CONF']
121
- require "yaml"
122
- YAML.dump(@opts,$stdout)
123
- exit
124
- end
125
- if @opts['GC_PROFILE']
126
- GC::Profiler.enable
127
- end
128
- @counter = Counter.new
129
- end
130
-
131
- attr_reader :host_list
132
- attr_reader :counter
133
- attr_reader :logfile
134
- attr_reader :queue_class
135
- attr_reader :shell_class
136
- attr_reader :task_logger
137
-
138
- def pwrake_options
139
- @opts
140
- end
141
-
142
- def init_options
143
- # Read pwrake_conf
144
- @pwrake_conf = Rake.application.options.pwrake_conf
145
-
146
- if @pwrake_conf
147
- if !File.exist?(@pwrake_conf)
148
- raise "Configuration file not found: #{@pwrake_conf}"
149
- end
150
- else
151
- @pwrake_conf = DEFAULT_CONFFILES.find{|fn| File.exist?(fn)}
152
- end
153
-
154
- if @pwrake_conf.nil?
155
- @yaml = {}
156
- else
157
- Log.debug "--- @pwrake_conf=#{@pwrake_conf}"
158
- require "yaml"
159
- @yaml = open(@pwrake_conf){|f| YAML.load(f) }
160
- end
161
-
162
- @opts = { 'PWRAKE_CONF' => @pwrake_conf, }
163
-
164
- option_data.each do |a|
165
- prc = nil
166
- keys = []
167
- case a
168
- when String
169
- keys << a
170
- when Array
171
- a.each do |x|
172
- case x
173
- when String
174
- keys << x
175
- when Proc
176
- prc = x
177
- end
178
- end
179
- end
180
- key = keys[0]
181
- val = search_opts(keys)
182
- val = prc.call(val) if prc
183
- @opts[key] = val if !val.nil?
184
- instance_variable_set("@"+key.downcase, val)
185
- end
186
-
187
- feedback_options [
188
- 'DRYRUN',
189
- 'IGNORE_SYSTEM',
190
- 'IGNORE_DEPRECATE',
191
- 'LOAD_SYSTEM',
192
- 'NOSEARCH',
193
- 'RAKELIB',
194
- 'SHOW_PREREQS',
195
- 'SILENT',
196
- 'TRACE',
197
- 'TRACE_RULES']
198
- Rake.verbose(false) if Rake.application.options.silent
199
- end
200
-
201
- def feedback_options(a)
202
- a.each do |k|
203
- if v=@opts[k]
204
- m = (k.downcase+"=").to_sym
205
- Rake.application.options.send(m,v)
206
- end
207
- end
208
- end
209
-
210
- # Option order:
211
- # command_option > ENV > pwrake_conf > DEFAULT_OPTIONS
212
- def search_opts(keys)
213
- val = Rake.application.options.send(keys[0].downcase.to_sym)
214
- return parse_opt(val) if !val.nil?
215
- #
216
- keys.each do |k|
217
- val = ENV[k.upcase]
218
- return parse_opt(val) if !val.nil?
219
- end
220
- #
221
- return nil if !@yaml
222
- keys.each do |k|
223
- val = @yaml[k.upcase]
224
- return val if !val.nil?
225
- end
226
- nil
227
- end
228
-
229
- def cwd_relative_to_home
230
- Pathname.pwd.relative_path_from(Pathname.new(ENV['HOME'])).to_s
231
- end
232
-
233
- def cwd_relative_if_under_home
234
- home = Pathname.new(ENV['HOME']).realpath
235
- path = pwd = Pathname.pwd.realpath
236
- while path != home
237
- if path.root?
238
- return pwd.to_s
239
- end
240
- path = path.parent
241
- end
242
- return pwd.relative_path_from(home).to_s
243
- end
244
-
245
- def init_pass_env
246
- if envs = @opts['PASS_ENV']
247
- pass_env = {}
248
-
249
- case envs
250
- when Array
251
- envs.each do |k|
252
- k = k.to_s
253
- if v = ENV[k]
254
- pass_env[k] = v
255
- end
256
- end
257
- when Hash
258
- envs.each do |k,v|
259
- k = k.to_s
260
- if v = ENV[k] || v
261
- pass_env[k] = v
262
- end
263
- end
264
- else
265
- raise "invalid option for PASS_ENV in pwrake_conf.yaml"
266
- end
267
-
268
- if pass_env.empty?
269
- @opts.delete('PASS_ENV')
270
- else
271
- @opts['PASS_ENV'] = pass_env
272
- end
273
- end
274
- end
275
-
276
- def init_logger
277
- if Rake.application.options.debug
278
- Log.level = Log::DEBUG
279
- elsif Rake.application.options.trace
280
- Log.level = Log::INFO
281
- else
282
- Log.level = Log::WARN
283
- end
284
-
285
- if @logfile
286
- logdir = File.dirname(@logfile)
287
- if !File.directory?(logdir)
288
- mkdir_p logdir
289
- end
290
- Log.open(@logfile)
291
- else
292
- Log.open($stdout)
293
- end
294
-
295
- if @tasklog
296
- @task_logger = File.open(@tasklog,'w')
297
- h = %w[
298
- task_id task_name start_time end_time elap_time preq preq_host
299
- exec_host shell_id has_action executed file_size file_mtime file_host
300
- ].join(',')+"\n"
301
- @task_logger.print h
302
- end
303
- end
304
-
305
- # ----- setup -----
306
-
307
- def setup_option
308
- set_hosts
309
- set_filesystem
310
- end
311
-
312
- def set_hosts
313
- if @hostfile && @num_threads
314
- raise "Cannot set `hostfile' and `num_threads' simultaneously"
315
- end
316
- @host_list = HostList.new(@hostfile || @num_threads)
317
- Log.info "num_cores=#{@host_list.size}"
318
- end
319
-
320
- def set_filesystem
321
- if fn = @opts["PROFILE"]
322
- Shell.profiler.open(fn,@opts['GNU_TIME'],@opts['PLOT_PARALLELISM'])
323
- end
324
-
325
- @shell_opt = {
326
- :work_dir => @opts['WORK_DIR'],
327
- :pass_env => @opts['PASS_ENV'],
328
- :ssh_opt => @opts['SSH_OPTION']
329
- }
330
-
331
- if @filesystem.nil?
332
- case mount_type
333
- when /gfarm2fs/
334
- @opts['FILESYSTEM'] = @filesystem = 'gfarm'
335
- end
336
- end
337
-
338
- n_noaction_th = @opts['NUM_NOACTION_THREADS']
339
-
340
- case @filesystem
341
- when 'gfarm'
342
- require "pwrake/locality_aware_queue"
343
- require "pwrake/gfarm_feature"
344
- GfarmPath.subdir = @opts['GFARM_SUBDIR']
345
- @filesystem = 'gfarm'
346
- @shell_class = GfarmShell
347
- @shell_opt.merge!({
348
- :work_dir => Dir.pwd,
349
- :single_mp => @opts['GFARM_SINGLE_MP'],
350
- :basedir => @opts['GFARM_BASEDIR'],
351
- :prefix => @opts['GFARM_PREFIX']
352
- })
353
- if @opts['DISABLE_AFFINITY']
354
- @queue_class = TaskQueue
355
- else
356
- @queue_class = LocalityAwareQueue
357
- end
358
- @num_noaction_threads = (n_noaction_th || [8,@host_list.num_threads].max).to_i
359
- @postprocess = GfarmPostprocess.new
360
- Log.debug "--- @queue_class=#{@queue_class}"
361
- else
362
- @filesystem = 'nfs'
363
- @shell_class = Shell
364
- @queue_class = TaskQueue
365
- @num_noaction_threads = (n_noaction_th || 1).to_i
366
- end
367
- end
368
-
369
- def mount_type(d=nil)
370
- mtab = '/etc/mtab'
371
- if File.exist?(mtab)
372
- d ||= mountpoint_of_cwd
373
- open(mtab,'r') do |f|
374
- f.each_line do |l|
375
- if /#{d} (?:type )?(\S+)/o =~ l
376
- return $1
377
- end
378
- end
379
- end
380
- end
381
- nil
382
- end
383
-
384
- def mountpoint_of_cwd
385
- d = Pathname.pwd
386
- while !d.mountpoint?
387
- d = d.parent
388
- end
389
- d
390
- end
391
-
392
- # ----- finish -----
393
-
394
- def finish_option
395
- @task_logger.close if @task_logger
396
- Log.close
397
- end
398
-
399
- end
400
- end
@@ -1,14 +0,0 @@
1
- module Rake
2
-
3
- class Task
4
- include Pwrake::TaskAlgorithm
5
-
6
- alias invoke_orig :invoke
7
-
8
- def invoke(*args)
9
- invoke_modify(*args)
10
- end
11
-
12
- end
13
-
14
- end # module Rake
@@ -1,186 +0,0 @@
1
- module Pwrake
2
-
3
- class Shell
4
- CHARS='0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'
5
- TLEN=32
6
-
7
- OPEN_LIST={}
8
-
9
- def self.nice=(nice)
10
- @@nice=nice
11
- end
12
-
13
- def self.reset_id
14
- @@current_id = 0
15
- end
16
-
17
- @@nice = "nice"
18
- @@shell = "sh"
19
- @@current_id = 0
20
- @@profiler = Profiler.new
21
-
22
- def self.profiler
23
- @@profiler
24
- end
25
-
26
- def initialize(host,opt={})
27
- @host = host || 'localhost'
28
- @lock = Mutex.new
29
- @@current_id += 1
30
- @id = @@current_id
31
- @option = opt
32
- @work_dir = @option[:work_dir] || Dir.pwd
33
- @pass_env = @option[:pass_env]
34
- @ssh_opt = @option[:ssh_opt]
35
- @terminator = ""
36
- TLEN.times{ @terminator << CHARS[rand(CHARS.length)] }
37
- end
38
-
39
- attr_reader :id, :host
40
- attr_accessor :current_task
41
-
42
- def system_cmd(*arg)
43
- if ['localhost','localhost.localdomain','127.0.0.1'].include? @host
44
- [@@nice,@@shell].join(' ')
45
- else
46
- "ssh -x -T -q #{@ssh_opt} #{@host} #{@@nice} #{@@shell}"
47
- end
48
- end
49
-
50
- def start
51
- open(system_cmd)
52
- cd_work_dir
53
- end
54
-
55
- def open(cmd,path=nil)
56
- if path.nil?
57
- path = ENV['PATH']
58
- end
59
- @io = IO.popen( cmd, "r+" )
60
- OPEN_LIST[__id__] = self
61
- _system "export PATH='#{path}'"
62
- if @pass_env
63
- @pass_env.each do |k,v|
64
- _system "export #{k}='#{v}'"
65
- end
66
- end
67
- end
68
-
69
- attr_reader :host, :status, :profile
70
-
71
- def finish
72
- close
73
- end
74
-
75
- def close
76
- @lock.synchronize do
77
- if !@io.closed?
78
- @io.puts("exit")
79
- @io.close
80
- end
81
- OPEN_LIST.delete(__id__)
82
- end
83
- end
84
-
85
- def backquote(*command)
86
- command = command.join(' ')
87
- @lock.synchronize do
88
- a = []
89
- _execute(command){|x| a << x}
90
- a.join("\n")
91
- end
92
- end
93
-
94
- def system(*command)
95
- command = command.join(' ')
96
- Log.debug "--- command=#{command.inspect}"
97
- @lock.synchronize do
98
- _execute(command){|x| Log.stdout_puts x}
99
- end
100
- @status == 0
101
- end
102
-
103
- def cd_work_dir
104
- _system("cd #{@work_dir}") or die
105
- end
106
-
107
- def cd(dir="")
108
- _system("cd #{dir}") or die
109
- end
110
-
111
- def die
112
- raise "Failed at #{@host}, id=#{@id}, cmd='#{@cmd}'"
113
- end
114
-
115
- END {
116
- OPEN_LIST.map do |k,v|
117
- v.close
118
- end
119
- Shell.profiler.close
120
- }
121
-
122
- private
123
-
124
- def _system(cmd)
125
- @cmd = cmd
126
- raise "@io is closed" if @io.closed?
127
- @lock.synchronize do
128
- @io.puts(cmd+"\necho '#{@terminator}':$? ")
129
- @io.flush
130
- status = io_read_loop{}
131
- Integer(status||1) == 0
132
- end
133
- end
134
-
135
- def _backquote(cmd)
136
- @cmd = cmd
137
- raise "@io is closed" if @io.closed?
138
- a = []
139
- @lock.synchronize do
140
- @io.puts(cmd+"\necho '#{@terminator}':$? ")
141
- status = io_read_loop{|x| a << x}
142
- end
143
- a.join("\n")
144
- end
145
-
146
- def _execute(cmd,quote=nil,&block)
147
- @cmd = cmd
148
- raise "@io is closed" if @io.closed?
149
- status = nil
150
-
151
- start_time = Time.now
152
- begin
153
- @io.puts @@profiler.command(cmd,@terminator)
154
- status = io_read_loop(&block)
155
- ensure
156
- end_time = Time.now
157
- @status = @@profiler.profile(@current_task, cmd,
158
- start_time, end_time, host, status)
159
- end
160
- end
161
-
162
- def io_read_loop
163
- while x = @io.gets
164
- x.chomp!
165
- if x[0,TLEN] == @terminator
166
- return x[TLEN+1..-1]
167
- end
168
- yield x
169
- end
170
- end
171
- end
172
-
173
-
174
- class NoActionShell < Shell
175
- def initialize()
176
- @host = '(noaction)'
177
- @@current_id += 1
178
- @id = @@current_id
179
- end
180
- def start
181
- end
182
- def finish
183
- end
184
- end
185
-
186
- end # module Pwrake