Создание DLL для использования в LabVIEW

Простейшие вопросы в области инженерной разработки
Аватара пользователя
IvanLis

Activity Professionalism Tutorials Gold Man of the year 2012
Автор
guru
guru
Сообщения: 5501
Зарегистрирован: 02 дек 2009, 17:44
Награды: 7
Версия LabVIEW: 2015, 2016
Откуда: СССР
Благодарил (а): 32 раза
Поблагодарили: 93 раза

Создание DLL для использования в LabVIEW

Сообщение IvanLis »

Народ, сделал программу, но скорость работы неудовлетворительная.
Есть несколько функций, которые многократно и параллельно вызываются в процессе работы.
Хочу попробовать переписать их в C# (С++), надеюсь поможет.
Но особо никогда этим не занимался, по этому возник ряд сложностей.

Может кто поделится примером (исходниками) такой dll и взаимодействия с ней из LabVIEW, рекомендациями по сборке и используемой среде разработки.
С простыми типами проблем как бы нет, интересует обмен структурами типа Cluster и Cluster Array.
Евгений Панин
junior
junior
Сообщения: 53
Зарегистрирован: 02 фев 2012, 21:49
Версия LabVIEW: 18
Откуда: Москва
Благодарил (а): 1 раз

Re: Создание DLL для использования в LabVIEW

Сообщение Евгений Панин »

Опыта такого не было. Но читал когда-то давно мануал.
Допустим, если мы создаём массив с числами. Он работает быстро и занимает относительно мало памяти. А если создать массив из кластеров, внутри которых те же числа, то это будет занимать гораздо больше памяти и т.п.
Это был мануал от 8 версии ))
PAG
junior
junior
Сообщения: 66
Зарегистрирован: 27 ноя 2020, 15:51
Версия LabVIEW: 19
Благодарил (а): 13 раз
Поблагодарили: 3 раза
Контактная информация:

Re: Создание DLL для использования в LabVIEW

Сообщение PAG »

Писал простенькие DLL на VC++ для работы с принтером.
Нормально все работает. Оболочка LV для DLL нормально их поддерживает.
Все в рамках мануалов. Делал и 32 и 64-битные версии.
Использовал VC++ потому что в дотнете очень много несовместимых версий, и их тоже надо устанавливать на целевую машину при деплойменте, если там поддержки нет.
Borjomy_1

Activity Professionalism Silver
doctor
doctor
Сообщения: 2228
Зарегистрирован: 28 июн 2012, 09:32
Награды: 3
Версия LabVIEW: 2009..2020
Откуда: город семи холмов
Благодарил (а): 28 раз
Поблагодарили: 29 раз

Re: Создание DLL для использования в LabVIEW

Сообщение Borjomy_1 »

Вот пример Dll ки. В Microsoft Studio надо создать проект DLL и заменить эти два файла. Есть даже мультипоточное выполнение.
Библиотека lvlib оболочки для LabView создавалась через Tools->Import->Shared Library (.dll), с некоторым редактированием.
Вложения
HDRDll_sample.zip
(134.22 КБ) 15 скачиваний
Controls.zip
Контролы, которые забыл добавить в архив
(10.78 КБ) 9 скачиваний
Аватара пользователя
dadreamer

Activity Professionalism Автор
professor
professor
Сообщения: 3951
Зарегистрирован: 17 фев 2013, 16:33
Награды: 4
Версия LabVIEW: 2.5 — 2022
Благодарил (а): 12 раз
Поблагодарили: 137 раз
Контактная информация:

Re: Создание DLL для использования в LabVIEW

Сообщение dadreamer »

IvanLis писал(а): 25 июн 2024, 13:57Может кто поделится примером (исходниками) такой dll и взаимодействия с ней из LabVIEW, рекомендациями по сборке и используемой среде разработки.
С простыми типами проблем как бы нет, интересует обмен структурами типа Cluster и Cluster Array.
С кластерами тоже не должно быть проблем, это обычные структуры. С массивами :labview: сложнее, если хочется модифицировать их внутри DLL, то нужно использовать функции менеджера памяти :labview: : https://www.ni.com/docs/en-US/bundle/la ... nager.html (сюда же LV-строки относятся). По-хорошему нужно подключать "extcode.h" и labview(v).lib, вот небольшой примерчик, как заполнять кластер error in/out: viewtopic.php?p=48040#p48040 Для небольших библиотек можно определить функции динамически через GetProcAddress.

