Меню

Abap/4 vs C++

В статье автор сравнивает производительность программ, написанных на языках Abap/4 и C++, на примере алгоритма формирования расшифровки строк баланса по основным средствам.

Введение

В гугле можно найти много статей – противопоставлений: «Python vs C++», «Ruby vs Python», «Java vs C#» и т.д. В них языки, кроме своих выразительных способностей, сравниваются по скорости работы программ, написанных на этих языках. Но статей «ABAP vs …» я не нашёл. Хотелось бы узнать: насколько скорость работы программы на проприетарном языке программирования (ABAP), который используется только в SAP R/3, отличается от скорости работы программы, написанной на другим языке программирования, который используется не только в SAP R/3.

По скорости работы все языки сравниваются с C/C++. Так как последняя парочка обладает самыми большими способностями по написанию скоростных программ и хранится в парижской палате мер и весов.

Я не стал измерять скорость по базовым алгоритмам типа «а+б», quicksort или обходы по графу. Такие синтетические тесты может быть и дают некоторое понятие о порядке, но не надо забывать, что одна и та же функциональная часть программы может быть записана по разному в зависимости от способностей языка. Поэтому применяется реальный тест. Я взял главный алгоритм программы для формирования расшифровки строк баланса по основным средствам.

На abap его кодировал опытный разработчик.

Разработчика на С++ у меня не было, поэтому эту часть выполнял сам.

Результат теста

ABAP: ~40 секунд

C++: 0.15 секунды.

Анализ причин

Различие в скорости работы объясняется тем, что в С++ нет некоторых конструкций. Например, нет «loop at table where key = “x”». А в abap есть. С учётом этого abapером было написано:

Loop at lt_rowsettings into ls_rowsets.

Loop at lt_obj into ls_obj where type = ls_rowsets-type.

               append initial line to <out> assigning <ls_out>.

assign component “rownum” of structure <ls_out> to <ls_out_field>.

                              <ls_out_field> = ls_rowsets-rownum.

               Loop at lt_transactions into ls_trans where objnum = ls_obj-objnum.

               Loop at lt_columnsettings into ls_colsets where  type = ls_trans-type.

                              Assign component ls_colsets-colname of structure <ls_out> to <ls_out_field>.

                              Add lt_trans-sum to <ls_out_field>.

Endloop.

Endloop.

Endloop.

Endloop.

Далее шёл цикл, который делал «подсуммировку» сумм по колонкам (в структуре <ls_out> эти поля имеют имя colname) по полю rownum.

Но для решения задачи на С++ надо применять другие подходы. Дальше я буду рассматривать примеры преобразования реализации алгоритма на ABAP к реализации алгоритма на C++.

Пример 1.

В SAP есть некоторая таблица настроек, в которой мы задаём соответствие хозяйственной операции множеству кодов видов движений. В отображаемой alv-таблице суммы по каждой хозяйственной операции располагаются в своём столбце. По сути (но не по реализации) настроечная таблица (Таблица 1) выглядит так:

Таблица 1

Название столбца хоз. операции

Columnsettings-colname

Название хоз. операции

Код хоз. операции в системе

Columnsettings-type

SUM1

Приход

100

SUM1

Приход

Z01

SUM2

Расход

200

SUM2

Расход

Z02

В программе реализуется цикл по таблице объектов lt_obj , и для каждого объекта мы находим перечень операций. В зависимости от кода операции добавляем сумму операции в нужную колонку выходной таблицы lt_out. Это выглядит так:

               Loop at lt_obj into ls_obj.

               Loop at lt_transactions into ls_trans where objnum = ls_obj-objnum.

               Loop at lt_columnsettings into ls_colsets where  type = ls_trans-type.

                              Assign component ls_colsets-colname of structure <ls_out> to <ls_out_field>.

                              Add lt_trans-sum to <ls_out_field>.

Endloop.

Endloop.

Endloop.

Разумеется, это можно оптимизировать: заменим assign component по имени на assign по номеру. Но проблему это не решит. Проблема здесь – тройной цикл.

