PDA

Click to See Complete Forum and Search --> : DLL Or Not


storm5510
May 25th, 2010, 05:48 PM
I have an application that I wrote with VB6 several years ago, and I have continued to modify/improve on the code so that it can execute faster. I took some heavy math and placed it in a DLL. I'm looking around my code to see what else I can move. I don't know if there would be any point to moving something like a simple incrementation of a number, i.e. A = B + 1. I have some string operations that I might be able to move. It's a function returning a value, so I don't see a reason not to. I don't see any point of putting a Sub in a DLL since it can't return anything to the external caller. The only reason I see to put a Sub in a DLL is if a function residing in the DLL could use it internally. There was a very noticeable performance improvement by creating the DLL. Note: It is not a VB6 DLL. I created it with another platform. If anyone has any comments, I would like to hear them.

:)

RhinoBull
May 25th, 2010, 07:33 PM
The only reason to have dll is if it can reused by more than one project/program - otherwise you can simply implement all of your common functionality in the module or class.
Internal processing is much faster than calling the same functionality from dll.
Also VB6 is pretty fast except for parsing large strings but even that can be improved with some advanced technique.

Having said that I'm not really sure what you're asking... :)

storm5510
May 25th, 2010, 09:24 PM
...Having said that I'm not really sure what you're asking... :)

I wasn't asking for anything except comments. :blush:

I can put the same code inline, or in an internal function, and the application performance drops dramatically. I have not tried creating the same DLL with VB6 or VB2010. It seems these would fall back on the same dependencies as the applications themselves, MSVBM60.DLL, for VB6 as an example. What I am using only depends on the core routines that Windows uses itself. I was able to find this by using a dependency tracking application I found on the net.

I will give it a try as a VB DLL and see what happens. :)

RhinoBull
May 26th, 2010, 07:12 AM
I can put the same code inline, or in an internal function, and the application performance drops dramatically...

I don't buy that - it totally depends on how things are done.
Say you need to multiply two numbers so you can do a*b in-line and be done with it. Guess what? You can get the same result by calling dozens of different subs/functions as well. Would that be reasonable?
Look at your code and try tunning it up.

Regards. :wave:

Shaggy Hiker
May 26th, 2010, 08:49 AM
What's the dll written in? If it is C/C++ using unmanaged code, you should see a performance gain. The code generated by VB does not make the most efficient use of the processor for math operations. For example, in VB.NET:

Dim A as Integer = 2
Dim B as Integer = 1

A = A + B
A = A / B

Those two calculations take the same amount of time, despite the fact that addition should be between 20-40 times as fast as integer division.

Since the Pentium, there has been a core set of operations (the RISC subset) that could perform at one or less cycles per operation. I haven't paid attention to the newer processors, and with all the prefetch, branch prediction, and so forth, there is no absolute timing for any instruction, but the general rule should still hold true. Back with the original Pentium, while integer addition (part of the RISC subset) could operate in 1 or less cycles per operation, integer division would be up near 60-80 cycles. Yet in VB, you don't see a benefit for addition over integer division (floating point math has completely different considerations).

Therefore, if you really want to squeeze the last cycle out of math operations, the language they are written in is critical.

storm5510
May 26th, 2010, 12:36 PM
My DLL is written in PowerBasic Windows 8. It's very good at that. I tried VB6 and I got an error; "Cannot find DLL entry point." It didn't seem to understand "Alias" and "Export".

I don't buy that - it totally depends on how things are done.

I think it may come down to the cap on "Mod". In VB6, it's something like 2^31. The ceiling in PB is the maximum value of a double precision number. I wrote a short VB program to push the DLL to it's max. I got to X * 10^307; I think I wrote that correctly. It was what the manual says. I am dealing with very large numbers in my primary application.

JuggaloBrotha
May 26th, 2010, 07:52 PM
My DLL is written in PowerBasic Windows 8. It's very good at that. I tried VB6 and I got an error; "Cannot find DLL entry point." It didn't seem to understand "Alias" and "Export".



I think it may come down to the cap on "Mod". In VB6, it's something like 2^31. The ceiling in PB is the maximum value of a double precision number. I wrote a short VB program to push the DLL to it's max. I got to X * 10^307; I think I wrote that correctly. It was what the manual says. I am dealing with very large numbers in my primary application..Net can handle larger numbers than vb6...

storm5510
May 26th, 2010, 09:11 PM
.Net can handle larger numbers than vb6...

Yes it can, but much more slowly.

One of my college programming instructors said, "Division is expensive." He was quite correct. One of the things I'm doing is to determine if the result of a division is even or if it has a floating-point component:

