cloudscale-benchmark 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,28 @@
1
+ require "hashable"
2
+
3
+ ##
4
+ #
5
+ # @author Johannes Hiemer, cloudscale.
6
+ #
7
+ ##
8
+ module Cloudscale
9
+ module Benchmark
10
+
11
+ class BenchmarkRunResultValue
12
+ include Hashable
13
+
14
+ attr_accessor :name, :description, :arguments, :value, :rawString, :scale, :timestamp
15
+
16
+ def initialize()
17
+ end
18
+
19
+ def to_h
20
+ hash = {}
21
+ instance_variables.each {|var| hash[var.to_s.delete("@")] = instance_variable_get(var) }
22
+ return hash
23
+ end
24
+
25
+ end
26
+
27
+ end
28
+ end
@@ -0,0 +1,5 @@
1
+ module Cloudscale
2
+ module Benchmark
3
+ VERSION = "0.0.2"
4
+ end
5
+ end
@@ -0,0 +1,98 @@
1
+ require "#{File.dirname(__FILE__)}/benchmark/version"
2
+ require "http"
3
+ require "optparse"
4
+ require "singleton"
5
+ require "yaml"
6
+ require "json"
7
+ require "#{File.dirname(__FILE__)}/benchmark/agent/init"
8
+ require "#{File.dirname(__FILE__)}/plugins/plugin"
9
+ require "#{File.dirname(__FILE__)}/plugins/preops/plugin_preop"
10
+ Dir["#{File.dirname(__FILE__)}/plugins/*/*.rb"].each { | f | require f }
11
+
12
+ ##
13
+ #
14
+ # @author Johannes Hiemer, cloudscale.
15
+ #
16
+ ##
17
+ module Cloudscale
18
+ module Benchmark
19
+ options = {}
20
+ mandatory = Array.new
21
+
22
+ agent_instance = Cloudscale::Benchmark::Init.new
23
+ agent_instance_id = agent_instance.agent_instance_id()
24
+
25
+ Plugins::PluginPreop.instance.init
26
+
27
+ parser = OptionParser.new do | parser |
28
+
29
+ parser.banner = "Usage: benchmark COMMAND [OPTIONS]"
30
+ parser.separator ""
31
+ parser.separator "Commands"
32
+ parser.separator " start: Start cloudscale benchmark agent"
33
+ parser.separator " stop: Stop cloudscale benchmark agent"
34
+ parser.separator ""
35
+ parser.separator "Options"
36
+
37
+ parser.on("-v", "--version", "Show version information about this program and quit.") do
38
+ puts "Cloudscale Benchmarking " + VERSION
39
+ exit
40
+ end
41
+
42
+ parser.separator "\n"
43
+ parser.separator "Plugin specific Settings"
44
+
45
+ Plugins::PluginPreop.instance.options.each do | key, value |
46
+ if (value[:required])
47
+ mandatory.push(key)
48
+ end
49
+ parser.on(value[:argument][1,2] + " n", value[:argument] + "=n", value[:description]) do | value |
50
+ Plugins::PluginPreop.instance.set_option_value(key, value)
51
+ end
52
+ end
53
+ end
54
+
55
+ begin
56
+ parser.parse!
57
+ missing = mandatory.select{ | param |
58
+ Plugins::PluginPreop.instance.get_option_value(param).nil?
59
+ }
60
+ if not missing.empty?
61
+ puts "\n"
62
+ puts "Error during execution: "
63
+ puts " Missing options: #{missing.join(', ')}"
64
+ puts "\n"
65
+ puts parser
66
+ exit
67
+ else
68
+ Plugins::PluginPreop.instance.save_options
69
+ end
70
+ rescue OptionParser::InvalidOption, OptionParser::MissingArgument
71
+ puts $!.to_s
72
+ puts parser
73
+ exit
74
+ end
75
+
76
+ case ARGV[0]
77
+ when "start"
78
+ plugins = Set.new
79
+
80
+ Plugins::Plugin.plugins.each do | plugin_class |
81
+ plugin = plugin_class.new
82
+ plugins << plugin
83
+ end
84
+
85
+ plugins.each do | plugin |
86
+ if plugin.respond_to?('run')
87
+ plugin.run(agent_instance_id)
88
+ end
89
+ end
90
+
91
+ when "stop"
92
+ puts "call stop on options #{options.inspect}"
93
+ else
94
+ puts parser
95
+ end
96
+
97
+ end
98
+ end
@@ -0,0 +1,42 @@
1
+ require "yaml/store"
2
+
3
+ ##
4
+ #
5
+ # @author Johannes Hiemer, cloudscale.
6
+ #
7
+ ##
8
+ module Cloudscale
9
+ module Constants
10
+ class AgentInstance
11
+
12
+ @@AGENT_INSTANCE_STORE_PATH = "#{File.dirname(__FILE__)}/../store/agent/agent_instance.yml"
13
+
14
+ def self.create(hash)
15
+ settings = YAML::Store.new(@@AGENT_INSTANCE_STORE_PATH)
16
+
17
+ settings.transaction {
18
+ hash.each { | key, value |
19
+ settings[key] = value
20
+ }
21
+ }
22
+ end
23
+
24
+ def self.load
25
+ begin
26
+ YAML.load(File.read(@@AGENT_INSTANCE_STORE_PATH))
27
+ rescue
28
+ return nil
29
+ end
30
+ end
31
+
32
+
33
+ def self.remove
34
+ file = File.read(@@AGENT_INSTANCE_STORE_PATH)
35
+ if (file)
36
+ File.delete(@@AGENT_INSTANCE_STORE_PATH)
37
+ end
38
+ end
39
+
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,25 @@
1
+ require "yaml/store"
2
+
3
+ ##
4
+ #
5
+ # @author Johannes Hiemer, cloudscale.
6
+ #
7
+ ##
8
+ module Cloudscale
9
+
10
+ module Constants
11
+ class Agent
12
+
13
+ @@AGENT_STORE = "#{File.dirname(__FILE__)}/../store/agent/agent.yml"
14
+
15
+ def self.load
16
+ begin
17
+ YAML.load(File.read(@@AGENT_STORE))
18
+ rescue
19
+ return nil
20
+ end
21
+ end
22
+ end
23
+ end
24
+
25
+ end
@@ -0,0 +1,259 @@
1
+ require "popen4"
2
+ require "#{File.dirname(__FILE__)}/../../benchmark/model/benchmark/benchmark_run"
3
+ require "#{File.dirname(__FILE__)}/../../benchmark/model/benchmark/benchmark_run_result"
4
+ require "#{File.dirname(__FILE__)}/../../benchmark/model/benchmark/benchmark_run_result_value"
5
+ require "#{File.dirname(__FILE__)}/../../plugins/preops/plugin_preop"
6
+ require "#{File.dirname(__FILE__)}/../../plugins/plugin"
7
+ require "#{File.dirname(__FILE__)}/../../rest/rest_client"
8
+ require "xmlsimple"
9
+ require "socket"
10
+
11
+
12
+ ##
13
+ #
14
+ # @author Johannes Hiemer, cloudscale.
15
+ # @author Joerg Gottschlich, cloudscale.
16
+ #
17
+ ##
18
+ module Cloudscale
19
+ module Plugins
20
+ class PhoronixBulkExecutor < Plugins::Plugin
21
+ attr_reader :none, :homeDir, :fileSeparator, :development, :numberOfRuns, :properties, :nanoSeconds
22
+ attr_accessor :benchmarkRun, :benchmarkRunResult, :benchmarkTest, :environment
23
+
24
+ def log
25
+ @log = Logger.new(STDOUT)
26
+ end
27
+
28
+ def initialize
29
+ super
30
+ @options = Plugins::PluginPreop.instance.options
31
+ @settings = load_hash()
32
+ @homeDir = Dir.home
33
+ @fileSeparator = File::Separator
34
+ @nanoSeconds = 1000000000
35
+ @environment = []
36
+ # select first non-loopback ip address
37
+ @ip_address = Socket.ip_address_list.find { |ai| ai.ipv4? && !ai.ipv4_loopback? }.ip_address
38
+ @hostname = Socket.gethostname
39
+ end
40
+
41
+ def load_hash()
42
+ begin
43
+ YAML.load(File.read("#{File.dirname(__FILE__)}/../../store/settings/phoronix.yml"))
44
+ rescue
45
+ return nil
46
+ end
47
+ end
48
+
49
+ def resultDir
50
+ @homeDir + @fileSeparator + ".phoronix-test-suite" + @fileSeparator + "test-results"
51
+ end
52
+
53
+ def lockFile
54
+ @homeDir + @fileSeparator + ".phoronix-test-suite" + @fileSeparator + "run_lock"
55
+ end
56
+
57
+ def compileParams(benchmarkCommand, testLabel)
58
+ benchmarkCommand + " " + testLabel
59
+ end
60
+
61
+ def testLabel(benchmarkTest)
62
+ "pts/" + benchmarkTest["identifier"] + "-" + benchmarkTest["version"]
63
+ end
64
+
65
+ def isRunning
66
+ File.exists?(lockFile)
67
+ end
68
+
69
+ def run(agentInstanceId)
70
+
71
+ begin # main loop
72
+
73
+ if (isRunning())
74
+ log.info("There are currently test cases running on this machine. Don't run two instances at a time.")
75
+ abort
76
+ else
77
+ puts "Querying server for scheduled benchmark tests..."
78
+ benchmarkRuns = client.searchAny('benchmarkRuns', 'findByBenchmarkInstanceAgentInstanceIdAndStatus',
79
+ { :agentInstanceId => agentInstanceId, :status => 'scheduled' })
80
+
81
+ benchmarkRuns = benchmarkRuns["content"]; # TODO: better put to rest client helper
82
+
83
+ # if we have benchmarks => run
84
+ if (benchmarkRuns.any?)
85
+ puts "Received " + benchmarkRuns.length.to_s + " scheduled tests, starting execution..."
86
+ benchmarkRuns.each do |benchmarkRun|
87
+ reset()
88
+ @benchmarkRun = Benchmark::BenchmarkRun.new(benchmarkRun)
89
+ executeBenchmark()
90
+ end
91
+ else
92
+ puts Time.now.utc.to_s + ": There are currently no tests scheduled for this agent. Running execution again in two minutes."
93
+ sleep 120
94
+ end
95
+ end
96
+ end until false
97
+ end
98
+
99
+ def executeBenchmark()
100
+ @benchmarkTest = @benchmarkRun.benchmarkTest
101
+ @environment.push(@settings["env"]["numberOfRunsVar"] + "=" + @benchmarkTest["numberOfRuns"].to_s)
102
+ @benchmarkRunResult = Benchmark::BenchmarkRunResult.new(@benchmarkRun)
103
+
104
+
105
+ puts "Executing BenchmarkTest " + @benchmarkTest["name"];
106
+
107
+ # install benchmark test
108
+ # update status on server
109
+ @benchmarkRun.running!("Installing BenchmarkTest " + @benchmarkTest["name"]);
110
+ post_status_update()
111
+ batchInstall()
112
+
113
+ # execute benchmark test
114
+ # update status on server
115
+ @benchmarkRun.running!("Running BenchmarkTest " + @benchmarkTest["name"]);
116
+ post_status_update()
117
+ batchRun()
118
+
119
+ # Post results
120
+ # Replace object with url
121
+ @benchmarkRunResult.benchmarkRun = RestClientWrapper.load_entity_ref(@benchmarkRunResult.benchmarkRun.to_h)["href"]
122
+
123
+ # post result entity
124
+ client.post("benchmarkRunResults", @benchmarkRunResult)
125
+
126
+ puts "Results posted to server."
127
+
128
+ end
129
+
130
+ def batchInstall
131
+ installCommand = compileParams("batch-install", testLabel(@benchmarkTest))
132
+ status = POpen4.popen4("sh") do | stdout, stderr, stdin, pid |
133
+ stdin.puts @settings["executable"] + " " + installCommand
134
+ stdin.close
135
+
136
+ puts "pid : #{ pid }"
137
+ puts "stdout : #{ stdout.read.strip }"
138
+ puts "stderr : #{ stderr.read.strip }"
139
+ end
140
+ end
141
+
142
+ def batchRun
143
+ installCommand = compileParams("batch-run", testLabel(@benchmarkTest))
144
+ startStamp = Time.now
145
+ puts "Start time: "+startStamp.utc.to_s
146
+ if (!@options["development"])
147
+ status = POpen4.popen4("sh") do | stdout, stderr, stdin, pid |
148
+ stdin.puts @settings["executable"] + " " + installCommand
149
+ stdin.close
150
+
151
+ puts "pid : #{ pid }"
152
+ puts "stdout : #{ stdout.read.strip }"
153
+ puts "stderr : #{ stderr.read.strip }"
154
+ end
155
+ end
156
+ stopStamp = Time.now
157
+ puts "End time: "+stopStamp.utc.to_s
158
+ executionTime = (stopStamp - startStamp) # / @nanoSeconds;
159
+
160
+ puts "Benchmark " + testLabel(@benchmarkTest) + " executed in " + executionTime.to_s + " seconds"
161
+
162
+
163
+ # storing benchmarking execution gross timer
164
+ resultValueTimer = Benchmark::BenchmarkRunResultValue.new()
165
+ resultValueTimer.name = "ExecRuntime"
166
+ resultValueTimer.description = "Benchmark runtime measured by execution handler"
167
+ resultValueTimer.value = executionTime.to_s
168
+ resultValueTimer.scale = "Seconds"
169
+ # add timer value to result
170
+ @benchmarkRunResult.pushResultValue(resultValueTimer)
171
+
172
+ # get results here
173
+ puts "Collecting results from xml"
174
+ # walk result files (usually only one)
175
+ files = resultFiles()
176
+ files.each do |f|
177
+ puts "Processing #{f}..."
178
+
179
+ # read result file contents
180
+ resultxml = File.read(f)
181
+ if (resultxml == nil)
182
+ @benchmarkRun.failed!("ERROR, no xml results found")
183
+ post_status_update()
184
+ return
185
+ end
186
+
187
+ # convert xml to result objects
188
+ results = compileResults(resultxml)
189
+ if (! results.empty?)
190
+ @benchmarkRun.succeed!("OK, finished successfully.")
191
+ else
192
+ @benchmarkRun.failed!("ERROR, no results")
193
+ end
194
+ post_status_update()
195
+
196
+ end
197
+
198
+ end # batchRun
199
+
200
+
201
+ def compileResults(xml)
202
+
203
+ @benchmarkRunResult.rawBenchmarkOutput = xml
204
+ @benchmarkRunResult.ip_address = @ip_address
205
+ @benchmarkRunResult.hostname = @hostname
206
+
207
+ # parse result xml and convert to object
208
+ results = XmlSimple.xml_in(xml)
209
+
210
+ # loop over results and create
211
+ results['Result'].each do |res|
212
+
213
+ res['Data'].each do |entry|
214
+
215
+ # create BenchmarkRunResultValue - copy values from result XML
216
+ value = Benchmark::BenchmarkRunResultValue.new()
217
+ value.name = results['System'][0]['Identifier'][0]
218
+ value.timestamp = results['System'][0]['Timestamp']
219
+ value.description = res['Description'][0] || results["Generated"][0]["TestClient"][0] + "\n" + results["Generated"][0]["Description"][0]
220
+ value.arguments = res['Arguments'][0].empty? ? "" : res['Arguments'][0]
221
+ value.scale = res['Scale'][0]
222
+ value.value = entry['Entry'][0]['Value'][0]
223
+ value.rawString = entry['Entry'][0]['RawString'][0]
224
+
225
+ # add benchmark to result instance var
226
+ @benchmarkRunResult.pushResultValue(value)
227
+
228
+ value
229
+
230
+ end
231
+ end
232
+
233
+ end
234
+
235
+
236
+ def resultFiles
237
+ puts "Loading files from " + resultDir + @fileSeparator + "**/test-1.xml"
238
+ Dir[resultDir() + @fileSeparator + "**/test-1.xml"] ## TODO CHECK if this yields one file only and the right one, too :)
239
+ end
240
+
241
+ def reset()
242
+ @benchmarkRun = nil
243
+ @benchmarkRunResult = nil
244
+ if (!@options["development"] && File.exists?(resultDir))
245
+ FileUtils.rm_rf(resultDir)
246
+ end
247
+ end
248
+
249
+ def post_status_update
250
+ # post benchmarkRun status update
251
+ client.patch("benchmarkRuns", @benchmarkRun.id, @benchmarkRun.get_status_hash())
252
+ # TODO: error handling
253
+ end
254
+
255
+
256
+ end
257
+ end
258
+ end
259
+