refal-5-lambda
refal-5-lambda copied to clipboard
Анализ и оптимизация производительности Рефала-5λ
Эта задача — подзадача для #185.
Выяснилось, что компилятор Рефала-05, собранный Рефалом-5λ, в три раза медленнее компилятора, собранного самим собой, и компилятора, собранного refc
. И это не смотря на максимально доступные оптимизации (-OdPRC
).
То, что обгоняет refgo
, можно объяснить более оптимальным форматом языка сборки. Команды сопоставления функциональны, они не изменяют значения уже присвоенных ячеек стека, а инициализируют новые. В то время как в Рефале-5λ при каждом сопоставлении изменяется содержимое ячейки-диапазона.
Но при этом Рефал-05 вообще не содержит никаких оптимизаций и его идеология языка сборки совпадает с идеологией в Рефале-5λ.
Можно предположить следующие причины:
-
В коде Рефала-5λ слишком много слоёв абстракций и используемый BCC 5.5 не может всё заинлайнить. Соответственно, нужно упрощать вручную. В частности, для функций и идентификаторов их указатель получается вызовом
vm->ref(descr)
. -
В Рефале-05 очень дешёвая функция
Mu
(в силу особенностей языка) и она активно используется. Например, в кодогенераторе инструкции формируются путём косвенного вызова их тегов в цикле. И, возможно, за счёт дешевизныMu
Рефал-05 обгоняетrefc
+refgo
. -
Встроенные функции реализованы на Рефале, при этом для каждой из них корректируется виртуальный счётчик шагов функциями
<__Step-Start>
и<__Step-End>
-
Используется неоптимальное построение результатных выражений, а именно, без учёта последовательного распределения строящихся элементов и с проверками успешности команд аллокации.
В Рефале-5λ
Mu
не оптимизирована. Мало того, что она написана на Рефале с условиями и несколькими вспомогательными функциями, так ещё и сам поиск имени достаточно тяжеловесен.
Что нужно сделать:
-
[ ] Замерить время без использования функции
Mu
— конвертировать программу на Рефале-05 в Рефал-5λ, заменив все идентификаторыFunc
на указатели&Func
и вызовы<Mu s.F …>
на непосредственный вызов<s.F …>
. Для этого можно написать препроцессор на Рефале-05, тем более что Рефал-05 декларируется как язык для написания таких инструментальных средств.В результате получится программа, семантически идентичная Рефалу-05, а значит, сравнение будет честнее.
-
[ ] Попробовать исключить лишние слои абстракций.
-
[ ] Посчитать количество, и, возможно, время выполнения вызовов каждой из функций программы для Рефала-05 и Рефала-5 и сделать выводы. Такие замеры уже делались (d6255fb10cf14418403ef9ff0a361bf9c8987111, 674963791fab8b6312b09186eeac03b2bc27ea23).
-
[ ] Оптимизировать построение результатных выражений (#196).
-
[ ] Пересмотреть и оптимизировать язык сборки, сделав команды сопоставления функциональными (#204).
Замеры производительности
Запуск crefal
(компиляция MRefal.r5.ref
)
Начиная с версии 2.2.6 Рефал-5λ умеет декодировать и компилировать .rsl-файлы. А это значит, что можно сравнить производительность.
Замеры в консоли
D:\Mazdaywik\Documents\Refal-5-lambda\build>refgo -a crefal MRefal.r5.ref
Copyright (C): RefalScope Project, 2004-2018
Refal-5 System. Version PZ Oct 29 2004
*** The View Field:
<STOP$ <Exit 0 >>
*** Number of Steps = 4640529
Elapsed system time: 13.486 seconds
*** Buried:
((Warnings '=' 0 )(Errors '=' 0 )(Mode '=' crefal )(Testing '=' False )
(Output '=MRefal.r5.rsl'
)(Input '=MRefal.r5.ref' )
)
Memory allocated = 10412032 Bytes
D:\Mazdaywik\Documents\Refal-5-lambda\build>srefc crefal.rsl
Srefc, a part of Refal-5-lambda compiler toolkit, version 2.2.6.1
Copyright (c) 2008-2016, Alexander Konovalov, 2016-2019, BMSTU IU9 Department
All rights reserved.
*Compiling crefal.rsl:
Decompiled "crefal.rsl" to "crefal-decompiled.ref"
** Compilation completed successfully **
D:\Mazdaywik\Documents\Refal-5-lambda\build>crefal.exe MRefal.r5.ref
Copyright (C): RefalScope Project, 2004-2018
Total program time: 44.953 seconds (100.0 %).
(Total refal time): 43.266 seconds (96.2 %).
t- and e-var copy time: 32.068 seconds (71.3 %).
Linear result time: 5.736 seconds (12.8 %).
Open e-loop time (clear): 2.950 seconds (6.6 %).
Linear pattern time: 2.123 seconds (4.7 %).
Native time: 1.142 seconds (2.5 %).
Runtime time overhead: 0.545 seconds (1.2 %).
Repeated t-var match time (inside e-loops): 0.389 seconds (0.9 %).
Step count 9159285
Memory used 650513 nodes, 650513 * 16 = 10408208 bytes
И без усреднения по N замерам очевидно, что Рефал-5λ работает в 3 раза медленнее.
Попробуем с оптимизациями.
Замеры в консоли
D:\Mazdaywik\Documents\Refal-5-lambda\build>set CPPLINEE=bcc32 -w -e
D:\Mazdaywik\Documents\Refal-5-lambda\build>srmake --scratch -X-OdPRC crefal.rsl --runtime=refalrts-diagnostic-initializer
SRMake, a part of Refal-5-lambda compiler toolkit, version 2.2.6.1
Copyright (c) 2008-2016, Alexander Konovalov, 2016-2019, BMSTU IU9 Department
All rights reserved.
Srefc, a part of Refal-5-lambda compiler toolkit, version 2.2.6.1
Copyright (c) 2008-2016, Alexander Konovalov, 2016-2019, BMSTU IU9 Department
All rights reserved.
*Compiling crefal.rsl:
Decompiled "crefal.rsl" to "crefal-decompiled.ref"
... natives generated
+Linking (+ natives) C:\Users\Mazdaywik\AppData\Roaming\Refal-5-lambda\srlib\scratch/Library.rasl
+Linking (+ natives) C:\Users\Mazdaywik\AppData\Roaming\Refal-5-lambda\srlib\scratch/refalrts-main.rasl
+Linking (+ natives) C:\Users\Mazdaywik\AppData\Roaming\Refal-5-lambda\srlib\scratch/refalrts.rasl
+Linking (+ natives) C:\Users\Mazdaywik\AppData\Roaming\Refal-5-lambda\srlib\scratch/refalrts-allocator.rasl
+Linking (+ natives) C:\Users\Mazdaywik\AppData\Roaming\Refal-5-lambda\srlib\scratch/refalrts-functions.rasl
+Linking (+ natives) C:\Users\Mazdaywik\AppData\Roaming\Refal-5-lambda\srlib\scratch/refalrts-dynamic.rasl
+Linking (+ natives) C:\Users\Mazdaywik\AppData\Roaming\Refal-5-lambda\srlib\scratch\platform-Windows/refalrts-platform-specific.rasl
+Linking (+ natives) C:\Users\Mazdaywik\AppData\Roaming\Refal-5-lambda\srlib\scratch/refalrts-vm.rasl
+Linking (+ natives) C:\Users\Mazdaywik\AppData\Roaming\Refal-5-lambda\srlib\scratch/refalrts-profiler.rasl
+Linking (+ natives) C:\Users\Mazdaywik\AppData\Roaming\Refal-5-lambda\srlib\scratch/refalrts-diagnostic-initializer.rasl
+Linking (+ natives) C:\Users\Mazdaywik\AppData\Roaming\Refal-5-lambda\srlib\scratch/refalrts-debugger.rasl
Borland C++ 5.5.1 for Win32 Copyright (c) 1993, 2000 Borland
crefal.cpp:
c:\users\mazdaywik\appdata\roaming\refal-5-lambda\srlib\scratch/library.cpp:
c:\users\mazdaywik\appdata\roaming\refal-5-lambda\srlib\scratch/refalrts-main.cpp:
c:\users\mazdaywik\appdata\roaming\refal-5-lambda\srlib\scratch/refalrts.cpp:
c:\users\mazdaywik\appdata\roaming\refal-5-lambda\srlib\scratch/refalrts-allocator.cpp:
c:\users\mazdaywik\appdata\roaming\refal-5-lambda\srlib\scratch/refalrts-functions.cpp:
c:\users\mazdaywik\appdata\roaming\refal-5-lambda\srlib\scratch/refalrts-dynamic.cpp:
c:\users\mazdaywik\appdata\roaming\refal-5-lambda\srlib\scratch\platform-windows/refalrts-platform-specific.cpp:
c:\users\mazdaywik\appdata\roaming\refal-5-lambda\srlib\scratch/refalrts-vm.cpp:
c:\users\mazdaywik\appdata\roaming\refal-5-lambda\srlib\scratch/refalrts-profiler.cpp:
c:\users\mazdaywik\appdata\roaming\refal-5-lambda\srlib\scratch/refalrts-diagnostic-initializer.cpp:
c:\users\mazdaywik\appdata\roaming\refal-5-lambda\srlib\scratch/refalrts-debugger.cpp:
Turbo Incremental Link 5.00 Copyright (c) 1997, 2000 Borland
** Compilation completed successfully **
D:\Mazdaywik\Documents\Refal-5-lambda\build>crefal.exe MRefal.r5.ref
Copyright (C): RefalScope Project, 2004-2018
Total program time: 38.703 seconds (100.0 %).
(Total refal time): 37.008 seconds (95.6 %).
t- and e-var copy time: 30.571 seconds (79.0 %).
Linear result time: 2.634 seconds (6.8 %).
Open e-loop time (clear): 2.277 seconds (5.9 %).
Native time: 1.002 seconds (2.6 %).
Linear pattern time: 0.998 seconds (2.6 %).
Runtime time overhead: 0.693 seconds (1.8 %).
Repeated t-var match time (inside e-loops): 0.496 seconds (1.3 %).
Repeated e-var match time (inside e-loops): 0.032 seconds (0.1 %).
Step count 9159285
Memory used 650510 nodes, 650510 * 16 = 10408160 bytes
Разницы немного. В обоих случаях ≈30 секунд времени уходит на копирование переменных.
Рассмотрим другой тест.
Запуск crefal
(компиляция себя)
Замеры в консоли
D:\Mazdaywik\Documents\Refal-5-lambda\build>rsl-decompiler.exe crefal.rsl
Decompiled "crefal.rsl" to "crefal-decompiled.ref"
D:\Mazdaywik\Documents\Refal-5-lambda\build>refgo -a crefal crefal-decompiled.ref
Copyright (C): RefalScope Project, 2004-2018
Refal-5 System. Version PZ Oct 29 2004
*** The View Field:
<STOP$ <Exit 0 >>
*** Number of Steps = 1397550
Elapsed system time: 1.075 seconds
*** Buried:
((Warnings '=' 0 )(Errors '=' 0 )(Mode '=' crefal )(Testing '=' False )
(Output '=crefal-decompiled.rsl'
)(Input '=crefal-decompiled.ref' )
)
Memory allocated = 2686976 Bytes
D:\Mazdaywik\Documents\Refal-5-lambda\build>srefc crefal.rsl
Srefc, a part of Refal-5-lambda compiler toolkit, version 2.2.6.1
Copyright (c) 2008-2016, Alexander Konovalov, 2016-2019, BMSTU IU9 Department
All rights reserved.
*Compiling crefal.rsl:
Decompiled "crefal.rsl" to "crefal-decompiled.ref"
** Compilation completed successfully **
D:\Mazdaywik\Documents\Refal-5-lambda\build>rsl-decompiler.exe crefal.rsl
Decompiled "crefal.rsl" to "crefal-decompiled.ref"
D:\Mazdaywik\Documents\Refal-5-lambda\build>crefal.exe crefal-decompiled.ref
Copyright (C): RefalScope Project, 2004-2018
Total program time: 4.015 seconds (100.0 %).
(Total refal time): 3.450 seconds (85.9 %).
Linear result time: 1.346 seconds (33.5 %).
t- and e-var copy time: 1.173 seconds (29.2 %).
Linear pattern time: 0.572 seconds (14.2 %).
Open e-loop time (clear): 0.328 seconds (8.2 %).
Native time: 0.328 seconds (8.2 %).
Runtime time overhead: 0.237 seconds (5.9 %).
Repeated e-var match time (inside e-loops): 0.016 seconds (0.4 %).
Repeated t-var match time (inside e-loops): 0.015 seconds (0.4 %).
Step count 2894003
Memory used 167827 nodes, 167827 * 16 = 2685232 bytes
D:\Mazdaywik\Documents\Refal-5-lambda\build>srmake --scratch -X-OdPRC crefal.rsl --runtime=refalrts-diagnostic-initializer
SRMake, a part of Refal-5-lambda compiler toolkit, version 2.2.6.1
Copyright (c) 2008-2016, Alexander Konovalov, 2016-2019, BMSTU IU9 Department
All rights reserved.
Srefc, a part of Refal-5-lambda compiler toolkit, version 2.2.6.1
Copyright (c) 2008-2016, Alexander Konovalov, 2016-2019, BMSTU IU9 Department
All rights reserved.
*Compiling crefal.rsl:
Decompiled "crefal.rsl" to "crefal-decompiled.ref"
... natives generated
+Linking (+ natives) C:\Users\Mazdaywik\AppData\Roaming\Refal-5-lambda\srlib\scratch/Library.rasl
+Linking (+ natives) C:\Users\Mazdaywik\AppData\Roaming\Refal-5-lambda\srlib\scratch/refalrts-main.rasl
+Linking (+ natives) C:\Users\Mazdaywik\AppData\Roaming\Refal-5-lambda\srlib\scratch/refalrts.rasl
+Linking (+ natives) C:\Users\Mazdaywik\AppData\Roaming\Refal-5-lambda\srlib\scratch/refalrts-allocator.rasl
+Linking (+ natives) C:\Users\Mazdaywik\AppData\Roaming\Refal-5-lambda\srlib\scratch/refalrts-functions.rasl
+Linking (+ natives) C:\Users\Mazdaywik\AppData\Roaming\Refal-5-lambda\srlib\scratch/refalrts-dynamic.rasl
+Linking (+ natives) C:\Users\Mazdaywik\AppData\Roaming\Refal-5-lambda\srlib\scratch\platform-Windows/refalrts-platform-specific.rasl
+Linking (+ natives) C:\Users\Mazdaywik\AppData\Roaming\Refal-5-lambda\srlib\scratch/refalrts-vm.rasl
+Linking (+ natives) C:\Users\Mazdaywik\AppData\Roaming\Refal-5-lambda\srlib\scratch/refalrts-profiler.rasl
+Linking (+ natives) C:\Users\Mazdaywik\AppData\Roaming\Refal-5-lambda\srlib\scratch/refalrts-diagnostic-initializer.rasl
+Linking (+ natives) C:\Users\Mazdaywik\AppData\Roaming\Refal-5-lambda\srlib\scratch/refalrts-debugger.rasl
Borland C++ 5.5.1 for Win32 Copyright (c) 1993, 2000 Borland
crefal.cpp:
c:\users\mazdaywik\appdata\roaming\refal-5-lambda\srlib\scratch/library.cpp:
c:\users\mazdaywik\appdata\roaming\refal-5-lambda\srlib\scratch/refalrts-main.cpp:
c:\users\mazdaywik\appdata\roaming\refal-5-lambda\srlib\scratch/refalrts.cpp:
c:\users\mazdaywik\appdata\roaming\refal-5-lambda\srlib\scratch/refalrts-allocator.cpp:
c:\users\mazdaywik\appdata\roaming\refal-5-lambda\srlib\scratch/refalrts-functions.cpp:
c:\users\mazdaywik\appdata\roaming\refal-5-lambda\srlib\scratch/refalrts-dynamic.cpp:
c:\users\mazdaywik\appdata\roaming\refal-5-lambda\srlib\scratch\platform-windows/refalrts-platform-specific.cpp:
c:\users\mazdaywik\appdata\roaming\refal-5-lambda\srlib\scratch/refalrts-vm.cpp:
c:\users\mazdaywik\appdata\roaming\refal-5-lambda\srlib\scratch/refalrts-profiler.cpp:
c:\users\mazdaywik\appdata\roaming\refal-5-lambda\srlib\scratch/refalrts-diagnostic-initializer.cpp:
c:\users\mazdaywik\appdata\roaming\refal-5-lambda\srlib\scratch/refalrts-debugger.cpp:
Turbo Incremental Link 5.00 Copyright (c) 1997, 2000 Borland
** Compilation completed successfully **
D:\Mazdaywik\Documents\Refal-5-lambda\build>rsl-decompiler.exe crefal.rsl
Decompiled "crefal.rsl" to "crefal-decompiled.ref"
D:\Mazdaywik\Documents\Refal-5-lambda\build>crefal.exe crefal-decompiled.ref
Copyright (C): RefalScope Project, 2004-2018
Total program time: 2.828 seconds (100.0 %).
(Total refal time): 2.284 seconds (80.8 %).
t- and e-var copy time: 0.985 seconds (34.8 %).
Linear result time: 0.794 seconds (28.1 %).
Runtime time overhead: 0.279 seconds (9.9 %).
Native time: 0.265 seconds (9.4 %).
Linear pattern time: 0.253 seconds (8.9 %).
Open e-loop time (clear): 0.236 seconds (8.3 %).
Repeated t-var match time (inside e-loops): 0.016 seconds (0.6 %).
Step count 2894003
Memory used 167824 nodes, 167824 * 16 = 2685184 bytes
Другая программа, другой стиль её написания. Компиляция без оптимизаций выполняется в 4 раза медленнее, с оптимизациями — только в 3 раза.
Тест TimeElapsed.OK.ref
Тест скопирован из каталога тестов совместимости.
Замеры в консоли
D:\Mazdaywik\Documents\Refal-5-lambda\build>refgo crefal TimeElapsed.OK.ref
Copyright (C): RefalScope Project, 2004-2018
D:\Mazdaywik\Documents\Refal-5-lambda\build>refgo -a TimeElapsed.OK.rsl && type REFAL7.DAT
Refal-5 System. Version PZ Oct 29 2004
*** The View Field:
<STOP$ >
*** Number of Steps = 128
Elapsed system time: 2.614 seconds
*** Buried:
()
Memory allocated = 8192 Bytes
Time elapsed 0.000
Time elapsed 0.552
Time elapsed 1.192
Time elapsed 0.672
Time elapsed 1.422
D:\Mazdaywik\Documents\Refal-5-lambda\build>srefc TimeElapsed.OK.ref
Srefc, a part of Refal-5-lambda compiler toolkit, version 2.2.6.1
Copyright (c) 2008-2016, Alexander Konovalov, 2016-2019, BMSTU IU9 Department
All rights reserved.
*Compiling TimeElapsed.OK.ref:
** Compilation completed successfully **
D:\Mazdaywik\Documents\Refal-5-lambda\build>TimeElapsed.OK.exe && type REFAL7.DAT
Total program time: 4.485 seconds (100.0 %).
Open e-loop time (clear): 4.469 seconds (99.6 %).
(Total refal time): 4.469 seconds (99.6 %).
Native time: 0.016 seconds (0.4 %).
Identifiers allocated: 88
Step count 203
Memory used 151 nodes, 151 * 16 = 2416 bytes
Time elapsed 0.000000
Time elapsed 1.125000
Time elapsed 2.219000
Time elapsed 1.140000
Time elapsed 2.250000
D:\Mazdaywik\Documents\Refal-5-lambda\build>srmake --scratch -X-OdPRC TimeElapsed.OK.ref --runtime=refalrts-diagnostic-initializer
SRMake, a part of Refal-5-lambda compiler toolkit, version 2.2.6.1
Copyright (c) 2008-2016, Alexander Konovalov, 2016-2019, BMSTU IU9 Department
All rights reserved.
Srefc, a part of Refal-5-lambda compiler toolkit, version 2.2.6.1
Copyright (c) 2008-2016, Alexander Konovalov, 2016-2019, BMSTU IU9 Department
All rights reserved.
*Compiling TimeElapsed.OK.ref:
... natives generated
+Linking (+ natives) C:\Users\Mazdaywik\AppData\Roaming\Refal-5-lambda\srlib\scratch/Library.rasl
+Linking (+ natives) C:\Users\Mazdaywik\AppData\Roaming\Refal-5-lambda\srlib\scratch/refalrts-main.rasl
+Linking (+ natives) C:\Users\Mazdaywik\AppData\Roaming\Refal-5-lambda\srlib\scratch/refalrts.rasl
+Linking (+ natives) C:\Users\Mazdaywik\AppData\Roaming\Refal-5-lambda\srlib\scratch/refalrts-allocator.rasl
+Linking (+ natives) C:\Users\Mazdaywik\AppData\Roaming\Refal-5-lambda\srlib\scratch/refalrts-functions.rasl
+Linking (+ natives) C:\Users\Mazdaywik\AppData\Roaming\Refal-5-lambda\srlib\scratch/refalrts-dynamic.rasl
+Linking (+ natives) C:\Users\Mazdaywik\AppData\Roaming\Refal-5-lambda\srlib\scratch\platform-Windows/refalrts-platform-specific.rasl
+Linking (+ natives) C:\Users\Mazdaywik\AppData\Roaming\Refal-5-lambda\srlib\scratch/refalrts-vm.rasl
+Linking (+ natives) C:\Users\Mazdaywik\AppData\Roaming\Refal-5-lambda\srlib\scratch/refalrts-profiler.rasl
+Linking (+ natives) C:\Users\Mazdaywik\AppData\Roaming\Refal-5-lambda\srlib\scratch/refalrts-diagnostic-initializer.rasl
+Linking (+ natives) C:\Users\Mazdaywik\AppData\Roaming\Refal-5-lambda\srlib\scratch/refalrts-debugger.rasl
Borland C++ 5.5.1 for Win32 Copyright (c) 1993, 2000 Borland
timeelapsed.ok.cpp:
c:\users\mazdaywik\appdata\roaming\refal-5-lambda\srlib\scratch/library.cpp:
c:\users\mazdaywik\appdata\roaming\refal-5-lambda\srlib\scratch/refalrts-main.cpp:
c:\users\mazdaywik\appdata\roaming\refal-5-lambda\srlib\scratch/refalrts.cpp:
c:\users\mazdaywik\appdata\roaming\refal-5-lambda\srlib\scratch/refalrts-allocator.cpp:
c:\users\mazdaywik\appdata\roaming\refal-5-lambda\srlib\scratch/refalrts-functions.cpp:
c:\users\mazdaywik\appdata\roaming\refal-5-lambda\srlib\scratch/refalrts-dynamic.cpp:
c:\users\mazdaywik\appdata\roaming\refal-5-lambda\srlib\scratch\platform-windows/refalrts-platform-specific.cpp:
c:\users\mazdaywik\appdata\roaming\refal-5-lambda\srlib\scratch/refalrts-vm.cpp:
c:\users\mazdaywik\appdata\roaming\refal-5-lambda\srlib\scratch/refalrts-profiler.cpp:
c:\users\mazdaywik\appdata\roaming\refal-5-lambda\srlib\scratch/refalrts-diagnostic-initializer.cpp:
c:\users\mazdaywik\appdata\roaming\refal-5-lambda\srlib\scratch/refalrts-debugger.cpp:
Turbo Incremental Link 5.00 Copyright (c) 1997, 2000 Borland
** Compilation completed successfully **
D:\Mazdaywik\Documents\Refal-5-lambda\build>TimeElapsed.OK.exe && type REFAL7.DAT
(Total refal time): 2.938 seconds (100.0 %).
Total program time: 2.938 seconds (100.0 %).
Open e-loop time (clear): 2.938 seconds (100.0 %).
Identifiers allocated: 88
Step count 203
Memory used 151 nodes, 151 * 16 = 2416 bytes
Time elapsed 0.000000
Time elapsed 0.719000
Time elapsed 1.469000
Time elapsed 0.719000
Time elapsed 1.469000
Без оптимизаций работает примерно в 2 раза медленнее, с оптимизациями — почти догнало.
Выводы
Вывод в том, что функция Mu
не при чём. Особенно, в последнем тесте, где бо́льшую часть времени выполняется цикл по открытой переменной. В предыдущих двух тестах немалую часть затрат составляли копирования переменных.
Впрочем, измерения, предложенные выше, сделать всё равно было бы полезно.
В заявке #264 приведён бенчмарк, также демонстрирующий проблемы с производительностью.
Ещё один бенчмарк, показывающий проблемы с производительностью:
https://groups.google.com/d/msg/refal/Bc429ngDJf4/ccUeOsbRBwAJ
Профилировка показывает, что треть времени уходит на функцию DoFirst
. Так что есть проблемы производительности из-за того, что библиотечные функции написаны на смеси Рефала и Си++.
В коммите ca96a728969fcbb6b8b8b3772045ea0560bd620b сделаны интересные замеры производительности. В частности, замечено, что сопоставление с повторной переменной на 15 % медленнее, чем копирование той же переменной.
Бенчмарк из комментария https://github.com/bmstu-iu9/refal-5-lambda/issues/194#issuecomment-552890284:
primes-swi2.ref
$ENTRY Go {
= <Br 'n=' <bi <Card>>> <erit () <i ('0') (<Cp 'n'>)>>;
}
bi {
e.1 ' ' e.e = e.1;
e.1 = e.1;
}
* забиваем массив единичками
i {
t.1 t.1 = ;
t.1 t.2 = '1' <i (<add t.1 '1'>) t.2>;
}
erit {
() s.1 s.2 e.e = <f0 (s.1 s.2) e.e>;
(e.0) e.1 '1' e.e = <f0 (e.0 e.1 '1') e.e>;
}
f0 {
(e.1) e.e = <fc (<Lenw e.1>) (<Lenw <Cp 'n'>>) e.e>;
}
fc {
* часть проверки, что квадрат простого числа не больше размера массива
(s.n e.1) e.e = <f1 (e.1 s.n) (<Lenw <mul (<Symb s.n>) <Symb s.n>>>) e.e>;
}
f1 {
t.0 (s.1 e.2) (s.1 e.4) e.e = <f2 <cmp (e.2) e.4> t.0 e.e>;
t.0 (s.1 e.2) (s.3 e.4) e.e = <f2 <cmp (s.1) s.3> t.0 e.e>;
}
f2 {
'>' (e.0 s.n) e.e = <e ('1') e.0 e.e>;
s.s (e.0 s.n) e.e = <fe <f s.n (e.0) <First s.n e.e>>>;
}
fe {
e.e (e.0) (e.1) = <erit (e.0 e.1) e.e>;
}
*f (e0)(s1)s2ee='0'k/f/()(e0s1)ee.
* (e0)(s1e2)ssee=ssk/f/(e0s1)(e2)ee.
* (e0)(e1)=(e0)(e1)
f {
* заменяем дырку на нуль
s.n t.0 (e.1 s.2) e.e = e.1 '0' <f s.n t.0 <First s.n e.e>>;
s.n t.0 () e.e= e.e() t.0;
}
e {
t.0 '0' e.e = <e (<add t.0 '1'>) e.e>;
(e.0) '1' e.e = <Prout e.0> <e (<add (e.0) '1'>) e.e>;
* вывод полученного списка
t.0 = ;
}
cmp {
(e.L) e.R
, <Compare <Numb e.L> <Numb e.R>>
: {
'+' = '>';
'0' = '=';
'-' = '<';
}
}
mul { (e.L) e.R = <Symb <* <Numb e.L> <Numb e.R>>> }
add { (e.L) e.R = <Symb <+ <Numb e.L> <Numb e.R>>> }
Скачать: primes-swi2.ref.txt.
Такой странный стиль кодирования (в частности, mul
и add
связан с тем, что программа была конвертирована с Рефала/2 Стеллецкого. И благодаря этому, служит хорошим бенчмарком на встроенные функции арифметики.
Вот так выглядит начало бенчмарка функций:
_profile_time.txt
Total time: 40.93800 s
Total steps: 58673181
Mean step time: 0.697729 us
DoFirst (8851) -> 15466.0 ms (37.78 %, += 37.78 %) rel step time 1.51
Sub-Digits (8851) -> 4337.0 ms (10.59 %, += 48.37 %) rel step time 0.44
Add-Nat (8851) -> 3780.0 ms (9.23 %, += 57.61 %) rel step time 1.20
DoNumb (8851) -> 2983.0 ms (7.29 %, += 64.89 %) rel step time 1.45
DoNumb-AddDigit (8851) -> 2144.0 ms (5.24 %, += 70.13 %) rel step time 1.37
Add-Nat$1:1 (8851) -> 1817.0 ms (4.44 %, += 74.57 %) rel step time 1.16
Mul-Nat-Line (8851) -> 1518.0 ms (3.71 %, += 78.28 %) rel step time 0.97
Add-Digits (8851) -> 888.0 ms (2.17 %, += 80.45 %) rel step time 0.49
NormNumber (8851) -> 825.0 ms (2.02 %, += 82.46 %) rel step time 1.67
__Step-End (0000) -> 688.0 ms (1.68 %, += 84.14 %) rel step time 0.69
Numb (0000) -> 622.0 ms (1.52 %, += 85.66 %) rel step time 1.26
Mul-Digits (8851) -> 615.0 ms (1.50 %, += 87.16 %) rel step time 0.39
__Step-Start (0000) -> 593.0 ms (1.45 %, += 88.61 %) rel step time 0.60
f (3443) -> 515.0 ms (1.26 %, += 89.87 %) rel step time 2.02
. . .
Библиотека собрана с RLC_FLAGS=-OCDPRS
.
Скачать: _profile_time.txt, _profile_count.txt.
Функция прикладной программы впервые появляется в 14-й строчке — остальное это реализация встроенных функций библиотеки. Причём 40 % времени занимает реализация функции First
(функция DoFirst
+ Sub-Digits
).
В самом компиляторе заметную долю времени занимает DoLenw
— реализация Lenw
, написанная на Рефале. Она вызывает Add-Digits
, которая, однако, вызывается не только из DoLenw
. Причина — для блоков, из которых формируется RASL, вычисляется их объём в байтах — для каждого байта вызывается в цикле DoLenw
, которая вызывает Add-Digits
.
Профиль выглядит так:
_profile_time.txt
DoLenw (7641) -> 1582.0 ms (4.46 %, += 4.46 %) rel step time 1.02
NumberFromOpcode (0000) -> 1345.0 ms (3.80 %, += 8.26 %) rel step time 5.52
IncCol (8693) -> 1124.0 ms (3.17 %, += 11.43 %) rel step time 0.97
GenCommand-RASL (4746) -> 938.0 ms (2.65 %, += 14.08 %) rel step time 3.75
Map (9549) -> 890.0 ms (2.51 %, += 16.59 %) rel step time 2.77
Add-Digits (7641) -> 890.0 ms (2.51 %, += 19.10 %) rel step time 0.34
DoGenSubst (0177) -> 837.0 ms (2.36 %, += 21.46 %) rel step time 18.85
Add (0000) -> 796.0 ms (2.25 %, += 23.71 %) rel step time 0.73
DoMapAccum (8023) -> 690.0 ms (1.95 %, += 25.66 %) rel step time 1.26
DoMapAccum (9549) -> 659.0 ms (1.86 %, += 27.52 %) rel step time 1.94
Режимы:
set RLC_FLAGS=-OCDPRS
set RLMAKE_FLAGS=
Скачать: _profile_time.txt, _profile_count.txt.
Так что надо оптимизировать Lenw
, First
и Last
, переписав их на C++. А в перспективе — вообще все функции арифметики. Но первые три выигрываю по соотношению затраты/результат в этих бенчмарках.
Замеры времени для предшествующих коммитов:
- benchmark-1-before-03.05.2020-15-28-06,60.time.txt
- benchmark-2-step-drop-03.05.2020-15-36-26,23.time.txt
- benchmark-3-lenw-03.05.2020-22-05-41,40.time.txt
- benchmark-4-inccol-03.05.2020-23-01-44,19.time.txt
Профиль для программы primes-swi2.ref
теперь выглядит так:
_profile_time.txt
Total time: 19.84400 s
Total steps: 28999547
Mean step time: 0.684287 us
Add-Nat (1508) -> 3616.0 ms (18.22 %, += 18.22 %) rel step time 1.18
DoNumb (1508) -> 2479.0 ms (12.49 %, += 30.71 %) rel step time 1.23
DoNumb-AddDigit (1508) -> 2410.0 ms (12.14 %, += 42.86 %) rel step time 1.57
Mul-Nat-Line (1508) -> 1522.0 ms (7.67 %, += 50.53 %) rel step time 0.99
Add-Nat$1:1 (1508) -> 1518.0 ms (7.65 %, += 58.18 %) rel step time 0.99
Add-Digits (1508) -> 1065.0 ms (5.37 %, += 63.55 %) rel step time 0.60
NormNumber (1508) -> 810.0 ms (4.08 %, += 67.63 %) rel step time 1.68
__Step-End (0000) -> 670.0 ms (3.38 %, += 71.00 %) rel step time 0.92
Numb (0000) -> 640.0 ms (3.23 %, += 74.23 %) rel step time 1.32
Mul-Digits (1508) -> 635.0 ms (3.20 %, += 77.43 %) rel step time 0.41
f (3443) -> 391.0 ms (1.97 %, += 79.40 %) rel step time 1.57
__Step-Start (0000) -> 391.0 ms (1.97 %, += 81.37 %) rel step time 0.54
Numb-Aux (1508) -> 359.0 ms (1.81 %, += 83.18 %) rel step time 0.74
Symb=1 (1508) -> 312.0 ms (1.57 %, += 84.75 %) rel step time 1.29
NormNumber$9?1 (1508) -> 297.0 ms (1.50 %, += 86.25 %) rel step time 1.23
Add (0000) -> 295.0 ms (1.49 %, += 87.73 %) rel step time 1.22
Type (0000) -> 267.0 ms (1.35 %, += 89.08 %) rel step time 0.55
add (3443) -> 264.0 ms (1.33 %, += 90.41 %) rel step time 1.09
AllDigits-SwFirst (1508) -> 263.0 ms (1.33 %, += 91.74 %) rel step time 1.09
Symb (0000) -> 218.0 ms (1.10 %, += 92.83 %) rel step time 0.90
AllDigits (1508) -> 217.0 ms (1.09 %, += 93.93 %) rel step time 0.90
i (3443) -> 216.0 ms (1.09 %, += 95.02 %) rel step time 1.79
__Step-Drop (0000) -> 206.0 ms (1.04 %, += 96.05 %) rel step time 0.82
Symb-Nat (1508) -> 186.0 ms (0.94 %, += 96.99 %) rel step time 0.77
e (3443) -> 172.0 ms (0.87 %, += 97.86 %) rel step time 1.42
NormNumber$7?1 (1508) -> 158.0 ms (0.80 %, += 98.65 %) rel step time 0.65
StrFromMacroDigit (1508) -> 143.0 ms (0.72 %, += 99.38 %) rel step time 0.59
First (0000) -> 93.0 ms (0.47 %, += 99.84 %) rel step time 0.37
Putout-Aux (1508) -> 31.0 ms (0.16 %, += 100.00 %) rel step time 2.83
1. D:\Mazdaywik\Documents\MEGA\primes\primes-swi2.exe
SCOPES:
1. #2820 - slim-prefix-exe.ref
2. #1508 - Library.ref
3. #9313 - Platform.ref
4. #3443 - primes-swi2.ref
Скачать: _profile_time.txt, _profile_count.txt.
Функция First
теперь последняя! Общее время работы программы уполовинилось. Но функции арифметики оптимизировать надо.
В случае самоприменимого компилятора «медленные» DoLenw
, Add-Digits
и IncCol
теперь даже не в третьей десятке! (Замеры: _profile_time.txt, _profile_count.txt.)
Первые по списку функции уже оптимизировать не так интересно:
NumberFromOpcode (0000) -> 1420.0 ms (4.60 %, += 4.60 %) rel step time 5.55
DoGenSubst (0177) -> 1001.0 ms (3.24 %, += 7.84 %) rel step time 21.46
Map (9549) -> 950.0 ms (3.08 %, += 10.92 %) rel step time 2.82
Map (4746) -> 759.0 ms (2.46 %, += 13.38 %) rel step time 1.41
DoMapAccum (8023) -> 640.0 ms (2.07 %, += 15.45 %) rel step time 1.12
GenCommand-RASL (4746) -> 610.0 ms (1.98 %, += 17.43 %) rel step time 2.32
Apply (8023) -> 581.0 ms (1.88 %, += 19.31 %) rel step time 0.71
Apply (2191) -> 526.0 ms (1.70 %, += 21.01 %) rel step time 0.57
Close (0000) -> 516.0 ms (1.67 %, += 22.68 %) rel step time 1850.30
DoMapAccum (9549) -> 512.0 ms (1.66 %, += 24.34 %) rel step time 1.43
__Step-Drop (0000) -> 502.0 ms (1.63 %, += 25.97 %) rel step time 0.34
Функцию DoGenSubst
нужно переписывать — делать команды сопоставления функциональными (#204), остальные функции оптимизируются при прогонке или специализации, а также имеют небольшой вклад.
Замеры производительности к предыдущему коммиту (f2484e9):
- Рефал-5λ:
- MSCP-A: