-
Notifications
You must be signed in to change notification settings - Fork 183
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
Cpu optimization #149
Open
jer1ck0
wants to merge
2
commits into
hardcode-dev:master
Choose a base branch
from
jer1ck0:cpu-optimization
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
Cpu optimization #149
Changes from all commits
Commits
Show all changes
2 commits
Select commit
Hold shift + click to select a range
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 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,46 @@ | ||
require 'benchmark' | ||
require 'lazy' | ||
require_relative 'task-1' | ||
|
||
# array = (1..10000000).to_a | ||
|
||
# def eqeq_test(array) | ||
# array.select { |el| el == 500000 } | ||
# end | ||
|
||
# def include_test(array) | ||
# array.include?(500000) | ||
# end | ||
|
||
# def in_test(array) | ||
# 500000.in?(array) | ||
# end | ||
# def map_test(array) | ||
# array.map { |el| el % 10 == 0 ? el : nil }.compact | ||
# end | ||
|
||
# def test_select(array) | ||
# array.select { |el| el % 10 == 0 } | ||
# end | ||
|
||
# def test_reject(array) | ||
# array.reject { |el| el % 10 == 0 } | ||
# end | ||
|
||
# def test_slice(array) | ||
# array.slice_after { |element| element % 10 == 0 }.to_a | ||
# end | ||
|
||
# def test_lazy(array) | ||
# array.lazy.select { |el| el % 10 == 0 } | ||
# end | ||
|
||
# def test_set(array) | ||
# array.to_set.select { |el| el % 10 == 0 } | ||
# end | ||
|
||
# Benchmark.bm do |benchmark| | ||
# benchmark.report('eqeq') { eqeq_test(array) } | ||
# benchmark.report('include') { include_test(array) } | ||
# benchmark.report('in') { in_test(array) } | ||
# end |
This file contains 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,82 @@ | ||
# Case-study оптимизации | ||
|
||
## Актуальная проблема | ||
В нашем проекте возникла серьёзная проблема. | ||
|
||
Необходимо было обработать файл с данными, чуть больше ста мегабайт. | ||
|
||
У нас уже была программа на `ruby`, которая умела делать нужную обработку. | ||
|
||
Она успешно работала на файлах размером пару мегабайт, но для большого файла она работала слишком долго, и не было понятно, закончит ли она вообще работу за какое-то разумное время. | ||
|
||
Я решил исправить эту проблему, оптимизировав эту программу. | ||
|
||
## Формирование метрики | ||
Для того, чтобы понимать, дают ли мои изменения положительный эффект на быстродействие программы я придумал использовать такую метрику: *тут ваша метрика* | ||
|
||
## Гарантия корректности работы оптимизированной программы | ||
Программа поставлялась с тестом. Выполнение этого теста в фидбек-лупе позволяет не допустить изменения логики программы при оптимизации. | ||
|
||
## Feedback-Loop | ||
Для того, чтобы иметь возможность быстро проверять гипотезы я выстроил эффективный `feedback-loop`, который позволил мне получать обратную связь по эффективности сделанных изменений за *время, которое у вас получилось* | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
|
||
Вот как я построил `feedback_loop`: *как вы построили feedback_loop* | ||
|
||
## Вникаем в детали системы, чтобы найти главные точки роста | ||
Для того, чтобы найти "точки роста" для оптимизации я воспользовался *инструментами, которыми вы воспользовались* | ||
|
||
Вот какие проблемы удалось найти и решить | ||
|
||
### Ваша находка №1 | ||
- какой отчёт показал главную точку роста | ||
- как вы решили её оптимизировать | ||
- как изменилась метрика | ||
- как изменился отчёт профилировщика - исправленная проблема перестала быть главной точкой роста? | ||
|
||
### Ваша находка №2 | ||
- какой отчёт показал главную точку роста | ||
- как вы решили её оптимизировать | ||
- как изменилась метрика | ||
- как изменился отчёт профилировщика - исправленная проблема перестала быть главной точкой роста? | ||
|
||
### Ваша находка №X | ||
- какой отчёт показал главную точку роста | ||
- как вы решили её оптимизировать | ||
- как изменилась метрика | ||
- как изменился отчёт профилировщика - исправленная проблема перестала быть главной точкой роста? | ||
|
||
## Результаты | ||
В результате проделанной оптимизации наконец удалось обработать файл с данными. | ||
Удалось улучшить метрику системы с *того, что у вас было в начале, до того, что получилось в конце* и уложиться в заданный бюджет. | ||
|
||
*Какими ещё результами можете поделиться* | ||
|
||
## Защита от регрессии производительности | ||
Для защиты от потери достигнутого прогресса при дальнейших изменениях программы *о performance-тестах, которые вы написали* | ||
|
||
- Подготовил тестовые образцы на 10 20 30 40 50 к строк | ||
- Добавил скрипт для генерации флэт отчета | ||
- Изменил исходный файл для обработки параметра с именем файла | ||
- с помощью стакпрофа замерил время выполнения для избранных объемов | ||
- 10000 - 3с, 20000 - 17с, 30000 - 46, 40000 - killed | ||
- явный экспонентный рост сложности обработки | ||
- во всех отчетах есть 2 явных ботлнека: select & == | ||
- нужно заменить == на более быстрый аналог | ||
- проверяем через бенчмарк == и include? (второй гораздо быстрее) | ||
- применяем | ||
- 10000 - 2с, 20000 - 7с, 30000 - 15c, 40000 - killed | ||
- select раз за разом перебирает массив сессий. Гипотеза: скорость обработки хэша гораздо быстрее. И поиск быстрее идет по ключам. разделим изначальный массив на сессии и пользователей. | ||
- сборка сессий и пользователей на 40к пользователей в изначальном варианте занимает почти две секунды, а при использовании group_by это время около тысячных долей секунды | ||
- сгрупировал сессии и пользователей | ||
- распарсил в хэши | ||
- добавил группированные сессии где ключ - это айди пользователя, а значение - массив сессий. Благодаря такоц структуре стало возможным отказаться от тяжелого селекта перебирающего сессии для каждого пользователя. | ||
- исправил возникающие ошибки | ||
- получилось добиться зависимости производительности, приближенной к линейной: 20к-0,2с..1кк-4с | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. да, это самая главная оптимизация тут, так как вместе с ней исправляется асимптотика всего алгоритма |
||
- прогон 1kk записей занимает 24 сек(далеко до идеала) | ||
- просмотрев флэт отчет видим что функция collect_stats_from_users вызывается 7 раз, внутрянка работает целых 18 секунд, а массив пользователей прогоняется в каждом блоке. | ||
- объединил обработку данных в один блок | ||
- отказался от сборки сессий и пользователей черех group_by использовал << при проходе по начальному файлу. получил незначительный прирост производительности | ||
- использовал << везде где складывались массивы. Обработался файл на 3млн записей за 59 секунд. data_large упорно продолжает падать(проверял с отключенным и включенным GC). | ||
- в последнем отчете для 3кк записей увидел что чтение данных из массива в сборке данных пользователя вызывается 13кк раз вынес сессий в переменную. Количество вызовов [] сократилось вдвое. | ||
- последние показания 1кк ~ 19сек, 2кк ~ 38сек, 3кк ~ 58 сек, large ~ 65 сек | ||
|
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.
*это был плейсхолдер*