Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make overview page display one data point per week #280

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,4 @@ vendor/bundle

*.swp
*.swo
.ruby-version
11 changes: 10 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ before_install:
tar -xvf $PWD/travis_phantomjs/phantomjs-2.1.1-linux-x86_64.tar.bz2 -C $PWD/travis_phantomjs;
fi
- "export DISPLAY=:99.0"
- "sh -e /etc/init.d/xvfb start"
- gem install bundler:1.17.3
script:
- bundle exec rubocop
- bundle exec rake test
Expand All @@ -41,5 +41,14 @@ after_success:
fi
addons:
postgresql: "9.3"
apt:
packages:
- postgresql-9.3
- postgresql-client-9.3
- postgresql-contrib-9.3
services:
- redis-server
- xvfb
env:
global:
- PGPORT=5433
79 changes: 65 additions & 14 deletions app/models/repo.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,20 +17,71 @@ def generate_sparkline_data

charts = {}

self.benchmark_types.map do |benchmark_type|
benchmark_type.benchmark_result_types.each do |benchmark_result_type|
benchmark_runs = BenchmarkRun.select(:initiator_id, :result, :initiator_type).fetch_commit_benchmark_runs(
benchmark_type.category,
benchmark_result_type,
2000
)

runs = benchmark_runs.sort_by { |run| run.initiator.created_at }
chart_builder = ChartBuilder.new(runs, benchmark_result_type).build_columns