Dim A As Double, B as Double, Result As Double

A = 7
B = 5

Result = A / B - Fix(A / B)

Before anyone asks, I'm using "Double" for A and B because they would be beyond the maximum value for a "Long".

If "Result" holds zero, then it was an even division. If not, then it will contain some fractional number in decimal form. I don't care about the remainder. I can't see a better way to do this on large values past what VB6's "Mod" can handle.

Note: .Net can make a lot of this easier because I've tried and it works. Some of the other things are not so easy. My DLL works fine with it too.

IanS
May 27th, 2010, 04:33 AM
Years ago back in the days of CPM and DOS 'Basic' programs weren't very quick so we usually used C. When Windows 9x came along we started adding GUIs to our existing applications and the easiest way to do that was to bodge the C code into a DLL with a visual basic 'front end'.

This actually worked very well and apps were very quick so we kept up that design strategy for many years. (Right through the 90's)

Nowadays though VB generates very efficient code and processing power is so cheap that there really isn't much of an advantage putting logic out to a DLL just for the sake of it. I really can't believe there's much of a performance improvement - if any.

Somebody mentioned the only real advantage - the ability for applications to share code. Update the DLL and all applications that use that dll are instantly using the latest code - (and they all break together - d'oh !)

IanS
May 27th, 2010, 04:44 AM
I don't know if there would be any point to moving something like a simple incrementation of a number, i.e. A = B + 1

Every call to a function or sub has an 'overhead' It doesn't matter if the function is in an external DLL or if it's in the same vb module - By 'overhead' I mean the processing that the computer has to do just to call a function.

When you call a function the processor has to make a note of where it is in the current function - push all the local variables of the new function on to the stack - execute the new function - put the result somewhere - move the stack pointer back to the where it was before the call so that all the local variables are 'popped' off the stack again and then put the instruction pointer back to the instruction after the original function call.

I suspect simply doing A = B + 1 in the current function would be quicker.

Why not test it and come back and tell us.

Test 1. Do the maths 100,000 times in a loop in the current function

Test 2. Put the math into a separate function in the same module and loop 100,000 times calling that function.

Test 3. Put the math out in a C DLL and call that 100,000 times

Then come back and tell us.

Shaggy Hiker
May 27th, 2010, 08:13 AM
Since VB has flattened the execution time for math operations such that division = addition as far as timing is concerned, I wouldn't be at all surprised if putting such a simple function out as a C routine would prove to be faster, but it would certainly be interesting to find out....though not interesting enough for me to do it.

storm5510
May 27th, 2010, 10:29 AM
To get any meaningful measurements for time, I modified the parameters a bit. I changed the max value to 10 ^ 8 and did division.

Inline: 3.18 seconds.
Function: 12.93 seconds.
DLL: 5.52 seconds.

I used "Timer" to get the elapsed time for all.

What I am doing in my other application is like nested loops. The value of the outer loop increments upwards, and the inner loop does division on all values of the current outer loop value, more or less. To run one block of 80 thousand iterations, the DLL takes about 25 seconds. An internal function takes 153 seconds. I tried inline a while back and it was not much better than the internal. Each case is different and to say one condition will apply to all is not accurate in this case.

Shaggy Hiker
May 27th, 2010, 11:17 AM
You might be interested in this little code timer class I wrote. You can create an instance in a project, then insert calls to Track to start and stop timing of different pieces. The class allows for multiple nested tracking blocks, and uses the Stopwatch object for pretty high precision measurements:


Public Class ProfileTimer
Private mStop As Stopwatch
Private mRegister As System.Collections.Generic.List(Of TimeHolder)
Private mIsRunning As Boolean
Private mLock As Boolean

Public Shared TheTime As New ProfileTimer

Private Sub New()
mStop = New Stopwatch
mRegister = New System.Collections.Generic.List(Of TimeHolder)
mIsRunning = False
mLock = False
End Sub

#Region "Properties"

Public ReadOnly Property GetString(ByVal index As Integer) As String
Get
If index >= 0 AndAlso index < mRegister.Count Then
Return mRegister(index).TokenName & ": " & (mRegister(index).StopTime - mRegister(index).StartTime).ToString & "ms"
Else
Return ""
End If
End Get
End Property

Public ReadOnly Property Count() As Integer
Get
Return mRegister.Count
End Get
End Property

Public ReadOnly Property GetString(ByVal tokn As String) As String
Get
Dim n As Integer = GetIndex(tokn)
If n >= 0 Then
Return mRegister(n).TokenName & ": " & (mRegister(n).StopTime - mRegister(n).StartTime).ToString & "ms"
Else
Return ""
End If
End Get
End Property

Public ReadOnly Property GetString() As String
Get
If mRegister.Count = 0 Then
Return "No Timing"
Else
Dim x As Integer
Dim sb As New System.Text.StringBuilder

For x = 0 To mRegister.Count - 1
sb.Append(mRegister(x).TokenName & ": " & (mRegister(x).StopTime - mRegister(x).StartTime).ToString & "ms" & Environment.NewLine)
Next

Return sb.ToString
End If
End Get
End Property

Public Property Lock() As Boolean
Get
Return mLock
End Get
Set(ByVal value As Boolean)
mLock = value
End Set
End Property

#End Region

#Region "Methods"

Public Sub StopAll()
Dim x As Integer
Dim th As TimeHolder

For x = 0 To mRegister.Count - 1
If mRegister(x).StopTime = -1 Then
th = mRegister(x)
th.StopTime = mStop.ElapsedMilliseconds
mRegister(x) = th
End If
Next
End Sub

Private Function StopTrack(ByVal tokn As String) As Long
Dim n As Integer = GetIndex(tokn)
Dim th As TimeHolder

If n >= 0 Then
th = mRegister(n)
th.StopTime = mStop.ElapsedMilliseconds
mRegister(n) = th
Return mRegister(n).StopTime - mRegister(n).StartTime
End If
End Function

Private Sub StartTrack(ByVal tokn As String)
mRegister.Add(New TimeHolder(tokn, GetTick))
End Sub

Public Sub Track(ByVal tokn As String)
Dim n As Integer = GetIndex(tokn)
If n = -1 Then
StartTrack(tokn)
ElseIf mRegister(n).StopTime >= 0 Then
If Not Lock Then
mRegister.RemoveAt(n)
StartTrack(tokn)
End If
Else
StopTrack(tokn)
End If
End Sub

Private Function GetTick() As Long
If mIsRunning Then
Return mStop.ElapsedMilliseconds
Else
mIsRunning = True
mStop.Start()
Return 0
End If
End Function

Private Function GetIndex(ByVal tokn As String) As Integer
Dim x As Integer

For x = 0 To mRegister.Count - 1
If mRegister(x).TokenName = tokn Then
Return x
End If
Next
Return -1
End Function

#End Region
End Class

Public Structure TimeHolder
Implements IEquatable(Of String)

Public StartTime As Long
Public StopTime As Long
Public TokenName As String

Public Sub New(ByVal tokn As String, ByVal sTime As Long)
StartTime = sTime
TokenName = tokn
StopTime = -1
End Sub

Public Function Equals1(ByVal other As String) As Boolean Implements System.IEquatable(Of String).Equals
Return (other = TokenName)
End Function
End Structure

storm5510
May 27th, 2010, 12:29 PM
Well, I appreciate your effort. That zooms right over my head. I recognize very little of what is in there. I know it's .Net, but not much more.

Sorry!
:blush:

Shaggy Hiker
May 27th, 2010, 02:10 PM
I've gotta put out a CodeBank on that one. The point to a class is not needing to understand all of the implementation.

What I do with that class is add it to a project, then, when I want to time something, I add lines like this:

ProfileTimer.TheTime.Track("First Track")
'Do a bunch of code that might take a long time.
ProfileTimer.TheTime.Track("Second Track")
'Do more code that might take a long time
ProfileTimer.TheTime.Track("Second Track") 'Stop the 'second track'
'Do more code.
ProfileTimer.TheTime.StopAll 'The only one still running is First Track.

'Now show the time taken by the tracks.
Windows.Forms.MessageBox.Show(ProfileTimer.TheTime.GetString)

Tracks can be started and stopped at will by calling Track with the name of the track you want to start or stop. You can see the timing for all the tracks, or just some of them with some of the overloads of GetString, and you can nest tracks as deep as you want. Pretty quick and useful if you have a process that you think it taking too long, as you can litter track calls through it and narrow down exactly where the slowdown is happening.

Of course, commercial profilers can do all that and more, and some versions of VS2010 can do that, too.

RhinoBull
May 27th, 2010, 02:15 PM
Inline: 3.18 seconds.
Function: 12.93 seconds.
DLL: 5.52 seconds.

That's basically what Ian and I said - inline is fater

storm5510
May 27th, 2010, 07:07 PM
That's basically what Ian and I said - inline is fater

99.9% of the time, this would be correct. I always get stuck with the other 0.1%, as in the case of my application.

:)