Делаем тот же расчёт на С++. Для начала определим, что входную таблицу (таблица 1) удобно преобразовать к виду, приведённому в Таблице 2:

Таблица 2

Код хоз. операции

Columnsettings-type

Номер столбца хоз. операции

Columnsettings-colnum

100

1

Z01

1

200

2

Z02

2

Далее преобразуем тип поля Columnsettings-type. В sap это NUMC 3 знака. Т.е. кроме цифр 100 и 200 можно задать и цифробуквенное сочетание. Например, значение Z01. Вводим 36 разрядную систему измерений, где 0 = 0, 1 = 1… A = 10, B=11…Z = 35. В результате, Z01 будет иметь значение 35*36*36 + 0* 36 + 1 = 45 361. Пишем функцию int typconv(const char*). Текст приводить не буду. Она небольшая и разумеется её выгодно сделать inline.

Максимально число видов движений 36^3 = 46 656.

Создаём массив нужного размера:

typedef unsigned int  uint;

std::vector<uint> typecol;

typecol.reserve(46656);

Заполняем его значениями:

for(const auto &ls: columnsettings){

typecol[typconv(ls.type)] = ls.colnum;

}

Теперь, когда в нужную колонку требуется добавить сумму, достаточно написать следующую конструкцию:

ls_out[row][typecol[typconv(lt_trans.type)]] += lt_trans.sum;

Никаких binary search  - все на порядки быстрее. Фактически, мы заменили внутренний цикл на конструкцию вида:

typeconv_outval = macros_typconv(lt_trans-type).

read table typecol into ls_typecol index typeconv_outval.

assign component ls_typecol of structure <ls_out> to <ls_out_field>.

add lt_trans-sum to <ls_out_field>.

Пример 2.

Изначально, речь шла про 4х-кратно вложенный цикл. Перед выводом поля структур с суммами в <lt_out> мы «подсуммируем» по номерам строки rownum. Над тройным циклом, описанным в прошлом примере, располагается ещё один, который служит для определения номера строки в alv-таблицу:

Loop at lt_rowsettings into ls_rowsets.

Assign component “rownum” of structure <ls_out> to <ls_out_field>.

                              <ls_out_field> = lt_rowsetttings-rownum.

Есть настройка для соответствия класса объекта и номером строки. Настроечная таблица (Таблица 3) выглядит так:

Таблица 3

Номер строки

rowsettings-rownum

Название строки

Класс

rowsettings-type

1

Здания

Если хотите прочитать статью полностью и оставить свои комментарии присоединяйтесь к sapland

У вас уже есть учетная запись?

Войти

Обсуждения Количество комментариев13

Комментарий от  

Павел Телепко

  |  08 июня 2014, 16:12

Добрый день, прочитал только заключение, и решил заметить, что выборку и обработку данных с помощью Abap также можно легко распараллелить...например так:
help.sap.com/saphelp_nw04/helpdata

Комментарий от  

Олег Точенюк

  |  09 июня 2014, 23:07

Роман, можно личный вопрос? Вы по образованию надеюсь не программист? А то если таки программист, то ваше чудное сравнение теплого с мягким разрушит последние надежды на то, что и как преподают текущим программистам.

Комментарий от  

Юрий Сычов

  |  10 июня 2014, 08:50

"Замер времени выполнения проводился на разных машинах, так как возможность разработки на С++ у меня есть только дома."
 
ABAP задача выполнялась на сервере (возможно еще чем-то нагруженном), который брал данные из реальной СУБД ( Oracle, например). Такие вещи не сэмулируешь и не сравнишь.
 
Хотя бы время работы с СУБД исключите с помощью тр. SE30.
 
Да, Assembler и C оказались быстрее SAP. Как эта информация поможет практикующим Саперам?

Комментарий от  

Николай Кронский

  |  10 июня 2014, 10:04

