jkr 0.0.1 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
File without changes
data/Rakefile CHANGED
@@ -1,12 +1,11 @@
1
1
  # -*- ruby -*-
2
2
 
3
3
  require 'rubygems'
4
- require 'hoe'
4
+ require 'rspec/core/rake_task'
5
+ require 'bundler/gem_tasks'
5
6
 
6
- Hoe.spec 'jkr' do
7
- developer('Yuto HAYAMIZU', 'y.hayamizu@gmail.com')
7
+ RSpec::Core::RakeTask.new("spec")
8
8
 
9
- # self.rubyforge_name = 'jkrx' # if different than 'jkr'
10
- end
9
+ task :default => [:spec]
11
10
 
12
11
  # vim: syntax=ruby
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "jkr"
5
+
6
+ require "pry"
7
+ Pry.start
@@ -0,0 +1,32 @@
1
+ # -*- mode: ruby -*-
2
+
3
+ title "example"
4
+ description "this is an example."
5
+ short_desc ""
6
+
7
+ def_parameters do
8
+ constant :foo => 123
9
+ variable :trial_no => [1,2,3]
10
+ end
11
+
12
+ def_prep do |plan|
13
+ end
14
+
15
+ # This is optional routine for presenting estimated execution time for users.
16
+ # Return estimated execution time in seconds.
17
+ exec_time_estimate do |plan|
18
+ # 30 seconds for each trial
19
+ 30 * plan.vars[:trial_no].size
20
+ end
21
+
22
+ def_routine do |plan, params|
23
+ # store various information with metastore
24
+ # metastore data is saved in "metastore.msh" with Marshal.dump for each trial
25
+ plan.metastore[:foo] = "bar"
26
+ end
27
+
28
+ def_cleanup do |plan|
29
+ end
30
+
31
+ def_analysis do |plan|
32
+ end
@@ -0,0 +1,82 @@
1
+ #compdef jkr
2
+
3
+ # Subcommand completion function
4
+ __jkr-execute-cmd() {
5
+ local curcontext context state line
6
+ local env_dir
7
+
8
+ integer ret=1
9
+ _arguments \
10
+ -C -S \
11
+ '--debug[enable debug mode]' \
12
+ {-C,--directory}':Jkr directory:_directories' \
13
+ '(-): :->jkr_plans' \
14
+ && return
15
+
16
+ case $state in
17
+ (jkr_plans)
18
+ if [[ -n ${opt_args[(I)-C|--directory]} ]]; then
19
+ env_dir=${opt_args[${opt_args[(I)-C|--directory]}]}
20
+ else
21
+ env_dir=""
22
+ fi
23
+
24
+ __jkr_plans $env_dir && ret=0
25
+ ;;
26
+ esac
27
+ return $ret
28
+ }
29
+
30
+ __jkr-list-cmd() {
31
+ _arguments \
32
+ -C -S \
33
+ '--debug[enable debug mode]' \
34
+ {-C,--directory}':Jkr directory:_directories' \
35
+ && return
36
+ }
37
+
38
+ __jkr_plans() {
39
+ local old_IFS="$IFS" # save IFS
40
+ IFS=$'\n'
41
+ if [[ -n $1 ]]; then
42
+ _values "Available plans" $(JKR_ZSHCOMP_HELPER=y jkr list --directory=$1)
43
+ else
44
+ _values "Available plans" $(JKR_ZSHCOMP_HELPER=y jkr list)
45
+ fi
46
+ IFS="$old_IFS" # restore IFS
47
+ }
48
+
49
+ # Main completion function
50
+ _jkr() {
51
+ local curcontext context state line
52
+ declare -A opt_args
53
+ integer ret=1
54
+
55
+ _arguments \
56
+ -C -S \
57
+ '(-): :->subcmds' \
58
+ '(-)*:: :->option-or-argument' \
59
+ && return
60
+
61
+ case $state in
62
+ (subcmds)
63
+ __jkr_subcmds && ret=0
64
+ ;;
65
+ (option-or-argument)
66
+ if (( $+functions[__jkr-$words[1]-cmd] )); then
67
+ _call_function ret __jkr-$words[1]-cmd
68
+ else
69
+ _message 'no completion'
70
+ fi
71
+ ;;
72
+ esac
73
+
74
+ return $ret
75
+ }
76
+
77
+ __jkr_subcmds() {
78
+ _values 'Jkr command' \
79
+ 'execute[Execute a plan]' \
80
+ 'list[List jkr plans]' \
81
+ 'analyze[Analyze a result]'
82
+ }
data/exe/jkr ADDED
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $LOAD_PATH.unshift(File.expand_path("../lib", __dir__))
4
+ require 'jkr'
5
+
6
+ Jkr::CLI.start(ARGV)
@@ -0,0 +1,31 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'jkr/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "jkr"
8
+ spec.version = Jkr::VERSION
9
+ spec.authors = ["Yuto Hayamizu"]
10
+ spec.email = ["y.hayamizu@gmail.com"]
11
+ spec.licenses = ["GPL-3.0"]
12
+
13
+ spec.summary = %q{Script execution manager for experimental measurements.}
14
+ spec.description = %q{Jkr is a script execution manager for experimental measurements.}
15
+ spec.homepage = "https://github.com/as110-tkl/jkr"
16
+
17
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
18
+ spec.bindir = "exe"
19
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
20
+ spec.require_paths = ["lib"]
21
+
22
+ spec.add_dependency 'thor'
23
+ spec.add_dependency 'term-ansicolor'
24
+
25
+ spec.add_development_dependency 'pry'
26
+ spec.add_development_dependency 'bundler'
27
+ spec.add_development_dependency 'guard'
28
+ spec.add_development_dependency 'guard-rspec'
29
+ spec.add_development_dependency 'rspec'
30
+ spec.add_development_dependency "rake"
31
+ end
data/lib/jkr.rb CHANGED
@@ -1,9 +1,18 @@
1
1
 
