rubella 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (36) hide show
  1. checksums.yaml +7 -0
  2. data/Gemfile +3 -0
  3. data/LICENSE +12 -0
  4. data/README.md +21 -0
  5. data/Rakefile +36 -0
  6. data/lib/rubella.rb +4 -0
  7. data/lib/rubella/input/base.rb +33 -0
  8. data/lib/rubella/input/json.rb +47 -0
  9. data/lib/rubella/map.rb +87 -0
  10. data/lib/rubella/output/ascii.rb +102 -0
  11. data/lib/rubella/output/base.rb +37 -0
  12. data/lib/rubella/output/image.rb +68 -0
  13. data/lib/rubella/storage.rb +94 -0
  14. data/lib/rubella/weighting/base.rb +58 -0
  15. data/lib/rubella/weighting/exponential.rb +48 -0
  16. data/lib/rubella/weighting/per_count.rb +61 -0
  17. data/lib/rubella/weighting/per_overall_load.rb +54 -0
  18. data/lib/rubella/weighting/per_value.rb +43 -0
  19. data/spec/fixtures/json/test_01.json +1 -0
  20. data/spec/spec.opts +3 -0
  21. data/spec/spec_helper.rb +11 -0
  22. data/spec/unit/rubella/input/base/data_spec.rb +11 -0
  23. data/spec/unit/rubella/input/base/each_spec.rb +16 -0
  24. data/spec/unit/rubella/input/base/new_spec.rb +17 -0
  25. data/spec/unit/rubella/input/json/data_spec.rb +11 -0
  26. data/spec/unit/rubella/input/json/each_spec.rb +16 -0
  27. data/spec/unit/rubella/input/json/self_file_spec.rb +17 -0
  28. data/spec/unit/rubella/input/json/self_string_spec.rb +17 -0
  29. data/spec/unit/rubella/storage/add_spec.rb +29 -0
  30. data/spec/unit/rubella/storage/data_spec.rb +11 -0
  31. data/spec/unit/rubella/storage/dataset_length_spec.rb +29 -0
  32. data/spec/unit/rubella/storage/each_spec.rb +16 -0
  33. data/spec/unit/rubella/storage/length_eql_spec.rb +68 -0
  34. data/spec/unit/rubella/storage/length_spec.rb +11 -0
  35. data/spec/unit/rubella/storage/new_spec.rb +43 -0
  36. metadata +97 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: c1a3fa7e3e6308ae4c40b2eafed842d45becec8f