Также есть пример по работе с массивами кластеров. Когда-то делал DLL, вычисляющую точки пересечения двух эллипсов (на основе кода EEOver). В то время использовал MinGW, сейчас бы взял MSVS, тем более что есть Community-версия. call_ee.cpp - исходник, EEOver-Test.vi - пример вызова. Библиотека 64-битная.
Вложения
EEOver_DLL64.rar
(2.18 МБ) 7 скачиваний
Аватара пользователя
IvanLis

Activity Professionalism Tutorials Gold Man of the year 2012
Автор
guru
guru
Сообщения: 5501
Зарегистрирован: 02 дек 2009, 17:44
Награды: 7
Версия LabVIEW: 2015, 2016
Откуда: СССР
Благодарил (а): 32 раза
Поблагодарили: 93 раза

Создание DLL для использования в LabVIEW

Сообщение IvanLis »

Собственно, для чего я все это нужно.

Необходимо оптимизировать структуру и параметры антенной решетки.
Вот пример видео работы алгоритма: https://youtu.be/--apigVyMVg?si=0Gd4oLGDkMKrQOco


Здесь относительно быстро все происходит, но в реальности это сжатое видео длительностью более 70 минут.
Хотя оптимизация выполняется только по азимуту в интервале -Pi..Pi с шагом 1 градус, т.е. вычисление 180 точек диаграммы направленности (ДН).

Оптимизация выполняется "направленным перебором" с использованием генетического алгоритма, почему именно так, долго пояснять,если коротко - не имеет численного решения :think: .

Для определения параметров сигнала в каждой точке ДН необходимо вычислить сигнал от каждого элементарного излучателя (здесь их 32), получается 180*32 = 5760.
Размер популяции 333, имеем 1918080 вычислений функции на одну эпоху.
На видео прогнали 10000 эпох, что позволило достичь цели, получается 19 180 800 000 раз вычисляется одна и та же (не совсем простая) функция от многих параметров.

Однако для вычисления ДН в двух плоскостях (азимут + угол места), получаем уже 180*180 = 32400 точек ДН, т.е. количество вызовов возрастает еще.
Количество элементарных излучателей тоже возрастает, в реальности их около 1000.
Вот пример ДН для 64 элементов.
image-000000000.png
image-000000134.png
А ближе к концу, все что можно подавить, давится.
image-000006116.png
И тогда все становится грустно, для получения нормального результата, уходит около 30-40 часов (при 64 излучателях), т.к. пространство поиска расширяется.
Именно с нее и хочу начать попытки ускорения, потом буду подниматься вверх по иерархии функций.
ujin1
adviser
adviser
Сообщения: 238
Зарегистрирован: 06 ноя 2020, 15:37
Версия LabVIEW: 19
Благодарил (а): 19 раз
Поблагодарили: 38 раз
Контактная информация:

Re: Создание DLL для использования в LabVIEW

Сообщение ujin1 »

IvanLis писал(а): 25 июн 2024, 13:57 Народ, сделал программу, но скорость работы неудовлетворительная.
Есть несколько функций, которые многократно и параллельно вызываются в процессе работы.
Хочу попробовать переписать их в C# (С++), надеюсь поможет.
Но особо никогда этим не занимался, по этому возник ряд сложностей.

Может кто поделится примером (исходниками) такой dll и взаимодействия с ней из LabVIEW, рекомендациями по сборке и используемой среде разработки.
С простыми типами проблем как бы нет, интересует обмен структурами типа Cluster и Cluster Array.
1. В IDE какой-нибудь сделать проект dll.
2. Функции dll обьявляются например так

Код: Выделить всё

#ifdef _WIN32
__declspec(dllexport) void LVAIparamHandlingExt (
#endif
#ifdef __unix__
void LVAIparamHandlingExt (
#endif
    long initialise,
    double AI[],
    unsigned long AISize,
    LVInputStateS AIState[],
    LVAlrStateS AIAlrState[],
    long connect[],
    unsigned long InputRegisters[][20],
    unsigned long InputRegistersSize,
    double AIParametersTable[][20],
    double AP[],
    unsigned long APSize,
    long APcode[],
    SensorHandlingRegOldS HAIPReg[] //массив структур
);
для примера массив структур типа SensorHandlingRegOldS

Код: Выделить всё

typedef struct {
    double filter_pv_out, filter_T, filter_dT;
    unsigned long long RS32_Q;
} SensorHandlingRegOldS;
вызов функции

Код: Выделить всё

void LVAIparamHandlingExt (
    long initialise,
    double AI[],
    unsigned long AISize,
    LVInputStateS AIState[],
    LVAlrStateS AIAlrState[],
    long connect[],
    unsigned long InputRegisters[][20],
    unsigned long InputRegistersSize,
    double AIParametersTable[][20],
    double AP[],
    unsigned long APSize,
    long APcode[],
    SensorHandlingRegOldS HAIPReg[]
){... код};
Изображение
ujin1
adviser
adviser
Сообщения: 238
Зарегистрирован: 06 ноя 2020, 15:37
Версия LabVIEW: 19
Благодарил (а): 19 раз
Поблагодарили: 38 раз
Контактная информация:

Re: Создание DLL для использования в LabVIEW

Сообщение ujin1 »

IvanLis писал(а): 25 июн 2024, 13:57 Народ, сделал программу, но скорость работы неудовлетворительная.
Есть несколько функций, которые многократно и параллельно вызываются в процессе работы.
Хочу попробовать переписать их в C# (С++), надеюсь поможет.
Но особо никогда этим не занимался, по этому возник ряд сложностей.

Может кто поделится примером (исходниками) такой dll и взаимодействия с ней из LabVIEW, рекомендациями по сборке и используемой среде разработки.
С простыми типами проблем как бы нет, интересует обмен структурами типа Cluster и Cluster Array.
Вызов в Labview через указатели на массив
вызов dll.png
вызов dll 1.png
Несколько лет назад использовал, но преимуществ не было по скорости, так как мало сигналов (меньше 500)
Сейчас почему то сломана, но разбираться некогда.
Изображение
Borjomy_1

Activity Professionalism Silver
doctor
doctor
Сообщения: 2228
Зарегистрирован: 28 июн 2012, 09:32
Награды: 3
Версия LabVIEW: 2009..2020
Откуда: город семи холмов
Благодарил (а): 28 раз
Поблагодарили: 29 раз

Re: Создание DLL для использования в LabVIEW

Сообщение Borjomy_1 »

IvanLis писал(а): 27 июн 2024, 14:24 И тогда все становится грустно, для получения нормального результата, уходит около 30-40 часов (при 64 излучателях), т.к. пространство поиска расширяется.
А загрузка процессора при этом какая? Сколько ядер загружено? Просто по умолчанию DLL код выполняется в один поток. И не раскидывается на разные ядра.

Кстати, для таких вычислений двухмерные массивы - зло, ИМХО. Потому что требуют на каждой итерации выборки элемента два регистра, сложение и умножение. Пусть даже максимально оптимизированных, но все равно.

И еще замечу. Возможно, имеет смысл кэшировать вычисления функций типа sin, cos, tan. И т.п. именно на них тратится бо́льшая часть времени вычислений.

А для фильтров надо контролировать количество коэффициентов - при схожих характеристиках их количество при разных способах вычисления коэффициентов, может различаться на порядок- другой.
Аватара пользователя
IvanLis

Activity Professionalism Tutorials Gold Man of the year 2012
Автор
guru
guru
Сообщения: 5501
Зарегистрирован: 02 дек 2009, 17:44
Награды: 7
Версия LabVIEW: 2015, 2016
Откуда: СССР
Благодарил (а): 32 раза
Поблагодарили: 93 раза

Re: Создание DLL для использования в LabVIEW

Сообщение IvanLis »

Borjomy_1 писал(а): 28 июн 2024, 08:53 А загрузка процессора при этом какая? Сколько ядер загружено? Просто по умолчанию DLL код выполняется в один поток. И не раскидывается на разные ядра.
Я пока не делал DLL, времени нет, может на выходных покопаюсь.
В LabVIEW я все настроил, все функции реентерабельны, компьютер работает в режиме утюга, все ядра на 100% загружаются.
AndreyDmitriev

Activity Professionalism Tutorials Gold Black
VIP
VIP
Сообщения: 1372
Зарегистрирован: 03 фев 2010, 00:42
Награды: 6
Версия LabVIEW: 6.1 - 2024
Откуда: Германия
Благодарил (а): 1 раз
Поблагодарили: 59 раз
Контактная информация:

Re: Создание DLL для использования в LabVIEW

Сообщение AndreyDmitriev »

IvanLis писал(а): 25 июн 2024, 13:57 Народ, сделал программу, но скорость работы неудовлетворительная.
Есть несколько функций, которые многократно и параллельно вызываются в процессе работы.
Хочу попробовать переписать их в C# (С++), надеюсь поможет.
Но особо никогда этим не занимался, по этому возник ряд сложностей.

Может кто поделится примером (исходниками) такой dll и взаимодействия с ней из LabVIEW, рекомендациями по сборке и используемой среде разработки.
С простыми типами проблем как бы нет, интересует обмен структурами типа Cluster и Cluster Array.
Ну вот как пример во вложении. Это вообще говоря работа на конкурс была, но её из-за DLL не приняли, не пропадать же добру, вот и пригодилось.
Конкретно там надо в двумерном массиве букв искать слова по гиризонтали, вертикали и диагонали. Поиск в DLL сделан на алгоритме Рабина — Карпа, с суммой в качестве хеширующей функции.
И там код и в LabVIEW (я в 2020 сохранил) и на DLL. Три функции всего, и как раз в одной из них массив кластеров в DLL отправляется.
Для простеньких DLL я использую компилятор NI CVI (просто потому что есть и прост как пять копеек, по сути там clang под капотом), но можно и в Visual Studio скомпилировать, или в gcc. Для высокопроизводительного кода я использую исключительно интеловский компилятор, который в OneAPI.
Вложения
DLL Example.7z
(218.13 КБ) 13 скачиваний
Аватара пользователя
IvanLis

Activity Professionalism Tutorials Gold Man of the year 2012
Автор
guru
guru
Сообщения: 5501
Зарегистрирован: 02 дек 2009, 17:44
Награды: 7
Версия LabVIEW: 2015, 2016
Откуда: СССР
Благодарил (а): 32 раза
Поблагодарили: 93 раза

Re: Создание DLL для использования в LabVIEW

Сообщение IvanLis »

Сегодня было время.
Ну что я могу сказать, при вызове элементарной функции выигрыша нет.
Видимо на вызов ее из DLL тратиться много времени, что не компенсируется скоростью исполнения.
Снимок экрана от 2024-06-30 13-14-05.png
Сделал расчет диаграммы полностью в С. Выигрыш есть, но не как ожидал.
Снимок экрана от 2024-06-30 23-01-22.png
Если распараллелить вычисления, то получается веселее. Во первых радует, что функции из DLL нормально работают параллельно, и выигрыш получается почти в 3 раза.
Снимок экрана от 2024-06-30 23-48-13.png
В Linux результат вообще поражает, видимо компилятор сборку осуществляет более качественно.
Снимок экрана от 2024-07-01 00-38-21.png
В качестве вывода, можно сказать, что выигрыш есть, но необходимо соблюдать баланс, т.к. на вызов самой функции из DLL тоже тратится время.
Завтра попробую кешировать SIN и COS, т.к. они постоянно вычисляются, но сравнивать с LabVIEW уже будет некорректно.
Писал все в блокноте на чистом "C", сборку осуществлял компилятором MinGW в Linux.

Код: Выделить всё

#include <math.h>
#include <complex.h>
#include <unistd.h>
#include "lv_epilog.h"

typedef struct {
	float x;
	float y;
	float z;
	} Coordinate3D;

void AntennaRadiationCalculation(float AntennaRadiation[], float complex Excitation[], int ExcSize, Coordinate3D Coordinate[], float Wavelength, float Azimuth[], int AzSize, float Elevation[], int ElSizee);

inline void AntennaRadiationCalculation(float AntennaRadiation[], float complex Excitation[], int ExcSize, Coordinate3D Coordinate[], float Wavelength, float Azimuth[], int AzSize, float Elevation[], int ElSize)
{
   int el, az, ex;
   float phase = 0;
   float complex sum = 0 + 0 * I;
   float complex p = 0 + 0 * I;
   int ind = 0;
   float maxValue = 0;
   float a1, a2, b1, b2;
	
   for (el=0; el < ElSize; el++) {
      for (az=0; az < AzSize; az++) {
         for (ex=0; ex < ExcSize; ex++){
            phase = (sinf(Azimuth[az])*cosf(Elevation[el])*Coordinate[ex].x + sinf(Elevation[el])*cosf(Azimuth[az])*Coordinate[ex].y + Coordinate[ex].z)/Wavelength;
            p = cexpf(0 + 2 * M_PI * phase * I);

            a1 = creal(Excitation[ex]);
            a2 = creal(p);
            b1 = cimag(Excitation[ex]);
            b2 = cimag(p);
            
            sum += (a1*a2 - b1*b2) + (a1*b2 + b1*a2) * I;
            //sum += Excitation[ex] * p; //умножение тянет стороннюю libgcc_s_dw2-1.dll
         }
         AntennaRadiation[ind] = cabsf(sum);

         if (AntennaRadiation[ind] > maxValue){
            maxValue = AntennaRadiation[ind];
         }

         sum = 0 + 0 * I;
         ind += 1;
      }
   }
   for (ex=0; ex < ind; ex++) {
      AntennaRadiation[ex] = AntennaRadiation[ex] / maxValue;	
   }
}

Аватара пользователя
dadreamer

Activity Professionalism Автор
professor
professor
Сообщения: 3951
Зарегистрирован: 17 фев 2013, 16:33
Награды: 4
Версия LabVIEW: 2.5 — 2022
Благодарил (а): 12 раз
Поблагодарили: 137 раз
Контактная информация:

Re: Создание DLL для использования в LabVIEW

Сообщение dadreamer »

IvanLis писал(а): 01 июл 2024, 00:05Ну что я могу сказать, при вызове элементарной функции выигрыша нет.
Попробуйте отключить wrapper, создаваемый :labview: . Поместите эти строчки в конфиг :labview: :

Код: Выделить всё

extFuncGenNoWrapperEnabled=True
extFuncBreakOnGenNoWrapper=False
extFuncShowMagic=True
Запустите :labview: , откройте :vi: , нажмите ПКМ на CLFN и снимите галочку с опции "Generate Wrapper". Подробнее тут: https://lavag.org/topic/18469-i-found-s ... ent=132079
Аватара пользователя
IvanLis

Activity Professionalism Tutorials Gold Man of the year 2012
Автор
guru
guru
Сообщения: 5501
Зарегистрирован: 02 дек 2009, 17:44
Награды: 7
Версия LabVIEW: 2015, 2016
Откуда: СССР
Благодарил (а): 32 раза
Поблагодарили: 93 раза

Re: Создание DLL для использования в LabVIEW

Сообщение IvanLis »

dadreamer писал(а): 01 июл 2024, 00:31 Попробуйте отключить wrapper, создаваемый :labview: . Поместите эти строчки в конфиг :labview: :
Эффект есть :super: но только при частых вызовах DLL, что в принципе логично.
Снимок экрана от 2024-07-01 00-49-18.png
Если "тяжелые" функции, то незаметно
Снимок экрана от 2024-07-01 01-00-05.png
AndreyDmitriev

Activity Professionalism Tutorials Gold Black
VIP
VIP
Сообщения: 1372
Зарегистрирован: 03 фев 2010, 00:42
Награды: 6
Версия LabVIEW: 6.1 - 2024
Откуда: Германия
Благодарил (а): 1 раз
Поблагодарили: 59 раз
Контактная информация:

Re: Создание DLL для использования в LabVIEW

Сообщение AndreyDmitriev »

В принципе в вашем случае можно ещё побороться за производительность векторными инструкциями.
Is it possible to get multiple sines in AVX/SSE? https://stackoverflow.com/questions/279 ... in-avx-sse
Вот смотрите, допустим у меня есть массивов в сотню миллионов элементов и я хочу вычислить синус да косинус и сложить их вместе:
Изображение
Код этот выполняется у меня где-то за полторы секунды.
Я могу сложить цикл в DLL (мне лень прокидывать массивы через параметры, они глобальные):

Код: Выделить всё

SINECOSINE_API int fnSineCosineCompute(int n)
{
    for (int i = 0; i < n; i++) dst[i] = sin(src[i]) + cos(src[i]);
    return 0;
}
Будет уже раза в полтора быстрее, что-то около секунды.

А теперь я могу воспользоваться векторными операциями и вычислять четыре синуса и косинуса одной командой, и складывать тоже векторно, прыгая по циклу через четыре элемента:

Код: Выделить всё

SINECOSINE_API int fnSineCosineComputeAVX2(int n)
{
    for (int i = 0; i < n; i += 4) {
        __m256d sin_vec = _mm256_load_pd(&src[i]);
        __m256d cos_vec = _mm256_load_pd(&src[i]);

        __m256d sin_result = _mm256_sin_pd(sin_vec);
        __m256d cos_result = _mm256_cos_pd(cos_vec);

        __m256d sum = _mm256_add_pd(sin_result, cos_result);

        _mm256_store_pd(&dst[i], sum);
    }
    return 0;
}
Результат будет тот же, только время выполнения сократится ещё почти вчетверо, до чуть больше чем четверти секунды, по итогу имеем почти шестикратное ускорение по сравнению с исходным LabVIEW кодом.
Единственно - массивы нужно будет аллоцировать выровненными. Для AVX2 нужно выравнивание на границу 32 байта, я предпочитаю выравнивать сразу на страницу 4096:

Код: Выделить всё

#include <immintrin.h>
#include "framework.h"
#include "SineCosine.h"

#define M_PI 3.14159265358979323846

static double* src;
static double* dst;

SINECOSINE_API int fnSineCosineAllocate(int n)
{
    src = (double*)_aligned_malloc(sizeof(double) * n, 4096);
    dst = (double*)_aligned_malloc(sizeof(double) * n, 4096);
    if (src  && dst) {
        for (int i = 0; i < n; i++) {
            src[i] = ((double)i / n) * M_PI;
            dst[i] = 0;
        }
    }    
    return 0;
}
Ну и освобождать память тоже надо соотвтетствующими функциями:

Код: Выделить всё

SINECOSINE_API int fnSineCosineFree()
{
    _aligned_free(src);
    _aligned_free(dst);
    return 0;
}
Там, конечно возни много при чуть более сложных вычислениях, кроме того, если количество элементов на четыре не делится, то надо будет "хвост" обрабатывать, типа так

Код: Выделить всё

    // Handle any remaining elements
    for (int i = (size / 4) * 4; i < size; i++) {
        dst[i] = sin(src[i]) + cos(src[i]);
    }
Но иногда оно того стоит, да и процесс программирования на интринсиках довольно увлекательный.
Да, и если у вас идут умножения и сложения, есть ещё FMA в запасе — https://en.wikipedia.org/wiki/FMA_instruction_set
Ответить
  • Похожие темы
    Ответы
    Просмотры
    Последнее сообщение

Вернуться в «Для чайников»