LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

Slow labview dll

Solved!
Go to solution

Hi helpers!

 

I'm using a very simple VI as a DLL in a c++ program (using Visual studio 2013).

 

I make an explicit load for the DLL and create a pointer on my VI using LoadLibrary and GetProcAddress.


My program works but it is unfortunately very slow (around 2 sec to compute 1+1 and output the result ).

 

 

DWORD dw = GetLastError();

typedef double(CALLBACK* LPFNDLLFUNC2)(void); hDLL = LoadLibrary("SharedLib.dll"); if (hDLL != NULL) { lpfnDllFunc1 = (LPFNDLLFUNC1)GetProcAddress(hDLL, "Vi1"); if (!lpfnDllFunc1) { FreeLibrary(hDLL); std::cout << "failed to create pointer on function << std::endl;
ExitProcess(dw); } else { std::cout << "Function loaded" << std::endl; double test = lpfnDllFunc1(); }
}
    else
    {
        ExitProcess(dw);
    }

double __cdecl Vi2(void);

 

I'm using the _cdecl convention.

Can somone help me get this dll call faster?

What am I doing wrong?

0 Kudos
Message 1 of 8
(3,787 Views)

How are you timing this? Just executing the program as you printed it in your post? If so you are not seeing the time of the function call to the DLL function at all, but the time of the LoadLibrary() call and possibly the overal initialization of your process!

 

Make a meaningfull program that loads the library on startup and then executes and times the function call alone. Loading of the LabVIEW DLL will never be fast. It needs to load and intialize the entire LabVIEW runtime system in the background too.

 

Process creation on Windows is slow too!! So if you create an executable that does not much more than what you posted then you are really only seeing the process initialization and LabVIEW DLL load time. The function execution itself should be in the order of a few 100 nanoseconds.

Rolf Kalbermatter
My Blog
0 Kudos
Message 2 of 8
(3,761 Views)
#include <SharedLib.h>
#include <Windows.h>
#include <windowsx.h>
#include <stdio.h>
#include <iostream>
#include <ctime>
#include <delayimp.h>
//#include <delayloadhandler.h>

int main(int argc, char *argv[])
{
//	bool button = false;
//	bool stop = false;

	//	typedef double(*LPGETNUMBER)(double Nbr);
	typedef void(CALLBACK* LPFNDLLFUNC1)(LVBoolean, LVBoolean);
	typedef double(CALLBACK* LPFNDLLFUNC2)(void);

	HINSTANCE hDLL;
	LPFNDLLFUNC1 lpfnDllFunc1;
	LPFNDLLFUNC2 lpfnDllFunc2;
	std::cin.ignore();
	hDLL = LoadLibrary("SharedLib.dll");


	if (hDLL != NULL)
	{
		lpfnDllFunc1 = (LPFNDLLFUNC1)GetProcAddress(hDLL, "Vi1");
		if (!lpfnDllFunc1)
		{
			FreeLibrary(hDLL);
			std::cout << "failed to create pointer on function" << std::endl;
		}
		else
		{
			std::cout << "Function loaded" << std::endl;
		}
		lpfnDllFunc2 = (LPFNDLLFUNC2)GetProcAddress(hDLL, "Vi2");
		if (!lpfnDllFunc2)
		{
			FreeLibrary(hDLL);
			std::cout << "failed to create pointer on function" << std::endl;
		}
		else
		{
			std::cout << "Function 2 loaded" << std::endl;
#if _DEBUG
			std::clock_t start;
			start = std::clock();
#endif
			double test = lpfnDllFunc2();
#if _DEBUG
			std::cout << test << " : " << (std::clock() - start) / (double)(CLOCKS_PER_SEC / 1000) << std::endl;
#endif
			
			
		}
		
		

	}
	else
	{
		DWORD dw = GetLastError();
		ExitProcess(dw);
	}
	

	std::cout << std::endl << "End";
	std::cin.ignore();
	
	FreeLibrary(hDLL);

	return 0;
}

 Here is the code I am actually using. As you can see I am timing the function from my 2nd Vi..

0 Kudos
Message 3 of 8
(3,753 Views)
#include <SharedLib.h>
#include <Windows.h>
#include <windowsx.h>
#include <stdio.h>
#include <iostream>
#include <ctime>
#include <delayimp.h>
//#include <delayloadhandler.h>

