Posts: 3
Threads: 1
Joined: Jun 2022
Reputation:
0
Hi all,
I was looking at creating C/C++ Dll's to add functionality to QB64PE, and I was doing timings to see what would be best done in a dll vs native to QB64PE and I got some results that confused me.
I have a simple c function I created which adds 2 numbers:
int Add(int a, int b)
{
return (a + b);
}
I have a QB64PE function that does the same as the c function:
Function addit% (a%, b%)
addit% = a% + b%
End Function
and as a baseline/control I do inline addition, each is done in a loop (500000000 times).
The results gave me pause:
Dll - 7.25 seconds
inline - 5.38 seconds
internal function - 41.16 seconds
I expected that the internal function would be between the dll and inline in timing. Why would calling external to a dll to a function to add 2 numbers be quicker than calling internal to a function to add 2 numbers?
My code:
' dll test
Declare Dynamic Library "c:\users\bob\qb64\mydll"
Function Add% (ByVal a As Integer, Byval b As Integer) 'SDL procedure name
End Declare
f% = 6
e% = 23
Locate 2, 1
Print "external dll call";
Locate 4, 1
Print "QB64PE inline addition";
Locate 6, 1
Print "QB64PE internal function";
a = Timer
For x& = 1 To 500000000
k% = Add%(f%, e%)
Next
b = Timer
Locate 1, 1
Print Using "##.##########"; (b - a);
c = Timer
For x& = 1 To 500000000
k% = f% + e%
Next
d = Timer
Locate 3, 1
Print Using "##.##########"; (d - c);
g = Timer
For x& = 1 To 500000000
k% = addit%(f%, e%)
Next
h = Timer
Locate 5, 1
Print Using "##.##########"; (h - g);
End
Function addit% (a%, b%)
addit% = a% + b%
End Function
If you want the c code for the dll let me know.
Posts: 3,987
Threads: 178
Joined: Apr 2022
Reputation:
222
Looks like a great time machine in the works!
Code: (Select All) tstart# = Timer(.001)
For i = 1 To 5000000
a = 2 + 2
Next
timesUp# = Timer(.001) - tstart#
Print timesUp#
b = b + ...
Posts: 1,000
Threads: 50
Joined: May 2022
Reputation:
27
The Time Machine - is a great film.
Posts: 1,000
Threads: 50
Joined: May 2022
Reputation:
27
07-01-2022, 11:57 PM
(This post was last modified: 07-02-2022, 12:03 AM by Kernelpanic.)
@bobkreid - I don't understand what you want to show or prove. Do you want to show how long it takes to add two numbers in C or in Basic with a function?
So, in the two examples, probably about 0.0001 second, or something.
Code: (Select All) //Addiert zwei Zahlen - 1. Juni 2022
#include <stdlib.h>
#include <stdio.h>
//Funktionsdeklaration
int addiere_zwei_zahlen(int zahl1, int zahl2);
int main(void)
{
int zahl1, zahl2;
printf("\nGeben Sie 2 Zahlen ein (Zahl1 <Leertaste> Zahl2\n");
scanf("%d %d", &zahl1, &zahl2);
printf("\nDie Summe ist: %d\n", addiere_zwei_zahlen(zahl1, zahl2));
return(0);
}
int addiere_zwei_zahlen(int zahl1, int zahl2)
{
return(zahl1 + zahl2);
}
Code: (Select All) 'Addition zweier Zahlen, 1. Juni 2022
Option _Explicit
Declare Function addiere(Zahl1 as Integer, Zahl2 as Integer) as Integer
Dim Zahl1 As Integer, Zahl2 As Integer
Print "Geben Sie 2 Zahlen ein: "
Input "Zahl1: ", Zahl1
Input "Zahl2: ", Zahl2
Print
Print Using "Die Summe der beiden Zahlen ist: ####"; addiere(Zahl1, Zahl2)
End
Function addiere (Zahl1 As Integer, Zahl2 As Integer)
addiere = Zahl1 + Zahl2
End Function
The Time Machine is really a very well film (1960!).
Posts: 303
Threads: 10
Joined: Apr 2022
Reputation:
44
(07-01-2022, 07:56 PM)bobkreid Wrote: Hi all,
I was looking at creating C/C++ Dll's to add functionality to QB64PE, and I was doing timings to see what would be best done in a dll vs native to QB64PE and I got some results that confused me.
I have a simple c function I created which adds 2 numbers:
...
If you want to understand what's going I would recommend taking a look in `./internal/temp/main.txt` and some of the other files (But main.txt is where most of the code goes). That has the actual generated C++ which you could then compare. Sub's and Function's get their own C++ function, they're listed in that file after the main code.
That said I can offer a simple explanation - QB64 SUBs and FUNCTIONs have a variety of resource setup and cleanup that happens at the beginning and end of the generated C++ function for them. It's not necessarily slow, but since the code you're testing does so little that extra logic ends up taking significantly longer than your actual code. For slightly longer SUBs and FUNCTIONs the overhead should be less noticeable.
So your original assumption about the timings was probably correct, the issue is that the C++ function you wrote isn't really equivalent to the QB64 generated function.
Posts: 2,700
Threads: 328
Joined: Apr 2022
Reputation:
219
Aye, the issue is as Matt stated: *All QB64 subs and functions come with some built in overhead.*
In this case, the function you produce is basically:
Function Add (v1, v2)
Step 1: Check for errors. If any, send error message. Pause.
Step 2: Check for break/exit conditions. Ctrl-C, or Red X in top right of Window. Quit if clicked.
Step 3: Allocate temp variable.
Step 4: Add v1 + v2, assign to temp
Step 5: Assign temp to Add for return value
Step 6: Cleanup temp variables
END FUNCTION
Compared to a base C function of:
Function Add (v1, v2)
Return v1 + v2
END FUNCTION
If necessary, you can remove some of that overhead with $CHECKING:OFF before your Function, but be aware that it'll disable the check for exit conditions and error reporting, if you do so. (And remember to turn $Checking:On after the Function.)
But I think the example above easily explains why you're seeing the results you're seeing here.
Posts: 733
Threads: 103
Joined: Apr 2022
Reputation:
14
07-02-2022, 09:35 PM
(This post was last modified: 07-02-2022, 09:36 PM by madscijr.)
Maybe instead of using a DLL to add functionality, let's look at what it is you ultimately want the DLL to do. Is it something that can be done directly in QB64, avoiding the overhead you would incur by using an external library?
Posts: 303
Threads: 10
Joined: Apr 2022
Reputation:
44
(07-02-2022, 09:35 PM)madscijr Wrote: Maybe instead of using a DLL to add functionality, let's look at what it is you ultimately want the DLL to do. Is it something that can be done directly in QB64, avoiding the overhead you would incur by using an external library?
Well the reality here is that the 'overhead' of using an external library is basically non-existent, and with that a C version of some functionality will basically always be faster than a QB64 version. But I don't think this should be all that surprising, lots of languages are like this. The advantage of a language like QB64 is ease of use, not speed at all costs.
Posts: 3
Threads: 1
Joined: Jun 2022
Reputation:
0
(07-02-2022, 12:32 AM)DSMan195276 Wrote: (07-01-2022, 07:56 PM)bobkreid Wrote: Hi all,
I was looking at creating C/C++ Dll's to add functionality to QB64PE, and I was doing timings to see what would be best done in a dll vs native to QB64PE and I got some results that confused me.
I have a simple c function I created which adds 2 numbers:
...
If you want to understand what's going I would recommend taking a look in `./internal/temp/main.txt` and some of the other files (But main.txt is where most of the code goes). That has the actual generated C++ which you could then compare. Sub's and Function's get their own C++ function, they're listed in that file after the main code.
That said I can offer a simple explanation - QB64 SUBs and FUNCTIONs have a variety of resource setup and cleanup that happens at the beginning and end of the generated C++ function for them. It's not necessarily slow, but since the code you're testing does so little that extra logic ends up taking significantly longer than your actual code. For slightly longer SUBs and FUNCTIONs the overhead should be less noticeable.
So your original assumption about the timings was probably correct, the issue is that the C++ function you wrote isn't really equivalent to the QB64 generated function.
Thank you, that explains it. I did not even consider that there was that much going on behind the curtain.
Posts: 3
Threads: 1
Joined: Jun 2022
Reputation:
0
(07-02-2022, 01:10 AM)SMcNeill Wrote: Aye, the issue is as Matt stated: *All QB64 subs and functions come with some built in overhead.*
In this case, the function you produce is basically:
Function Add (v1, v2)
Step 1: Check for errors. If any, send error message. Pause.
Step 2: Check for break/exit conditions. Ctrl-C, or Red X in top right of Window. Quit if clicked.
Step 3: Allocate temp variable.
Step 4: Add v1 + v2, assign to temp
Step 5: Assign temp to Add for return value
Step 6: Cleanup temp variables
END FUNCTION
Compared to a base C function of:
Function Add (v1, v2)
Return v1 + v2
END FUNCTION
If necessary, you can remove some of that overhead with $CHECKING:OFF before your Function, but be aware that it'll disable the check for exit conditions and error reporting, if you do so. (And remember to turn $Checking:On after the Function.)
But I think the example above easily explains why you're seeing the results you're seeing here.
Thank you Sam, hope all is going well for you. A lot more is going on in QB64 than I imagined and will take that into account in the future when I see these types of things. Thank you for helping a noob with this.
|