2
+ require 'jkr/array'
3
+ require 'jkr/numeric'
2
4
  require 'jkr/env'
5
+ require 'jkr/error'
3
6
  require 'jkr/plan'
7
+ require 'jkr/planfinder'
4
8
  require 'jkr/trial'
5
9
  require 'jkr/analysis'
6
-
7
- class Jkr
8
- VERSION = '0.0.1'
9
- end
10
+ require 'jkr/cpufreq'
11
+ require 'jkr/cpu_usage'
12
+ require 'jkr/sysinfo'
13
+ require 'jkr/analytics'
14
+ require 'jkr/plot'
15
+ require 'jkr/stat'
16
+ require 'jkr/userutils'
17
+ require 'jkr/dirlock'
18
+ require 'jkr/cli'
@@ -1,27 +1,18 @@
1
1
 
2
- class Jkr
2
+ module Jkr
3
3
  class Analysis
4
4
  def self.analyze(env, resultset_num)
5
- resultset_num = sprintf "%03d", resultset_num.to_i
5
+ resultset_num = sprintf "%05d", resultset_num.to_i
6
6
  resultset_dir = Dir.glob(File.join(env.jkr_result_dir, resultset_num)+"*")
7
7
  if resultset_dir.size != 1
8
8
  raise RuntimeError.new "cannot specify resultset dir (#{resultset_dir.join(" ")})"
9
9
  end
10
10
  resultset_dir = resultset_dir.first
11
11
 
12
- plan_files = Dir.glob(File.join(resultset_dir, "*.plan"))
13
- if plan_files.size == 0
14
- raise RuntimeError.new "cannot find plan file"
15
- elsif plan_files.size > 1
16
- raise RuntimeError.new "there are two or more plan files"
17
- end
18
- plan_file_path = plan_files.first
19
-
20
- plan = Jkr::Plan.new(env, plan_file_path)
12
+ plan = Plan.create_by_result_id(env, resultset_num)
13
+ plan.resultset_dir = File.dirname(plan.file_path)
21
14
 
22
- Jkr::AnalysisUtils.define_analysis_utils(resultset_dir, plan)
23
- plan.analysis.call(plan)
24
- Jkr::AnalysisUtils.undef_analysis_utils(plan)
15
+ plan.do_analysis()
25
16
  end
26
17
  end
27
18
  end