int main(int argc, char *argv[])
{
//	bool button = false;
//	bool stop = false;

	//	typedef double(*LPGETNUMBER)(double Nbr);
	typedef void(CALLBACK* LPFNDLLFUNC1)(LVBoolean, LVBoolean);
	typedef double(CALLBACK* LPFNDLLFUNC2)(void);

	HINSTANCE hDLL;
	LPFNDLLFUNC1 lpfnDllFunc1;
	LPFNDLLFUNC2 lpfnDllFunc2;
	std::cin.ignore();
	hDLL = LoadLibrary("SharedLib.dll");


	if (hDLL != NULL)
	{
		lpfnDllFunc1 = (LPFNDLLFUNC1)GetProcAddress(hDLL, "Vi1");
		if (!lpfnDllFunc1)
		{
			FreeLibrary(hDLL);
			std::cout << "failed to create pointer on function" << std::endl;
		}
		else
		{
			std::cout << "Function loaded" << std::endl;
		}
		lpfnDllFunc2 = (LPFNDLLFUNC2)GetProcAddress(hDLL, "Vi2");
		if (!lpfnDllFunc2)
		{
			FreeLibrary(hDLL);
			std::cout << "failed to create pointer on function" << std::endl;
		}
		else
		{
			std::cout << "Function 2 loaded" << std::endl;
#if _DEBUG
			std::clock_t start;
			start = std::clock();
#endif
			double test = lpfnDllFunc2();
#if _DEBUG
			std::cout << test << " : " << (std::clock() - start) / (double)(CLOCKS_PER_SEC / 1000) << std::endl;
#endif
			
			
		}
		
		

	}
	else
	{
		DWORD dw = GetLastError();
		ExitProcess(dw);
	}
	

	std::cout << std::endl << "End";
	std::cin.ignore();
	
	FreeLibrary(hDLL);

	return 0;
}

 Here is the code I am actually using. As you can see I am timing the function from my 2nd Vi..

0 Kudos
Message 4 of 8
(3,752 Views)
Solution
Accepted by topic author VincentR

And what is your "test : xxxxx" output in the console?

 

Also there could be a lazy initialization of the DLL and its interface that has to get resolved on first call! Try to call it several times and see if subsequent calls are still as slow as you believe it is.

Rolf Kalbermatter
My Blog
Message 5 of 8
(3,746 Views)

Hi again,

Thank you for your answer I did not know about lazy initialization which is resolved on first call.

 

I tried a for loop on the function itself like that : ( I changed the function name for pVi2 as pointer Vi2)

 

			for (int i = 0; i < 15; i++)
			{

#if _DEBUG
				std::clock_t start;
				start = std::clock();
#endif
				test = pVi2();
#if _DEBUG
				std::cout << test << " : " << (std::clock() - start) / (double)(CLOCKS_PER_SEC / 1000) << std::endl;
#endif
			}

 The function is very long on first call (between 1700 and 2500) and is almost instantly done on next calls (<1ms).

Looks like what you said is exactly what happens. The output of the "test" double is 2.. As I said my Vi only compute a basic addition 1+1 for know.

 

Do you know any way I can prevent this "lazy initailization"? And could you explain me why this is happening? I don't know much about DLL yet.. Only the basics (I presume).

 

Thank you again.

Vincent

 

0 Kudos
Message 6 of 8
(3,739 Views)

Well, First a LabVIEW DLL is a somewhat complex beast. There are C compiled wrappers that implement the function interface that your DLL exposes to other applications. These functions then load the actual VI code, intialize it and pass data to it and receive any return values and pass it back to the caller. The loading of the VI code takes time, the initialization also. Suppose you create a DLL that has many hundred such functions. And this DLL does all the initializtion of every such function when it is loaded, while your application maybe only makes use of one or two of them. The loading of the DLL would be delayed by the entire initialization of each of these functions while 99% of them were never really called in your application!

 

By delaying the initialization of each function interface to the point when it is first used, the load time of the DLL can be kept short even if the DLL potentially contains many hundred functions.

 

There is no way to prevent that delay and as far as I know there is no way to force the DLL to do that delay on load instead of on first function call. If that is a problem for you, you will have to devise a mechanisme that will not only LoadLibrary() the DLL on initialization of your application and retrieve the function pointer but also call it once with dummy data during that initialization.

Rolf Kalbermatter
My Blog
Message 7 of 8
(3,728 Views)

Thank you, the idea about the dummy data for first initialization was what I was thinking. I can't be sure that will be a problem for me but I needed to be sure I need to take this time in consideration while I make my program.

0 Kudos
Message 8 of 8
(3,723 Views)