server_scripts 0.0.5 → 0.0.8

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 49c64405f9a8b3a97c13db36fad927e3e3f3353a
4
- data.tar.gz: 795ee015600d00c84752634fbdb0bc56c5325d4f
3
+ metadata.gz: 0d900565278f9df7242f33d23a8b8e22ee67429a
4
+ data.tar.gz: 6deaa6599e7bc742ebcabeee802ea699f9f9d44f
5
5
  SHA512:
6
- metadata.gz: 5f361a20a9bd64803525ec921662a99c03ed91ba290e9c499ecf6872a709da26bb602d742919f227537925787fbad5e39f44889626bb6b8cdf3652bbde230b05
7
- data.tar.gz: 7b4b5ffe44d28777b75b8a669eff5f3180f9bcd860ec6a652716a930f7e87b55fce64713e21048db5e0dc63739816795fb52b9533182b8a6ba523789a4c6a001
6
+ metadata.gz: 685af965add627451c130b29c557d13c3231e6b94730c2d2dfe7882027492d15933a353002978f3df5137222a19eccc7656d5c7307771f866f3ea820de22b411
7
+ data.tar.gz: 9f5c6cd9efd59294f7e8a430be9fa4abd99989a67c6591486dcdf735a9da33d549e5b1671371b2b7073eeacd34c4020da3d280a3485c784e3be96914ba3a835d
@@ -1,8 +1,12 @@
1
1
  # -*- coding: utf-8 -*-
2
+ require 'ptools'
3
+
2
4
  require 'server_scripts/node_type'
3
5
  require 'server_scripts/executor'
4
6
  require 'server_scripts/computer'
5
7
  require 'server_scripts/parser'
8
+ require 'server_scripts/experiment'
9
+ require 'server_scripts/batch_job'
6
10
  require 'server_scripts/version'
7
11
 
8
12
  module ServerScripts
@@ -25,108 +29,6 @@ module ServerScripts
25
29
  ENV["GROUP_NAME"]
26
30
  end
27
31
  end
28
-
29
- class BatchJob
30
- attr_accessor :job_name
31
- attr_accessor :out_file
32
- attr_accessor :err_file
33
- attr_accessor :wall_time
34
- attr_accessor :node_type
35
- attr_accessor :options
36
- attr_accessor :nodes
37
- attr_accessor :npernode
38
- attr_accessor :nprocs
39
- attr_accessor :run_cmd, :executor, :executable
40
- attr_accessor :additional_commands
41
- attr_accessor :enable_intel_itac
42
- attr_accessor :intel_vtune_fname
43
- attr_accessor :source_bashrc
44
- attr_accessor :modules
45
-
46
- attr_reader :env
47
- attr_reader :job_fname
48
- attr_reader :system
49
-
50
- def initialize job_fname
51
- @job_fname = job_fname
52
- @job_name = "sample"
53
- @out_file = "sample_out.log"
54
- @err_file = "sample_err.log"
55
- @wall_time = "1:00:00"
56
- @node_type = NodeType::FULL
57
- @nodes = 1
58
- @npernode = 1
59
- @nprocs = nil
60
- @run_cmd = nil
61
- @executor = :vanilla
62
- @env = {}
63
- @executable = "./a.out"
64
- @job_script = nil
65
- @enable_intel_itac = false
66
- @additional_commands = []
67
- @modules = []
68
- @source_bashrc = true
69
-
70
- yield self
71
- end
72
-
73
- def set_env var, value
74
- raise ArgumentError, "Env #{var} is already set to #{value}." if @env[var]
75
- @env[var] = value
76
- end
77
-
78
- def write_job_script!
79
- generate_job_script! unless @job_script
80
- File.write(@job_fname, @job_script)
81
- end
82
-
83
- def submit!
84
- write_job_script!
85
- Kernel.system(@system.job_submit_cmd(batch_script: @job_fname))
86
- end
87
-
88
- private
89
-
90
- def generate_job_script!
91
- @system = ServerScripts.system.new(@node_type, @nodes, @job_name,
92
- @wall_time, @out_file, @err_file, @env, @modules)
93
- configure_executor!
94
-
95
- @job_script = ""
96
- @job_script += @system.header
97
- @job_script += "\nsource ~/.bashrc\n" if @source_bashrc
98
- @job_script += @system.module_load_cmd
99
-
100
- @job_script += @system.env_setter
101
- @additional_commands.each do |c|
102
- @job_script += c + "\n"
103
- end
104
- @job_script += "#{@executor.run_cmd} #{@executable} #{@options}\n"
105
- end
106
-
107
- def configure_executor!
108
- check_process_counts
109
- @nprocs = @npernode * @nodes
110
-
111
- if @executor == :openmpi
112
- @executor = Executor::OpenMPI.new(npernode: @npernode, nprocs: @nprocs, env: @env)
113
- elsif @executor == :intel
114
- @executor = Executor::IntelMPI.new(npernode: @npernode, nprocs: @nprocs, env: @env)
115
- @executor.enable_itac = !!@enable_intel_itac
116
- @executor.vtune_fname = @intel_vtune_fname
117
- elsif @executor == :vanilla
118
- @executor = Executor::Vanilla.new
119
- else
120
- raise ArgumentError, "Cannot find MPI implementation #{@executor}."
121
- end
122
- end
123
-
124
- def check_process_counts
125
- if @nprocs && @nprocs != @npernode * @nodes
126
- raise ArgumentError, "Number of processes should be #{@npernode * @nodes} not #{@nprocs}"
127
- end
128
- end
129
- end
130
32
  end # module ServerScripts
