-
Notifications
You must be signed in to change notification settings - Fork 24
Task 1 + Task 2 #18
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
Open
holyketzer
wants to merge
9
commits into
spajic:master
Choose a base branch
from
holyketzer:master
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Task 1 + Task 2 #18
Changes from all commits
Commits
Show all changes
9 commits
Select commit
Hold shift + click to select a range
8dbb64c
Initial cleanup
holyketzer 87b183c
Memory optimization
holyketzer 714e4bf
CPU optimization session (target achived, file can be processed)
holyketzer 359609c
Measure memory with Valgrind
holyketzer 6e2f30f
Added progress bar + stream processing to decrease RAM usage
holyketzer 1a7c35e
Stream JSON writing + remove double splitting
holyketzer 151fe66
Fill case study
holyketzer a9af158
Extend asymptotics benchamerking
holyketzer 9da725f
Optimize readlines
holyketzer File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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/* |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| 2.6.1-railsexpress |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,14 @@ | ||
| source 'https://rubygems.org' | ||
| # 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' | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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 | ||
|
|
This file was deleted.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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 |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍 Лайк за
GemfileThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ееее! Значит не сильно переугорел )