gargor 0.0.4 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.travis.yml +1 -1
- data/Gemfile +6 -3
- data/README.md +16 -4
- data/README_ja.md +14 -2
- data/VERSION +1 -1
- data/bin/gargor +1 -38
- data/lib/gargor.rb +66 -97
- data/lib/gargor/cli.rb +91 -0
- data/lib/gargor/dsl.rb +111 -0
- data/lib/gargor/exceptions.rb +11 -0
- data/lib/gargor/individual.rb +7 -1
- data/lib/gargor/individuals.rb +11 -0
- data/lib/gargor/reporter.rb +20 -0
- data/spec/gargor_cli_spec.rb +12 -0
- data/spec/gargor_individual_spec.rb +2 -2
- data/spec/gargor_spec.rb +13 -4
- data/spec/helper.rb +4 -0
- metadata +18 -17
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 9a0e56e2f33609bb3a739df6ca00ddb576f05cb8
|
4
|
+
data.tar.gz: be55f9ee9f9acf5f4364c0ab69f9205253cc6e36
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: ab25e90cdf88f4d5d233de33f40595f950dfb5178eb8503d710ef02faea8bcea325d94da31e83a7d17c8ae59ece8b436149034ec93505cba5e1fba18be6ecbf7
|
7
|
+
data.tar.gz: e941026cbc712e296415605b7a7d4ba409f28fa8e63a0f130c5a3937757abe72fade5d2b5a7e31d37dd0c48d31979352c5631b14e08b32574ab3a00a0b958bd8
|
data/.travis.yml
CHANGED
data/Gemfile
CHANGED
@@ -1,9 +1,12 @@
|
|
1
1
|
source 'https://rubygems.org'
|
2
2
|
|
3
|
-
gem
|
4
|
-
gem
|
3
|
+
gem "rake", "~> 10.1.0"
|
4
|
+
gem "json", "~> 1.8.0"
|
5
|
+
gem "jsonpath", "~> 0.5.3"
|
5
6
|
gem "progressbar", "~> 0.20.0"
|
6
7
|
gem "version", "~> 1.0.0"
|
8
|
+
gem "thor", "~> 0.18.1"
|
9
|
+
gem "terminal-table", "~> 1.4.5"
|
7
10
|
|
8
11
|
group :development do
|
9
12
|
gem 'pry'
|
@@ -15,8 +18,8 @@ group :test, :development do
|
|
15
18
|
gem 'coveralls'
|
16
19
|
gem 'fakeweb'
|
17
20
|
gem 'rspec'
|
18
|
-
gem 'rspec-mocks'
|
19
21
|
gem 'simplecov'
|
22
|
+
gem 'coveralls', require: false
|
20
23
|
end
|
21
24
|
|
22
25
|
# Specify your gem's dependencies in gargor.gemspec
|
data/README.md
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# gargor [![Build Status](https://travis-ci.org/tumf/gargor.png?branch=master)](https://travis-ci.org/tumf/gargor) [![Gem Version](https://badge.fury.io/rb/gargor.png)](http://badge.fury.io/rb/gargor) [![Code Climate](https://codeclimate.com/github/tumf/gargor.png)](https://codeclimate.com/github/tumf/gargor) [![Dependency Status](https://gemnasium.com/tumf/gargor.png)](https://gemnasium.com/tumf/gargor)
|
1
|
+
# gargor [![Build Status](https://travis-ci.org/tumf/gargor.png?branch=master)](https://travis-ci.org/tumf/gargor) [![Gem Version](https://badge.fury.io/rb/gargor.png)](http://badge.fury.io/rb/gargor) [![Code Climate](https://codeclimate.com/github/tumf/gargor.png)](https://codeclimate.com/github/tumf/gargor) [![Dependency Status](https://gemnasium.com/tumf/gargor.png)](https://gemnasium.com/tumf/gargor) [![Coverage Status](https://coveralls.io/repos/tumf/gargor/badge.png)](https://coveralls.io/r/tumf/gargor)
|
2
2
|
|
3
3
|
`gargor` is software which uses genetic algorithm to support parameter tuning of the servers controlled by Chef.Using this software, you are able to optimize and automate the server tuning, which you did until now based on a combination of my experience and intuition.
|
4
4
|
|
@@ -19,7 +19,7 @@ Ruby 1.9-
|
|
19
19
|
|
20
20
|
## Usage
|
21
21
|
|
22
|
-
$ gargor [dsl-file]
|
22
|
+
$ gargor [options] tune [dsl-file]
|
23
23
|
|
24
24
|
The dsl-file of `gargor` should be written as belows:
|
25
25
|
|
@@ -33,7 +33,7 @@ population 10
|
|
33
33
|
# elite number of some generation.(carried over)
|
34
34
|
elite 1
|
35
35
|
|
36
|
-
# Probability of mutation set "0.01"
|
36
|
+
# Probability of mutation set "0.01" (is 1%)
|
37
37
|
mutation 0.01
|
38
38
|
|
39
39
|
# target cook command : '%s' will replace by node name.
|
@@ -49,7 +49,10 @@ attack_cmd "ssh attacker.example ./bin/ghakai www-1.example.yml 2>/dev/null"
|
|
49
49
|
# logger
|
50
50
|
logger "gargor.log"
|
51
51
|
|
52
|
-
#
|
52
|
+
# state
|
53
|
+
state ".gargor.state"
|
54
|
+
|
55
|
+
# or optional settings like belows:
|
53
56
|
#
|
54
57
|
# logger "gargor.log" do |log|
|
55
58
|
# log.level = Logger::INFO
|
@@ -236,6 +239,15 @@ I use [green hakai](https://github.com/KLab/green-hakai/).
|
|
236
239
|
|
237
240
|
You can use ab(Apache bench) and so on.
|
238
241
|
|
242
|
+
## Continuous Performance Tuning
|
243
|
+
|
244
|
+
After v1.0, `gargor` can save last status of the individuals to file (which indicates `state` in DSL or `--state=FILE` option).
|
245
|
+
You can excecute `gargor` by the daily cron, your servers will be tuned continuouslly.
|
246
|
+
|
247
|
+
```
|
248
|
+
0 4 * * * cd /path/to/project && gargor --state=.gargor.status
|
249
|
+
```
|
250
|
+
|
239
251
|
## Contributing
|
240
252
|
|
241
253
|
1. Fork it
|
data/README_ja.md
CHANGED
@@ -19,7 +19,9 @@ Ruby 1.9以降が必要です
|
|
19
19
|
|
20
20
|
## 使い方
|
21
21
|
|
22
|
-
$ gargor [dsl-file]
|
22
|
+
$ gargor [options] tune [dsl-file]
|
23
|
+
|
24
|
+
### DSLファイル
|
23
25
|
|
24
26
|
`gargor`の設定情報は、内部DSLによりに以下のように記述します。
|
25
27
|
|
@@ -247,7 +249,17 @@ MaxRequestsPerChild <%= node["httpd"]["max_request_per_child"] %>
|
|
247
249
|
|
248
250
|
***** EXTERMINATION ******
|
249
251
|
|
250
|
-
これは、個体の環境が厳しすぎるためで負荷の条件を緩めて再度実施してください。
|
252
|
+
これは、個体の環境が厳しすぎるためで負荷の条件を緩めて再度実施してください。
|
253
|
+
|
254
|
+
`v1.0`より個体が全滅すると、初期状態のパラメータに戻すようになりました。
|
255
|
+
|
256
|
+
## 継続的パフォーマンスチューニング
|
257
|
+
|
258
|
+
`v1.0`より、`gargor`は最後の世代状態をファイル保存し再利用する事ができるようになりました。このファイル名はDSLの中で`state`か`--state=FILE` オプションで指定します。`gargor`を毎日動作するようにcronに仕掛けることで継続的なパフォーマンスチューニングを行うことができます。
|
259
|
+
|
260
|
+
```
|
261
|
+
0 4 * * * cd /path/to/project && gargor --state=.gargor.status
|
262
|
+
```
|
251
263
|
|
252
264
|
## FAQ
|
253
265
|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.0
|
1
|
+
1.0.0
|
data/bin/gargor
CHANGED
@@ -1,41 +1,4 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
$:.unshift(File.dirname(__FILE__) + '/../lib')
|
3
3
|
$TESTING=false
|
4
|
-
require 'gargor'
|
5
|
-
require 'progressbar'
|
6
|
-
|
7
|
-
dsl_file=ARGV.last||"gargor.rb"
|
8
|
-
|
9
|
-
def usage
|
10
|
-
STDERR.print "usage: #{$0} [dsl-file]\n"
|
11
|
-
end
|
12
|
-
|
13
|
-
begin
|
14
|
-
Gargor.start
|
15
|
-
Gargor.load_dsl(dsl_file)
|
16
|
-
rescue =>e
|
17
|
-
STDERR.puts e.backtrace.join("\n")
|
18
|
-
|
19
|
-
usage
|
20
|
-
exit 1
|
21
|
-
end
|
22
|
-
|
23
|
-
pbar = ProgressBar.new("auto-tuning",Gargor.total_trials)
|
24
|
-
loop {
|
25
|
-
Gargor.populate.each { |i|
|
26
|
-
if i.fitness == nil
|
27
|
-
i.set_params
|
28
|
-
i.attack if i.deploy
|
29
|
-
end
|
30
|
-
pbar.set(Gargor.total_trials-Gargor.last_trials)
|
31
|
-
}
|
32
|
-
break unless Gargor.next_generation
|
33
|
-
}
|
34
|
-
pbar.finish
|
35
|
-
|
36
|
-
best = Gargor.individuals.max { |a,b| a.fitness <=> b.fitness }
|
37
|
-
if best
|
38
|
-
best.set_params
|
39
|
-
best.deploy
|
40
|
-
end
|
41
|
-
p best
|
4
|
+
require 'gargor/cli'
|
data/lib/gargor.rb
CHANGED
@@ -5,33 +5,11 @@ require "logger"
|
|
5
5
|
require "gargor/version"
|
6
6
|
require "gargor/individual"
|
7
7
|
require "gargor/parameter"
|
8
|
+
require "gargor/exceptions"
|
9
|
+
require "gargor/individuals"
|
10
|
+
require "gargor/dsl"
|
8
11
|
|
9
12
|
class Gargor
|
10
|
-
class GargorError < RuntimeError; end
|
11
|
-
class ExterminationError < GargorError; end
|
12
|
-
class ParameterError < GargorError; end
|
13
|
-
class ValidationError < GargorError; end
|
14
|
-
class ArgumentError < GargorError; end
|
15
|
-
|
16
|
-
class Individuals < Array
|
17
|
-
def has? i
|
18
|
-
!!self.find { |ii| ii.params == i.params }
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
GLOBAL_OPTS = ["population","max_generations","target_nodes",
|
23
|
-
"attack_cmd","elite","mutation","target_cooking_cmd",
|
24
|
-
"fitness_precision"]
|
25
|
-
|
26
|
-
GLOBAL_OPTS.each { |name|
|
27
|
-
define_method(name) { |val|
|
28
|
-
Gargor.class_variable_set("@@#{name}", val)
|
29
|
-
}
|
30
|
-
}
|
31
|
-
|
32
|
-
def log message,level=Logger::INFO
|
33
|
-
Gargor.log(message,level)
|
34
|
-
end
|
35
13
|
class << self
|
36
14
|
def log message,level=Logger::INFO
|
37
15
|
return if $TESTING
|
@@ -43,34 +21,51 @@ class Gargor
|
|
43
21
|
end
|
44
22
|
|
45
23
|
def params
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
24
|
+
@@dsl.params
|
25
|
+
end
|
26
|
+
|
27
|
+
def generation
|
28
|
+
@@generation
|
29
|
+
end
|
30
|
+
|
31
|
+
def prev_generation
|
32
|
+
@@prev_generation
|
33
|
+
end
|
34
|
+
|
35
|
+
def individuals
|
36
|
+
@@individuals
|
37
|
+
end
|
38
|
+
|
39
|
+
def logger
|
40
|
+
@@logger
|
41
|
+
end
|
42
|
+
|
43
|
+
def logger= logger
|
44
|
+
@@logger = logger
|
45
|
+
end
|
46
|
+
|
47
|
+
def opt name
|
48
|
+
@@dsl.send(name)
|
49
|
+
end
|
50
|
+
|
51
|
+
def base
|
52
|
+
@@base
|
51
53
|
end
|
52
54
|
|
53
55
|
def start
|
54
56
|
@@logger = Logger.new(STDOUT)
|
55
|
-
@@
|
56
|
-
@@prev_generation = nil
|
57
|
+
@@base = nil
|
57
58
|
@@individuals = []
|
58
|
-
@@
|
59
|
-
@@population = 0
|
60
|
-
@@max_generations = 1
|
59
|
+
@@prev_generation = nil
|
61
60
|
@@generation = 1
|
62
|
-
@@
|
63
|
-
@@attack_cmd = "false"
|
64
|
-
@@attack_proc = nil
|
65
|
-
@@evaluate_proc = Proc.new { 0 }
|
66
|
-
@@target_nodes = []
|
61
|
+
@@dsl = Dsl.new
|
67
62
|
@@dsl_file = nil
|
68
63
|
true
|
69
64
|
end
|
70
65
|
Gargor.start
|
71
66
|
|
72
67
|
def validate
|
73
|
-
raise ValidationError,"POPULATION isn't > 0" unless
|
68
|
+
raise ValidationError,"POPULATION isn't > 0" unless opt("population") > 0
|
74
69
|
true
|
75
70
|
end
|
76
71
|
|
@@ -87,28 +82,27 @@ class Gargor
|
|
87
82
|
def load_dsl(params_file)
|
88
83
|
@@dsl_file = params_file
|
89
84
|
contents = File.read(params_file)
|
90
|
-
|
85
|
+
@@dsl.instance_eval(contents)
|
91
86
|
validate
|
92
87
|
end
|
93
88
|
|
89
|
+
def options= options
|
90
|
+
@@dsl.options = options
|
91
|
+
end
|
92
|
+
|
94
93
|
def mutate
|
95
|
-
individual =
|
96
|
-
@@param_procs.each { |name,proc|
|
97
|
-
param = Parameter.new(name)
|
98
|
-
param.instance_eval(&proc)
|
99
|
-
individual.params[name] = param
|
100
|
-
}
|
94
|
+
individual = @@dsl.create_individual
|
101
95
|
log "mutate #{individual}"
|
102
96
|
individual
|
103
97
|
end
|
104
98
|
|
105
99
|
# 浮動小数点対応のrand
|
106
|
-
def float_rand(f,p = @@fitness_precision)
|
100
|
+
def float_rand(f,p = @@dsl.fitness_precision)
|
107
101
|
raise ArgumentError,"max must be > 0" unless f > 0
|
108
|
-
f *=
|
102
|
+
f *= p
|
109
103
|
i = f.to_i
|
110
104
|
f = rand(i)
|
111
|
-
f /
|
105
|
+
f / p.to_f
|
112
106
|
end
|
113
107
|
|
114
108
|
def crossover a,b
|
@@ -131,13 +125,15 @@ class Gargor
|
|
131
125
|
end
|
132
126
|
|
133
127
|
def populate_first_generation
|
134
|
-
|
135
|
-
individuals
|
136
|
-
|
137
|
-
|
138
|
-
individuals <<
|
139
|
-
|
140
|
-
|
128
|
+
@@base = @@dsl.create_individual.load_now
|
129
|
+
individuals = @@dsl.load_state if @@dsl.has_state?
|
130
|
+
unless individuals
|
131
|
+
individuals = Gargor::Individuals.new
|
132
|
+
individuals << base
|
133
|
+
until individuals.length >= opt("population")
|
134
|
+
individuals << mutate
|
135
|
+
end
|
136
|
+
end
|
141
137
|
Gargor::Individuals.new(individuals.shuffle)
|
142
138
|
end
|
143
139
|
|
@@ -146,7 +142,7 @@ class Gargor
|
|
146
142
|
Gargor::Individuals.new(g.sort{ |a,b| a.fitness<=>b.fitness }.last(count))
|
147
143
|
end
|
148
144
|
|
149
|
-
def mutation? mutation
|
145
|
+
def mutation? mutation= opt("mutation")
|
150
146
|
rand <= mutation
|
151
147
|
end
|
152
148
|
|
@@ -164,15 +160,12 @@ class Gargor
|
|
164
160
|
|
165
161
|
def populate_next_generation
|
166
162
|
log "population: #{@@prev_generation.length}"
|
167
|
-
individuals = Gargor::Individuals.new(select_elites @@prev_generation
|
163
|
+
individuals = Gargor::Individuals.new(select_elites @@prev_generation,opt("elite"))
|
168
164
|
|
169
|
-
|
170
|
-
break if individuals.length >= @@population
|
165
|
+
until individuals.length >= opt("population") do
|
171
166
|
i = populate_one
|
172
167
|
individuals << i unless individuals.has?(i)
|
173
|
-
|
174
|
-
log "populate:"
|
175
|
-
individuals.each { |i| log i }
|
168
|
+
end
|
176
169
|
Gargor::Individuals.new(individuals.shuffle)
|
177
170
|
end
|
178
171
|
|
@@ -185,33 +178,29 @@ class Gargor
|
|
185
178
|
raise ExterminationError unless prev_count >= 2
|
186
179
|
populate_next_generation
|
187
180
|
end
|
188
|
-
end
|
189
181
|
|
182
|
+
@@dsl.save_state(@@individuals) if @@dsl.has_state?
|
183
|
+
|
184
|
+
log "populate:"
|
185
|
+
@@individuals.each { |i| log i }
|
186
|
+
end
|
190
187
|
|
191
188
|
def next_generation
|
192
189
|
log "<== end generation #{@@generation}"
|
193
190
|
@@generation += 1
|
194
|
-
return false if @@generation >
|
191
|
+
return false if @@generation > opt("max_generations")
|
195
192
|
|
196
193
|
log "==> next generation #{@@generation}"
|
197
194
|
@@prev_generation = @@individuals
|
198
195
|
true
|
199
196
|
end
|
200
197
|
|
201
|
-
def individuals
|
202
|
-
@@individuals
|
203
|
-
end
|
204
|
-
|
205
|
-
def opt name
|
206
|
-
Gargor.class_variable_get("@@#{name}")
|
207
|
-
end
|
208
|
-
|
209
198
|
def logfile file
|
210
199
|
File.expand_path(File.join(File.dirname(@@dsl_file),file))
|
211
200
|
end
|
212
201
|
|
213
202
|
def total_trials
|
214
|
-
|
203
|
+
opt("population")+(opt("population")-opt("elite"))*(opt("max_generations")-1)
|
215
204
|
end
|
216
205
|
|
217
206
|
def last_trials_at_this_generation
|
@@ -220,28 +209,8 @@ class Gargor
|
|
220
209
|
|
221
210
|
def last_trials
|
222
211
|
last_trials_at_this_generation +
|
223
|
-
(
|
212
|
+
(opt("max_generations")-@@generation)*(opt("population")-opt("elite"))
|
224
213
|
end
|
225
214
|
|
226
215
|
end
|
227
|
-
|
228
|
-
def param name,&block
|
229
|
-
@@param_procs[name] = block
|
230
|
-
end
|
231
|
-
|
232
|
-
def attack cmd,&block
|
233
|
-
@@attack_cmd = cmd
|
234
|
-
@@attack_proc = block
|
235
|
-
end
|
236
|
-
|
237
|
-
def evaluate &block
|
238
|
-
@@evaluate_proc = block
|
239
|
-
end
|
240
|
-
|
241
|
-
def logger *args, &block
|
242
|
-
file = args.shift
|
243
|
-
@@logger = Logger.new(Gargor.logfile(file),*args)
|
244
|
-
block.call(@@logger) if block
|
245
|
-
end
|
246
|
-
|
247
216
|
end
|
data/lib/gargor/cli.rb
ADDED
@@ -0,0 +1,91 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
require "gargor"
|
3
|
+
require "thor"
|
4
|
+
class Gargor
|
5
|
+
class Double
|
6
|
+
def method_missing(name, *arguments);end
|
7
|
+
end
|
8
|
+
|
9
|
+
class CLI < Thor
|
10
|
+
default_command :tune
|
11
|
+
class_option :verbose, :type => :boolean, :aliases =>:v
|
12
|
+
|
13
|
+
desc "tune [gargor.rb]", "execute GA-search"
|
14
|
+
option :no_progress_bar, :type => :boolean, :aliases =>:q
|
15
|
+
option :max_generations, :type => :numeric, :aliases =>:g
|
16
|
+
option :population, :type => :numeric, :aliases =>:p
|
17
|
+
option :elite, :type => :numeric, :aliases =>:e
|
18
|
+
option :mutation, :type => :numeric, :aliases =>:m
|
19
|
+
option :target_cooking_cmd, :type =>:string, :banner =>"<COMMAND>"
|
20
|
+
option :target_nodes, :type =>:string, :banner =>"<NODE1,NODE2,NODE3...>"
|
21
|
+
option :attack_cmd, :type => :string, :banner =>"<COMMAND>"
|
22
|
+
option :logger, :type =>:string, :banner =>"<FILE>"
|
23
|
+
option :state, :type=>:string, :banner =>"<FILE>"
|
24
|
+
|
25
|
+
def tune file="gargor.rb"
|
26
|
+
require 'gargor/reporter'
|
27
|
+
require 'progressbar'
|
28
|
+
Gargor.start
|
29
|
+
Gargor.load_dsl(file)
|
30
|
+
Gargor.options = options
|
31
|
+
|
32
|
+
pbar.set(0)
|
33
|
+
trials
|
34
|
+
best = best_individual
|
35
|
+
deploy best
|
36
|
+
pbar.finish
|
37
|
+
puts Gargor::OptimizeReporter.table(Gargor.base,best)
|
38
|
+
rescue ExterminationError =>e
|
39
|
+
recover
|
40
|
+
report_error_exit(e)
|
41
|
+
rescue =>e
|
42
|
+
report_error_exit(e)
|
43
|
+
end
|
44
|
+
|
45
|
+
no_commands{
|
46
|
+
def trials
|
47
|
+
begin
|
48
|
+
Gargor.populate.each { |i|
|
49
|
+
trial(i) if i.fitness == nil
|
50
|
+
pbar.set(Gargor.total_trials-Gargor.last_trials)
|
51
|
+
}
|
52
|
+
end while(Gargor.next_generation)
|
53
|
+
end
|
54
|
+
|
55
|
+
def recover
|
56
|
+
Gargor.base && deploy(Gargor.base)
|
57
|
+
end
|
58
|
+
|
59
|
+
def report_error_exit e,ret = 1
|
60
|
+
unless $TESTING
|
61
|
+
STDERR.puts e.message
|
62
|
+
STDERR.puts e.backtrace.join("\n") if options["verbose"]
|
63
|
+
end
|
64
|
+
exit ret
|
65
|
+
end
|
66
|
+
|
67
|
+
def pbar
|
68
|
+
@pbar = Double.new if options["no_progress_bar"]
|
69
|
+
@pbar ||= ProgressBar.new(" Tuning",Gargor.total_trials)
|
70
|
+
end
|
71
|
+
|
72
|
+
def deploy i
|
73
|
+
i.set_params
|
74
|
+
i.deploy
|
75
|
+
end
|
76
|
+
|
77
|
+
def trial i
|
78
|
+
deploy i
|
79
|
+
i.attack
|
80
|
+
rescue Gargor::DeployError =>e
|
81
|
+
i.fitness = 0
|
82
|
+
end
|
83
|
+
|
84
|
+
def best_individual
|
85
|
+
Gargor.individuals.max { |a,b| a.fitness <=> b.fitness }
|
86
|
+
end
|
87
|
+
}
|
88
|
+
|
89
|
+
end
|
90
|
+
end
|
91
|
+
Gargor::CLI.start(ARGV)
|
data/lib/gargor/dsl.rb
ADDED
@@ -0,0 +1,111 @@
|
|
1
|
+
require 'json'
|
2
|
+
class Gargor
|
3
|
+
class Dsl
|
4
|
+
GLOBAL_OPTS = ["population","max_generations","target_nodes",
|
5
|
+
"attack_cmd","elite","mutation","target_cooking_cmd",
|
6
|
+
"fitness_precision","state"]
|
7
|
+
|
8
|
+
GLOBAL_OPTS.each { |name|
|
9
|
+
define_method(name) { |*args|
|
10
|
+
if args.count > 0
|
11
|
+
instance_variable_set("@#{name}", args.shift)
|
12
|
+
end
|
13
|
+
instance_variable_get("@#{name}")
|
14
|
+
}
|
15
|
+
}
|
16
|
+
def target_nodes *args
|
17
|
+
return @target_nodes if args.count == 0
|
18
|
+
nodes = args.shift
|
19
|
+
@target_nodes = if nodes.is_a? Array
|
20
|
+
nodes
|
21
|
+
else
|
22
|
+
nodes.split(",")
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
attr_accessor :param_procs, :attack_proc, :evaluate_proc
|
27
|
+
|
28
|
+
def initialize
|
29
|
+
@param_procs = {}
|
30
|
+
@attack_proc = nil
|
31
|
+
@evaluate_proc = Proc.new { 0 }
|
32
|
+
@fitness_precision = 100000000
|
33
|
+
@population = 0
|
34
|
+
@max_generations = 1
|
35
|
+
@elite = 0
|
36
|
+
@attack_cmd = "false"
|
37
|
+
@target_nodes = []
|
38
|
+
@state = nil
|
39
|
+
end
|
40
|
+
|
41
|
+
def params
|
42
|
+
result = {}
|
43
|
+
GLOBAL_OPTS.map { |name| result[name] = send(name) }
|
44
|
+
result
|
45
|
+
end
|
46
|
+
|
47
|
+
def options= options
|
48
|
+
GLOBAL_OPTS.each { |name|
|
49
|
+
send(name.to_sym,options[name]) if options.has_key?(name)
|
50
|
+
}
|
51
|
+
end
|
52
|
+
|
53
|
+
def log message,level=Logger::INFO
|
54
|
+
Gargor.log(message,level)
|
55
|
+
end
|
56
|
+
|
57
|
+
def param name,&block
|
58
|
+
@param_procs[name] = block
|
59
|
+
end
|
60
|
+
|
61
|
+
def attack cmd,&block
|
62
|
+
@attack_cmd = cmd
|
63
|
+
@attack_proc = block
|
64
|
+
end
|
65
|
+
|
66
|
+
def evaluate &block
|
67
|
+
@evaluate_proc = block
|
68
|
+
end
|
69
|
+
|
70
|
+
def logger *args, &block
|
71
|
+
file = args.shift
|
72
|
+
logger = Logger.new(Gargor.logfile(file),*args)
|
73
|
+
block.call(logger) if block
|
74
|
+
Gargor.logger = logger
|
75
|
+
end
|
76
|
+
|
77
|
+
def has_state?
|
78
|
+
!!@state
|
79
|
+
end
|
80
|
+
|
81
|
+
def create_individual values = nil
|
82
|
+
individual = Individual.new
|
83
|
+
param_procs.each { |name,proc|
|
84
|
+
param = Parameter.new(name)
|
85
|
+
param.instance_eval(&proc)
|
86
|
+
values && param.value = values[name]
|
87
|
+
individual.params[name] = param
|
88
|
+
}
|
89
|
+
individual
|
90
|
+
end
|
91
|
+
|
92
|
+
def load_state file=@state
|
93
|
+
log "load state #{file}"
|
94
|
+
state = JSON.parse(File.read(file))
|
95
|
+
individuals = Individuals.new
|
96
|
+
state.each { |i|
|
97
|
+
individuals << create_individual(i)
|
98
|
+
}
|
99
|
+
individuals
|
100
|
+
rescue Errno::ENOENT =>e
|
101
|
+
false
|
102
|
+
end
|
103
|
+
|
104
|
+
def save_state individuals,file = @state
|
105
|
+
log "save state #{file}"
|
106
|
+
json = individuals.to_json
|
107
|
+
File.open(file,"w") { |f| f.write(json) }
|
108
|
+
end
|
109
|
+
|
110
|
+
end
|
111
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
|
2
|
+
|
3
|
+
class Gargor
|
4
|
+
class GargorError < RuntimeError; end
|
5
|
+
|
6
|
+
class ExterminationError < GargorError; end
|
7
|
+
class DeployError < GargorError; end
|
8
|
+
class ParameterError < GargorError; end
|
9
|
+
class ValidationError < GargorError; end
|
10
|
+
class ArgumentError < GargorError; end
|
11
|
+
end
|
data/lib/gargor/individual.rb
CHANGED
@@ -15,6 +15,12 @@ class Gargor
|
|
15
15
|
[@params,@fitness].to_s
|
16
16
|
end
|
17
17
|
|
18
|
+
def to_hash
|
19
|
+
hash = {}
|
20
|
+
@params.each { |name,param| hash[name] = param.value }
|
21
|
+
hash
|
22
|
+
end
|
23
|
+
|
18
24
|
def log message,level = Logger::INFO
|
19
25
|
Gargor.log message,level
|
20
26
|
end
|
@@ -59,7 +65,7 @@ class Gargor
|
|
59
65
|
log "deploy failed",Logger::ERROR
|
60
66
|
@fitness = 0
|
61
67
|
sleep 1
|
62
|
-
|
68
|
+
raise Gargor::DeployError
|
63
69
|
end
|
64
70
|
}
|
65
71
|
true
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'terminal-table'
|
2
|
+
class Gargor
|
3
|
+
class Reporter;end
|
4
|
+
class OptimizeReporter < Reporter
|
5
|
+
class << self
|
6
|
+
def table from,to
|
7
|
+
table = Terminal::Table.new :headings => ['param', 'from', 'to'] do |t|
|
8
|
+
from.params.each do |name,f|
|
9
|
+
t << [name,f,to.params[name]]
|
10
|
+
end
|
11
|
+
t << :separator
|
12
|
+
t << ['Fitness', from.fitness,to.fitness]
|
13
|
+
end
|
14
|
+
[1,2].map { |n| table.align_column(n, :right) }
|
15
|
+
table.style={:border_y => "", :border_i => "-"}
|
16
|
+
table
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
require 'helper'
|
2
|
+
require 'gargor/cli'
|
3
|
+
|
4
|
+
describe Gargor::CLI,".start" do
|
5
|
+
it "exits when raise ExterminationError" do
|
6
|
+
to_load_fixture "sample-1.rb"
|
7
|
+
Gargor.stub(:start) {
|
8
|
+
raise Gargor::ExterminationError
|
9
|
+
}
|
10
|
+
expect{Gargor::CLI.start([])}.to raise_error(SystemExit)
|
11
|
+
end
|
12
|
+
end
|
@@ -27,11 +27,11 @@ describe Gargor::Individual, "#deploy" do
|
|
27
27
|
expect(@i.deploy).to be true
|
28
28
|
end
|
29
29
|
|
30
|
-
it "
|
30
|
+
it "raise Gargor::DeployError if deploy failed" do
|
31
31
|
@i.stub(:shell) { |cmd|
|
32
32
|
["",255]
|
33
33
|
}
|
34
|
-
expect
|
34
|
+
expect{@i.deploy}.to raise_error Gargor::DeployError
|
35
35
|
|
36
36
|
end
|
37
37
|
end
|
data/spec/gargor_spec.rb
CHANGED
@@ -53,9 +53,9 @@ describe Gargor,".poplutate" do
|
|
53
53
|
Gargor.load_dsl("dummy")
|
54
54
|
to_load_contents("{}") # dummy json
|
55
55
|
expect(Gargor.populate.size).to be Gargor.params["population"]
|
56
|
-
expect(Gargor.
|
56
|
+
expect(Gargor.generation).to be 1
|
57
57
|
expect(Gargor.next_generation).to be true
|
58
|
-
expect(Gargor.
|
58
|
+
expect(Gargor.generation).to be 2
|
59
59
|
|
60
60
|
expect{
|
61
61
|
Gargor.populate
|
@@ -177,7 +177,16 @@ describe Gargor, ".logger" do
|
|
177
177
|
to_load_fixture "sample-1.rb"
|
178
178
|
Gargor.start
|
179
179
|
Gargor.load_dsl("/tmp/test.rb")
|
180
|
-
expect(Gargor.
|
181
|
-
expect(Gargor.
|
180
|
+
expect(Gargor.logger).to be_kind_of Logger
|
181
|
+
expect(Gargor.logger.level).to be Logger::INFO
|
182
182
|
end
|
183
183
|
end
|
184
|
+
|
185
|
+
describe Gargor, ".options=" do
|
186
|
+
it "set options['target_nodes'] to array " do
|
187
|
+
options = {"target_nodes" => "node1,node2,node3"}
|
188
|
+
Gargor.options= options
|
189
|
+
expect(Gargor.opt("target_nodes")).to be_kind_of Array
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
data/spec/helper.rb
CHANGED
metadata
CHANGED
@@ -1,20 +1,18 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: gargor
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
5
|
-
prerelease:
|
4
|
+
version: 1.0.0
|
6
5
|
platform: ruby
|
7
6
|
authors:
|
8
7
|
- Yoshihiro TAKAHARA
|
9
8
|
autorequire:
|
10
9
|
bindir: bin
|
11
10
|
cert_chain: []
|
12
|
-
date: 2013-07-
|
11
|
+
date: 2013-07-15 00:00:00.000000000 Z
|
13
12
|
dependencies:
|
14
13
|
- !ruby/object:Gem::Dependency
|
15
14
|
name: bundler
|
16
15
|
requirement: !ruby/object:Gem::Requirement
|
17
|
-
none: false
|
18
16
|
requirements:
|
19
17
|
- - ~>
|
20
18
|
- !ruby/object:Gem::Version
|
@@ -22,7 +20,6 @@ dependencies:
|
|
22
20
|
type: :development
|
23
21
|
prerelease: false
|
24
22
|
version_requirements: !ruby/object:Gem::Requirement
|
25
|
-
none: false
|
26
23
|
requirements:
|
27
24
|
- - ~>
|
28
25
|
- !ruby/object:Gem::Version
|
@@ -30,21 +27,19 @@ dependencies:
|
|
30
27
|
- !ruby/object:Gem::Dependency
|
31
28
|
name: rake
|
32
29
|
requirement: !ruby/object:Gem::Requirement
|
33
|
-
none: false
|
34
30
|
requirements:
|
35
|
-
- -
|
31
|
+
- - '>='
|
36
32
|
- !ruby/object:Gem::Version
|
37
33
|
version: '0'
|
38
34
|
type: :development
|
39
35
|
prerelease: false
|
40
36
|
version_requirements: !ruby/object:Gem::Requirement
|
41
|
-
none: false
|
42
37
|
requirements:
|
43
|
-
- -
|
38
|
+
- - '>='
|
44
39
|
- !ruby/object:Gem::Version
|
45
40
|
version: '0'
|
46
|
-
description:
|
47
|
-
|
41
|
+
description: 'An auto-tuning tool for internet servers w/ Genetic Algorithm and Chef.
|
42
|
+
You can get good settings during sleeping ;) '
|
48
43
|
email:
|
49
44
|
- y.takahara@gmail.com
|
50
45
|
executables:
|
@@ -65,10 +60,16 @@ files:
|
|
65
60
|
- doc/sample.rb
|
66
61
|
- gargor.gemspec
|
67
62
|
- lib/gargor.rb
|
63
|
+
- lib/gargor/cli.rb
|
64
|
+
- lib/gargor/dsl.rb
|
65
|
+
- lib/gargor/exceptions.rb
|
68
66
|
- lib/gargor/individual.rb
|
67
|
+
- lib/gargor/individuals.rb
|
69
68
|
- lib/gargor/parameter.rb
|
69
|
+
- lib/gargor/reporter.rb
|
70
70
|
- lib/gargor/version.rb
|
71
71
|
- spec/fixtures/sample-1.rb
|
72
|
+
- spec/gargor_cli_spec.rb
|
72
73
|
- spec/gargor_individual_spec.rb
|
73
74
|
- spec/gargor_spec.rb
|
74
75
|
- spec/gargor_version_spec.rb
|
@@ -76,31 +77,31 @@ files:
|
|
76
77
|
homepage: https://github.com/tumf/gargor
|
77
78
|
licenses:
|
78
79
|
- MIT
|
80
|
+
metadata: {}
|
79
81
|
post_install_message:
|
80
82
|
rdoc_options: []
|
81
83
|
require_paths:
|
82
84
|
- lib
|
83
85
|
required_ruby_version: !ruby/object:Gem::Requirement
|
84
|
-
none: false
|
85
86
|
requirements:
|
86
|
-
- -
|
87
|
+
- - '>='
|
87
88
|
- !ruby/object:Gem::Version
|
88
89
|
version: '0'
|
89
90
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
90
|
-
none: false
|
91
91
|
requirements:
|
92
|
-
- -
|
92
|
+
- - '>='
|
93
93
|
- !ruby/object:Gem::Version
|
94
94
|
version: '0'
|
95
95
|
requirements: []
|
96
96
|
rubyforge_project:
|
97
|
-
rubygems_version:
|
97
|
+
rubygems_version: 2.0.5
|
98
98
|
signing_key:
|
99
|
-
specification_version:
|
99
|
+
specification_version: 4
|
100
100
|
summary: It is software which uses generic algorithm to support parameter tuning of
|
101
101
|
the servers controlled by Chef.
|
102
102
|
test_files:
|
103
103
|
- spec/fixtures/sample-1.rb
|
104
|
+
- spec/gargor_cli_spec.rb
|
104
105
|
- spec/gargor_individual_spec.rb
|
105
106
|
- spec/gargor_spec.rb
|
106
107
|
- spec/gargor_version_spec.rb
|