131
33
 
132
34
 
@@ -0,0 +1,107 @@
1
+ module ServerScripts
2
+ class BatchJob
3
+ attr_accessor :job_name
4
+ attr_accessor :out_file
5
+ attr_accessor :err_file
6
+ attr_accessor :wall_time
7
+ attr_accessor :node_type
8
+ attr_accessor :options
9
+ attr_accessor :nodes
10
+ attr_accessor :npernode
11
+ attr_accessor :nprocs
12
+ attr_accessor :run_cmd, :executor, :executable
13
+ attr_accessor :additional_commands
14
+ attr_accessor :enable_intel_itac
15
+ attr_accessor :intel_vtune_fname
16
+ attr_accessor :source_bashrc
17
+ attr_accessor :modules
18
+ attr_accessor :reservation_id
19
+
20
+ attr_reader :env
21
+ attr_reader :job_fname
22
+ attr_reader :system
23
+
24
+ def initialize job_fname="sample_job.sh"
25
+ @job_fname = job_fname
26
+ @job_name = "sample"
27
+ @out_file = "sample_out.log"
28
+ @err_file = "sample_err.log"
29
+ @wall_time = "1:00:00"
30
+ @node_type = NodeType::FULL
31
+ @nodes = 1
32
+ @npernode = 1
33
+ @nprocs = nil
34
+ @run_cmd = nil
35
+ @executor = :vanilla
36
+ @env = {}
37
+ @executable = "./a.out"
38
+ @job_script = nil
39
+ @enable_intel_itac = false
40
+ @additional_commands = []
41
+ @modules = []
42
+ @source_bashrc = true
43
+ @reservation_id = nil
44
+
45
+ yield self
46
+ end
47
+
48
+ def set_env var, value
49
+ raise ArgumentError, "Env #{var} is already set to #{value}." if @env[var]
50
+ @env[var] = value
51
+ end
52
+
53
+ def write_job_script!
54
+ generate_job_script! unless @job_script
55
+ File.write(@job_fname, @job_script)
56
+ end
57
+
58
+ def submit!
59
+ write_job_script!
60
+ Kernel.system(@system.job_submit_cmd(
61
+ batch_script: @job_fname,
62
+ res_id: @reservation_id))
63
+ end
64
+
65
+ private
66
+
67
+ def generate_job_script!
68
+ @system = ServerScripts.system.new(@node_type, @nodes, @job_name,
69
+ @wall_time, @out_file, @err_file, @env, @modules)
70
+ configure_executor!
71
+
72
+ @job_script = ""
73
+ @job_script += @system.header
74
+ @job_script += "\nsource ~/.bashrc\n" if @source_bashrc
75
+ @job_script += @system.module_load_cmd
76
+
77
+ @job_script += @system.env_setter
78
+ @additional_commands.each do |c|
79
+ @job_script += c + "\n"
80
+ end
81
+ @job_script += "#{@executor.run_cmd} #{@executable} #{@options}\n"
82
+ end
83
+
84
+ def configure_executor!
85
+ check_process_counts
86
+ @nprocs = @npernode * @nodes
87
+
88
+ if @executor == :openmpi
89
+ @executor = Executor::OpenMPI.new(npernode: @npernode, nprocs: @nprocs, env: @env)
90
+ elsif @executor == :intel
91
+ @executor = Executor::IntelMPI.new(npernode: @npernode, nprocs: @nprocs, env: @env)
92
+ @executor.enable_itac = !!@enable_intel_itac
93
+ @executor.vtune_fname = @intel_vtune_fname
94
+ elsif @executor == :vanilla
95
+ @executor = Executor::Vanilla.new
96
+ else
97
+ raise ArgumentError, "Cannot find MPI implementation #{@executor}."
98
+ end
99
+ end
100
+
101
+ def check_process_counts
102
+ if @nprocs && @nprocs != @npernode * @nodes
103
+ raise ArgumentError, "Number of processes should be #{@npernode * @nodes} not #{@nprocs}"
104
+ end
105
+ end
106
+ end
107
+ end
@@ -0,0 +1,17 @@
1
+ module ServerScripts
2
+ # Class that represents an experiment that needs to be conducted. Accepts
3
+ # various parameters that need to be tested and a BatchJob object which it
4
+ # customize depending on the test parameters.
5
+ class Experiment
6
+ attr_accessor :batch_job
7
+ attr_accessor :exp_params
8
+ attr_accessor :job_params
9
+ attr_accessor :executable
10
+
11
+ def initialize exp_name
12
+ @exp_name = exp_name
13
+ end
14
+
15
+
16
+ end # class Experiment
17
+ end # module ServerScripts
@@ -1,16 +1,136 @@
1
1
  module ServerScripts
