Skip to content

Latest commit

 

History

History
105 lines (82 loc) · 9 KB

File metadata and controls

105 lines (82 loc) · 9 KB

Case-study оптимизации

Актуальная проблема

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

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

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

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

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

Для начала я запустил небольшой бенчмарк, чтобы понять, какая асимптотика у программы. Для каждого измерения взял первые n строк из файла с полными данными. Результаты бенчмарка выглядели так:

                    user       system     total    real
line_count = 10     0.001417   0.000258   0.001675 (  0.011769)
line_count = 50     0.001417   0.000258   0.001675 (  0.011346)
line_count = 100    0.002608   0.000000   0.002608 (  0.013075)
line_count = 500    0.002582   0.009544   0.012126 (  0.022563)
line_count = 1000   0.009544   0.010132   0.019676 (  0.030331)
line_count = 5000   0.218717   0.020935   0.239652 (  0.253703)
line_count = 10000  0.979160   0.000000   0.979160 (  1.010272)
line_count = 20000  4.887525   0.017847   4.905372 (  4.930110)
line_count = 30000 13.817134   0.099889  13.917023 ( 13.935027)
line_count = 40000 29.488743   0.109932  29.598675 ( 29.619598)
line_count = 50000 50.501303   0.109971  50.611274 ( 50.648952)

График зависимости времени работы программы от объёма входных данных выглядел так:

График зависимости времени работы программы

Судя по графику, программа работала с асимптотикой O(n^2).

Формирование метрики

Для того, чтобы понимать, дают ли мои изменения положительный эффект на быстродействие программы я придумал использовать такую метрику: время работы программы на полном объёме данных.

Гарантия корректности работы оптимизированной программы

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

Feedback-Loop

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

Вот как я построил feedback_loop:

  1. Запуск профилировщик rbspy на малом объёме данных.
  2. Анализ отчёта профилировщика и выявление главной точки роста.
  3. Оптимизация главной точки роста.
  4. Запуск теста идущего в комплекте с программой.
  5. Запуск бенчмарка на малых объёмах данных и проверка попадания в бюджет.
  6. Закрепление изменений в системе контроля версий.
  7. Обновление бюджета в бенчмарке.

Вникаем в детали системы, чтобы найти главные точки роста

Для того, чтобы найти "точки роста" для оптимизации я воспользовался инструментами, которыми вы воспользовались

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

Итерация №1

  • Использовался отчёт профилировщика rbspy при запуске на файле с 10000 строк. Отчёт показал, что больше всего времени программа тратит на выборку сессий по пользователю из массива сессий.

  • Было принято решение вынести эту строку из цикла и вместо этого выполнить Array#group_by.

  • Время выполнения программы на файле с 10000 строками уменьшилось с 1.010272 до 0.283054 секунды.

  • Также уменьшилось время выполнения программы на файлах большего размера.

                        user       system     total    real
    line_count = 11     0.001461   0.000487   0.001948 (  0.012805)
    line_count = 51     0.002695   0.000898   0.003593 (  0.009555)
    line_count = 100    0.003591   0.001197   0.004788 (  0.010995)
    line_count = 501    0.006650   0.000000   0.008918 (  0.019601)
    line_count = 1000   0.012564   0.000000   0.015094 (  0.029157)
    line_count = 5000   0.050438   0.019783   0.073774 (  0.103414)
    line_count = 10000  0.160801   0.000000   0.170127 (  0.283054)
    line_count = 20001  0.400933   0.048675   0.455922 (  0.547208)
    line_count = 30000  0.637398   0.019211   0.666364 (  0.770074)
    line_count = 40000  0.978085   0.010174   1.003803 (  1.200759)
    line_count = 50000  1.290851   0.019795   1.325995 (  1.518988)
    
  • График зависимости времени работы программы от объёма входных данных стал выглядеть так (синие точки):

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

  • Отчёт профилировщика изменился значительно: исправленная проблема перестала быть главной точкой роста, время подключения библиотек стало основным.

Ваша находка №2

  • какой отчёт показал главную точку роста
  • как вы решили её оптимизировать
  • как изменилась метрика
  • как изменился отчёт профилировщика - исправленная проблема перестала быть главной точкой роста?

Ваша находка №X

  • какой отчёт показал главную точку роста
  • как вы решили её оптимизировать
  • как изменилась метрика
  • как изменился отчёт профилировщика - исправленная проблема перестала быть главной точкой роста?

Результаты

В результате проделанной оптимизации наконец удалось обработать файл с данными. Удалось улучшить метрику системы с того, что у вас было в начале, до того, что получилось в конце и уложиться в заданный бюджет.

Какими ещё результами можете поделиться

Защита от регрессии производительности

Для защиты от потери достигнутого прогресса при дальнейших изменениях программы о performance-тестах, которые вы написали