Skip to content

Latest commit

 

History

History
94 lines (72 loc) · 7.48 KB

File metadata and controls

94 lines (72 loc) · 7.48 KB

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

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

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

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

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

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

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

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

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

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

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

Feedback-Loop

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

Вот как я построил feedback_loop: профилирование для выявления главной точки роста изменение кода проблемного участка тестирование проверка скорости выполнения коммит

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

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

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

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

  • Отчет в ruby-prof показал главную точку роста в методе work - метод select в коде, считающем статистику по пользователям, выполнялся большее количество времени выполнения программы
  • Я сгруппировал сессии по id пользователя, чтобы избавиться от прохождения по всему массиву сессий для каждого пользователя
  • Скорость обработки 100 записей уменьшилась с 20 до 15 мс
  • Array#select исчез из списка методов, которые выполняются много времени

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

  • Отчет в ruby-prof показал что главная точка роста была методом Array#all? в коде для подсчета количества уникальных браузеров
  • Переписал код чтобы получить все браузеры за один цикл и потом использовал метод uniq чтобы вернуть только уникальные браузеры
  • Скорость обработки 100 записей уменьшилась с 15 до 10 мс
  • Array#all? исчез из списка методов, которые выполняются много времени

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

  • Отчет в ruby-prof показал что главная точка роста - Date.parse в коде для получения даты сессий
  • Убрал парсинг даты и форматирование дат, потому что в этом нет необходимости
  • Скорость обработки 100 записей уменьшилась с 10 до 6 мс
  • Парсинг даты перестал быть главной точкой роста

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

  • Главная точка роста - Array#each в коде для формирования отчета
  • Объединил несколько проходов по массиву с пользователями в один
  • Метрики изменились очень незначительно
  • Array#each опустился на второе место в списке методов в ruby-prof

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

  • Главная точка роста - Array#map
  • Убрал лишние map
  • Метрики изменились очень незначительно
  • Array#map опустился на третье место в списке методов в ruby-prof

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

  • Главная точка роста снова Array#each в методе work
  • Оптимизировал код в блоках each - убрал пересоздание массивов
  • Скорость обработки 1000 записей уменьшилась с 130 до 50 мс
  • Array#each опустился на второе место в списке методов в ruby-prof

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

  • Главная точка роста String#split в методе work
  • Убрал лишние вызовы split
  • Скорость обработки 1000 записей уменьшилась с 50 до 45 мс
  • String#split опустился на третье место в списке методов в ruby-prof, количество его вызовов уменьшилось с 1300 до 659

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

  • Главная точка роста снова Array#each в методе collect_stats_from_users
  • Изменил код в блоке и метод
  • Метрики изменились очень незначительно
  • Array#each опустился на второе место в списке методов в ruby-prof

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

  • Главная точка роста - метод to_json
  • заменил
  • Скорость обработки 1000 записей уменьшилась с 45 до 35 мс
  • to_json исчез из списка методов, которые выполняются много времени

Результаты

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

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

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