2
2
  module Parser
3
3
  class ITAC
4
- attr_reader :ideal_trace_file, :real_trace_file
4
+ attr_accessor :real_itac_fname
5
+ attr_reader :ideal_itac_fname
5
6
 
6
7
  def initialize itac_file
7
- @itac_file = itac_file
8
- @ideal_trace_file = nil
9
- @real_trace_file = nil
8
+ check_for_traceanalyzer
9
+
10
+ @real_itac_fname = itac_file
11
+ @ideal_itac_fname = "#{@real_itac_fname}.ideal.single.stf"
12
+ @real_function_profile = nil
13
+ @ideal_function_profile = nil
14
+
15
+ yield self if block_given?
16
+ end
17
+
18
+ def trace!
19
+ generate_ideal_trace!
20
+ analyze_function_profiles!
10
21
  end
11
22
 
12
23
  def generate_ideal_trace!
13
-
24
+ unless File.file?(@ideal_itac_fname)
25
+ Kernel.system(
26
+ "traceanalyzer --cli --ideal -u -o #{@ideal_itac_fname} #{@real_itac_fname}")
27
+ end
28
+ end
29
+
30
+ def analyze_function_profiles!
31
+ unless @real_function_profile
32
+ @real_function_profile = `traceanalyzer --cli --functionprofile #{@real_itac_fname}`
33
+ @real_function_profile = @real_function_profile.split("\n")
34
+ end
35
+ unless @ideal_function_profile
36
+ @ideal_function_profile = `traceanalyzer --cli --functionprofile #{@ideal_itac_fname}`
37
+ @ideal_function_profile = @ideal_function_profile.split("\n")
38
+ end
39
+ end
40
+
41
+ # Total time of real execution including intialization etc.
42
+ def real_app_time
43
+ @total_app_time ||= event_time("Application", kind: :real, how: :all_procs)
44
+ @total_app_time
45
+ end
46
+
47
+ # Ideal MPI time. Only wait time.
48
+ def ideal_mpi_time
49
+ @ideal_mpi_time ||= event_time("MPI", kind: :ideal)
50
+ @ideal_mpi_time
51
+ end
52
+
53
+ # Actual MPI time. Includes wait time and communication time.
54
+ def real_mpi_time
55
+ @real_mpi_time ||= event_time("MPI")
56
+ @real_mpi_time
57
+ end
58
+
59
+ # Time that MPI spent in communication.
60
+ def mpi_comm_time
61
+ real_mpi_time - ideal_mpi_time
62
+ end
63
+
64
+ # Get event time for a particular event. Specify whether from ideal trace or real trace.
65
+ def event_time(event, kind: :real, how: :all_procs)
66
+ if kind == :real
67
+ parse_real_event_time(event, how: how)
68
+ elsif kind == :ideal
69
+ parse_ideal_event_time(event, how: how)
70
+ else
71
+ raise ArgumentError, "kind argument should be either :real or :ideal, not #{kind}."
72
+ end
73
+ end
74
+
75
+ private
76
+
77
+ def get_allprocs_event_time(func_profile, event)
78
+ regex_event = Regexp.quote(event)
79
+ event_time = nil
80
+ func_profile.each do |l|
81
+ if l.match(/"All_Processes";"#{regex_event}"/)
82
+ match_data = l.match /"All_Processes";"#{regex_event}";(\d+);(\d+);(\d+);(\d+)/
83
+ event_time = match_data[2].to_f / 1e9
84
+ break
85
+ end
86
+ end
87
+
88
+ unless event_time
89
+ raise RuntimeError, "no event #{event} could be found in the function profile"
90
+ end
91
+
92
+ event_time
93
+ end
94
+
95
+ def get_perproc_event_time(func_profile, event)
96
+ regex_event = Regexp.quote(event)
97
+ per_proc_event_time = {}
98
+
99
+ func_profile.each do |l|
100
+ if l.match(/"Process\s(\d+)";"#{regex_event}"/)
101
+ match_data = l.match(/"Process\s(\d+)";"#{regex_event}";(\d+);(\d+);(\d+);(\d+)/)
102
+ per_proc_event_time[match_data[1].to_i] = match_data[3].to_f / 1e9
103
+ end
104
+ end
105
+
106
+ values = per_proc_event_time.values
107
+ [values.inject(:+).to_f / values.size, values.min, values.max]
108
+ end
109
+
110
+ def parse_real_event_time(event, how:)
111
+ if how == :all_procs
112
+ get_allprocs_event_time(@real_function_profile, event)
113
+ elsif how == :per_proc
114
+ get_perproc_event_time(@real_function_profile, event)
115
+ else
116
+ raise ArgumentError, "how argument should be either :all_procs or :per_proc, not #{how}."
117
+ end
118
+ end
119
+
120
+ def parse_ideal_event_time(event, how:)
121
+ if how == :all_procs
122
+ get_allprocs_event_time(@ideal_function_profile, event)
123
+ elsif how == :per_proc
124
+ get_perproc_event_time(@ideal_function_profile, event)
125
+ else
126
+ raise ArgumentError, "how argument should be either :all_procs or :per_proc, not #{how}."
127
+ end
128
+ end
129
+
130
+ def check_for_traceanalyzer
131
+ unless File.which("traceanalyzer")
132
+ raise RuntimeError, "Must have intel traceanalyzer executable installed."
133
+ end
14
134
  end
