roadrunner 4.0.3
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.
- data/LICENSE +3 -0
- data/README +3 -0
- data/Rakefile +41 -0
- data/bin/controller.rb +76 -0
- data/bin/hostmgr.rb +69 -0
- data/bin/nbd_prepare.sh +88 -0
- data/conf/servers.yaml +29 -0
- data/controller/dd.sh +92 -0
- data/controller/ioperf.rb +108 -0
- data/controller/mysql.rb +74 -0
- data/controller/mysql.sh +9 -0
- data/controller/svn.sh +49 -0
- data/controller/wrap.rb +23 -0
- data/lib/action.rb +14 -0
- data/lib/db.rb +51 -0
- data/lib/ended.rb +14 -0
- data/lib/init.rb +14 -0
- data/lib/model.rb +10 -0
- data/lib/report.rb +100 -0
- data/lib/roadrunner.rb +122 -0
- data/lib/rrhelper.rb +25 -0
- data/lib/rrmonitor.rb +174 -0
- data/lib/run.rb +113 -0
- data/log/dd.log +129 -0
- data/log/log.rb +17 -0
- data/log/stdout.log +4 -0
- data/log/stdout.log.20100421 +0 -0
- data/log/svn.log +502 -0
- data/test/baidu.rb +100 -0
- data/test/blog.rb +100 -0
- data/test/db/development.sqlite3 +0 -0
- data/test/download_processes.rb +38 -0
- data/test/fibonacci.rb +27 -0
- data/test/get163.rb +38 -0
- data/test/get19Lou.rb +39 -0
- data/test/getHawaii.rb +95 -0
- data/test/httpclient-rfuzz-vs-httparty.rb +31 -0
- data/test/mysql_processes.rb +66 -0
- data/test/pi.rb +37 -0
- data/test/pi_db.rb +41 -0
- data/test/pi_monitor.rb +45 -0
- data/test/prime.rb +33 -0
- data/test/prime_p.rb +36 -0
- data/test/test_db.rb +29 -0
- data/test/vbd_kv.rb +123 -0
- metadata +100 -0
data/lib/db.rb
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
#
|
2
|
+
|
3
|
+
module RoadRunnerModule
|
4
|
+
|
5
|
+
module Dbhelper
|
6
|
+
|
7
|
+
def migrate(tables)
|
8
|
+
tables.each do |table|
|
9
|
+
case table
|
10
|
+
when "scenarios" then
|
11
|
+
unless ActiveRecord::Base.connection.tables.include?(table.to_s) then
|
12
|
+
ActiveRecord::Base.connection.create_table(table.to_sym) do |t|
|
13
|
+
t.column :name, :string, :limit => 256
|
14
|
+
t.column :create_at,:string, :limit => 32
|
15
|
+
t.column :script, :string,:limit => 10240
|
16
|
+
t.column :author, :string, :default => 'Anonymous'
|
17
|
+
t.column :author, :tps, :int
|
18
|
+
t.column :desc, :string
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
when "transactions" then
|
23
|
+
unless ActiveRecord::Base.connection.tables.include?(table.to_s) then
|
24
|
+
ActiveRecord::Base.connection.create_table(table.to_sym) do |t|
|
25
|
+
t.column :name,:string,:limit => 256
|
26
|
+
t.column :scenario_id,:string,:limit => 256
|
27
|
+
t.column :success_rate,:string, :limit => 8
|
28
|
+
t.column :create_at,:string, :limit => 32
|
29
|
+
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
when "records" then
|
34
|
+
unless ActiveRecord::Base.connection.tables.include?(table.to_s) then
|
35
|
+
ActiveRecord::Base.connection.create_table(table.to_sym) do |t|
|
36
|
+
t.column :cost, :string, :limit => 32
|
37
|
+
t.column :ts, :string, :limit => 32
|
38
|
+
t.column :seq, :int
|
39
|
+
t.column :stats,:int
|
40
|
+
t.column :transaction_id,:string,:limit => 256
|
41
|
+
t.column :create_at,:string, :limit => 32
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
module_function :migrate
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
data/lib/ended.rb
ADDED
data/lib/init.rb
ADDED
data/lib/model.rb
ADDED
data/lib/report.rb
ADDED
@@ -0,0 +1,100 @@
|
|
1
|
+
#After roadRunner.run() executed,
|
2
|
+
#execute roadRunner.report() show the Performance report
|
3
|
+
|
4
|
+
module RoadRunnerModule
|
5
|
+
|
6
|
+
def report(label='',width=0)
|
7
|
+
p " Wait for moment,the report is collecting......"
|
8
|
+
content = if @rep
|
9
|
+
@succRates = getSuccessRate @transactions
|
10
|
+
<<-DOC
|
11
|
+
#{"Performance Reports".center(50, '*')}
|
12
|
+
#{label.ljust(width)}
|
13
|
+
#{Benchmark::Tms::CAPTION}
|
14
|
+
#{@rep.format}
|
15
|
+
#{'--'*32}
|
16
|
+
The Virtual User is #{@users}.
|
17
|
+
Total Execute #{@iterations*@users} Action(s).
|
18
|
+
Total Cost #{@rep.real} Second(s).
|
19
|
+
This Scenario's TPS : #{@tps}.
|
20
|
+
The longest action cost #{@longest || 0} seconds.
|
21
|
+
#{'Transaction Report'.center(50, '-')}
|
22
|
+
#{@transactions.inject("") { |str,k|
|
23
|
+
str += "#{k[0].to_s} : count => #{k[1].size} time(s) , cost => #{k[1].inject(0){|c,v|c+=v[:cost].to_f}.to_s[0..3]} sec(s) , success rate => #{@succRates[k[0]]}\n "
|
24
|
+
}.gsub(/\n$/,'')}
|
25
|
+
#{'--'*32}
|
26
|
+
User defined params as below:
|
27
|
+
#{@global}
|
28
|
+
#{"End of Reports".center(50, '*')}
|
29
|
+
DOC
|
30
|
+
else
|
31
|
+
"None Report before RoadRunner run."
|
32
|
+
end
|
33
|
+
puts content
|
34
|
+
self.log.info content
|
35
|
+
end
|
36
|
+
|
37
|
+
def save_report(opts={:author=>'Anonymous',:script=>""})
|
38
|
+
|
39
|
+
p " Saving report to database......"
|
40
|
+
opts={:author=>'Anonymous',:script=>""}.merge opts
|
41
|
+
if @data_write then
|
42
|
+
unless opts[:name] then
|
43
|
+
self.log.warn "scenario name may be needed."
|
44
|
+
require 'uuidtools' unless defined?UUID
|
45
|
+
# scenario || UUID.random_create.to_s is for debug
|
46
|
+
opts[:name] = opts[:name] || UUID.random_create.to_s
|
47
|
+
self.log.info "scenario is created as #{opts[:name]}"
|
48
|
+
end
|
49
|
+
# => scenario = Scenario.find_or_create_by_name(opts.merge({:create_at=>Time.now})).shift
|
50
|
+
scenario = Scenario.find_or_create_by_name(opts.merge({:create_at=>Time.now}))
|
51
|
+
scenario.tps+=@iterations*@users/@rep.real
|
52
|
+
|
53
|
+
# => if opts[:script] is set as <your script>.rb 's path
|
54
|
+
# => opts[:script] = __FILE__
|
55
|
+
# => then scenario.script will be set.
|
56
|
+
if FileTest.exist?(opts[:script]) then
|
57
|
+
scenario.script = ""
|
58
|
+
IO.foreach(opts[:script]){|x|scenario.script << x}
|
59
|
+
end
|
60
|
+
|
61
|
+
@succRates = @succRates || (getSuccessRate @transactions)
|
62
|
+
# k is transaction name ,
|
63
|
+
# v is reports in every transaction.
|
64
|
+
@transactions.each do |k,v|
|
65
|
+
transaction = Transaction.new({:name=>k,:create_at=>Time.now,:success_rate=>@succRates[k]})
|
66
|
+
v.each_index do |id|
|
67
|
+
transaction.records << Record.new(v[id].merge({:seq=>id,:ts=>v[id][:create_at].to_f-@strat_time.to_f}))
|
68
|
+
self.log.debug "v[#{id}] = #{v[id].inspect}"
|
69
|
+
end
|
70
|
+
scenario.transactions << transaction
|
71
|
+
end
|
72
|
+
begin
|
73
|
+
scenario.save!
|
74
|
+
p " Saved OK!"
|
75
|
+
rescue =>e
|
76
|
+
self.log.error e
|
77
|
+
p e
|
78
|
+
end
|
79
|
+
self.log.info "records has saved in DB."
|
80
|
+
else
|
81
|
+
p ' Error:You didn\'t connect any database.'
|
82
|
+
self.log.error 'You didn\'t connect any database.'
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def getSuccessRate(transactions)
|
87
|
+
result = {}
|
88
|
+
transactions.each do |h|
|
89
|
+
success,faile = 0,0
|
90
|
+
h[1].each do |r|
|
91
|
+
r[:stats]==0?success+=1:faile+=1
|
92
|
+
end
|
93
|
+
result[h[0]]=success.to_f/(success+faile)
|
94
|
+
end
|
95
|
+
result
|
96
|
+
end
|
97
|
+
|
98
|
+
private :getSuccessRate
|
99
|
+
|
100
|
+
end
|
data/lib/roadrunner.rb
ADDED
@@ -0,0 +1,122 @@
|
|
1
|
+
# Author : zheng.cuizh@gmail.com
|
2
|
+
# RoadRunner named lik LoadRunner which is a industry performance test tool of HP.
|
3
|
+
# I'm happy to user LR and Ruby,
|
4
|
+
# so i coded the RoadRunner.
|
5
|
+
# Using RR,you'll find somethings similar to LR.
|
6
|
+
|
7
|
+
$:.unshift File.dirname(__FILE__)
|
8
|
+
require 'rubygems'
|
9
|
+
require 'benchmark'
|
10
|
+
require 'logger'
|
11
|
+
require 'pp'
|
12
|
+
|
13
|
+
Dir[File.join(File.dirname(__FILE__),"*.rb")].select{|x|not (x =~ /.*model\.rb/ || x =~ /.*db\.rb/ || x =~ /.*roadrunner\.rb/)}.each { |x| require x }
|
14
|
+
|
15
|
+
class RoadRunner
|
16
|
+
|
17
|
+
include RoadRunnerModule
|
18
|
+
attr :iterations, true
|
19
|
+
attr :users,true
|
20
|
+
attr :global,true
|
21
|
+
attr :iterationId
|
22
|
+
attr :record
|
23
|
+
attr :userId
|
24
|
+
attr :mode,true
|
25
|
+
attr :log
|
26
|
+
attr :tps
|
27
|
+
alias_method :g,:global
|
28
|
+
alias_method :g=,:global=
|
29
|
+
|
30
|
+
def initialize(opts={})
|
31
|
+
# => DEBUG < INFO < WARN < ERROR < FATAL < UNKNOWN
|
32
|
+
opts = {:out=>File.join(File.dirname(__FILE__),'..','log',"stdout.log"),:frequency=>'daily',:size=>1048576,:level=>Logger::DEBUG}.merge opts
|
33
|
+
@users,@iterations,@longest,@userId,@iterationId=1,1,0,0,0
|
34
|
+
@initBlk,@actBlk,@endBlk=proc{},proc{},proc{}
|
35
|
+
@global,@transactions={},{}
|
36
|
+
@log=Logger.new(opts[:out],opts[:frequency],opts[:size])
|
37
|
+
@log.level=opts[:level]
|
38
|
+
# => mode : sequence<default>,thread|t,process|p
|
39
|
+
@mode='sequence'
|
40
|
+
|
41
|
+
@transaction_blk={}
|
42
|
+
|
43
|
+
if block_given? then
|
44
|
+
begin
|
45
|
+
gem 'active_record'
|
46
|
+
require 'active_record'
|
47
|
+
rescue Exception => e
|
48
|
+
require 'activerecord'
|
49
|
+
end
|
50
|
+
|
51
|
+
require 'db'
|
52
|
+
require "model"
|
53
|
+
|
54
|
+
session = {}
|
55
|
+
_session = yield session
|
56
|
+
session = _session if session == {}
|
57
|
+
|
58
|
+
begin
|
59
|
+
ActiveRecord::Base.establish_connection(
|
60
|
+
#
|
61
|
+
# === session defined in block :
|
62
|
+
#
|
63
|
+
# :adapter=>session[:adapter],
|
64
|
+
# :encoding=>session[:encoding],
|
65
|
+
# :database=>session[:database],
|
66
|
+
# :username=>session[:username],
|
67
|
+
# :password=>session[:password],
|
68
|
+
# :host=>session[:host]
|
69
|
+
#
|
70
|
+
session
|
71
|
+
)
|
72
|
+
self.log.info "connect db ok."
|
73
|
+
rescue =>ex
|
74
|
+
self.log.error "adapter:#{session[:adapter]}.connect db faile."
|
75
|
+
end
|
76
|
+
|
77
|
+
default_report_table = %w"scenarios transactions records"
|
78
|
+
|
79
|
+
unless @data_write = default_report_table.inject(true){|r,t| r = r && ActiveRecord::Base.connection.tables.include?(t)} then
|
80
|
+
self.log.warn "table rreports doesn't defined and will be created."
|
81
|
+
Dbhelper::migrate default_report_table
|
82
|
+
if @data_write = default_report_table.inject(true){|r,t| r = r && ActiveRecord::Base.connection.tables.include?(t)} then
|
83
|
+
self.log.info "create table #{default_report_table.inspect} successful."
|
84
|
+
else
|
85
|
+
self.log.error "create table #{default_report_table.inspect} fail."
|
86
|
+
end
|
87
|
+
end
|
88
|
+
require 'model' unless defined? Scenario
|
89
|
+
self.log.debug 'model Rreport is reqruired.'
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def transaction(name,&blk)
|
94
|
+
@transactions[name] || @transactions[name] = []
|
95
|
+
status = "AUTO"
|
96
|
+
# => Status is the last expression in the action block
|
97
|
+
rcost = Benchmark::realtime{status = yield} if block_given?
|
98
|
+
# => status's value is:
|
99
|
+
# => 0=>success
|
100
|
+
# => -1=>faile
|
101
|
+
case status
|
102
|
+
when false,'false','-1',-1 then status = -1
|
103
|
+
else status = 0
|
104
|
+
end
|
105
|
+
# {:stats=>status,:cost=>rcost,:create_at=>Time.now} is one record
|
106
|
+
@transactions[name] << {:stats=>status,:cost=>rcost,:create_at=>Time.now}
|
107
|
+
# => the below sentence cost a lot of system resource
|
108
|
+
# => if you run for production result,keep it annotated!!!
|
109
|
+
# self.log.debug @transactions[name].inspect
|
110
|
+
rcost
|
111
|
+
end
|
112
|
+
|
113
|
+
def register_transactions(name,&blk)
|
114
|
+
@transaction_blk[name]=blk
|
115
|
+
end
|
116
|
+
|
117
|
+
def method_missing(name,*args,&blk)
|
118
|
+
# self.transaction(name.to_s,&blk)
|
119
|
+
register_transactions(name,&blk)
|
120
|
+
end
|
121
|
+
|
122
|
+
end
|
data/lib/rrhelper.rb
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
# Rrhelper will include many helpful methods for RoadRunner
|
2
|
+
|
3
|
+
module RoadRunnerModule
|
4
|
+
|
5
|
+
def iterationId
|
6
|
+
if(@mode=='thread')then
|
7
|
+
@thread_pool[Thread.current][:iterationId]
|
8
|
+
else
|
9
|
+
@iterationId
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def userId
|
14
|
+
if(@mode=='thread')then
|
15
|
+
@thread_pool[Thread.current][:userId]
|
16
|
+
else
|
17
|
+
@userId
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
module Rrhelper
|
22
|
+
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
data/lib/rrmonitor.rb
ADDED
@@ -0,0 +1,174 @@
|
|
1
|
+
require "rubygems"
|
2
|
+
require "net/ssh"
|
3
|
+
require 'fileutils'
|
4
|
+
|
5
|
+
module RoadRunnerModule
|
6
|
+
|
7
|
+
=begin
|
8
|
+
RRMonitor is used for Xnix system.
|
9
|
+
=end
|
10
|
+
|
11
|
+
class RRMonitor
|
12
|
+
def initialize(opt={:server=>"0.0.0.0", :username=>"admin", :password=>"123456"})
|
13
|
+
raise(ArgumentError,"Logger is needed!") unless opt[:log]
|
14
|
+
@log=opt[:log]
|
15
|
+
|
16
|
+
@server=opt[:server]
|
17
|
+
|
18
|
+
begin
|
19
|
+
@sess=Net::SSH.start(opt[:server], opt[:username], :password => opt[:password],:timeout => 120)
|
20
|
+
@log.info "#{opt[:server]} ssh connection OK."
|
21
|
+
rescue Exception => e
|
22
|
+
@log.error e
|
23
|
+
@log.error opt.inspect
|
24
|
+
raise e
|
25
|
+
end
|
26
|
+
|
27
|
+
|
28
|
+
@log.info("monitor initialize.".center(60,"*"))
|
29
|
+
@log.debug("monitor => #{self.inspect}")
|
30
|
+
|
31
|
+
@ts=( opt[:ts] || Time.now.to_i )
|
32
|
+
|
33
|
+
@path="#{File.join File.dirname(__FILE__),'..','log'}/monitor/#{@ts}"
|
34
|
+
@log.info "monitor local log path :#{@path}"
|
35
|
+
|
36
|
+
@rpath="~/.monit/#{@ts}"
|
37
|
+
@log.info "monitor remote log path(rpath) :#{@rpath}"
|
38
|
+
|
39
|
+
@sess.exec!("rm -rf #{@rpath}")
|
40
|
+
@sess.exec!("mkdir -p #{@rpath}")
|
41
|
+
|
42
|
+
@pids={}
|
43
|
+
end
|
44
|
+
|
45
|
+
=begin
|
46
|
+
run!(cmd) =>
|
47
|
+
the cmd will be execed at remote server(0),
|
48
|
+
and the stdout will write in log file.
|
49
|
+
|
50
|
+
cmd =>[
|
51
|
+
'ifstat',# network io
|
52
|
+
'iostat 3',# disk io
|
53
|
+
'vmstat 3',# memory info
|
54
|
+
'while((1>0));do sar -u -d 3 10; done',# disk and cpu info
|
55
|
+
'while((1>0));do sar -u -n DEV 3 10; done'# network and cpu info
|
56
|
+
]
|
57
|
+
|
58
|
+
"while((1>0));do #{cmd}; done" is needed for non-consist output cmd.
|
59
|
+
|
60
|
+
cmd sample =>
|
61
|
+
|
62
|
+
run!(["while((1>0));do /home/admin/apsara/build/debug64/bin/ku --command=getallpart --appname=blog1 --interactive=false|tail -n1; done"])
|
63
|
+
|
64
|
+
when exec!(cmd)
|
65
|
+
=>
|
66
|
+
exec!("while((1>0));do /home/admin/apsara/build/debug64/bin/ku --command=getallpart --appname=blog1 --interactive=false|tail -n1; done >> #{kupath} 2>/dev/null &")
|
67
|
+
=end
|
68
|
+
|
69
|
+
def run!(cmd=['ifstat','iostat 3','while((1>0));do sar -u -d 3 10; done','vmstat 3','while((1>0));do sar -u -n DEV 3 10; done'])
|
70
|
+
(@log.error "run!(cmd) cmd type require array.";exit) unless cmd.is_a?(Array)
|
71
|
+
(@log.error "run!(cmd) require commands.";exit) if cmd.none?
|
72
|
+
|
73
|
+
@cmd=cmd
|
74
|
+
|
75
|
+
begin
|
76
|
+
@log.info("RUN!".center(60,"*"))
|
77
|
+
@log.debug @server
|
78
|
+
cmd.each { |e| self.exec!(e)}
|
79
|
+
rescue Exception => e
|
80
|
+
@log.error("#{self.inspect} run error!")
|
81
|
+
@log.error(e.to_s)
|
82
|
+
# raise e
|
83
|
+
end
|
84
|
+
|
85
|
+
end
|
86
|
+
|
87
|
+
def exec!(cmd)
|
88
|
+
# >> cmd='while((1>0));do sar -u -d 3 10; # done';cmdpath="#{cmd.gsub(/([^a-zA-Z0-9\-])/,'_')}.log"
|
89
|
+
# => "while__1_0___do_sar_-u_-d_3_10__done.log"
|
90
|
+
|
91
|
+
# cmdpath="#{@rpath}/#{cmd.gsub(/[\s|\t|\$|\`|\(|\)|\&|\>|\<|\;|\||\'|\"]/,'_')}.log"
|
92
|
+
cmdpath="#{@rpath}/#{cmd.gsub(/[^a-zA-Z0-9\-]/,'_')}.log"
|
93
|
+
@cmdpath=cmdpath
|
94
|
+
|
95
|
+
@log.debug "#{cmd} path => #{cmdpath}"
|
96
|
+
@log.info "Start #{cmd}.".center(60,"*")
|
97
|
+
|
98
|
+
@log.debug("#{cmd} >> #{cmdpath} 2>/dev/null &")
|
99
|
+
@sess.exec!("#{cmd} >> #{cmdpath} 2>/dev/null &")
|
100
|
+
|
101
|
+
@pids[cmd]=@sess.exec!("echo $!")
|
102
|
+
@log.debug("#{cmd} pid => #{@pids[:ku]}")
|
103
|
+
end
|
104
|
+
|
105
|
+
def stop!
|
106
|
+
@pids.each do |key,value|
|
107
|
+
@sess.exec!("kill -9 #{value}")
|
108
|
+
@log.info("#{key} => #{value} stop!")
|
109
|
+
end
|
110
|
+
|
111
|
+
# if other user exec the same cmd,
|
112
|
+
# below cmd will kill all of the cmd.
|
113
|
+
|
114
|
+
# @sess.exec!(%q@ps axf|grep while|grep -v grep|awk '{printf "%s\n",$1}'|xargs kill -9@)
|
115
|
+
#
|
116
|
+
# @cmd.each { |e|
|
117
|
+
# @sess.exec!(%q@ps axf|grep "#{e}"|grep -v grep|awk '{printf "%s\n",$1}'|xargs kill -9@)
|
118
|
+
# }
|
119
|
+
|
120
|
+
@log.debug @server
|
121
|
+
@log.info("Monitor STOP!".center(60,"*"))
|
122
|
+
end
|
123
|
+
|
124
|
+
def collect
|
125
|
+
@log.debug "mkdir -p #{@path}/#{@server}"
|
126
|
+
%x{mkdir -p #{@path}/#{@server}}
|
127
|
+
|
128
|
+
path = @path.gsub('~',`echo ~`.gsub(/[\r\n]/,''))
|
129
|
+
@log.info "Collecting...".center(60,"*")
|
130
|
+
@log.debug "collect path => #{path}/#{@server}"
|
131
|
+
`scp -r admin@#{@server}:#{@rpath} #{path}/#{@server}`
|
132
|
+
@log.info "collected files => #{Dir[path+'/'+@server+'/**/*'].join($/)}"
|
133
|
+
end
|
134
|
+
|
135
|
+
#-----------------------------monit method--------------------------------#
|
136
|
+
|
137
|
+
def self.monit(servers,log,cmd=['ifstat','iostat 3','while((1>0));do sar -u -d 3 10; done','vmstat 3','while((1>0));do sar -u -n DEV 3 10; done'],ts="PerformanceTest")
|
138
|
+
|
139
|
+
case servers
|
140
|
+
when Hash
|
141
|
+
# do nothing
|
142
|
+
when String
|
143
|
+
File.open( servers ) { |yf|
|
144
|
+
begin
|
145
|
+
servers=YAML::load( yf )
|
146
|
+
rescue Exception => e
|
147
|
+
log.error("Servers' config YAML Load Error!Plz check your yaml file => #{servers}.#{$/}#{e.to_s}")
|
148
|
+
exit 1
|
149
|
+
end
|
150
|
+
}
|
151
|
+
end
|
152
|
+
|
153
|
+
_servers = {}
|
154
|
+
|
155
|
+
servers.each do |ip,obj|
|
156
|
+
_servers[ip] = RoadRunnerModule::RRMonitor.new({:server=>ip, :log=>log, :username=>obj[:username], :password=>obj[:password], :ts=>obj[:obj]||ts})
|
157
|
+
|
158
|
+
_servers[ip].run! cmd
|
159
|
+
end
|
160
|
+
|
161
|
+
yield
|
162
|
+
|
163
|
+
_servers.each do |k,v|
|
164
|
+
v.stop!
|
165
|
+
v.collect
|
166
|
+
end
|
167
|
+
|
168
|
+
end
|
169
|
+
|
170
|
+
end
|
171
|
+
|
172
|
+
end
|
173
|
+
|
174
|
+
|
data/lib/run.rb
ADDED
@@ -0,0 +1,113 @@
|
|
1
|
+
#After roadRunner.run() executed,
|
2
|
+
#execute roadRunner.report() show the Performance report
|
3
|
+
|
4
|
+
module RoadRunnerModule
|
5
|
+
def run
|
6
|
+
@strat_time = Time.now
|
7
|
+
@initBlk.call
|
8
|
+
@thread_pool = {}
|
9
|
+
@counter = 0
|
10
|
+
|
11
|
+
@log.debug "Mode => #{@mode}"
|
12
|
+
iterationBlk = case @mode
|
13
|
+
when /thread/,/t/ then
|
14
|
+
proc {
|
15
|
+
@users.times do |userId|
|
16
|
+
@thread_pool[Thread.start(){
|
17
|
+
@iterations.times do |iterationId|
|
18
|
+
|
19
|
+
rcost = 0
|
20
|
+
@transaction_blk.each_pair{|k,v|
|
21
|
+
rcost = self.transaction(k,v)
|
22
|
+
}
|
23
|
+
|
24
|
+
# rcost = self.transaction('Action',&@actBlk)
|
25
|
+
self.log.debug "IterationID is #{self.iterationId};UserID is #{self.userId};This Action Cost #{rcost} seconds"
|
26
|
+
@longest = (@longest<rcost)?rcost:@longest
|
27
|
+
@thread_pool[Thread.current][:iterationId] = iterationId
|
28
|
+
end
|
29
|
+
@counter += 1
|
30
|
+
}]={:userId=>userId}
|
31
|
+
end
|
32
|
+
# @thread_pool.keys.each{|t|t.join}
|
33
|
+
while @counter != @users do
|
34
|
+
Thread.pass
|
35
|
+
end
|
36
|
+
}
|
37
|
+
when /process/,/p/ then
|
38
|
+
proc {
|
39
|
+
ppid=Process.pid
|
40
|
+
@log.info("Main Process pid => #{ppid}")
|
41
|
+
|
42
|
+
pids=[]
|
43
|
+
@users.times { |userId|
|
44
|
+
pids << Process.fork {
|
45
|
+
@userId=userId
|
46
|
+
@iterations.times do |iterationId|
|
47
|
+
@iterationId=iterationId
|
48
|
+
|
49
|
+
rcost = 0
|
50
|
+
@transaction_blk.each_pair{|k,v|
|
51
|
+
rcost = self.transaction(k,v)
|
52
|
+
}
|
53
|
+
|
54
|
+
# rcost = self.transaction('Action',&@actBlk)
|
55
|
+
@longest = (@longest<rcost)?rcost:@longest
|
56
|
+
end
|
57
|
+
@log.info("<PID:#{Process.pid}> going down.Longest job cost #{@longest}")
|
58
|
+
|
59
|
+
Process.kill("HUP", ppid)
|
60
|
+
}
|
61
|
+
}
|
62
|
+
|
63
|
+
switch=true
|
64
|
+
c=0
|
65
|
+
Signal.trap("HUP", proc { @log.info("One User(Process) done."); (switch = false;p "Main process<#{Process.pid}> going down.") if ((c+=1) == @users) })
|
66
|
+
|
67
|
+
@log.info "Waiting Processes => #{pids.inspect}"
|
68
|
+
|
69
|
+
p "Processes<#{pids.inspect}> working."
|
70
|
+
while switch
|
71
|
+
STDOUT.puts '.'
|
72
|
+
sleep 5
|
73
|
+
end
|
74
|
+
p $/
|
75
|
+
|
76
|
+
Process.waitall
|
77
|
+
@log.info "Processes down."
|
78
|
+
}
|
79
|
+
else
|
80
|
+
proc {
|
81
|
+
@iterations.times do |iterationId|
|
82
|
+
@iterationId=iterationId
|
83
|
+
@users.times do |userId|
|
84
|
+
@userId=userId
|
85
|
+
|
86
|
+
rcost = 0
|
87
|
+
@transaction_blk.each_pair{|k,v|
|
88
|
+
rcost = self.transaction(k,v)
|
89
|
+
}
|
90
|
+
|
91
|
+
# rcost = self.transaction('Action',&@actBlk)
|
92
|
+
|
93
|
+
# => the below sentence cost a lot of system resource
|
94
|
+
# => if you run for production result,keep it annotated!!!
|
95
|
+
# self.log.debug "IterationID is #{self.iterationId};UserID is #{self.userId};This Action Cost #{rcost} seconds"
|
96
|
+
@longest = (@longest<rcost)?rcost:@longest
|
97
|
+
end
|
98
|
+
end
|
99
|
+
}
|
100
|
+
end
|
101
|
+
|
102
|
+
p ' '+"RoadRunner".center(50, '*')
|
103
|
+
p ' *'+"---Run , on your way.".rjust(48, ' ')+'*'
|
104
|
+
p ' '+'*'*50
|
105
|
+
p
|
106
|
+
p " Running......"
|
107
|
+
@rep = Benchmark::measure(&iterationBlk)
|
108
|
+
p " Ending......"
|
109
|
+
@endBlk.call
|
110
|
+
|
111
|
+
@tps = @iterations*@users/@rep.real
|
112
|
+
end
|
113
|
+
end
|