@@ -0,0 +1,75 @@
1
+
2
+ module Jkr
3
+ class Analytics
4
+ class << self
5
+ def normalize_param(key, value = nil)
6
+ if value.is_a? TrueClass
7
+ return key.to_s + "_true"
8
+ elsif value.is_a? FalseClass
9
+ return key.to_s + "_false"
10
+ end
11
+
12
+ value
13
+ end
14
+
15
+ def each_group(results, variable, opt = {})
16
+ # extract parameters given as variables
17
+ param_keys = results.first[:params].keys.select do |param_key|
18
+ values = results.map do |result|
19
+ normalize_param(param_key, result[:params][param_key])
20
+ end
21
+ values.all?{|val| ! val.nil?} && values.sort.uniq.size > 1
22
+ end
23
+
24
+ unless param_keys.include?(variable)
25
+ raise ArgumentError.new("Invalid variable: #{variable.inspect}")
26
+ end
27
+ [:start_time, :end_time].each do |obsolete_key|
28
+ if param_keys.include?(obsolete_key)
29
+ $stderr.puts("#{obsolete_key} should not be included in result[:params]")
30
+ param_keys.delete(obsolete_key)
31
+ end
32
+ end
33
+ param_keys.delete(:trial)
34
+ param_keys.delete(variable)
35
+ if opt[:except]
36
+ opt[:except].each do |key|
37
+ param_keys.delete(key)
38
+ end
39
+ end
40
+
41
+ results.group_by do |result|
42
+ param_keys.map{|key| normalize_param(key, result[:params][key])}
43
+ end.sort_by do |group_param, group|
44
+ group_param
45
+ end.each do |group_param, group|
46
+ group = group.sort_by{|result| result[:params][variable]}
47
+ yield(group_param, group)
48
+ end
49
+ end
50
+
51
+ def hton(str)
52
+ if str.is_a? Numeric
53
+ return str
54
+ end
55
+
56
+ units = {
57
+ 'k' => 1024, 'K' => 1024,
58
+ 'm' => 1024*1024, 'M' => 1024*1024,
59
+ 'g' => 1024*1024*1024, 'G' => 1024*1024*1024,
60
+ }
61
+
62
+ if str =~ /(\d+)([kKmMgG]?)/
63
+ num = $1.to_i
64
+ unit = $2
65
+ if unit.size > 0
66
+ num *= units[unit]
67
+ end
68
+ else
69
+ raise ArgumentError.new("#{str} is not a valid number expression")
70
+ end
71
+ num
72
+ end
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,47 @@
1
+
2
+ class Array
3
+ def sum()
4
+ self.inject(&:+)
5
+ end
6
+
7
+ def avg()
8
+ if self.empty?
9
+ nil
10
+ else
11
+ self.sum.to_f / self.size
12
+ end
13
+ end
14
+
15
+ def stdev()
16
+ avg = self.avg
17
+ var = self.map{|val| (val - avg) ** 2}.sum
18
+ if self.size > 1
19
+ var /= self.size - 1
20
+ end
21
+ Math.sqrt(var)
22
+ end
23
+
24
+ def sterr()
25
+ self.stdev / Math.sqrt(self.size)
26
+ end
27
+
28
+ def every?(&block)
29
+ ret = true
30
+ self.each do |elem|
31
+ unless block.call(elem)
32
+ ret = false
33
+ break
34
+ end
35
+ end
36
+ ret
37
+ end
38
+
39
+ def group_by()
40
+ ret = Hash.new{ Array.new }
41
+ self.each do |elem|
42
+ ret[yield(elem)] += [elem]
43
+ end
44
+
45
+ ret
46
+ end
47
+ end
@@ -0,0 +1,131 @@
1
+
2
+ module Jkr
3
+ class Blktrace
4
+ class << self
5
+ def open(input_basename)
6
+ self.new(input_basename)
7
+ end
8
+
9
+ def each(input_basename, &block)
10
+ self.new(input_basename).each(&block)
11
+ end
12
+ end
13
+
14
+ def initialize(input_basename)
15
+ input_basename = Pathname.new(input_basename).relative_path_from(Pathname.new(`pwd`.strip)).to_s
16
+ if Dir.glob(input_basename + ".blktrace.*").size > 0
17
+ @input_basename = input_basename
18
+ puts "multi file: #{input_basename}"
19
+ else
20
+ if File.exists?(input_basename)
21
+ @input_singlefile = input_basename
22
+ puts "single file: #{input_basename}"
23
+ else
24
+ raise ArgumentError.new("No such blktrace data: #{input_basename}")
25
+ end
26
+ end
27
+ end
28
+
29
+ def raw_each(option = {}, &block)
30
+ if option[:limit]
31
+ limit = "| head -n #{option[:limit]}"
32
+ else
33
+ limit = ""
34
+ end
35
+ if @input_basename
36
+ cmd = "blkparse -f \"bt\\t%c\\t%s\\t%T.%t\\t%a\\t%d\\t%S\\t%n\\n\" -i #{@input_basename} #{limit} | grep '^bt'|sort -k4,4"
37
+ elsif @input_singlefile
38
+ cmd = "cat #{@input_singlefile}|blkparse -f \"bt\\t%c\\t%s\\t%T.%t\\t%a\\t%d\\t%S\\t%n\\n\" -i - #{limit} | grep '^bt'|sort -k4,4"
39
+ end
40
+ IO.popen(cmd, "r") do |io|
41
+ while line = io.gets
42
+ _, cpu, seqno, time, action, rwbs, pos_sec, sz_sec = line.split("\t")
43
+ cpu = cpu.to_i
44
+ seqno = seqno.to_i
45
+ time = time.to_f
46
+ pos_sec = pos_sec.to_i
47
+ sz_sec = sz_sec.to_i
48
+ record = [cpu, seqno, time, action, rwbs, pos_sec, sz_sec]
49
+
50
+ block.call(record)
51
+ end
52
+ end
53
+ end
54
+
55
+ def each(option = {}, &block)
56
+ self.map(option, &block)
57
+ true
58
+ end
59
+
60
+ def map(option = {}, &block)
61
+ if ! option.include?(:cache)
62
+ option[:cache] = true
63
+ end
64
+ if option[:limit]
65
+ limit = "| head -n #{option[:limit]}"
66
+ else
67
+ limit = ""
68
+ end
69
+
70
+ if @input_basename
71
+ cache_file_path = @input_basename + ".cache"
72
+ else
73
+ cache_file_path = @input_singlefile + ".cache"
74
+ end
75
+
76
+ if option[:cache] && File.exists?(cache_file_path)
77
+ records = Marshal.load(File.open(cache_file_path))
78
+ else
79
+ records = []
80
+ issues = []
81
+ if @input_basename
82
+ cmd = "blkparse -f \"bt\\t%c\\t%s\\t%T.%t\\t%a\\t%d\\t%S\\t%n\\n\" -i #{@input_basename} #{limit} | grep '^bt'|sort -k4,4"
83
+ elsif
84
+ cmd = "cat #{@input_singlefile}|blkparse -f \"bt\\t%c\\t%s\\t%T.%t\\t%a\\t%d\\t%S\\t%n\\n\" -i - #{limit} | grep '^bt'|sort -k4,4"
85
+ end
86
+ IO.popen(cmd, "r") do |io|
87
+ while line = io.gets
88
+ _, cpu, seqno, time, action, rwbs, pos_sec, sz_sec = line.split("\t")
89
+ cpu = cpu.to_i
90
+ seqno = seqno.to_i
91
+ time = time.to_f
92
+ pos_sec = pos_sec.to_i
93
+ sz_sec = sz_sec.to_i
94
+
95
+ record = [cpu, seqno, time, action, rwbs, pos_sec, sz_sec]
96
+ if action == "D"
97
+ issues.push(record)
98
+ elsif action == "C"
99
+ # check pos and sz
100
+ del_idx = nil
101
+ issues.each_with_index do |rec, idx|
102
+ if pos_sec == rec[5] && sz_sec == rec[6]
103
+ del_idx = idx
104
+ rt = time - rec[2]
105
+ record.push(rt) # append response time
106
+ records.push(record)
107
+ break
108
+ end
109
+ end
110
+ if del_idx.nil?
111
+ puts("Unmatched complete record: #{record.inspect}")
112
+ # raise StandardError.new("Unmatched complete record: #{record.inspect}")
113
+ next
114
+ end
115
+ issues.delete_at(del_idx)
116
+ else
117
+ raise NotImplementedError.new("Action #{action} handler is not implemented.")
118
+ end
119
+ end
120
+ end
121
+ File.open(cache_file_path, "w") do |file|
122
+ Marshal.dump(records, file)
123
+ end
124
+ end
125
+
126
+ records.map do |*record|
127
+ block.call(*record)
128
+ end
129
+ end
130
+ end
131
+ end