jkr 0.0.1 → 0.1.0

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.
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