- Журнал изменений в версиях системы Papyrus
- PAPYRUS (Демо)
- Papyrus: development
- ppd-chapter-000
- Зарезервированные объекты
- Проект SARTR
- Протокол взаимодействия
- Регламентированные задания
- Введение #2
- Инструментарий
- Сборка проекта
- Code style
- Заметки по производительности
- Общие функции
- Базовые типы данных
- Базовые структуры данных
- Базовые алгоритмы
- Управление строковыми ресурсами
- Соображения по вопросу неотрицательности товарных остатков
- Котировки
- Модель объемной оптимизации товарных запасов
- Papyrus: возможности системы
- Papyrus: руководство пользователя
- Библиотека
- Все об обязательной маркировке 2021
- Все об онлайн-кассах
- Презентации
- Руководства
- Свидетельство о регистрации системы Papyrus
- Технологии и функции
Заметки по производительности
Анализ производительности возврата функцией структур по значению
Практики современного c++ часто предполагают возврат сложных данных функцией по значению. То есть, если результатом работы функции является какой либо класс или структура, то функция непосредственно возвращает экземпляр этого класса (структуры) на стеке.Для примера, возьмет такой код. Здесь функция ничего важного не делает, просто производит очень малозатратные синтетические действия и потом возвращает результат.
struct Bechmark_ByRefVsByVal_TestStruct { const void * Ptr; uint32 A; uint8 BigChunk[32]; uint32 B; };Я же всегда предпочитал распределять результирующую структуру в вызывающем модуле и передавать ссылку на него функции дабы она сделала с экземпляром по ссылке необходимые изменения. Выглядит это как-то так:Bechmark_ByRefVsByVal_TestStruct Bechmark_ByRefVsByVal_Func_ByVal(uint arg) { Bechmark_ByRefVsByVal_TestStruct data; data.Ptr = (arg & 1) ? "abcdef" : "ghijkl"; data.A = (arg << 1); data.B = (arg >> 2); return data; }
void Bechmark_ByRefVsByVal_Func_ByRef(uint arg, Bechmark_ByRefVsByVal_TestStruct & rRef) { rRef.Ptr = (arg & 1) ? "abcdef" : "ghijkl"; rRef.A = (arg << 1); rRef.B = (arg >> 2); }
Предпочтение мое обусловлено моим собственным убеждением, что работа в c/c++ через значения - весьма затратная штука - вместо использования регистров, данные заносятся на стек и с него же забираются вызывающей функцией. Я был прав, но не полностью.Бенчмаркинг обеих функций показывает снижение производительности примерно в 2 раза при возврате сложной структуры по значению. Пара нюансов:
Влияние конструкторов/деструкторов
Я намеренно тестировал функции в применении к структуре без явных конструктора и деструктора. Наличие оных еще сильнее замедляет работу (move-семантика, конечно, сильно нивелирует проблему, но неявные вызовы конструктора/деструктора, пусть и в move-исполнении, все равно усугубляют проблему).Реализация теста
Описанный бенчмаркинг реализован в тестовом суб-проекте Papyrus в виде теста
SLTEST_R(Bechmark_ByRefVsByVal)