оптимизация создания DLL для VBA

Вопросы программирования на Free Pascal, использования компилятора и утилит.

Модератор: Модераторы

оптимизация создания DLL для VBA

Сообщение beria » 12.07.2022 01:17:42

Давно не работал с FPC, но встала тут задача ускорить работу древнего скрипта, не моего, на VBA, ибо люди жалуются...
Как выяснилось - основная проблема была в жутко медленном обходе больших строк...
Кто не знает, в VBA вообще нет операции, типа Строка(Номер символа). Для этого используются операции создания субстроки и приведения типа субстроки, то есть все это выглядит как Asc(Mid(Строка,Номер символа, 1)).... с соответствующей скоростью работы.. Только один прогон цикла по строке, без любой работы,
For j = 1 To Len(s)
a = Asc(Mid(s, j, 1))
Next j
занимает 1 СЕКУНДУ работы скрипта.. Это явно много.

.. Написал по-быстрому некую тестовую DLL, и к работоспособности её у меня нет вопросов...
library project1;

{$mode objfpc}{$H+}

uses
Classes
{ you can add units after this };

Function BB(Addr: Pointer;Index : longint): Integer; stdcall;
begin
result := integer((Addr+Index shl 1)^);
end;

exports
BB;
begin
end.

В VBA на Win64 она подключается как
Private Declare PtrSafe Function BB Lib "E:\lazarus\forVBA\project1.dll" (ByVal Arr As LongPtr, ByVal Index As Long) As Integer
... и работает всё нормально

А дальше проблемы...
1. производительность. Цикл обхода строки
p = StrPtr(s)
For j = 1 To Len(s)
a = BB(p, j)
Next j
занимает 18 СЕКУНД....... И это компилятор, против интерпретатора VBA

2...Повключал все оптимизации и убрал все что связано с отладкой, но все равно 269824 кб, что реально очень много....
Как нибуть и что-то из этого решаемо????
Аватара пользователя
beria
постоялец
 
Сообщения: 130
Зарегистрирован: 29.09.2016 08:57:13

Re: оптимизация создания DLL для VBA

Сообщение wavebvg » 12.07.2022 11:39:55

Вы делаете очень странные вещи.

1. Выделять такой маленький кусок логики в DLL -- это не ускорение работы, а... Перекладывание из пустого в порожнее. Нужно либо всю расчётную логику переносить, либо писать всё на базовом языке.

Но если уж очень хочется, тогда нужно было не BB писать, а хранить состояние в указателе

Код: Выделить всё
function BNext(var AAddr: Pointer): Byte; stdcall;
begin
  Result := PByte(AAddr)^;
  Inc(PByte(AAddr));
end;


2.
Код: Выделить всё
For j = 1 To Len(s)
Код: Выделить всё
Len(s)

Попробуйте сохранить длину строки во временную переменную.
wavebvg
постоялец
 
Сообщения: 354
Зарегистрирован: 28.02.2008 04:57:35

Re: оптимизация создания DLL для VBA

Сообщение SSerge » 12.07.2022 12:48:25

Подозреваю, что ваша проблема происходит из следующего:

Любое обращение к OLE automation, а именно через него общается с внешними программами VBA, чертовски затратный по ресурсам механизм. Достоверно об этом могу сказать, когда ваша программа, написанная другими средствами общается с чем-то через OLE Automation. Очень подозреваю обратный процесс - когда между вашей dll и виртуальной машиной VBA - постоянно вызываемая незаметно для вас прослойка, работающая примерно на том же принципе, что и OLE Automation. То есть, не процедура ваша работает медленно, а вызов этой процедуры и передача данных работает медленно.
SSerge
энтузиаст
 
Сообщения: 971
Зарегистрирован: 12.01.2012 05:34:14
Откуда: Барнаул

Re: оптимизация создания DLL для VBA

Сообщение beria » 12.07.2022 18:39:14

Тему можно закрывать...
Переделал процедуру цикла по строке. Все прекрасно

procedure RunProcStr2(Addr: Pointer; Proc: TStringProcedure); stdcall;
var
i: uint32;
Len: uint32;
begin
Len := uint32((Addr - 4)^);
if Len > 0 then
begin
Len := Len div 2 - 1;
for i := 0 to Len do Proc(smallint((Addr + i shl 1)^));
end;
end;


Вызывается как RunProcStr2 StrPtr(s), AddressOf MyProc


Что интересно простая передача по ссылке, а не по адресу переменной, как тут, не работает вообще никак. VBA при этом, как установили изыскания, сама по себе конвертирует нормальную юникодную двухбайтовую строку в однобайтовую, с соответствующими расходами времени и потерей возможного содержимого... Смысл не понятен.