Роман, можно личный вопрос? Вы по образованию надеюсь не программист? А то если таки программист, то ваше чудное сравнение теплого с мягким разрушит последние надежды на то, что и как преподают текущим программистам.

Тут, скорее не "теплое и мягкое" а, например, "часовая отвертка и газовый ключ" (можно что-то откручивать), "воробей и горный орел" (оба летают) :)
Роман, как сказано в предисловии, сравнений "АВАР vs ..." не нашел, но, мне кажется, сделал неверный вывод, что это упущение...

Комментарий от  

Степан Лаврентьев

  |  10 июня 2014, 13:50

Роман, вы пишете:
"В sap это NUMC 3 знака. Т.е. кроме цифр 100 и 200 можно задать и цифробуквенное сочетание. Например, значение Z01."
Либо я не понял глобальной мысли, либо написан бред. Тип n в SAP призван для хранения чисел в char-овском виде. То есть, с ведущими нулями (прим.: "001"). Никаких букв в такое поле не засунешь и значение типа "Z01" просто преобразуется, в поле такого типа, в "001".

Комментарий от  

Степан Лаврентьев

  |  10 июня 2014, 13:59

Да. Так и читается между строк - "Ваш SAP - гамно".
А для чистоты эксперимента, осталось реализовать интерфйс интергацию со смежными модулями, сами модули реализовать на C++. Так же, на отдельном сервере запустить процесс, сравнить время обработки данных, защитить докторскую и продавать ваш продукт как альтернативу SAP-у. Только, к моменту запуска продукта в серию, законодательство притерпит существенные изменения и ваш продукт никому уже не понадобится.
А текущие сравшения - очень уж притянуты за уши.

Комментарий от  

Олег Точенюк

  |  10 июня 2014, 14:25

Тут, скорее не "теплое и мягкое" а, например, "часовая отвертка и газовый ключ" (можно что-то откручивать), "воробей и горный орел" (оба летают) :)
Роман, как сказано в предисловии, сравнений "АВАР vs ..." не нашел, но, мне кажется, сделал неверный вывод, что это упущение...

Да у меня тоже было типа, двигатель внутреннего сгорания и реактивный двигатель, на основании наличия в обоих случаях слова двигатель. А вообще там интересные сравнения, на С++ он файл читал локальный, а на абапе что-то из базы как я понимаю или же файл тоже был локальными? Если нет, тогда в тест С++ надо включать так же выборку из БД. Хотя, что-то я уже тоже полез в какой-то бред из гаек, болтов и газовых ключей.

Комментарий от  

Роман Шахлович

  |  21 июня 2014, 16:21

Добрый день, прочитал только заключение, и решил заметить, что выборку и обработку данных с помощью Abap также можно легко распараллелить...например так:
help.sap.com/saphelp_nw04/helpdata

Это распределение задачи между серверами приложений - различными компьютерами. Используя эту возможность вы ускоряете задачу во столько раз сколько компьютеров дополнительно вы можете выделить. В заключении же речь идет о том, что задача выполнялась только на одном ядре 4х ядерного процессора. Т.е. фактически при том же количестве комьютеров (1 штука) ее можно ускорить в 4 раза, что в итоге даст ускорение в 1000-1500 относительно Абапа.

Комментарий от  

Роман Шахлович

  |  21 июня 2014, 16:40

"Замер времени выполнения проводился на разных машинах, так как возможность разработки на С++ у меня есть только дома."
 
ABAP задача выполнялась на сервере (возможно еще чем-то нагруженном), который брал данные из реальной СУБД ( Oracle, например). Такие вещи не сэмулируешь и не сравнишь.
 
Хотя бы время работы с СУБД исключите с помощью тр. SE30.
 
Да, Assembler и C оказались быстрее SAP. Как эта информация поможет практикующим Саперам?

Время работы СУБД исключено. В заключении есть небольшой абзац относительно работы СУБД. Задача не выполнялась на загруженном сервере, потому что замеры делал в разные времена суток - цифры одинаковые.
 
