|
1 | 1 | # ЗАМЕТКИ ПО РЕШЕНИЮ |
2 | 2 |
|
3 | | -## Процесс решения |
| 3 | +## Ход решения |
4 | 4 |
|
5 | 5 | Во-первых было интересно, спасибо! :) |
6 | 6 | Выполнение заняло сильно больше времени, чем я изначально оценил. |
7 | 7 |
|
8 | 8 | Было весьма унизительно, когда первая версия казалось бы очень оптимизированного решения со всякими |
9 | 9 | статически выделенными массивами без перевыделений памяти оказалась медленнее grep раз в 5-6. |
10 | | -А я ожидал, что резальтат уже должен быть лучше аналогов. Тем более, что у меня специализированный алгоритм, |
| 10 | +А я ожидал, что результат уже должен быть лучше аналогов. Тем более, что у меня специализированный алгоритм, |
11 | 11 | а у grep синтаксис иной и алгоритм по определению хуже должен быть. |
12 | 12 |
|
13 | 13 | Потом я заменил алгоритм матча строки с динамическим программированием и памятью O(P*N) на другой, более быстрый и с константной памятью. |
14 | 14 | И... я стал медленнее grep всего в 2 раза. Почти успех :))) При этом по профайлеру релизному у меня 80+% проводилось именно в матче строк. |
15 | 15 |
|
16 | 16 | Не буду томить, сомневаюсь, что более эффективный алгоритм существует для этой задачи. |
17 | 17 | Победить grep вышло лишь добавив несколько оптимизаций, которые просто ускоренно прокручивали алгоритм в популярных сценариях. |
18 | | -И эта победа всего лишь на 25%. |
| 18 | +Это ускорило матчинг примерно в 6 раз, а общее время работы программы раза в 3. И эта дало победу над grep всего лишь на 25-35%. |
19 | 19 |
|
20 | | -После этого согласно профайлеру почти ровно половина времени проводилась |
| 20 | +После этого? согласно профайлеру почти ровно половина времени проводилась |
21 | 21 | в матче строк, а процентов под 40 времени проводилось в синхронном ReadFile(). |
22 | 22 |
|
23 | 23 | Я решил, что вот он звёздный час асинхронного чтения файлов! |
24 | | -Запрограмировал, и... ничего. Общее время работы не изменилось. |
25 | | -Но профайлер показал перераспределение времени в сторону алгоритма матча. Очень странно. Я так и не понял почему так. |
26 | | -Я убеждён, что эти 40% можно было сжать до максимум 5% за что параллелизации вычитки данных и их обработки. |
| 24 | +Запрограммировал, и... ничего. Общее время работы не изменилось. |
| 25 | +Но профайлер показал перераспределение времени в сторону алгоритма матча. Очень странно, что он замедлился. Я так и не понял почему так. |
| 26 | +Я убеждён, что эти 40% можно было сжать до максимум 5% за счет параллелизации вычитки данных и их обработки. |
| 27 | +Возможно это как-то связано с тем, что данные лежат в файловом кэше, а не читаются с диска (более короткий путь IRP). |
| 28 | +Возможно это банальное копирование памяти в kernel mode плохо параллелизуется. Может стоило переписать, чтобы чтение с диска в выделенном потоке выполнялось... |
| 29 | +Если у вас есть идеи почему так вышло или в чём ошибка, то буду рад если поделитесь. |
| 30 | + |
| 31 | +Также заметил вставку перед циклом команды nop при оптимизации по скорости компилятором. |
| 32 | +Есть лишь предположения зачем. Если вы вдруг знаете - тоже дайте знать. Есть скриншот, приложил его в проект. |
| 33 | +Я спросил моих разных коллег, они не в курсе. |
27 | 34 |
|
28 | 35 | Попробовал на всякий случай отображать файл на память. |
29 | | -Но у меня были сомнения в эффективности для этого применения. |
30 | | -Так и вышло. Немного медленнее. Примерно как grep вышло. |
| 36 | +Но у меня были сомнения в эффективности скорости подгрузки новых страниц в этом решении. |
| 37 | +Так и вышло. Немного медленнее, процентов на 20% (время всей программы). |
| 38 | +Хотя тоже странно при прогретом кэше. |
| 39 | +Теоретически, если данные в кэше лежат, то можно было бы их отобразить на виртуальную память в read-only режиме за O(1), |
| 40 | +а потом экономить на переходах в kernel mode + экономить на копировании памяти. |
31 | 41 |
|
32 | 42 | ## Тестирование и заметки |
33 | 43 |
|
34 | | -Тестировал на логе веб сервера, 2 Гб, 5.5 млн строк, средняя длина строки 380 байт, все строки не длинее 1024 байт. |
| 44 | +Тестировал на логе веб сервера, 2 Гб, 5.5 млн строк, средняя длина строки 380 байт, все строки не длиннее 1024 байт. |
| 45 | +Подходило под паттерн 1600 строк. Паттерн был взят вида "*строка*" как наиболее популярный в обычной жизни. |
35 | 46 |
|
36 | | -Диск SSD, но прогревал чтобы всё в кэш легло файловый. 8 ядер логических core i5 gen8, прочей загрузки минимум, ноутбук. |
| 47 | +Диск SSD, но я прогревал чтобы всё легло в файловый кэш. 8 ядер логических core i5 gen8, ноутбук. |
37 | 48 |
|
38 | 49 | Сборка под x64 архитектуру работала быстрее вышла чем под x86. |
39 | 50 |
|
40 | | -Флаг FILE_FLAG_SEQUENTIAL_SCAN к моему разочарованию не дал ничего. |
| 51 | +Флаг FILE_FLAG_SEQUENTIAL_SCAN не дал прироста скорости на прогретом кэше. Без прогретого кэша надо измерять отдельно. |
41 | 52 |
|
42 | 53 | Иногда скорость надолго залипает на +25%, иногда на самом быстром варианте. |
43 | 54 | Скорее всего связано с тем, что у меня ноутбук и у ядер есть режимы экономные. Но не факт. |
44 | 55 |
|
| 56 | +В последней версии grep показывает 2.5 секунды, а моё решение - 1.6 секунды на тестовых данных. |
| 57 | + |
45 | 58 | ## Особенности реализации |
46 | 59 |
|
47 | 60 | В итоге у меня остались все три реализации чтения файлов. Я оставил асинхронную версию как самую перспективную. Переключаются так: |
|
64 | 77 |
|
65 | 78 | Я притянул часть STL на мой страх и риск. Ту, часть, которая не требует исключений и работает без лишних накладных расходов. |
66 | 79 |
|
| 80 | +--- |
0 commit comments