Skip to content
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
7 changes: 7 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
.DS_Store
*.json
*.html
massif.out.*
profile.callgrind.out.*
data/data_large.txt
tmp/*
1 change: 1 addition & 0 deletions .ruby-version
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
2.6.1-railsexpress
14 changes: 14 additions & 0 deletions Gemfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
source 'https://rubygems.org'
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 Лайк за Gemfile

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ееее! Значит не сильно переугорел )

# ruby '2.6.1'

gem 'pry', '~> 0.12'
gem 'minitest', '~> 5.11'
gem 'oj', '~> 3.7'
gem 'progress_bar', '~> 1.3'

# Profiling
gem 'benchmark-ips'
gem 'kalibera'
gem 'memory_profiler'
gem 'stackprof'
gem 'ruby-prof'
41 changes: 41 additions & 0 deletions Gemfile.lock
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
GEM
remote: https://rubygems.org/
specs:
benchmark-ips (2.7.2)
coderay (1.1.2)
highline (2.0.1)
kalibera (0.1)
memoist (~> 0.11.0)
rbzip2 (~> 0.2.0)
memoist (0.11.0)
memory_profiler (0.9.12)
method_source (0.9.2)
minitest (5.11.3)
oj (3.7.9)
options (2.3.2)
progress_bar (1.3.0)
highline (>= 1.6, < 3)
options (~> 2.3.0)
pry (0.12.2)
coderay (~> 1.1.0)
method_source (~> 0.9.0)
rbzip2 (0.2.0)
ruby-prof (0.17.0)
stackprof (0.2.12)

PLATFORMS
ruby

DEPENDENCIES
benchmark-ips
kalibera
memory_profiler
minitest (~> 5.11)
oj (~> 3.7)
progress_bar (~> 1.3)
pry (~> 0.12)
ruby-prof
stackprof

BUNDLED WITH
1.17.3
18 changes: 18 additions & 0 deletions asymptotics.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
require 'benchmark/ips'
require_relative 'task_1'
# require_relative 'task_1_original'

Benchmark.ips do |b|
b.warmup = 0
b.report('5k') { work('data/data_5k.txt') }
b.report('10k') { work('data/data_10k.txt') }
b.report('20k') { work('data/data_20k.txt') }
b.report('30k') { work('data/data_30k.txt') }
b.report('40k') { work('data/data_40k.txt') }
b.report('50k') { work('data/data_50k.txt') }
b.report('100k') { work('data/data_100k.txt') }
b.report('500k') { work('data/data_500k.txt') }

b.compare!
end

46 changes: 0 additions & 46 deletions case-study-template.md

This file was deleted.

54 changes: 54 additions & 0 deletions case-study.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
# Case-study оптимизации

## Актуальная проблема
В нашем проекте возникла серьёзная проблема.

Необходимо было обработать файл с данными, чуть больше ста мегабайт.

У нас уже была программа на `ruby`, которая умела делать нужную обработку.

Она успешно работала на файлах размером пару мегабайт, но для большого файла она работала слишком долго, и не было понятно, закончит ли она вообще работу за какое-то разумное время.

Я решил исправить эту проблему, оптимизировав эту программу.

## Формирование метрики
Для того, чтобы понимать, дают ли мои изменения положительный эффект на быстродействие программы я решил использовать такую метрику: сколько раз в секунду программа успевает обработать файл размером 10000 строк (IPS)

## Гарантия корректности работы оптимизированной программы
Программа поставлялась с тестом. Выполнение этого теста позволяет не допустить изменения логики программы при оптимизации.

## Feedback-Loop
Для того, чтобы иметь возможность быстро проверять гипотезы я выстроил эффективный `feedback-loop`, который позволил мне получать обратную связь по эффективности сделанных изменений за 20 секунд

Вот как я построил `feedback_loop`: создал скрипт `optimization_loop.rb` который автоматически запускал тест для проверки что ничего не сломано, и сразу же измерял целевую метрику.

## Вникаем в детали системы, чтобы найти 20% точек роста
Для того, чтобы найти "точки роста" для оптимизации я воспользовался Memory Profiler, StackProf, RubyProf, Vallgrind Massif.

Вот какие проблемы удалось найти и решить

### Находка №1
Неявный вложенный цикл в блоке select, исправил на предварительную сортировку сессий сразу после парсинга

### Находка №2
Неефективный сбор уникальных браузеров, переделал на множество

### Находка №3
Медленная генерация JSON, решение: использовал Oj

На данном этапе файл уже можно бло обработать за разумное время меншье 30 секунд и далее упор был сделан на уменьшение размера потребляемой памяти при обработке большого файла.

### Находка №4
Файл загружается и парсится в память целиком. Решение: файл обрабатывается построчно, новые данные пошагово агрегируются с предыдущими

### Находка №4
Программа хранить в памяти большие агрегаты (список всех браузеров и дат всех сессий). Решение: так как сессии в файле идут группированные по пользователю, то запись результатов в файл ведётся поточно для каждого пользователя, и в один момент времени в памяти хранится агрегат только для текущего пользвателя, также больше не хранится список пользователей

## Результаты
В результате проделанной оптимизации наконец удалось обработать файл с данными.
Удалось улучшить метрику системы (IPS) с 0.482, 25.237

Также была замерена асимтотика времени выполнения программы, и после оптимизации она стала почти линейной https://docs.google.com/spreadsheets/d/1g9OB3SIYXMOdno_0iH3xMKYZpoD3YuL9I0bo0YdyUDQ/edit?usp=sharing

## Защита от регресса производительности
Для защиты от потери достигнутого прогресса при дальнейших изменениях программы был добавлен performance test
18 changes: 18 additions & 0 deletions data/data.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
user,0,Leida,Cira,0
session,0,0,Safari 29,87,2016-10-23
session,0,1,Firefox 12,118,2017-02-27
session,0,2,Internet Explorer 28,31,2017-03-28
session,0,3,Internet Explorer 28,109,2016-09-15
session,0,4,Safari 39,104,2017-09-27
session,0,5,Internet Explorer 35,6,2016-09-01
user,1,Palmer,Katrina,65
session,1,0,Safari 17,12,2016-10-21
session,1,1,Firefox 32,3,2016-12-20
session,1,2,Chrome 6,59,2016-11-11
session,1,3,Internet Explorer 10,28,2017-04-29
session,1,4,Chrome 13,116,2016-12-28
user,2,Gregory,Santos,86
session,2,0,Chrome 35,6,2018-09-21
session,2,1,Safari 49,85,2017-05-22
session,2,2,Firefox 47,17,2018-02-02
session,2,3,Chrome 20,84,2016-11-25
Loading