Добавлено спустя 5 часов 53 минуты 50 секунд:
В дополнение.... Сделал ещё, помятую о быстрой работе в VBA адресации по массиву, хитровыебанный способ через адреса, наложения массива на строку и в дальнейшем адресации строки как массива.... Все работает тоже и даже без fpc.... И теперь померил скорость на строках разной длины на простой задаче приравнивая переменной значения символа строки....
Sym: 100000000
Byte: 200000000
Memory: 1,266
Pascal: 3,906
Sym: 100000
Byte: 200000
Memory: 0,023
Pascal: 0,008
То есть, на маленьких строках - fpc намного впереди, но с ростом длины строки начинает реально тормозить, в несколько раз быстрее чем растетм сложность задачи......
Вывод: грёбанный VBA и OLE. Логика вашей роботы - извращенная ))))
Аватара пользователя
beria
постоялец
 
Сообщения: 130
Зарегистрирован: 29.09.2016 08:57:13

Re: оптимизация создания DLL для VBA

Сообщение Sharfik » 14.07.2022 03:55:22

ПС:
В некоторых языках строка
Код: Выделить всё
For j = 1 To Len(s)

выполняется на каждом обходе. от греха подальше лучше длину через переменную заносить.
Ну и в VBA объявлять заранее переменные можно попробовать через DIm.
И в VBA вроде была где то компиляция, чтобы не тратить на это время во время выполнения кода.
Аватара пользователя
Sharfik
энтузиаст
 
Сообщения: 763
Зарегистрирован: 20.07.2013 01:04:30

Re: оптимизация создания DLL для VBA

Сообщение beria » 15.07.2022 05:43:02

Sharfik писал(а):ПС:
И в VBA вроде была где то компиляция, .


Это обычный бейсик. Только урезанный, где даже кучи типов переменных выкинули... К примеру вообще нет беззнаковых целых двух и четырехбайтовых типов, динамической памяти, потоков.... и кучи всего остального. Но зато очень удобно обращаться к самим документам и никакого зоопарка строк, как в FPC. Один widestring на все. А ещё есть только "компиляция" в псевдокод перед выполнением, которую можно включить и выключить, в зависимости от настроек..... Но дает они почти ничего.
Аватара пользователя
beria
постоялец
 
Сообщения: 130
Зарегистрирован: 29.09.2016 08:57:13

Re: оптимизация создания DLL для VBA

Сообщение Сквозняк » 15.07.2022 16:51:53

beria писал(а):Но зато очень удобно обращаться к самим документам и никакого зоопарка строк, как в FPC. Один widestring на все.


Так это же плохо. Не факт что тип нужный для конкретного типа программы выберут единственно правильным. Работать нужно не только с документами. Однобайтовые строки, которые не перекодируются, нужны чтобы не только в заголовке вбрасывать кучу данных записывая их в строчку, как в массивы при их определении, но и во время выполнения программы. RawByteString рулит и педалит, а если компилятор меньше 3 версии, то вместо него придётся использовать AnsiString. Двухбайтных не перекодируемых строк, для чисел >255, не хватает, но что есть, то есть.
Сквозняк
энтузиаст
 
Сообщения: 1110
Зарегистрирован: 29.06.2006 22:08:32

Re: оптимизация создания DLL для VBA

Сообщение Sharfik » 18.07.2022 03:42:11

beria писал(а):Это обычный бейсик. Только урезанный, где даже кучи типов переменных выкинули... К примеру вообще нет беззнаковых ц

Все что надо там есть. Недостатка там только два - программист и несовместимость кодов Win32 и 64 версий офиса. Код надо писать с приколами.
Аватара пользователя
Sharfik
энтузиаст
 
Сообщения: 763
Зарегистрирован: 20.07.2013 01:04:30

Re: оптимизация создания DLL для VBA

Сообщение beria » 19.07.2022 04:06:40

Sharfik писал(а):
beria писал(а):Это обычный бейсик. Только урезанный, где даже кучи типов переменных выкинули... К примеру вообще нет беззнаковых ц

Все что надо там есть. Недостатка там только два - программист и несовместимость кодов Win32 и 64 версий офиса

Как раз в этом несовместимости нет. Даже с макверсией нет, что лично прямо сегодня тестировал. Только прагмы условной компиляции для вызова внешних библиотек ставить надо и разный размер указателя в байтах в зависимости от того x64 или x32///

Вот кусочек кода,использования системных библиотек, что работает на маке, win32 и win64. Кстати маковские библиотеки от FPC тоже работают.
#If Mac Then
#If VBA7 Then
Public Declare PtrSafe Function CopyMemory Lib "/usr/lib/libc.dylib" Alias "memmove" (Destination As Any, Source As Any, ByVal Length As LongPtr) As LongPtr
#Else
Public Declare Function CopyMemory Lib "/usr/lib/libc.dylib" Alias "memmove" (Destination As Any, Source As Any, ByVal Length As Long) As Long
#End If
#Else 'Windows
#If VBA7 Then
Public Declare PtrSafe Sub CopyMemory Lib "Kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As LongPtr)
#Else
Public Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long)
#End If
#End If
Аватара пользователя
beria
постоялец
 
Сообщения: 130
Зарегистрирован: 29.09.2016 08:57:13


Вернуться в Free Pascal Compiler

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 27

Рейтинг@Mail.ru
cron