Научная статья УДК 004.4.021
https://doi.org/10.24151/1561-5405-2025-30-1-107-116 EDN: GCXUTX
Повышение производительности отладочного сервера за счет оптимизации функции дешифрации команд
Д. А. Гаврилова*
Национальный исследовательский университет «МИЭТ», г. Москва, Россия
АО «НИИ «Субмикрон», г. Москва, Россия * [email protected]
Аннотация. Встраиваемые системы, объединяющие аппаратную и программную составляющие, обеспечивают бесперебойную работу различных приборов и механизмов. Для повышения качества разработки активно применяются виртуальные прототипы встраиваемых систем. Отладка и тестирование программного обеспечения встраиваемых систем на виртуальных прототипах требуют создания отладочного сервера. При тестировании отладочный сервер обрабатывает большое количество запросов от оператора или от тестового сценария. В связи с ростом числа тестируемых устройств и усложнением тестовых сценариев время отклика сервера становится критичным. В работе рассмотрена оптимизация алгоритма дешифрации команд отладки с помощью линейного и бинарного поисков. Основное внимание уделено внедрению двухуровневой структуры обработки команд, обеспечивающей уменьшение времени обработки поступающих запросов. Исследована производительность программных решений с использованием экспериментальных методов. Для анализа эффективности предложенного метода проведены эксперименты с измерением времени выполнения функций обработки команд. Показано, что такой подход позволяет значительно повысить производительность функции дешифрации команд, в частности время выполнения функции уменьшилось с 10,6 до 4,8 мкс. Описаны методы измерения производительности алгоритмов. Результаты исследований показали целесообразность предложенного решения для повышения производительности отладочного сервера.
Ключевые слова: встраиваемые системы, отладочный сервер, линейный поиск, бинарный поиск, стандарт GNU Debugger, виртуальный прототип
Для цитирования: Гаврилова Д. А. Повышение производительности отладочного сервера за счет оптимизации функции дешифрации команд // Изв. вузов. Электроника. 2025. Т. 30. № 1. С. 107-116. https://doi.org/10.24151/1561-5405-2025-30-1-107-116. EDN: GCXUTX.
© Д. А. Гаврилова, 2025
Original article
Improving the performance of the debugging server by optimizing the command decryption function
D. A. Gavrilova*
National Research University of Electronic Technology, Moscow, Russia "Submicron Research Institute " JSC, Moscow, Russia
Abstract. Embedded systems that combine hardware and software components play a key role in ensuring the smooth operation of various devices and mechanisms. Virtual prototypes of embedded systems are actively used to improve the quality of development. Debugging and testing embedded systems software on virtual prototypes requires the creation of a debugging server. During testing, the debugging server processes a large number of requests from the operator or from the test script. Due to the growing number of devices being tested and the complexity of test scenarios, server response time is becoming critical. In this work, the optimization of the algorithm for decrypting debugging commands using linear and binary searches is considered. Main focus is on the implementation of a two-level command processing structure, which reduces the processing time of incoming requests. The productivity of software solutions was studied using experimental methods. To analyze the performance of the proposed method, experiments were conducted with measuring the execution time of command processing functions. It has been demonstrated that this approach allows significant improvement of the performance of command decryption function. In particular, the function execution time was reduced from 10.6 to 4.8 ^s. The methods for algorithms performance measuring are described. The research results have shown that it is advisable to use the proposed solution to improve the performance of the debugging server.
Keywords: embedded systems, debugging server, linear search, binary search, GNU Debugger, virtual prototype
For citation: Gavrilova D. A. Improving the performance of the debugging server by optimizing the command decryption function. Proc. Univ. Electronics, 2025, vol. 30, no. 1, pp. 107-116. https://doi.org/10.24151/1561-5405-2025-30-1-107-116.
Введение. Встраиваемые системы, как правило, предназначены для выполнения одной или нескольких сопутствующих задач и отвечают за критически важные задачи для работы устройств в составе больших систем. Последние часто являются системами реального времени, поэтому необходимо обеспечить высокую степень надежности таких систем [1]. Встраиваемые системы жестко ограничены в таких ресурсах, как память, мощность, энергопотребление, что объясняется требованиями к габаритам и цене оборудования.
Встраиваемые системы состоят из аппаратной части, включающей в себя физические компоненты, такие как микросхемы и датчики, и программной части, представленной программным кодом. Создание встраиваемой программной части не может эффективно выполняться до окончания разработки конструкторской документации на
аппаратную часть, а отладка программного обеспечения может проводиться только после изготовления и наладки аппаратуры. Для сокращения времени разработки встраиваемого программного обеспечения используются виртуальные прототипы аппаратуры -программные модели аппаратных средств встраиваемой системы, разрабатываемые с некоторой степенью абстрактности. С помощью виртуальных прототипов можно параллельно разрабатывать программное обеспечение и аппаратуру по спроектированной архитектуре системы [2, 3]. После появления штатной аппаратуры отладка встраиваемого программного обеспечения осуществляется на специализированных стендах.
Цель настоящей работы - поиск решения, которое позволит ускорить определение команды в запросе для повышения производительности отладочного сервера. Для этого разрабатываются функции поиска команд в списке, а также проводится сравнительный анализ времени выполнения этих функций.
Архитектура отладочного сервера. Отладка и тестирование программного обеспечения встраиваемых систем выполняются с применением промышленного стандарта GNU Debugger (GDB). Для перехода от виртуального прототипа к штатной аппаратуре необходим отладочный сервер, реализующий идентичное взаимодействие отладочных средств по протоколу GDB Remote Serial Protocol (RSP) [4] и позволяющий удаленно подключаться к виртуальному прототипу или тестовым стендам (рис. 1). Перед отладкой и тестированием программного обеспечения требуется выполнить настройку тестового окружения. Для упрощения начальной стадии отладки необходимо разработать скрипты, реализующие полный процесс настройки тестовых стендов.
Рис. 1. Структура отладочного сервера Fig. 1. Debugging server structure
Низкоуровневый сервер отладки llds поддерживает согласованность между целями отладки и отладочным сервером gdb-server. Связь между gdb-server и llds осуществляется с помощью протокола удаленного доступа Qt Remote Objects [5]. В протоколе GDB RSP прописаны команды, их аргументы и все возможные возвращаемые значения. GDB RSP посылает серверу запросы, содержащие имя команды и аргументы в определенном формате. Проблема заключается в том, что запросы для некоторых команд не имеют знака разделителя между именем команды и ее аргументами. Кроме того, некоторые
команды могут начинаться одинаково или имя одной команды может содержаться в имени другой команды (рис. 2). Распознавание команд - важнейшая задача сервера, так как именно таким образом осуществляется связь отладчика с сервером. Поэтому следует обеспечить корректное распознавание команд. В данном случае нельзя использовать контейнеры, например 81ё::шар, так как команды не имеют разделителя с аргументами и нельзя сравнить их с заранее подготовленными ключами [6].
Рис. 2. Преобразование команд Fig. 2. Command conversion
Исследование алгоритмов бинарного и линейного поисков. Для анализа алгоритмов поиска соответствия полученного запроса с командами рассмотрены алгоритмы бинарного и линейного поисков. Сложность задачи поиска напрямую зависит от размера списка. При поиске элемента в неупорядоченном списке с n элементами требуется в среднем n/2 сравнений. Это означает, что с увеличением размера списка время поиска будет увеличиваться пропорционально.
Бинарный поиск позволяет значительно повысить эффективность программы. Данный алгоритм работает только с упорядоченными списками и позволяет найти элемент за log2n сравнений [7]. Для реализации бинарного поиска необходимо хранить данные в упорядоченном виде в алфавитном порядке. Такое решение немного улучшает производительность линейного поиска за счет дополнительной проверки: если первый символ полученного запроса находится в алфавите до первого символа команды в упорядоченном списке, то следующие команды не имеет смысла проверять и поиск завершается. Команда определяется структурой Command (листинг 1), которая состоит из имени команды name и класса CommandClass, обеспечивающего ее поведение. Объекты структуры хранятся в векторе, где все поддерживаемые команды расположены в алфавитном порядке.
Листинг 1. Структура команды: struct Command{ std::string name;
std::shared_ptr<CommandClass>cmd_ptr; }
Линейный поиск заключается в обходе всего списка имен команд и сравнении каждого символа введенного запроса. Такой алгоритм универсален, но имеет небольшую производительность [8].
Функция линейного поиска представлена в листинге 2. Здесь и далее используется язык программирования С++. Список команд хранится в std::vector<Command> vec-tor_commands. Поиск осуществляется за счет сравнения имени команды списка в виде итератора it вектора vector_commands с полученным запросом search_word. Для этого сравнивается каждый соответствующий символ и подсчитывается число совпадений count_identical. Так как начало имени некоторых команд совпадает, необходимо проверить каждое имя и выбрать с наибольшим количеством совпавших символов max_identical. Эта команда хранится в переменной cmd_max_identical, которую впоследствии должна вернуть функция. Если команда не была найдена, функция возвращает пустую команду unsupported_cmd.
Листинг 2. Функция линейного поиска:
std::shared_ptr<Command> SimpleSearchLinear(const std::string &search_word) { int max_identical = 0;
std::shared_ptr<CommandClass> cmd_max_identical = unsupported_cmd; for(auto it = vector_commands.begin(); it != vector_commands.end();++it) { int count_identical = 0; if(it->name[0] > search_word [0]) break;
for(int i = 0; i < it->name.size() && i < search_word.size(); ++i) { if(it->name[i] == search_word [i]) ++count_identical;
else
break;
}
if(max_identical < count_identical) { max_identical = count_identical; cmd_max_identical = it->cmd_ptr;
} }
return cmd_max_identical;
}
Бинарный поиск - это алгоритм поиска элемента в упорядоченном списке, который путем сравнения среднего элемента с искомым значением исключает половину списка из дальнейшего рассмотрения (листинг 3). Если введенный запрос search_word находится выше (ниже) среднего элемента по алфавитному порядку, то далее так же рассматривается половина списка с первого begin (среднего middle) элемента до среднего middle (последнего end). Поиск команд осуществляется побуквенно. Сначала определяется диапазон команд с совпадающей первой буквой запроса, затем осуществляется переход на следующую букву под номером num_symb. Если символ под индексом num_symb среднего слова middle совпадает с символом запроса под индексом num_symb, то рассматриваются два диапазона: от начала до центра списка и от центра до его начала, из которых только один вызов рекуррентной функции вернет найденную команду, при наличии таковой. Когда диапазон рассматриваемых элементов сужается до одного или индекс рассматриваемого символа становится больше количества символов запроса, проходит проверка на полное соответствие запроса и полученной команды. Таким образом, бинарный поиск должен сократить время поиска команды [7].
Листинг 3. Функция простого бинарного поиска: std::shared_ptr<Command> SimpleSearchBinary ( const std::string & search_word, const std::vector<Command>::iterator &begin, const std::vector<Command>::iterator &end, int32_t num_symb = 0) {
if(num_symb == search_word.length() || begin == end) {
//проверка в конце поиска на полное соответствие команды
}
if(begin->name[num_symb] == search_word [num_symb] && end->name[num_symb] == search_word [num_symb]) { //проверка и переход поиска к следующей букве под номером num_symb
}
std::vector<Command>::iterator middle = begin + (end - begin) / 2;
//(middle ->name[num_symb] < search_word [num_symb])
return searchBinary(search_word, middle + 1, end, num_symb); else //(middle ->name[num_symb] > search_word [num_symb])
return searchBinary(search_word, begin, middle, num_symb); else //(middle ->name[num_symb] == search_word [num_symb]) { //бинарный поиск двух половин, в одной из них поиск закончится успешно, если введенный запрос содержит поддерживаемую команду return finded_cmd;
}
}
Для определения времени выполнения поиска используется инструмент QT Test [5], предназначенный для упрощения работы с модульными тестами. Он является частью библиотеки QT - кросс-платформенного программного обеспечения на языке программирования С++. С помощью макроса QBENCHMARK (листинг 4) измеряется время выполнения функции по поиску команды одного из алгоритмов. Функция do_process_command() вызывается несколько раз, что необходимо для подсчета наиболее точного усредненного времени выполнения, а затем выводится среднее время и количество итераций.
Листинг 4. Пример использования макроса измерения времени выполнения: name_cmd = "vCont?";
QBENCHMARK(do_process_command(name_cmd));
На рис. 3 представлены результаты выполнения линейного и бинарного поисков. Видно, что бинарный поиск имеет значительное преимущество по времени. Для первых команд эффективнее линейный поиск, но для большей части команд (84 %)
Рис. 3. Результаты выполнения линейного (кривая 1) и бинарного (кривая 2) поисков Fig. 3. Runtime results for linear (curve 1) and binary search (curve 2)
бинарный поиск осуществляется быстрее. На графике имеются отрезки, показывающие, что поиск нескольких команд занимает примерно равное время. Это команды, которые содержат в начале имени один или более общих символов, что требует больших затрат ресурсов на сравнение с каждой из этих команд и выбор наиболее подходящей. Бинарный поиск выполняется быстрее линейного на 3,1 мкс (7,5 мкс против 10,6 мкс).
Оптимизация алгоритма за счет двухуровневого дерева. Для сокращения времени выполнения функции переработаем способ хранения команд. Структура flrst_letter_command (листинг 5) содержит только первую букву команды и вектор команд, начинающихся с этой буквы. Поиск будет проходить по двухуровневому дереву [9, 10]. В результате поиск команд, состоящих из одной буквы и начинающихся с одной буквы, ускоряется, так как значительно сокращается диапазон поиска. Список команд до использования структуры first_letter_command и с ее применением показан на рис. 4.
Рис. 4. Строение списка команд: а - последовательный набор команд; б - список первых букв команд структур first_letter_command Fig. 4. Structure of a list of commands: a - a sequential set of commands; b - a list of the first letters of commands of the first letter command structures
Листинг 5. Структура для хранения команд по первой букве:
struct first_letter_command
{
std::string first_letter;
Std: :vector<Command> commands_list;
};
Таким образом, в существующие алгоритмы поисков необходимо добавить переход на внутренний список команд после нахождения соответствия первой буквы запроса. Программный код линейного поиска для новой структуры показан в листинге 6. В этом случае рассматривается вектор std::vector<first_letter_command> modif_commands. Сначала находится соответствующая первая буква, а затем просматриваются команды вектора структуры std::vector<Command> commands_list, так же как и в первоначальной функции SimpleSearchLinear().
Листинг 6. Функция линейного поиска с использованием структуры first_letter_comm and:
std::shared_ptr<Command> ModifSearchLinear (const std::string &search_word) { for(auto it = modif_commands.begin(); it != modif_commands.end(); ++it) {
if(it->name[0] > search_word[0]) break;
else if(it->name[0] == search_word[0]) {
for(Command &it_inside: it->commands_list) {
// простой линейный поиск для it->commands_list
return finded_cmd;
}
}
return unsupported_cmd;
}
Изменения в бинарном поиске (листинг 7) заключаются в первостепенном поиске соответствия первой буквы запроса search_word. После этого поиск переходит к стандартному бинарному поиску по вектору std::vector<Command> commands_list структуры first_letter_command.
Листинг 7. Функция бинарного поиска с использованием структуры first_letter_command:
std::shared_ptr<Command> ModifSearchBinary( const std::string & search_word,
const std::vector< first_letter_command >::iterator &begin, const std::vector< first_letter_command >::iterator &end, int32_t num_symb = 0) {
if(begin == end && search_word[0] == begin->name[0]){
// бинарный поиск по внутреннему вектору
return finded_cmd; }
auto middle = begin + (end - begin) / 2;
if(middle ->name[num_symb] >= search_word[num_symb])
return ModifSearchBinary (search_word, begin, middle, num_symb);
else
return ModifSearchBinary (search_word, middle + 1, end, num_symb); }
График зависимости времени выполнения поиска от номера команды в списке представлен на рис. 5. Из графика видно, что благодаря разработке модификации поиска соответствующей команды время выполнения функций значительно уменьшилось. В случае бинарного поиска 30 % команд выполняются примерно за одно время. За счет использования структуры первых букв команд среднее значение времени линейного поиска составило 7,6 мкс, бинарного (с использованием двухуровневого дерева) -4,8 мкс.
Рис. 5. Результаты выполнения линейного (кривая 1) и бинарного (кривая 2) поисков с использованием структуры first_letter_command, кривые 3 и 4 - улучшенные линейный и бинарный поиски
соответственно
Fig. 5. Runtime results for linear (curve 1) and binary (curve 2) search using the first_letter_command structure, curves 3 and 4 - improved linear and binary search, respectively
Заключение. Предложенная оптимизация алгоритма дешифрации команд отладки позволяет уменьшить время обработки введенных данных в среднем в два раза. В результате снижается потребление вычислительных ресурсов и улучшается работа отладочного сервера.
Литература
1. Marwedel P. Embedded system design: Embedded systems foundations of cyber-physical systems. 2nd ed. Dordrecht: Springer, 2010. XXI, 400 p. https://doi.org/10.1007/978-94-007-0257-8
2. Гаврилова Д. А. Обзор языков описания аппаратуры для разработки виртуальных прототипов встраиваемых систем // Научный аспект. 2023. Т. 1. № 3. С. 115-121. EDN: RHOCHW.
3. Bailey B., Martin G., Piziali A. ESL design and verification: A prescription for electronic system level methodology. Cambridge, MA: Morgan Kaufmann; Elsevier, 2007. 488 p.
4. Stallman R., Pesch R., Shebs S. Debugging with GDB: The GNU source-level debugger. Boston: 12th Media Services, 2018. 826 p.
5. Qt 5.13 // Qt 5.13 Documentation Archives [Электронный ресурс]. URL: https://doc.qt.io/archives/qt-5.13/index.html (дата обращения: 11.12.2024).
6. Уильямс Э. C++. Практика многопоточного программирования / пер. с англ. Н. Вильчинского. 2-е изд. СПб.: Питер, 2020. 640 с.
7. Стивенс Р. Алгоритмы: Теория и практическое применение / пер. с англ. В. Кириленко, Р. Волошко. 2-е изд. М.: Эксмо, 2021. 544 с.
8. Ла Рокка М. Продвинутые алгоритмы и структуры данных / пер. с англ. Л. Киселевой. СПб.: Питер, 2024. 848 с.
9. Кормен Т. Х., Лазерсон Ч. И., Ривест Р. Л., Штайн К. Алгоритмы: построение и анализ. 3-е изд. М.: Вильямс, 2013. 1323 с.
10. Рафгарден Т. Совершенный алгоритм. Жадные алгоритмы и динамическое программирование / пер. с англ. А. Логунова. СПб.: Питер, 2020. 256 с.
References
1. Marwedel P. Embedded system design: Embedded systems foundations of cyber-physical systems. 2nd ed. Dordrecht, Springer, 2010. xxi, 400 p. https://doi.org/10.1007/978-94-007-0257-8
2. Gavrilova D. A. Review of hardware description languages for the development of virtual prototypes of embedded systems. Nauchnyy aspekt, 2023, vol. 1, no. 3, pp. 115-121. (In Russian).
3. Bailey B., Martin G., Piziali A. ESL design and verification: A prescription for electronic system level methodology. Cambridge, MA, Morgan Kaufmann, Elsevier, 2007. 488 p.
4. Stallman R., Pesch R., Shebs S. Debugging with GDB: The GNU source-level debugger. Boston, 12th Media Services, 2018. 826 p.
5. Qt 5.13. Qt5.13 Documentation Archives. Available at: https://doc.qt.io/archives/qt-5.13/index.html (accessed: 11.12.2024).
6. Williams A. C++. Concurrency in action. 2nd ed. Shelter Island, NY, Manning, 2019. 592 p.
7. Stephens R. Essential algorithms: A practical approach to computer algorithms using Python and C#. 2nd ed. Hoboken, NJ, Wiley, 2019. 800 p.
8. La Rocca M. Advanced algorithms and data structures. Shelter Island, NY, Manning, 2021. 768 p.
9. Cormen Th. H., Leiserson Ch. E., Rivest R. L., Stein C. Introduction to algorithms. 3rd ed. Cambridge, MA, MIT Press, 2009. 1292 p.
10. Roughgarden T. Algorithms illuminated. Part 3: Greedy algorithms and dynamic programming. San Francisco, CA, Soundlikeyourself Publ., 2019. 232 p.
Информация об авторе
Гаврилова Дарья Александровна - магистрант Института системной и программной инженерии и информационных технологий Национального исследовательского университета «МИЭТ» (Россия, 124498, г. Москва, г. Зеленоград, пл. Шокина, 1), инженер-программист АО «НИИ «Субмикрон» (Россия, 124460, г. Москва, г. Зеленоград, Георгиевский пр-т, 5, стр. 2), [email protected]
Information about the author
Daria A. Gavrilova - Master's Student of the Institute of System and Software Engineering and Information Technologies, National Research University of Electronic Technology (Russia, 124498, Moscow, Zelenograd, Shokin sq., 1), Software Engineer of the "Submicron Research Institute" JSC (Russia, 124460, Moscow, Zelenograd, Georgievsky Ave, 5, bld. 2), [email protected]
Поступила в редакцию / Received 22.04.2024 Поступила после рецензирования / Revised 06.09.2024 Принята к публикации / Accepted 11.12.2024