15
135
  end # class ITAC
16
136
  end
@@ -1,48 +1,89 @@
1
1
  module ServerScripts
2
2
  module Parser
3
3
  class StarpuProfile
4
- attr_reader :total_time
5
- attr_reader :total_exec_time
6
- attr_reader :total_sleep_time
7
- attr_reader :total_overhead_time
8
-
4
+
5
+ attr_reader :time_hash
6
+ # Specify the regex that will allow finding the profile files for the given starpu
7
+ # processes. Each process will output one file.
8
+ #
9
+ # Usage:
10
+ # parser = Parser::StarpuProfile.new("4_proc_profile_1_*.starpu_profile")
11
+ # parser.total_time
9
12
  def initialize regex
10
13
  @regex = regex
11
- @total_time = 0.0
12
- @total_exec_time = 0.0
13
- @total_sleep_time = 0.0
14
- @total_overhead_time = 0.0
15
-
14
+ @time_hash = {}
16
15
  extract_data_from_profiles
17
16
  end
18
17
 
18
+ def total_time
19
+ extract_from_time_hash :total_time
20
+ end
21
+
22
+ def total_exec_time
23
+ extract_from_time_hash :exec_time
24
+ end
25
+
26
+ def total_sleep_time
27
+ extract_from_time_hash :sleep_time
28
+ end
29
+
30
+ def total_overhead_time
31
+ extract_from_time_hash :overhead_time
32
+ end
33
+
34
+ def proc_time event:, proc_id:
35
+ time = 0.0
36
+ @time_hash[proc_id].each_value do |thread_info|
37
+ time += thread_info[event]
38
+ end
39
+
40
+ time
41
+ end
42
+
43
+ def time event:, proc_id:, worker_id:
44
+ @time_hash[proc_id][worker_id][event]
45
+ end
46
+
19
47
  private