Как информация поможет практикующим саперам? Очень просто - есть задача: очень медленную программу надо сделать очень быстрой. Берет критический участок кода и пишете его на ассемблере (с++, c# и т.д.) и компилируете. Вместо этого куска кода в абап-программе запускаете полученный эзешник, в который передаете данные для обработки (файлами, через rfc или другой вариант). Получаете результаты и выводите в alv. Profit.
 
Это не очень другозатратно. Зная исходный алгоритм я переписал его за неделю.
 
Надо понимать, что этот способ работает если время выполнения формируется преимущественно из-за сложности вычисления, а не объемов данных.

Комментарий от  

Роман Шахлович

  |  21 июня 2014, 16:42

Роман, вы пишете:
"В sap это NUMC 3 знака. Т.е. кроме цифр 100 и 200 можно задать и цифробуквенное сочетание. Например, значение Z01."
Либо я не понял глобальной мысли, либо написан бред. Тип n в SAP призван для хранения чисел в char-овском виде. То есть, с ведущими нулями (прим.: "001"). Никаких букв в такое поле не засунешь и значение типа "Z01" просто преобразуется, в поле такого типа, в "001".

У поля тип CHAR 3 знака. В статье "опечатка".

Комментарий от  

Валерий Заузолков

  |  29 января 2015, 15:23

По моему опыту в хорошо написанной ABAP-программе основное время уходит на выборку из БД. Нет необходимости в бизнес-приложениях решать системы дифф. уравнений (это я про сложность алгоритмов с данными ;)
 
А как fun вполне интересно ... :)
 
П.С.: Единственно, что продолжительность "неделя" и характеристика "не очень трудозатратно" у меня не вяжутся. %)

Комментарий от  

Аркадий Семенов

  |  06 марта 2015, 00:27

Хотел заметить, что проблема быстродействия SAP кроется не в языке ABAP. ABAP полностью соответствует решаемым с его помощью задачам. Проблема в том, что многие SAP-продукты не доводятся до ума, ноты висят годами вместе с глюками и еще добавляется индийский фактор. Даже такая ерунда, как кривой перевод при локализации не исправляется годами.
И тут конечно возникает вопрос, почему это стоит таких денег. Все это похоже на эпоху колонизации, когда попуасы меняли на бусы свои острова.
При этом мы все вроде бы не дураки и программировать начинали на C++...

Комментарий от  

Виталий Глущенко

  |  27 октября 2015, 01:37

Время работы СУБД исключено. В заключении есть небольшой абзац относительно работы СУБД. Задача не выполнялась на загруженном сервере, потому что замеры делал в разные времена суток - цифры одинаковые.
 
Как информация поможет практикующим саперам? Очень просто - есть задача: очень медленную программу надо сделать очень быстрой. Берет критический участок кода и пишете его на ассемблере (с++, c# и т.д.) и компилируете. Вместо этого куска кода в абап-программе запускаете полученный эзешник, в который передаете данные для обработки (файлами, через rfc или другой вариант). Получаете результаты и выводите в alv. Profit.
 
Это не очень другозатратно. Зная исходный алгоритм я переписал его за неделю.
 
Надо понимать, что этот способ работает если время выполнения формируется преимущественно из-за сложности вычисления, а не объемов данных.

вы извините, но так и вижу директора ИТ отдела, или владельца SAP системы, который после вот такой оптимизации, с выпучеными глазами разыскивает спеца, чтобы тот починил сломавшийся функционал в кратчайшие сроки. Существует очень много причин, почему этот функионал поломается, начиная о антивируса, который залочит ваш exe-шник и заканчивая сменой платформы на которой ваш exe-шник должен выполнятся или проблемы с обратной связью до SAP сервера приложений.
 
Надеюсь вы понимаете, что реализуя часть функционала на языке типичном для SAP, то для решения проблемы с этим функционалом возможно вам прийдется взять 2-х специалистов, одного, который знаком с SAP'ом и одного, который знаком с этим другим языком(c++, c# и т.д.)?