--- a/web/app/assets/javascripts/charts.js Sat Jun 22 15:02:47 2013 +0200
+++ b/web/app/assets/javascripts/charts.js Sun Jun 23 11:22:20 2013 +0200
@@ -381,7 +381,6 @@
*/
function viewportResized() {
refreshCharts();
- convertMenu();
}
/**
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/web/app/assets/javascripts/compare.js Sun Jun 23 11:22:20 2013 +0200
@@ -0,0 +1,2 @@
+// Place all the behaviors and hooks related to the matching controller here.
+// All this logic will automatically be available in application.js.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/web/app/assets/stylesheets/compare.css.scss Sun Jun 23 11:22:20 2013 +0200
@@ -0,0 +1,3 @@
+// Place all the styles related to the Compare controller here.
+// They will automatically be included in application.css.
+// You can use Sass (SCSS) here: http://sass-lang.com/
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/web/app/controllers/compare_controller.rb Sun Jun 23 11:22:20 2013 +0200
@@ -0,0 +1,20 @@
+class CompareController < ApplicationController
+ def index
+ @compare_query = CompareQuery.new
+ @implementations = []
+ @benchmark_info = nil
+ end
+
+ def filter
+ @compare_query = CompareQuery.new(compare_query_params)
+ @implementations = @compare_query.filtered_implementations
+ @benchmark_info = @compare_query.benchmark_info
+ render "index"
+ end
+
+ private
+
+ def compare_query_params
+ params.require(:compare_query).permit!
+ end
+end
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/web/app/helpers/compare_helper.rb Sun Jun 23 11:22:20 2013 +0200
@@ -0,0 +1,13 @@
+module CompareHelper
+
+ def comparing_impls_headline(impls)
+ if impls.empty?
+ "Nothing to compare"
+ elsif impls.size == 1
+ "Showing only #{impls.first.name}"
+ else
+ "Comparing #{impls.map(&:name)[0..-2].join(", ")} and #{impls[-1].name}"
+ end
+ end
+
+end
--- a/web/app/helpers/settings/benchmark_infos_helper.rb Sat Jun 22 15:02:47 2013 +0200
+++ b/web/app/helpers/settings/benchmark_infos_helper.rb Sun Jun 23 11:22:20 2013 +0200
@@ -4,4 +4,7 @@
BenchmarkInfo.all
end
+ def benchmark_options
+ all_benchmarks.map { |l| [l.name, l.id] }
+ end
end
--- a/web/app/helpers/settings/language_implementations_helper.rb Sat Jun 22 15:02:47 2013 +0200
+++ b/web/app/helpers/settings/language_implementations_helper.rb Sun Jun 23 11:22:20 2013 +0200
@@ -5,7 +5,17 @@
end
def language_impls_options
- all_language_implementations.map { |l| [l.name, l.id] }
+ all_language_implementations.map { |l| [l.name, l.id.to_s] }
+ end
+
+ def all_dates_when_performed(implOrImpls)
+ if implOrImpls.kind_of?(LanguageImplementation)
+ implOrImpls.all_dates_when_performed
+ elsif implOrImpls.kind_of?(Enumerable) || implOrImpls.kind_of?(ActiveRecord::Relation)
+ SortedSet.new(implOrImpls.map(&:all_dates_when_performed).flatten).to_a
+ else
+ raise "Unexpected argument type: #{implOrImpls.class}"
+ end
end
end
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/web/app/models/compare_query.rb Sun Jun 23 11:22:20 2013 +0200
@@ -0,0 +1,24 @@
+class CompareQuery
+ include ActiveModel::Model
+
+ attr_accessor :benchmark_id, :implementations
+
+ def initialize(*args)
+ super
+ @implementations ||= {}
+ end
+
+ def filtered_implementations
+ LanguageImplementation.where(id: impls_to_array_of_ids)
+ end
+
+ def benchmark_info
+ BenchmarkInfo.find(benchmark_id)
+ end
+
+ private
+
+ def impls_to_array_of_ids
+ implementations.keys
+ end
+end
--- a/web/app/models/language_implementation.rb Sat Jun 22 15:02:47 2013 +0200
+++ b/web/app/models/language_implementation.rb Sun Jun 23 11:22:20 2013 +0200
@@ -25,11 +25,7 @@
end
def all_dates_when_performed
- result = Set.new
- benchmark_batches.each do |batch|
- result.add batch.performed_at
- end
- result
+ SortedSet.new(benchmark_batches.map(&:performed_at).flatten).to_a
end
def results_at(time)
@@ -39,4 +35,18 @@
end
end
+ def results_of(benchmark_info, time)
+ batch_with_given_date = benchmark_batches
+ .where(performed_at: time)
+ .first
+
+ if batch_with_given_date
+ batch_with_given_date
+ .benchmark_results(benchmark_info: benchmark_info)
+ .first
+ else
+ nil
+ end
+ end
+
end
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/web/app/views/compare/index.html.erb Sun Jun 23 11:22:20 2013 +0200
@@ -0,0 +1,31 @@
+<%= currently_at "compare" %>
+
+<div class="span3">
+ <div class="well">
+ <%= form_for @compare_query,
+ url: filter_compare_index_path,
+ builder: CalipelFormBuilder do |f| %>
+ <%= f.fieldset_item "Comparing" do %>
+ <%= f.select_field_item :benchmark_id, benchmark_options %>
+ <%= f.checkboxes_item :implementations, language_impls_options %>
+ <%= f.submit_item "Compare" %>
+ <% end %>
+ <% end %>
+ </div>
+</div>
+
+<div class="span9">
+ <% unless @implementations.empty? %>
+ <h1>
+ Comparison for
+ <%= @benchmark_info.name %>
+ </h1>
+ <p>
+ <%= comparing_impls_headline(@implementations) %>
+ </p>
+
+ <%= render "index/compare_table",
+ impls: @implementations,
+ benchmark_info: @benchmark_info %>
+ <% end %>
+</div>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/web/app/views/index/_compare_table.html.erb Sun Jun 23 11:22:20 2013 +0200
@@ -0,0 +1,27 @@
+<% make_chart = true if local_assigns[:make_chart].nil? %>
+<div >
+ <div class="<%= make_chart ? "line-chart flot time-chart" : "" %>">
+ <table class="table table-condensed">
+ <thead>
+ <tr>
+ <th>Měsíc</th>
+ <% impls.each do |impl| %>
+ <th><%= impl.name %></th>
+ <% end %>
+ </tr>
+ </thead>
+ <tbody>
+ <% all_dates_when_performed(impls).each do |date| %>
+ <tr>
+ <%= content_tag :th,
+ (make_chart ? date_to_millis(date) : t(date)),
+ 'data-timestamp' => date_to_millis(date) %>
+ <% impls.each do |impl| %>
+ td><%= impl.results_of(benchmark_info, date).try(:min_duration) %></td>
+ <% end %>
+ </tr>
+ <% end %>
+ </tbody>
+ </table>
+ </div>
+</div>
--- a/web/app/views/index/_main_nav.html.erb Sat Jun 22 15:02:47 2013 +0200
+++ b/web/app/views/index/_main_nav.html.erb Sun Jun 23 11:22:20 2013 +0200
@@ -19,6 +19,9 @@
<%= nav_tab("results",
current_tab: current_tab,
class: "special") { link_to("Results", results_path) } %>
+ <%= nav_tab("compare",
+ current_tab: current_tab,
+ class: "special") { link_to("Compare", compare_index_path) } %>
<%= nav_tab("about",
current_tab: current_tab,
class: "special") { link_to("About", about_path) } %>
--- a/web/app/views/index/_timeline_table.html.erb Sat Jun 22 15:02:47 2013 +0200
+++ b/web/app/views/index/_timeline_table.html.erb Sun Jun 23 11:22:20 2013 +0200
@@ -11,7 +11,7 @@
</tr>
</thead>
<tbody>
- <% impl.all_dates_when_performed.each do |date| %>
+ <% all_dates_when_performed(impl).each do |date| %>
<tr>
<%= content_tag :th,
(make_chart ? date_to_millis(date) : t(date)),
--- a/web/config/routes.rb Sat Jun 22 15:02:47 2013 +0200
+++ b/web/config/routes.rb Sun Jun 23 11:22:20 2013 +0200
@@ -23,6 +23,10 @@
end
end
+ resources :compare, only: :index do
+ post "filter", on: :collection
+ end
+
namespace "settings" do
resources :languages, except: [:new]
resources :language_implementations, except: [:new]
--- a/web/lib/calipel_form_builder.rb Sat Jun 22 15:02:47 2013 +0200
+++ b/web/lib/calipel_form_builder.rb Sun Jun 23 11:22:20 2013 +0200
@@ -2,14 +2,17 @@
def field_item(attribute, &block)
@template.content_tag(:div, class: "control-group #{'error' if errors_present?(attribute)}") do
- label_tag = label(attribute, class: "control-label")
input = @template.content_tag(:div, class: "controls") do
yield + errors_on(attribute)
end
- "#{label_tag}\n#{input}".html_safe
+ "#{label_item attribute}\n#{input}".html_safe
end
end
+ def label_item(attribute)
+ label(attribute, class: "control-label")
+ end
+
def errors_on(attribute)
if errors_present?(attribute)
@template.content_tag("span",
@@ -44,6 +47,27 @@
form_input_item(:file_field, attribute, *args)
end
+ def checkboxes_item(attribute, options, *args)
+ #omg what just happened
+ @template.content_tag(:div, class: "control-group") do
+ @template.content_tag(:div, class: "controls") do
+ options.each do |opt|
+ @template.concat(
+ label("[#{attribute}][#{opt[1]}]", class: "checkbox") do
+ checkbox = @template.check_box_tag("#{@object_name}[#{attribute}][#{opt[1]}]",
+ opt[1],
+ (true if
+ @object.public_send(attribute).include?(opt[1])))
+
+ @template.concat(checkbox)
+ @template.concat(opt[0])
+ end
+ )
+ end
+ end
+ end
+ end
+
def select_field_item(attribute, options, *args)
form_input_item(:select, attribute, options, *args)
end
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/web/test/controllers/compare_controller_test.rb Sun Jun 23 11:22:20 2013 +0200
@@ -0,0 +1,9 @@
+require 'test_helper'
+
+class CompareControllerTest < ActionController::TestCase
+ test "should get index" do
+ get :index
+ assert_response :success
+ end
+
+end
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/web/test/helpers/compare_helper_test.rb Sun Jun 23 11:22:20 2013 +0200
@@ -0,0 +1,4 @@
+require 'test_helper'
+
+class CompareHelperTest < ActionView::TestCase
+end
--- a/web/vendor/assets/javascripts/flot/jquery.flot.threshold.min.js Sat Jun 22 15:02:47 2013 +0200
+++ b/web/vendor/assets/javascripts/flot/jquery.flot.threshold.min.js Sun Jun 23 11:22:20 2013 +0200
@@ -40,4 +40,4 @@
cleared and the special "originSeries" attribute set to the original series.
You may need to check for this in hover events.
-*/(function(e){function n(t){function n(t,n,r,i,s){var o=r.pointsize,u,a,f,l,c,h=e.extend({},n);h.datapoints={points:[],pointsize:o,format:r.format},h.label=null,h.color=s,h.threshold=null,h.originSeries=n,h.data=[];var p=r.points,d=n.lines.show,v=[],m=[],g;for(u=0;u<p.length;u+=o){a=p[u],f=p[u+1],c=l,f<i?l=v:l=m;if(d&&c!=l&&a!=null&&u>0&&p[u-o]!=null){var y=a+(i-f)*(a-p[u-o])/(f-p[u-o+1]);c.push(y),c.push(i);for(g=2;g<o;++g)c.push(p[u+g]);l.push(null),l.push(null);for(g=2;g<o;++g)l.push(p[u+g]);l.push(y),l.push(i);for(g=2;g<o;++g)l.push(p[u+g])}l.push(a),l.push(f);for(g=2;g<o;++g)l.push(p[u+g])}r.points=m,h.datapoints.points=v;if(h.datapoints.points.length>0){var b=e.inArray(n,t.getData());t.getData().splice(b+1,0,h)}}function r(t,r,i){if(!r.threshold)return;r.threshold instanceof Array?(r.threshold.sort(function(e,t){return e.below-t.below}),e(r.threshold).each(function(e,o){n(t,r,i,o.below,o.color)})):n(t,r,i,r.threshold.below,r.threshold.color)}t.hooks.processDatapoints.push(r)}var t={series:{threshold:null}};e.plot.plugins.push({init:n,options:t,name:"threshold",version:"1.2"})})(jQuery);
\ No newline at end of file
+*/(function(e){function n(t){function n(t,n,r,i,s){var o=r.pointsize,u,a,f,l,c,h=e.extend({},n);h.datapoints={points:[],pointsize:o,format:r.format},h.label=null,h.color=s,h.threshold=null,h.originSeries=n,h.data=[];var p=r.points,d=n.lines.show,v=[],m=[],g;for(u=0;u<p.length;u+=o){a=p[u],f=p[u+1],c=l,f<i?l=v:l=m;if(d&&c!=l&&a!=null&&u>0&&p[u-o]!=null){var y=a+(i-f)*(a-p[u-o])/(f-p[u-o+1]);c.push(y),c.push(i);for(g=2;g<o;++g)c.push(p[u+g]);l.push(null),l.push(null);for(g=2;g<o;++g)l.push(p[u+g]);l.push(y),l.push(i);for(g=2;g<o;++g)l.push(p[u+g])}l.push(a),l.push(f);for(g=2;g<o;++g)l.push(p[u+g])}r.points=m,h.datapoints.points=v;if(h.datapoints.points.length>0){var b=e.inArray(n,t.getData());t.getData().splice(b+1,0,h)}}function r(t,r,i){if(!r.threshold)return;r.threshold instanceof Array?(r.threshold.sort(function(e,t){return e.below-t.below}),e(r.threshold).each(function(e,o){n(t,r,i,o.below,o.color)})):n(t,r,i,r.threshold.below,r.threshold.color)}t.hooks.processDatapoints.push(r)}var t={series:{threshold:null}};e.plot.plugins.push({init:n,options:t,name:"threshold",version:"1.2"})})(jQuery);