Skip to content

Commit

Permalink
Оптимизация лексического анализатора (#2)
Browse files Browse the repository at this point in the history
Удалось ускорить выборку следующего токена в 2,3 раза. Подробности в журнале
проекта.
  • Loading branch information
Mazdaywik committed Mar 7, 2016
1 parent d4d7f79 commit b6f113c
Show file tree
Hide file tree
Showing 6 changed files with 546 additions and 638 deletions.
50 changes: 49 additions & 1 deletion Documentation/Журнал/Changes.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7851,4 +7851,52 @@ back-end’ом компилируется весь набор исходник
(Версия 0.2.981)
[TODO: Изменения в лексике и комментариях]
Поведение звёздочки изменено: теперь она обозначает комментарий, только когда находится в первой
позиции строки. В остальных случаях происходит синтаксическая ошибка.
позиции строки. В остальных случаях происходит синтаксическая ошибка.


[07.03.2016 - 15:31:09,83]
(Версия 0.2.981)

[DONE: Изменения в лексике и комментариях]
Лексический анализатор оптимизирован, поведение «классических» комментариев «классическое».

Оптимизация была произведена путём отказа от промежуточной абстракции FE-MRefal.MSymStream.
Поскольку изменение довольно масштабное, лексический анализатор выглядит как полностью переписанный,
но при его переработке общий скелет логики максимально сохранён (в диффе фиксации можно наблюдать
неизменные заголовки функций с переписанным телом функции). Попутно в анализаторе обнаружилась
странная обработка макроцифр: при анализе длинной цепочки десятичных цифр, та бьётся на фрагменты
длиной 9 или 10 знаков, каждый из которых считается отдельной макроцифрой. Анализ был изменён
на более логичный: для длинной цепочки десятичных цифр проверяется, может ли она представлять собой
корректное целое число без переполнения. Если не может, фиксируется лексическая ошибка.
Наибольшее значение целого теперь не зафиксировано в лексическом анализаторе, а берётся как
MMath.MaxNum.
Компилятор самоприменяется успешно, но всестороннее тестирование лексического анализатора
не проводилось. Поэтому не исключены скрытые ошибки, особенно в коде восстановления после ошибок.

Производительность компилятора тестировалась на двух современных машинах. В качестве бенчмарка
использовался многократный запуск компилятора C++/SR с профилем Refal5. Компилятор был скомпилирован
при помощи BCC 5.5. Измерялось чистое время выполнения функции FE-MRefal.MLexer.Profiling-NextToken,
т. е. время без учёта времени выполнения встроенных функций. На точность замера могло повлиять то,
что объём кода нового лексического анализатора меньше старого, который включал в себя как
MLexer.mref, так и MSymStream.mref. Но, я думаю, этим смело можно пренебречь, поскольку
производилась полная компиляция, а в программе немало модулей, которые длиннее лексического
анализатора.

* Машина Intel® Core™ i3-4030U CPU @ 1,90 GHz, 12 Гбайт ОЗУ:
До оптимизации типичное время выполнения составляло 3,4 с, после — 2,0 с, что от времени
выполнения программы составляло 23 % и 15 % соответственно.
Прирост производительности −42,5 %.

* Машина Intel® Core™ i5-2430M CPU @ 2,40 Ghz, 8 Гбайт ОЗУ:
До оптимизации типичное время выполнения составляло 3,1 с, после — 1,7 с, что от времени
выполнения программы составляло 23 % и 15 % соответственно (да, проценты совпали).
Прирост производительности −43,3 %.

Следует также добавить, что сначала испытывались другие, эволюционные оптимизации, меняющие
незначительно символьный поток и лексический анализатор. Они давали прирост производительности
примерно 5…7…10 %. В основную ветку эти оптимизации не включены, они доступны в ветке
historical/lexopt. В принципе, возможно эти подходы включить и в основную ветку, но пока этого
не нужно, текущего прироста производительности достаточно.

Ранее лексический анализатор занимал первую строчку в профилировщике, теперь — третью-четвёртую.
Задача выполнена.
107 changes: 107 additions & 0 deletions Documentation/Журнал/DONEs.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,110 @@
====================================================================================================
[DONE] Изменения в лексике и комментариях
====================================================================================================

[TODO] 22.09.2008 - 23:27:35,87

Можно расширить лексику следующим образом: разрешить имена с маленькой буквы (будут проблемы толь-
ко если модуль имеет имя s, t или e -- в конце модуля ведь точка, и при импорте функций тоже). Можно
с большой буквы оставить имена только модулей или каких-либо других имён, разрешаемых точкой. Также
полезно избавиться от анахронизма -- комментариев, начинающихся со звёздочки. И так язык прекрасно
поддерживает комментарии C++ '//'. А звёздочку можно использовать для передачи функции по ссылке --
вместо амперсенда.
----------------------------------------------------------------------------------------------------
[TODO] 01.02.2009 - 21:42:25,09

Опять же, изменения в лексике не являются приоритетным для версии 0.2.
Изменения, связанные с именами с маленькой буквы я считаю сомнительными, а исключение комментари-
ев, начинающихся со звёздочки, я считаю вполне разумным.
----------------------------------------------------------------------------------------------------
[TODO] 01.05.2010 - 19:30:19,45

(Ревизия 01.05.2010) Не требуется для выпуска версии 0.2.
Мне хочется, чтобы версия 0.2 была совместима с синтаксисом языка версии 0.1, т.е. чтобы можно
было откомпилировать исходники выпуска 0.1 выпущенной версией 0.2. Поэтому комментарии со звёздоч-
кой я убирать пока не буду, а только назову их deprecated.
Комментарии со звёздочкой удалю при первой же переработке синтаксиса языка. А имена со строчной
буквы не нужны, т.к. никаких принципиально новых возможностей дать пока не могут.
----------------------------------------------------------------------------------------------------
[TODO] 25.07.2010 - 12:33:59,02

(Ревизия 25.07.2010) Не требуется для выпуска версии 0.2.
Вообще, мне бы хотелось, чтобы компилятор версии N мог бы компилировать исходный код версии N-1,
изменение лексики сделало бы это невозможным.
----------------------------------------------------------------------------------------------------
[RENAME] 07.09.2010 - 23:30:08,46

Old name is "[TODO] Продумать изменения в лексике и комментариях"
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
----------------------------------------------------------------------------------------------------
[TOTHINK] 07.09.2010 - 23:30:08,46

Удалено слово "продумать" ("обдумать") из заголовка, сменён тег с TODO на TOTHINK. (Переименова-
ние было проведено при первой возможности — сразу после того, как был введён тег RENAME.)
----------------------------------------------------------------------------------------------------
[TODO] 18.12.2015 - 16:11:11,60

(Ревизия 18.12.2015)
Менять указатель функции с & на * я считаю не особо нужным, а в остальном комментарий,
начинающийся со * проблем не создаёт. Единственное, что традиционно в Рефале комментарием
считается строка, у которой звёздочка находится в самой первой колонке, но в текущей версии
Модульного Рефала перед звёздочкой может находиться произвольное число пробельных символов.
Это несоответствие классическому подходу всё-таки стоит изменить на нормальное.
Параллельно с этим стоит сделать рефакторинг и оптимизацию лексического анализатора: при полной
пересборке на лексический анализ уходит примерно 20 % времени выполнения программы, на каждую
лексему приходится примерно 57 шагов рефал-машины.
----------------------------------------------------------------------------------------------------
[TODO] 28.02.2016 - 15:13:21,58

Поведение звёздочки изменено: теперь она обозначает комментарий, только когда находится в первой
позиции строки. В остальных случаях происходит синтаксическая ошибка.
----------------------------------------------------------------------------------------------------
[DONE] 07.03.2016 - 15:31:09,83

Лексический анализатор оптимизирован, поведение «классических» комментариев «классическое».

Оптимизация была произведена путём отказа от промежуточной абстракции FE-MRefal.MSymStream.
Поскольку изменение довольно масштабное, лексический анализатор выглядит как полностью переписанный,
но при его переработке общий скелет логики максимально сохранён (в диффе фиксации можно наблюдать
неизменные заголовки функций с переписанным телом функции). Попутно в анализаторе обнаружилась
странная обработка макроцифр: при анализе длинной цепочки десятичных цифр, та бьётся на фрагменты
длиной 9 или 10 знаков, каждый из которых считается отдельной макроцифрой. Анализ был изменён
на более логичный: для длинной цепочки десятичных цифр проверяется, может ли она представлять собой
корректное целое число без переполнения. Если не может, фиксируется лексическая ошибка.
Наибольшее значение целого теперь не зафиксировано в лексическом анализаторе, а берётся как
MMath.MaxNum.
Компилятор самоприменяется успешно, но всестороннее тестирование лексического анализатора
не проводилось. Поэтому не исключены скрытые ошибки, особенно в коде восстановления после ошибок.

Производительность компилятора тестировалась на двух современных машинах. В качестве бенчмарка
использовался многократный запуск компилятора C++/SR с профилем Refal5. Компилятор был скомпилирован
при помощи BCC 5.5. Измерялось чистое время выполнения функции FE-MRefal.MLexer.Profiling-NextToken,
т. е. время без учёта времени выполнения встроенных функций. На точность замера могло повлиять то,
что объём кода нового лексического анализатора меньше старого, который включал в себя как
MLexer.mref, так и MSymStream.mref. Но, я думаю, этим смело можно пренебречь, поскольку
производилась полная компиляция, а в программе немало модулей, которые длиннее лексического
анализатора.

* Машина Intel® Core™ i3-4030U CPU @ 1,90 GHz, 12 Гбайт ОЗУ:
До оптимизации типичное время выполнения составляло 3,4 с, после — 2,0 с, что от времени
выполнения программы составляло 23 % и 15 % соответственно.
Прирост производительности −42,5 %.

* Машина Intel® Core™ i5-2430M CPU @ 2,40 Ghz, 8 Гбайт ОЗУ:
До оптимизации типичное время выполнения составляло 3,1 с, после — 1,7 с, что от времени
выполнения программы составляло 23 % и 15 % соответственно (да, проценты совпали).
Прирост производительности −43,3 %.

Следует также добавить, что сначала испытывались другие, эволюционные оптимизации, меняющие
незначительно символьный поток и лексический анализатор. Они давали прирост производительности
примерно 5…7…10 %. В основную ветку эти оптимизации не включены, они доступны в ветке
historical/lexopt. В принципе, возможно эти подходы включить и в основную ветку, но пока этого
не нужно, текущего прироста производительности достаточно.

Ранее лексический анализатор занимал первую строчку в профилировщике, теперь — третью-четвёртую.
Задача выполнена.


====================================================================================================
[DONE] Удалить исходники Простого Рефала из Модульного Рефала
====================================================================================================
Expand Down
1 change: 0 additions & 1 deletion Documentation/Журнал/LIST.txt
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,3 @@
[TODO] Оптимизация совместного сопоставления с образцом
[TOTHINK] ВПВ: Opensource-лицензия
[TODO] Актуализировать back-end C++/SR
[TODO] Изменения в лексике и комментариях
Loading

0 comments on commit b6f113c

Please sign in to comment.