charts[benchmark_type.category] ||= []
charts[benchmark_type.category] << {
benchmark_result_type: benchmark_result_type.name,
query = <<~SQL
WITH min_max_dates AS (
SELECT MIN(date_trunc('week', created_at)) AS start_week,
MAX(date_trunc('week', created_at)) AS end_week
FROM (
SELECT created_at
FROM commits
WHERE repo_id = #{self.id}
) AS subq
),
weeks AS (
SELECT generate_series(start_week, end_week, '7 days') AS weekstart
FROM min_max_dates
)
SELECT
benchmark_result_type_id,
benchmark_type_id,
hstore_to_json(br.result) AS result,
category
FROM (
SELECT id, commit_date FROM (
SELECT
ROW_NUMBER() OVER(PARTITION BY w.weekstart ORDER BY c.created_at) AS row_num,
id,
created_at AS commit_date
FROM weeks w
INNER JOIN commits c
ON w.weekstart = date_trunc('week', c.created_at) AND c.repo_id = #{self.id}
) x
WHERE row_num = 1
) cw
INNER JOIN benchmark_runs br
ON cw.id = br.initiator_id AND br.initiator_type = 'Commit'
INNER JOIN benchmark_types bt
ON bt.id = br.benchmark_type_id AND bt.repo_id = #{self.id}
ORDER BY category, commit_date
SQL

raw_results = self.class.connection.execute(query).to_a
raw_results.each do |row|
row['result'] = JSON.parse(row['result'])
end

result_types = BenchmarkResultType
.where(id: raw_results.map { |row| row['benchmark_result_type_id'] }.uniq)
.map { |res_type| [res_type.id, res_type] }.to_h

results = {}
raw_results.each do |res|
results[res['benchmark_type_id']] ||= {}
results[res['benchmark_type_id']]['category'] = res['category']
hash = results[res['benchmark_type_id']]['res_types'] ||= {}
arr = hash[result_types[res['benchmark_result_type_id']].name] ||= []
arr << res['result']
hash.sort_by { |k| k }
results[res['benchmark_type_id']]['res_types'] = hash.sort_by { |k, v| k }.to_h
end
results.values.each do |res|
category = res['category']
next unless category
res['res_types'].each do |name, runs|
chart_builder = ChartBuilder.new(runs, nil).build_columns_hash
charts[category] ||= []
charts[category] << {
benchmark_result_type: name,
columns: chart_builder.columns
}
end
Expand Down
25 changes: 25 additions & 0 deletions app/services/chart_builder.rb
Original file line number Diff line number Diff line change
Expand Up @@ -60,4 +60,29 @@ def build_columns
@columns = new_columns
self
end

def build_columns_hash
keys = @benchmark_runs.map { |run| run.keys }.flatten.uniq
@benchmark_runs.each do |benchmark_run|
if block_given?
version = yield(benchmark_run)
@categories ||= []
@categories << version
end

keys.each do |key|
@columns[key] ||= []
@columns[key] << benchmark_run[key]&.to_f
end
end

new_columns = []

@columns.each do |name, data|
new_columns << { name: name, data: data }
end

@columns = new_columns
self
end
end
15 changes: 9 additions & 6 deletions app/views/organizations/index.html.haml
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,15 @@
%td
- organization.repos.each do |repo|
%ul.list-inline
%li
- if !repo.releases.empty?
= link_to "#{repo.title} #{t('.releases_benchmark')}",
- if !repo.releases.empty?
%li
= link_to t('.releases_benchmark'),
releases_path(organization_name: organization.name, repo_name: repo.name)

%li
- if !repo.commits.empty?
= link_to "#{repo.title} #{t('.commits_benchmark')}",
- if !repo.commits.empty?
%li
= link_to t('.commits_benchmark'),
commits_path(organization_name: organization.name, repo_name: repo.name), data: { no_turbolink: true }
%li
= link_to t('.overview'),
overview_path(organization_name: organization.name, repo_name: repo.name), data: { no_turbolink: true }
1 change: 1 addition & 0 deletions config/locales/en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ en:
title: Benchmarks
commits_benchmark: Commits Benchmarks
releases_benchmark: Releases Benchmarks
overview: Overview

repos:
select_benchmark: &select_benchmark
Expand Down
108 changes: 105 additions & 3 deletions test/models/repo_test.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,109 @@
require 'test_helper'

class RepoTest < ActiveSupport::TestCase
# test "the truth" do
# assert true
# end
test '#generate_sparkline_data picks first commit from every week' do
repo = create(:repo)

mem_res_type = create(:benchmark_result_type, name: 'Memory', unit: 'rss')
ips_res_type = create(:benchmark_result_type, name: 'Ips', unit: 'i/s')

type1 = create(:benchmark_type, repo: repo, category: 'Array map')
type2 = create(:benchmark_type, repo: repo, category: 'String to_i')

# Week of Mon 18-05-2020 to Sun 24-05-2020
c1 = create(:commit, repo: repo, created_at: Time.utc(2020, 5, 24, 1))
c2 = create(:commit, repo: repo, created_at: Time.utc(2020, 5, 24, 1, 1))
c3 = create(:commit, repo: repo, created_at: Time.utc(2020, 5, 24, 1, 1, 1))

# Week of Mon 25-05-2020 to Sun 31-05-2020
c4 = create(:commit, repo: repo, created_at: Time.utc(2020, 5, 26))
c5 = create(:commit, repo: repo, created_at: Time.utc(2020, 5, 29))
c6 = create(:commit, repo: repo, created_at: Time.utc(2020, 5, 30))

# Week of Mon 01-06-2020 to Sun 07-06-2020
c7 = create(:commit, repo: repo, created_at: Time.utc(2020, 6, 1))
c8 = create(:commit, repo: repo, created_at: Time.utc(2020, 6, 2))
c9 = create(:commit, repo: repo, created_at: Time.utc(2020, 6, 7))

commits = [c1, c2, c3, c4, c5, c6, c7, c8, c9]
commits.each_with_index do |commit, index|
[type1, type2].each do |type|
create(
:benchmark_run,
initiator_id: commit.id,
initiator_type: 'Commit',
result: { rss_kb: commit.id },
benchmark_result_type_id: mem_res_type.id,
benchmark_type_id: type.id
)
create(
:benchmark_run,
initiator_id: commit.id,
initiator_type: 'Commit',
result: { bench_1: commit.id, bench_2: commit.id + 1 },
benchmark_result_type_id: ips_res_type.id,
benchmark_type_id: type.id
)
end
end

# We should pick the first commit from each week.
# Since the commits are spread over a period of 3
# weeks, we should have 3 commits. These commits
# should be c1, c4 and c7.
# We will then pick the benchmark_runs records whose
# initiator_ids are the commits we picked up earlier.
data = repo.generate_sparkline_data
assert_equal(
data,
'Array map' => [
{
benchmark_result_type: 'Ips',
columns: [
{
name: 'bench_1',
data: [c1.id, c4.id, c7.id]
},
{
name: 'bench_2',
data: [c1.id + 1, c4.id + 1, c7.id + 1]
}
],
},
{
benchmark_result_type: 'Memory',
columns: [
{
name: 'rss_kb',
data: [c1.id, c4.id, c7.id]
}
]
}
],
'String to_i' => [
{
benchmark_result_type: 'Ips',
columns: [
{
name: 'bench_1',
data: [c1.id, c4.id, c7.id]
},
{
name: 'bench_2',
data: [c1.id + 1, c4.id + 1, c7.id + 1]
}
],
},
{
benchmark_result_type: 'Memory',
columns: [
{
name: 'rss_kb',
data: [c1.id, c4.id, c7.id]
}
]
}
]
)
end
end