4
+ data.tar.gz: cb9fba9155a39f45d4ad1b2b7bb07bde8d9c1005
5
+ SHA512:
6
+ metadata.gz: 6d06ae6ad7da68feeb86e7cfcccabd78a29ce56d385dcea9e52d32b36eef1e875a956f47d718bd3eef647bfbacc14959969279859a8e511a170e0fe7bffbd579
7
+ data.tar.gz: 23f46a46d389a7598e9019ed02ebd75ad5353056c9ab96f407bd1dcb66de8db952cb1942ebf5762472744ceb9781d0b1782e370b3eb081c1ae43702ddbcd8db4
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source "https://rubygems.org"
2
+
3
+ gem "RMagick"
data/LICENSE ADDED
@@ -0,0 +1,12 @@
1
+ Copyright (c) 2015, Rebecca Dietrich
2
+ All rights reserved.
3
+
4
+ Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
5
+
6
+ 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
7
+
8
+ 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
9
+
10
+ 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
11
+
12
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@@ -0,0 +1,21 @@
1
+ Rubella heatmap library
2
+ =======================
3
+
4
+ Rubella is a library to generate heatmaps to monitor visualize measured values
5
+ easier. Like the load of multiple CPU cores over time.
6
+
7
+ Therefore every CPU core gets its own JSON array over the measured time. So the
8
+ array gets it's own row in the headmap. The more the color itensity the higher
9
+ is the load.
10
+ (The values are in percent. So they must be beween 0 and 100.)
11
+
12
+ During the time you can see, if an unusual behavior occurs, because the image
13
+ shows a different load distribution.
14
+
15
+ see also:
16
+ http://dtrace.org/blogs/brendan/2011/12/18/visualizing-device-utilization/
17
+
18
+ Usage
19
+ -----
20
+
21
+ Coming soon.
@@ -0,0 +1,36 @@
1
+ # encoding: utf-8
2
+
3
+ require 'rake'
4
+
5
+ FileList['tasks/**/*.rake'].each { |task| import task }
6
+ desc 'run all specs'
7
+
8
+ task :spec => ['spec:unit', 'spec:integration']
9
+ desc 'run all integration tests'
10
+
11
+ task :integration => ['spec:integration']
12
+
13
+ namespace :spec do
14
+ spec_defaults = lambda do |spec|
15
+ spec.rspec_opts = ['--options', 'spec/spec.opts']
16
+ end
17
+
18
+ require 'rspec/core/rake_task'
19
+ RSpec::Core::RakeTask.new('unit') do |task|
20
+ spec_defaults.call(task)
21
+ task.pattern = 'spec/unit/**/*_spec.rb'
22
+ end
23
+
24
+ RSpec::Core::RakeTask.new('integration') do |task|
25
+ spec_defaults.call(task)
26
+ task.pattern = 'spec/integration/**/*_spec.rb'
27
+ end
28
+
29
+ RSpec::Core::RakeTask.new('coverage') do |task|
30
+ spec_defaults.call(task)
31
+ task.pattern = 'spec/{unit,integration}/*_spec.rb'
32
+ end
33
+
34
+ end
35
+
36
+ task :default => :spec
@@ -0,0 +1,4 @@
1
+ module Rubella
2
+ require "rubella/map"
3
+ require "rubella/storage"
4
+ end
@@ -0,0 +1,33 @@
1
+ module Rubella
2
+ module Input
3
+
4
+ # Gets the raw data and translate it into a readable format for the
5
+ # Rubella::Weighting::Base class.
6
+ # This must be an array within subarrays, which have all the same lenght
7
+ # and contains only numeric data.
8
+ #
9
+ class Base
10
+ attr_reader :data
11
+
12
+ # Constructor
13
+ # Create a new Rubella::Input::Base object using the given data
14
+ #
15
+ # @param var Input data
16
+ # @return Rubell::Input::Base
17
+ #
18
+ def initialize data
19
+ @data = data
20
+ end
21
+
22
+ # Passes each dataset trought the given block.
23
+ #
24
+ # @param pointer to block
25
+ #
26
+ def each &block
27
+ @data.each &block
28
+ end
29
+
30
+ end
31
+
32
+ end
33
+ end
@@ -0,0 +1,47 @@
1
+ require 'rubella/input/base'
2
+ require 'json'
3
+
4
+ module Rubella
5
+ module Input
6
+
7
+ # Gets data in JSON formate and translate it into a Ruby readable form to
8
+ # make it possible to handle the data.
9
+ #
10
+ class JSON < Base
11
+
12
+ # Constructor
13
+ # This constructer can create a new Rubella::Input::JSON object, but it
14
+ # is supposed to be private. Please use Rubella::Input::JSON.string or
15
+ # Rubella::Input::JSON.file to create a new instance.
16
+ #
17
+ # @param json_string string A string, which contains the data as json
18
+ # @return Rubella::Input::JSON
19
+ #
20
+ def initialize json_string
21
+ @data = ::JSON::load json_string
22
+ end
23
+
24
+ # Constructor
25
+ # Creates a new Rubella::Input::JSON object, from the given json.
26
+ #
27
+ # @param json_string string A string, which contains the data as json
28
+ # @return Rubella::Input::JSON
29
+ def self.string json_string
30
+ self.new json_string
31
+ end
32
+
33
+ # Constructor
34
+ # Creates a new Rubella::Input::JSON object, from the given file.
35
+ # Only the file name is required.
36
+ #
37
+ # @param json_file string The name of the file, which json contains
38
+ # @return Rubella:Input::JSON
39
+ #
40
+ def self.file json_file
41
+ self.new File.new json_file, 'r'
42
+ end
43
+
44
+ end
45
+
46
+ end
47
+ end
@@ -0,0 +1,87 @@
1
+ module Rubella
2
+
3
+ # Helps to process and create the heatmap
4
+ #
5
+ class Map
6
+ attr_reader :input
7
+ attr_reader :output
8
+ attr_reader :weighting
9
+
10
+ # Constructor
11
+ #
12
+ # @param input_name string Name of the input type in CamelCase
13
+ # @param output_name string Name of the output type in CamelCase
14
+ # @param weighting_name string Name of the weighting type in CamelCase
15
+ # @return Rubella::Map
16
+ # @raise NotImplementedError
17
+ def initialize(input_name, output_name, weighting_name)
18
+
19
+ # set the input type
20
+ input_by_name input_name
21
+
22
+ # set the output type
23
+ output_by_name output_name
24
+
25
+ # set the weighting
26
+ weighting_by_name weighting_name
27
+
28
+ end
29
+
30
+ # Set the input type by the given name
31
+ #
32
+ # @param input_name string Name of the input type in CamelCase
33
+ # @raise NotImplementedError
34
+ def input_by_name input_name
35
+ @input = load_by_name "Input", input_name
36
+ end
37
+
38
+ # Set the output type by the given name
39
+ #
40
+ # @param output_name string Name of the output type in CamelCase
41
+ # @raise NotImplementedError
42
+ def output_by_name output_name
43
+ @output = load_by_name "Output", output_name
44
+ end
45
+
46
+ # Set the weighting type by the given name
47
+ #
48
+ # @param weighting_name string Name of the weighting type in CamelCase
49
+ # @raise NotImplementedError
50
+ def weighting_by_name weighting_name
51
+ @weighting = load_by_name "Weighting", weighting_name
52
+ end
53
+
54
+ # Loads and returns the given class
55
+ #
56
+ # @param module_name string The Name of the module in CamelCase
57
+ # @param class_name string The Name of the class in CamelCase
58
+ # @return Class
59
+ # @raise NotImplementedError
60
+ def load_by_name module_name, class_name
61
+ # Remove the class, if someone wants to do this
62
+ if class_name == nil or class_name == ""
63
+ return nil
64
+ end
65
+
66
+ # Try to load the given class
67
+ require "rubella/"+underscore(module_name)+"/"+underscore(class_name)
68
+
69
+ # Try to get a class by the given name
70
+ return Object.const_get("Rubella").const_get(module_name).const_get(class_name)
71
+
72
+ # TODO raise this error, if class is not found
73
+ # raise NotImplementedError, "Not supported input type "+input_name+" given"
74
+ end
75
+
76
+ # Converts CamelCase words into snake_case
77
+ #
78
+ # @param camel_cased_word string Word in CamelCase
79
+ # @return string
80
+ def underscore(camel_cased_word)
81
+ camel_cased_word.to_s.gsub(/::/, '/').
82
+ gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').gsub(/([a-z\d])([A-Z])/,'\1_\2').
83
+ tr("-", "_").downcase
84
+ end
85
+
86
+ end
87
+ end
@@ -0,0 +1,102 @@
1
+ require "rubella/output/base"
2
+
3
+ module Rubella
4
+ module Output
5
+
6
+ # Creates a ascii art representation of the given storage data.
7
+ # In @data will a ordenary String be stored. Print the String to your
8
+ # output field and it will shows a nice ascii art graphic.
9
+ # There are also different ascii art themes available. Including the
10
+ # possibility to add own themes.
11
+ # You only need to push an Array within 10 chars for the representation
12
+ # into the :symbols Hash. Then you can select it with set the used_symbols
13
+ # variable to you theme name.
14
+ #
15
+ # TODO Use setted field_size for representation
16
+ #
17
+ class ASCII < Base
18
+ attr_accessor :symbols
19
+ attr_reader :used_symbols
20
+
21
+ # Constructor
22
+ # Sets the default field_size to 1.
23
+ # Also sets the used ascii art theme to "shades_ascii". See the
24
+ # used_symbols= for further information.
25
+ #
26
+ # @param data Rubella::Storage
27
+ # @param field_size int Used chars for one value
28
+ # @return Rubella::Output::ASCII
29
+ #
30
+ def initialize data, field_size = 1
31
+ @symbols = Hash.new
32
+ @symbols["shades"] =
33
+ [" ", " ", "░", "░", "▒", "▒", "▓", "▓", "█", "█"]
34
+ @symbols["shades_ascii"] =
35
+ [" ", "·", "⚬", "∞", "@", "#", "░", "▒", "▓", "█"]
36
+ @symbols["ascii"] =
37
+ [" ", "·", ",", ";", "o", "O", "%", "8", "@", "#"]
38
+ @symbols["numbers"] =
39
+ [" ", "1", "2", "3", "4", "5", "6", "7", "8", "9"]
40
+
41
+ self.used_symbols = "shades_ascii"
42
+ super data, field_size
43
+ end
44
+
45
+ # Sets the used ascii theme by the given name.
46
+ # The theme must exist. You can also choose your custom theme here.
47
+ # The at default avaliable themes are:
48
+ # * shades
49
+ # * shades_ascii
50
+ # * ascii
51
+ # * numbers
52
+ #
53
+ # @param value String The theme name
54
+ # @raise ArgumentError
55
+ #
56
+ def used_symbols= value
57
+ if @symbols.has_key? value
58
+ @used_symbols = value
59
+ return
60
+ end
61
+ raise ArgumentError, "Symbol set not found, must be one of: " +
62
+ @symbols.keys.join(", ")
63
+ end
64
+
65
+ # Creates an ascii art representation.
66
+ #
67
+ # @return String
68
+ #
69
+ def render
70
+ buckets = @data.dataset_length
71
+ # columns = @data.length
72
+
73
+ # image size
74
+ # x = columns*@field_size
75
+ # y = buckets*@field_size
76
+
77
+ # start drawing the damn thing
78
+ ascii_arr = []
79
+ 0.upto(buckets-1).each { |i| ascii_arr[i] = "" }
80
+
81
+ @data.each do |point|
82
+ i = 0
83
+ point.reverse.each do |part|
84
+ part = (part*10).to_i
85
+
86
+ # Fix to prevent possible overflow.. should never happen, but we
87
+ # are careful
88
+ if part > 9
89
+ part = 9
90
+ end
91
+
92
+ ascii_arr[i] << @symbols[@used_symbols][part]
93
+ i = i+1
94
+ end
95
+ end
96
+
97
+ ascii_arr.join("\n")
98
+ end
99
+ end
100
+
101
+ end
102
+ end
@@ -0,0 +1,37 @@
1
+ module Rubella
2
+ module Output
3
+
4
+ # Output base class
5
+ # The output class gets the storage within the already weighted and in
6
+ # buckets sorted content. It creates a visual representation of the given
7
+ # data and stores this local.
8
+ #
9
+ class Base
10
+ attr_accessor :field_size
11
+
12
+ # Constructor
13
+ # Gets the field size to store it local. It's the size of one value of
14
+ # the later created visual representation. The unit depends on the kind
15
+ # of representation.
16
+ #
17
+ # @param data Rubella::Storage
18
+ # @param field_size int size of one value
19
+ # @return Rubella::Output::Base
20
+ #
21
+ def initialize data, field_size
22
+ @data = data
23
+ @field_size = field_size
24
+ end
25
+
26
+ # Creates a visual representation.
27
+ #
28
+ # @return rendered data
29
+ #
30
+ def render
31
+ raise NotImplementedError.new "Please override 'render' in your "+
32
+ "concrete implementation"
33
+ end
34
+ end
35
+
36
+ end
37
+ end
@@ -0,0 +1,68 @@
1
+ require "rubella/output/base"
2
+ require 'RMagick'
3
+
4
+ module Rubella
5
+ module Output
6
+
7
+ # Creates a pixel based graphic as representation of the given storage
8
+ # data using ImageMagick.
9
+ # By the RMagick extention. @data will contain a Magick image for futher
10
+ # handling the data please read the RMagick library documentation:
11
+ # http://www.imagemagick.org/RMagick/doc/
12
+ #
13
+ class Image < Base
14
+
15
+ # Constructor
16
+ # Has a default field_size of 15 pixel.
17
+ #
18
+ # @param data Rubella::Storage
19
+ # @param field_size int How many pixel one value has
20
+ # @return Rubella::Output::Image
21
+ #
22
+ def initialize data, field_size = 15
23
+ super data, field_size
24
+ end
25
+
26
+ # Creates a pixel based graphic.
27
+ #
28
+ # @return RMagick::Image
29
+ #
30
+ def render
31
+ # image size
32
+ x = @data.length*@field_size # columns x field_size
33
+ y = @data.dataset_length*@field_size # buckets x field_size
34
+
35
+ # start drawing the damn thing
36
+ image = Magick::Image.new(x, y) { self.background_color = "white" }
37
+
38
+ i = 0
39
+ @data.each do |point|
40
+ j = 0
41
+ point.reverse.each do |part|
42
+ # draw a red rectangle on the white background
43
+ core = Magick::Draw.new
44
+
45
+ idensity = 127.5 * part
46
+ # Fix for float stupidity
47
+ idensity = 127.5 if idensity > 127.5
48
+
49
+ # Get the correct value
50
+ l = (255-idensity).round
51
+
52
+ # Draw
53
+ core.fill(Magick::Pixel.from_hsla(0, 255, l, 1).to_color)
54
+ core.rectangle((i*@field_size), (j*@field_size), ((i+1)*@field_size), ((j+1)*@field_size))
55
+ core.draw image
56
+ j = j + 1
57
+ end
58
+ i = i + 1
59
+ end
60
+
61
+ image
62
+ end
63
+
64
+
65
+ end
66
+
67
+ end
68
+ end
@@ -0,0 +1,94 @@
1
+ module Rubella
2
+
3
+ # The Rubella::Storage holds the weighted data.
4
+ # Storages can be added to get a timeline. But the Storage has no concrete
5
+ # knowledge of time.
6
+ # The Storage can have a defined length. If new data is added, it will drop
7
+ # the oldest entries.
8
+ #
9
+ class Storage
10
+ attr_reader :data
11
+ # :length
12
+
13
+ def initialize data, length = 0
14
+ @data = data
15
+ self.length = length
16
+ end
17
+
18
+ # Defines the length of the Storage.
19
+ #
20
+ # Be careful, if your Storage has more entries, tha the new length, the
21
+ # oldest entries will immediately be dropped. If your Storage has less
22
+ # entries, it will be filled up with empty entries.
23
+ # Happens only if data has entries.
24
+ #
25
+ # Setting the length to 0 will disable this feature
26
+ #
27
+ # TODO fill up with 0 values, if data is not multidemensional
28
+ #
29
+ # @param length Integer The size of the storage
30
+ # @return Integer The new size
31
+ #
32
+ def length= length
33
+ @length = length
34
+
35
+ # Use length only, if length is valid
36
+ if @length != 0 and self.length != 0
37
+ # Drop entries, if more than new length
38
+ while self.length > @length
39
+ @data.pop
40
+ end
41
+ # Prefill with empty content, if less than new length
42
+ dummy_data = Array.new(self.dataset_length, 0)
43
+ while self.length < @length
44
+ @data.unshift dummy_data
45
+ end
46
+ end
47
+
48
+ @length
49
+ end
50
+
51
+ # Returns the current length of the storage.
52
+ # (How many datasets it holds.)
53
+ #
54
+ # @return Integer length
55
+ #
56
+ def length
57
+ @data.length
58
+ end
59
+
60
+ # Returns the length of a dataset.
61
+ # Will return 0, if no datasets in storage.
62
+ #
63
+ # TODO Throw an error, if data has different lengths
64
+ #
65
+ # @return Integer length of one dataset
66
+ #
67
+ def dataset_length
68
+ return 0 if self.length == 0
69
+ return 1 unless @data[0].respond_to? "length"
70
+
71
+ @data[0].length
72
+ end
73
+
74
+ # Adds the data from the given storage to the own data and return this as a
75
+ # new Storage. Does not modify one of the storages.
76
+ #
77
+ # @param storage Rubella::Storage Storage with new data
78
+ # @return Rubella::Storage
79
+ #
80
+ def add storage
81
+ Storage.new (storage.data+@data), @length
82
+ end
83
+
84
+ # Passes each dataset through the given block.
85
+ #
86
+ # @param pointer to block
87
+ #
88
+ def each &block
89
+ @data.each &block
90
+ end
91
+
92
+ end
93
+
94
+ end
@@ -0,0 +1,58 @@
1
+ module Rubella
2
+ module Weighting
3
+
4
+
5
+ # The Rubella::Weighting object processes the given input data to an valid
6
+ # output processable Array.
7
+ # These arrays contain a subarray for every unit of time. And these Array
8
+ # contain the buckets within the values for the output objects.
9
+ # The Weighting of the print intensitiy is done here, so that the output
10
+ # objects job is simply to print the stuff.
11
+ #
12
+ class Base
13
+ attr_reader :buckets
14
+ # :steps
15
+
16
+ # Constructor
17
+ # Creates a new Rubella::Weighting::xy object.
18
+ #
19
+ # @param buckets int must be one of 1, 2, 5, 10, 20, 50 default is 10
20
+ # @return Rubella::Weighting::Base
21
+ # @raise ArgumentError
22
+ #
23
+ def initialize buckets = 10
24
+ self.buckets = buckets
25
+ end
26
+
27
+ # Sets the buckets, if the value is valid
28
+ #
29
+ # @param buckets int The amount of buckets
30
+ # @raise ArgumentError
31
+ #
32
+ def buckets= buckets
33
+ # Must be divideable by 100
34
+ if [1, 2, 5, 10, 20, 50].index(buckets) == nil
35
+ raise ArgumentError.new "Amount of buckets must be 1, 2, 5, 10, 20 "+
36
+ "or 50"
37
+ end
38
+
39
+ @steps = 100/buckets
40
+ @buckets = buckets
41
+ end
42
+
43
+ # Creates a output readable list.
44
+ # This list is Array within a subarrays, which contain the buckets for
45
+ # every time value unit.
46
+ #
47
+ # @param input Rubella::Input An input object
48
+ # @return Rubella::Storage
49
+ #
50
+ def parse input
51
+ raise NotImplementedError.new "Please override 'parse' in your "+
52
+ "concrete implementation"
53
+ end
54
+
55
+ end
56
+
57
+ end
58
+ end
@@ -0,0 +1,48 @@
1
+ require "rubella/weighting/base"
2
+
3
+ module Rubella
4
+ module Weighting
5
+
6
+ # The Rubella::Weighting::Exponential object weights every bucket per
7
+ # amount of cores. But the cores with higher load get a visualisation
8
+ # boost, which is exponential. So one high load core, will have much more
9
+ # color, than serveral less load cores.
10
+ #
11
+ class Exponential < Base
12
+
13
+ # Creates a output readable list.
14
+ # This list is Array within a subarrays, which contain the buckets for
15
+ # every time value unit.
16
+ #
17
+ # @param input Rubella::Input An input object
18
+ # @return Rubella::Storage
19
+ def parse input
20
+ # prepare data
21
+ data_list = Array.new()
22
+ bucket_no = 0
23
+
24
+ input.each do |cores|
25
+ # every 10 load percent one heatpoint
26
+ i = 0
27
+ data_list << Array.new(buckets) do
28
+ current_cores = cores.select do |core|
29
+ core >= i and
30
+ ((core < (i+@steps)) or (core <= (i+@steps) and i+@steps == 100))
31
+ end
32
+
33
+ amount = current_cores.length
34
+ i = i + @steps
35
+ core = (amount.to_f*bucket_no**0.8)/cores.length
36
+ bucket_no = bucket_no + 1
37
+
38
+ core
39
+ end
40
+ end
41
+
42
+ Rubella::Storage.new data_list
43
+ end
44
+
45
+ end
46
+
47
+ end
48
+ end
@@ -0,0 +1,61 @@
1
+ require "rubella/weighting/base"
2
+
3
+ module Rubella
4
+ module Weighting
5
+
6
+ # The Rubella::Weighting::PerCount create a field of each given value.
7
+ # The weighting is based on the maximum value.
8
+ #
9
+ class PerCount < Base
10
+
11
+ # Constructor
12
+ # Creates a new Rubella::Weighting::PerCount object.
13
+ #
14
+ # @param buckets int
15
+ # @return Rubella::Weighting::Base
16
+ # @raise ArgumentError
17
+ #
18
+ def initialize buckets = 7
19
+ super buckets
20
+ end
21
+
22
+ # Sets the buckets
23
+ #
24
+ # @param buckets int The amount of buckets
25
+ # @raise ArgumentError
26
+ #
27
+ def buckets= buckets
28
+ @buckets = buckets
29
+ end
30
+
31
+ # Creates a output readable list.
32
+ # This list is Array within a subarrays, which contain the buckets for
33
+ # every time value unit.
34
+ #
35
+ # @param input Rubella::Input An input object
36
+ # @return Rubella::Storage
37
+ def parse input
38
+ # prepare data
39
+ data_list = Array.new()
40
+
41
+ # Get the maximum of commits
42
+ max = input.sort.pop
43
+
44
+ i = 0
45
+ input.each do |commits|
46
+ data_list << Array.new() if i == 0
47
+ data_list.last << commits.to_f/max
48
+ if i == (buckets-1)
49
+ i = 0
50
+ else
51
+ i = i + 1
52
+ end
53
+ end
54
+
55
+ Rubella::Storage.new data_list
56
+ end
57
+
58
+ end
59
+
60
+ end
61
+ end
@@ -0,0 +1,54 @@
1
+ require "rubella/weighting/base"
2
+
3
+ module Rubella
4
+ module Weighting
5
+
6
+ # The Rubella::Weighting::PerOverallValue object summarizes the load of all
7
+ # cores in a time and computes how much load is one percent. Then it uses
8
+ # this as factor to weight the summarized load of every bucket.
9
+ # So your representation will show you the higher load cores more
10
+ # intensive, then the cores with lower load, depending on the current load.
11
+ #
12
+ class PerOverallLoad < Base
13
+
14
+ # Creates a output readable list.
15
+ # This list is Array within a subarrays, which contain the buckets for
16
+ # every time value unit.
17
+ #
18
+ # @param input Rubella::Input An input object
19
+ # @return Rubella::Storage
20
+ def parse input
21
+ # prepare data
22
+ data_list = Array.new()
23
+
24
+ input.each do |cores|
25
+
26
+ # Add all loads to compute how much % is one % load
27
+ load_sum = 0
28
+ cores.each { |core| load_sum = load_sum + core }
29
+ percent_load = 100.0/load_sum
30
+
31
+ # every 10 load percent one heatpoint
32
+ i = 0
33
+ data_list << Array.new(buckets) do
34
+ # Select all current cores
35
+ selected_cores = cores.select do |core|
36
+ core >= i and
37
+ ((core < (i+@steps)) or (core <= (i+@steps) and i+@steps == 100))
38
+ end
39
+ i = i + @steps
40
+
41
+ # add the load of the resulting cores and multiply it with the overall value
42
+ load_sum = 0
43
+ selected_cores.each { |core| load_sum = load_sum + core }
44
+ (load_sum.to_f*percent_load)/100
45
+ end
46
+ end
47
+
48
+ Rubella::Storage.new data_list
49
+ end
50
+
51
+ end
52
+
53
+ end
54
+ end
@@ -0,0 +1,43 @@
1
+ require "rubella/weighting/base"
2
+
3
+ module Rubella
4
+ module Weighting
5
+
6
+ # The Rubella::Weighting::PerValue object weights every bucket set to 1 in
7
+ # amount. So if you have have for example four cores, every core is
8
+ # weighted to 0.25 no matter how much the load of a single core is. It's
9
+ # just a "as is" weighting.
10
+ #
11
+ class PerValue < Base
12
+
13
+ # Creates a output readable list.
14
+ # This list is Array within a subarrays, which contain the buckets for
15
+ # every time value unit.
16
+ #
17
+ # @param input Rubella::Input An input object
18
+ # @return Rubella::Storage
19
+ def parse input
20
+ # prepare data
21
+ data_list = Array.new()
22
+
23
+ input.each do |cores|
24
+ # every 10 load percent one heatpoint
25
+ i = 0
26
+ data_list << Array.new(buckets) do
27
+ current_cores = cores.select do |core|
28
+ core >= i and
29
+ ((core < (i+@steps)) or (core <= (i+@steps) and i+@steps == 100))
30
+ end
31
+ amount = current_cores.length
32
+ i = i + @steps
33
+ amount.to_f/cores.length
34
+ end
35
+ end
36
+
37
+ Rubella::Storage.new data_list
38
+ end
39
+
40
+ end
41
+
42
+ end
43
+ end
@@ -0,0 +1 @@
1
+ [1, 2, 3]
@@ -0,0 +1,3 @@
1
+ --color
2
+ --order random
3
+ --format d
@@ -0,0 +1,11 @@
1
+ if ENV['SIMPLECOV']
2
+ require 'simplecov'
3
+ SimpleCov.start do
4
+ add_filter '_spec.rb'
5
+ add_filter 'spec_helper.rb'
6
+ end
7
+ end
8
+
9
+ require 'rubella'
10
+ require 'rubella/storage'
11
+ require 'rubella/input/json'
@@ -0,0 +1,11 @@
1
+ require 'spec_helper'
2
+
3
+ describe Rubella::Input::Base, '.data' do
4
+
5
+ it "retuns the stored data" do
6
+ input = Rubella::Input::Base.new [3, 4, 5]
7
+
8
+ expect(input.data).to eq([3, 4, 5])
9
+ end
10
+
11
+ end
@@ -0,0 +1,16 @@
1
+ require 'spec_helper'
2
+
3
+ describe Rubella::Input::Base, '.each' do
4
+
5
+ it "passes the data through the given block" do
6
+ input = Rubella::Input::Base.new [3, 4, 5]
7
+
8
+ sum = 0
9
+ input.each do |value|
10
+ sum = sum + value
11
+ end
12
+
13
+ expect(sum).to eq(12)
14
+ end
15
+
16
+ end
@@ -0,0 +1,17 @@
1
+ require 'spec_helper'
2
+
3
+ describe Rubella::Input::Base, '.new' do
4
+
5
+ it "creates a new Input instance" do
6
+ input = Rubella::Input::Base.new nil
7
+
8
+ expect(input).to be_instance_of(Rubella::Input::Base)
9
+ end
10
+
11
+ it "uses the given data" do
12
+ input = Rubella::Input::Base.new 54
13
+
14
+ expect(input.data).to eq(54)
15
+ end
16
+
17
+ end
@@ -0,0 +1,11 @@
1
+ require 'spec_helper'
2
+
3
+ describe Rubella::Input::JSON, '.data' do
4
+
5
+ it "returns the stored data" do
6
+ input = Rubella::Input::JSON.string "[3, 4, 5]"
7
+
8
+ expect(input.data).to eq([3, 4, 5])
9
+ end
10
+
11
+ end
@@ -0,0 +1,16 @@
1
+ require 'spec_helper'
2
+
3
+ describe Rubella::Input::JSON, '.each' do
4
+
5
+ it "passes the data through the given block" do
6
+ input = Rubella::Input::JSON.string "[3, 4, 5]"
7
+
8
+ sum = 0
9
+ input.each do |value|
10
+ sum = sum + value
11
+ end
12
+
13
+ expect(sum).to eq(12)
14
+ end
15
+
16
+ end
@@ -0,0 +1,17 @@
1
+ require 'spec_helper'
2
+
3
+ describe Rubella::Input::JSON, '#self.file' do
4
+
5
+ it 'returns a Rubella::Input::JSON object' do
6
+ input = Rubella::Input::JSON.file 'spec/fixtures/json/test_01.json'
7
+
8
+ expect(input).to be_instance_of(Rubella::Input::JSON)
9
+ end
10
+
11
+ it "uses the given data" do
12
+ input = Rubella::Input::JSON.file 'spec/fixtures/json/test_01.json'
13
+
14
+ expect(input.data).to eq([1, 2, 3])
15
+ end
16
+
17
+ end
@@ -0,0 +1,17 @@
1
+ require 'spec_helper'
2
+
3
+ describe Rubella::Input::JSON, '#self.string' do
4
+
5
+ it 'returns a Rubella::Input::JSON object' do
6
+ input = Rubella::Input::JSON.string '[]'
7
+
8
+ expect(input).to be_instance_of(Rubella::Input::JSON)
9
+ end
10
+
11
+ it "uses the given data" do
12
+ input = Rubella::Input::JSON.string '[1, 2, 3]'
13
+
14
+ expect(input.data).to eq([1, 2, 3])
15
+ end
16
+
17
+ end
@@ -0,0 +1,29 @@
1
+ require 'spec_helper'
2
+
3
+ describe Rubella::Storage, '.add' do
4
+
5
+ it "returns a new Storage with the given Storages data before the old" do
6
+ storage_1 = Rubella::Storage.new [3, 4, 5]
7
+ storage_2 = Rubella::Storage.new [0, 1, 2]
8
+
9
+ storage_new = storage_1.add storage_2
10
+ expect(storage_new.data).to eq([0, 1, 2, 3, 4, 5])
11
+ end
12
+
13
+ it "uses the length of the first given Storage" do
14
+ storage_1 = Rubella::Storage.new [3, 4, 5, 6, 7], 4
15
+ storage_2 = Rubella::Storage.new [0, 1, 2], 3
16
+
17
+ storage_new = storage_1.add storage_2
18
+ expect(storage_new.length).to eq 4
19
+ end
20
+
21
+ it "chops the data to the given length" do
22
+ storage_1 = Rubella::Storage.new [3, 4, 5, 6, 7], 4
23
+ storage_2 = Rubella::Storage.new [0, 1, 2], 3
24
+
25
+ storage_new = storage_1.add storage_2
26
+ expect(storage_new.data).to eq([0, 1, 2, 3])
27
+ end
28
+
29
+ end
@@ -0,0 +1,11 @@
1
+ require 'spec_helper'
2
+
3
+ describe Rubella::Storage, '.data' do
4
+
5
+ it "retuns the stored data" do
6
+ storage = Rubella::Storage.new [3, 4, 5]
7
+
8
+ expect(storage.data).to eq([3, 4, 5])
9
+ end
10
+
11
+ end
@@ -0,0 +1,29 @@
1
+ require 'spec_helper'
2
+
3
+ describe Rubella::Storage, '.dataset_length' do
4
+
5
+ it "returns 0 if Storage is empty" do
6
+ storage = Rubella::Storage.new []
7
+
8
+ expect(storage.dataset_length).to eq(0)
9
+ end
10
+
11
+ it "returns 1 if Storage holds one dimensional array" do
12
+ storage = Rubella::Storage.new [1, 2, 3]
13
+
14
+ expect(storage.dataset_length).to eq(1)
15
+ end
16
+
17
+ it "returns 1 if Storage datasets have a length of 1" do
18
+ storage = Rubella::Storage.new [[1], [2], [3]]
19
+
20
+ expect(storage.dataset_length).to eq(1)
21
+ end
22
+
23
+ it "returns the length of the datasets" do
24
+ storage = Rubella::Storage.new [[1, 2], [3, 4], [5, 6]]
25
+
26
+ expect(storage.dataset_length).to eq(2)
27
+ end
28
+
29
+ end
@@ -0,0 +1,16 @@
1
+ require 'spec_helper'
2
+
3
+ describe Rubella::Storage, '.each' do
4
+
5
+ it "passes the data through the given block" do
6
+ storage = Rubella::Storage.new [3, 4, 5]
7
+
8
+ sum = 0
9
+ storage.each do |value|
10
+ sum = sum + value
11
+ end
12
+
13
+ expect(sum).to eq(12)
14
+ end
15
+
16
+ end
@@ -0,0 +1,68 @@
1
+ require 'spec_helper'
2
+
3
+ describe Rubella::Storage, '.length=' do
4
+
5
+ it "sets the length to the given value" do
6
+ storage = Rubella::Storage.new [3, 4, 5]
7
+
8
+ storage.length = 2
9
+
10
+ expect(storage.length).to eq(2)
11
+ end
12
+
13
+ it "chops the data to the given length" do
14
+ storage = Rubella::Storage.new [3, 4, 5]
15
+
16
+ storage.length = 2
17
+
18
+ expect(storage.data.length).to eq(2)
19
+ end
20
+
21
+ it "disables the length chopping, if its set to 0" do
22
+ storage = Rubella::Storage.new [3, 4, 5]
23
+
24
+ storage.length = 0
25
+
26
+ expect(storage.data.length).to eq(3)
27
+ end
28
+
29
+ it "grows the data to the given length" do
30
+ storage = Rubella::Storage.new [[0, 1], [2, 3], [4, 5]]
31
+
32
+ storage.length = 5
33
+
34
+ expect(storage.data.length).to eq(5)
35
+ end
36
+
37
+ it "grows the data by using the length of the dataset as array length" do
38
+ storage = Rubella::Storage.new [[0, 1], [2, 3], [4, 5]]
39
+
40
+ storage.length = 5
41
+
42
+ expect(storage.data[0].length).to eq(2)
43
+ expect(storage.data[1].length).to eq(2)
44
+ expect(storage.data[2].length).to eq(2)
45
+ expect(storage.data[3].length).to eq(2)
46
+ expect(storage.data[4].length).to eq(2)
47
+ end
48
+
49
+ it "grows the data by using 0 values" do
50
+ storage = Rubella::Storage.new [[0, 1], [2, 3], [4, 5]]
51
+
52
+ storage.length = 5
53
+
54
+ expect(storage.data[0][0]).to eq(0)
55
+ expect(storage.data[0][1]).to eq(0)
56
+ expect(storage.data[1][0]).to eq(0)
57
+ expect(storage.data[1][1]).to eq(0)
58
+ end
59
+
60
+ it "does not grow the data, if Storage is empty" do
61
+ storage = Rubella::Storage.new []
62
+
63
+ storage.length = 5
64
+
65
+ expect(storage.data.length).to eq(0)
66
+ end
67
+
68
+ end
@@ -0,0 +1,11 @@
1
+ require 'spec_helper'
2
+
3
+ describe Rubella::Storage, '.length' do
4
+
5
+ it "returns the current length" do
6
+ storage = Rubella::Storage.new [3, 4, 5]
7
+
8
+ expect(storage.length).to eq 3
9
+ end
10
+
11
+ end
@@ -0,0 +1,43 @@
1
+ require 'spec_helper'
2
+
3
+ describe Rubella::Storage, '.new' do
4
+
5
+ it "creates a new Storage" do
6
+ storage = Rubella::Storage.new []
7
+
8
+ expect(storage).to be_an_instance_of(Rubella::Storage)
9
+ end
10
+
11
+ it "fills the Storage with the given data" do
12
+ storage = Rubella::Storage.new [1, 2, 3]
13
+
14
+ expect(storage.data).to eq([1, 2, 3])
15
+ end
16
+
17
+ it "disable length feature, if no length is given" do
18
+ storage = Rubella::Storage.new [1, 2, 3]
19
+
20
+ expect(storage.length).to eq(3)
21
+ expect(storage.data.length).to eq(3)
22
+ end
23
+
24
+ it "disable length feature, if length is 0" do
25
+ storage = Rubella::Storage.new [1, 2, 3], 0
26
+
27
+ expect(storage.length).to eq(3)
28
+ expect(storage.data.length).to eq(3)
29
+ end
30
+
31
+ it "sets the length" do
32
+ storage = Rubella::Storage.new [1, 2, 3], 2
33
+
34
+ expect(storage.length).to eq(2)
35
+ end
36
+
37
+ it "uses length feature, if length is given" do
38
+ storage = Rubella::Storage.new [1, 2, 3], 2
39
+
40
+ expect(storage.data.length).to eq(2)
41
+ end
42
+
43
+ end
metadata ADDED
@@ -0,0 +1,97 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rubella
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Stormwind
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-05-05 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: |-
14
+ Rubella is a library to generate heatmaps to monitor visualize measured values
15
+ easier. Like the load of multiple CPU cores over time.
16
+ email: rebecca@quantenteilchen.de
17
+ executables: []
18
+ extensions: []
19
+ extra_rdoc_files:
20
+ - README.md
21
+ files:
22
+ - Gemfile
23
+ - LICENSE
24
+ - README.md
25
+ - Rakefile
26
+ - lib/rubella.rb
27
+ - lib/rubella/input/base.rb
28
+ - lib/rubella/input/json.rb
29
+ - lib/rubella/map.rb
30
+ - lib/rubella/output/ascii.rb
31
+ - lib/rubella/output/base.rb
32
+ - lib/rubella/output/image.rb
33
+ - lib/rubella/storage.rb
34
+ - lib/rubella/weighting/base.rb
35
+ - lib/rubella/weighting/exponential.rb
36
+ - lib/rubella/weighting/per_count.rb
37
+ - lib/rubella/weighting/per_overall_load.rb
38
+ - lib/rubella/weighting/per_value.rb
39
+ - spec/fixtures/json/test_01.json
40
+ - spec/spec.opts
41
+ - spec/spec_helper.rb
42
+ - spec/unit/rubella/input/base/data_spec.rb
43
+ - spec/unit/rubella/input/base/each_spec.rb
44
+ - spec/unit/rubella/input/base/new_spec.rb
45
+ - spec/unit/rubella/input/json/data_spec.rb
46
+ - spec/unit/rubella/input/json/each_spec.rb
47
+ - spec/unit/rubella/input/json/self_file_spec.rb
48
+ - spec/unit/rubella/input/json/self_string_spec.rb
49
+ - spec/unit/rubella/storage/add_spec.rb
50
+ - spec/unit/rubella/storage/data_spec.rb
51
+ - spec/unit/rubella/storage/dataset_length_spec.rb
52
+ - spec/unit/rubella/storage/each_spec.rb
53
+ - spec/unit/rubella/storage/length_eql_spec.rb
54
+ - spec/unit/rubella/storage/length_spec.rb
55
+ - spec/unit/rubella/storage/new_spec.rb
56
+ homepage: https://github.com/Stormwind/rubella
57
+ licenses:
58
+ - 3-clause BSD
59
+ metadata: {}
60
+ post_install_message:
61
+ rdoc_options: []
62
+ require_paths:
63
+ - lib
64
+ required_ruby_version: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ required_rubygems_version: !ruby/object:Gem::Requirement
70
+ requirements:
71
+ - - ">="
72
+ - !ruby/object:Gem::Version
73
+ version: '0'
74
+ requirements: []
75
+ rubyforge_project:
76
+ rubygems_version: 2.4.6
77
+ signing_key:
78
+ specification_version: 4
79
+ summary: Library to generate heatmaps
80
+ test_files:
81
+ - spec/fixtures/json/test_01.json
82
+ - spec/spec.opts
83
+ - spec/spec_helper.rb
84
+ - spec/unit/rubella/input/base/data_spec.rb
85
+ - spec/unit/rubella/input/base/each_spec.rb
86
+ - spec/unit/rubella/input/base/new_spec.rb
87
+ - spec/unit/rubella/input/json/data_spec.rb
88
+ - spec/unit/rubella/input/json/each_spec.rb
89
+ - spec/unit/rubella/input/json/self_file_spec.rb
90
+ - spec/unit/rubella/input/json/self_string_spec.rb
91
+ - spec/unit/rubella/storage/add_spec.rb
92
+ - spec/unit/rubella/storage/data_spec.rb
93
+ - spec/unit/rubella/storage/dataset_length_spec.rb
94
+ - spec/unit/rubella/storage/each_spec.rb
95
+ - spec/unit/rubella/storage/length_eql_spec.rb
96
+ - spec/unit/rubella/storage/length_spec.rb
97
+ - spec/unit/rubella/storage/new_spec.rb