20
48
 
49
+ def extract_from_time_hash key
50
+ time = 0.0
51
+
52
+ @time_hash.each_value do |proc_time|
53
+ proc_time.each_value do |thread_time|
54
+ time += thread_time[key]
55
+ end
56
+ end
57
+
58
+ time
59
+ end
60
+
21
61
  def extract_data_from_profiles
22
62
  Dir.glob(@regex) do |fname|
63
+ proc_id = fname.match(@regex.gsub("*", "(\\d+)"))[1].to_i
64
+ @time_hash[proc_id] = {}
23
65
  output = File.read(fname).split("\n")
24
-
66
+ recent_cpu = nil
67
+
25
68
  output.each do |line|
69
+ cpu_match = line.match(/CPU\s(\d+)/)
70
+ recent_cpu = cpu_match[1].to_i if cpu_match
26
71
  match_data = line.match(/total\:\s+(\d+)\.\d+\sms\sexecuting\:\s(\d+).\d+\sms\ssleeping\:\s(\d+).\d+\sms\soverhead\s(\d+).\d+\sms/)
27
72
 
28
73
  if match_data
29
74
  exec_time = match_data[2].to_i
30
-
31
75
  if exec_time != 0
32
- @total_time += match_data[1].to_f
33
- @total_exec_time += exec_time.to_f
34
- @total_sleep_time += match_data[3].to_f
35
- @total_overhead_time += match_data[4].to_f
76
+ @time_hash[proc_id][recent_cpu] = {}
77
+ @time_hash[proc_id][recent_cpu][:total_time] = match_data[1].to_f / 1e3
78
+ @time_hash[proc_id][recent_cpu][:exec_time] = match_data[2].to_f / 1e3
79
+ @time_hash[proc_id][recent_cpu][:sleep_time] = match_data[3].to_f / 1e3
80
+ @time_hash[proc_id][recent_cpu][:overhead_time] = match_data[4].to_f / 1e3
36
81
  end
82
+ recent_cpu = nil
37
83
  end
38
84
  end
39
85
  end
40
-
41
- @total_time /= 1e3
42
- @total_exec_time /= 1e3
43
- @total_sleep_time /= 1e3
44
- @total_overhead_time /= 1e3
45
86
  end
46
- end
47
- end
87
+ end # class
88
+ end # module Parser
48
89
  end # module StarpuProfile
@@ -1,3 +1,3 @@
1
1
  module ServerScripts
2
- VERSION = "0.0.5"
2
+ VERSION = "0.0.8"
3
3
  end
@@ -35,6 +35,8 @@ Gem::Specification.new do |spec|
35
35
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
36
36
  spec.require_paths = ["lib"]
37
37
 
38
+ spec.add_runtime_dependency 'ptools'
39
+
38
40
  spec.add_development_dependency 'minitest', '~> 5.11'
39
41
  spec.add_development_dependency 'minitest-hooks'
40
42
  spec.add_development_dependency 'minitest-fail-fast'
metadata CHANGED
@@ -1,15 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: server_scripts
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.5
4
+ version: 0.0.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sameer Deshmukh
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-01-22 00:00:00.000000000 Z
11
+ date: 2020-01-26 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: ptools
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
13
27
  - !ruby/object:Gem::Dependency
14
28
  name: minitest
15
29
  requirement: !ruby/object:Gem::Requirement
@@ -65,6 +79,7 @@ files:
65
79
  - README.md
66
80
  - Rakefile
67
81
  - lib/server_scripts.rb
82
+ - lib/server_scripts/batch_job.rb
68
83
  - lib/server_scripts/computer.rb
69
84
  - lib/server_scripts/computer/abci.rb
70
85
  - lib/server_scripts/computer/base.rb
@@ -75,6 +90,7 @@ files:
75
90
  - lib/server_scripts/executor/mpi_program.rb
76
91
  - lib/server_scripts/executor/valgrind.rb
77
92
  - lib/server_scripts/executor/vanilla.rb
93
+ - lib/server_scripts/experiment.rb
78
94
  - lib/server_scripts/node_type.rb
79
95
  - lib/server_scripts/parser.rb
80
96
  - lib/server_scripts/parser/itac.rb