dcsimg
Results 1 to 10 of 10

Thread: [RESOLVED] Stack and Code Efficiency

  1. #1

    Thread Starter
    Hyperactive Member
    Join Date
    Feb 2017
    Posts
    442

    Resolved [RESOLVED] Stack and Code Efficiency

    Trying to determine best way to make more efficient code.
    In this regard trying to understand:
    1) how the stack in interacting with a local procedure
    2) whether a copy is being made which may slow up the code.

    For example take this old piece of code written years ago:

    Code:
    Private Sub SaveDefaults(strLookUp As String)
    
       On Error GoTo Error_SaveDefaults
       
       '--------------
    
       Dim rsTemp As DAO.Recordset
       Dim strTBLName As String
     
       '*******
       'STARTUP
       '*******
       strTBLName = gktblTest
       Set rsTemp = DaoDb.OpenRecordset(strTBLName, dbOpenTable)
       
       '****
       'MAIN
       '****
       With rsTemp
       
          'Find the Specific Record to Modify
          'Only one record
          .Index = "idxLookUp"
          .Seek "=", strLookUp
       
          If .NoMatch Then
          
             Err.Raise ERR_TBL_CORRUPTED
    
          Else
          
             .Edit
             
             'WHATEVER Properties
             
            
             'Found It, Change It
             .Update
          
          End If
         
          .Close
       
       End With
       
       '******
       'WRAPUP
       '******
       Exit Sub
       
    Error_SaveDefaults:
    
       With TError
          .Type = ERR_CRITICAL
          .Src = mstrModule & "SaveDefaults"
          .Action = MsgAndLog
         
          If Err.Number = ERR_TBL_CORRUPTED Then
             .Data = "Table " & strTBLName & " is Corrupted" & vbCrLf
             .Data = .Data & "idxLookUp " & cboLookUp.Text & " is Missing"
          End If
       End With
      
       Call DoError
    
    End Sub
    The global constant (gktblTest) is assigned to a local variable (strTBLName) in order to use in both
    OpenRecordset and in the Error routine. As I understand it the local variable (strTBLName) will be
    pushed on the stack and then an address pointing to the global constant (gktblTest) address will exist.
    So while No copy appears to be made (as gktblTest is a string), it does appear that one could eliminate
    the local variable (strTBLName) and use the constant directly.
    ----------
    Question
    ----------
    Now the question becomes since there will be two calls to the global constant which s/b on the heap,
    is using the global constant twice, more efficient than creating a local variable to that constant?


    ========================
    Given the above, this also raises the question is it better to assign a Called Functions return to a local variable
    and then use that variable [Option1], or is it better to have that return used directly[Option2]?
    In other words in Option2 is the return copied to the local stack since it is contained in "Sub ThisTest" -- or --
    is the local "Sub ThisTest" stack bypassed and is or is NOT a copy of the boolean return made when passed as
    a parameter to another function [Note: I recognize that the passed parameter will be on the stack of
    PassToThisFunction, but what about within "ThisTest" where PassToThisFunction resides]?


    Code:
    Private Sub ThisTest
    
    '[Option1]
       Dim blnReturn as Boolean
       blnReturn =  GetThisFunction
       Call PassToThisFunction(blnReturn)
    
    '[Option2]
       Call PassToThisFunction(GetThisFunction)
     
    End Sub
    Last edited by vb6forever; Nov 12th, 2019 at 11:11 AM.

  2. #2
    PowerPoster Elroy's Avatar
    Join Date
    Jun 2014
    Location
    Near Nashville TN
    Posts
    5,834

    Re: Stack and Code Efficiency

    Hi vb6forever,

    Here are some of my thoughts regarding this level of detail:

    • Error trapping will always slow things down somewhat.

    • Checking all the "Advanced Optimization" when compiling will help a bit.

    • And here's the tough one. At most we're talking about copying a few bytes of memory when we may not need to. And, you're not passing your string as ByVal, so that's good. However, with the minuscule amount of speed you might find, I'm not sure it's worth worrying about. And, if you're truly worried, then you should probably be thinking of writing an assembly routine (possibly an inserted thunk) rather than doing it in VB6.


    EDIT1: The one time in recent memory I was actually worried about speed at this level, I was writing an image smoothing function. Placed in my main program (with only the "Remove Safe Pentium" Advanced Optimization turned on), it ran a bit sluggish. I pulled it out and placed it in a DLL with all the Advanced Optimizations turned on ... and I was quite surprised at how much it helped. As a guess, I'd say it more than doubled the speed performance of the function.
    Last edited by Elroy; Nov 12th, 2019 at 11:39 AM.
    Any software I post in these forums written by me is provided AS IS without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. Please understand that Ive been programming since the mid-1970s and still have some of that code. My contemporary VB6 project is approaching 1,000 modules. In addition, I have a VB6 random code folder that is overflowing. Ive been at this long enough to truly not know with absolute certainty from whence every single line of my code has come, with much of it coming from programmers under my employ who signed intellectual property transfers. I have not deliberately attempted to remove any licenses and/or attributions from any software. If someone finds that I have inadvertently done so, I sincerely apologize, and, upon notice and reasonable proof, will re-attach those licenses and/or attributions. To all, peace and happiness.

  3. #3
    Super Moderator Shaggy Hiker's Avatar
    Join Date
    Aug 2002
    Location
    Idaho
    Posts
    34,293

    Re: Stack and Code Efficiency

    You're also going to have to define efficiency.

    The difference in performance between the alternatives you listed is going to be seriously tiny. If you are trying to squeeze every last cycle out of code, then are you willing to throw more memory at the problem to gain a few cycles, or are you also concerned about memory consumption? People generally opt for speed over size, and therefore use more memory if it saves clock cycles, but which matters more to you?
    My usual boring signature: Nothing

  4. #4
    Sinecure devotee
    Join Date
    Aug 2013
    Location
    Southern Tier NY
    Posts
    5,616

    Re: Stack and Code Efficiency

    Quote Originally Posted by vb6forever View Post
    ... As I understand it the local variable (strTBLName) will be
    pushed on the stack ...
    Not that it adds to the question of efficiency, but as a technical point, local variables are not pushed on to the stack. They are allocated on the stack.
    The difference being that pushing a value on the stack changes the stack pointer, and the value is copied to the top of the stack (the lower memory address).
    Allocating stack space for local variables doesn't go through that process.

    The stack space needed for all local variables is determined at compile time, and is allocated by decrementing the stack pointer by the amount necessary at the beginning of the sub or function. For instance if we had six local variables that required a combined memory footprint of 16 bytes of memory, then the stackpointer would be decremented by 16 at the start of the procedure. Each local variables location is an address relative to the stackpointer, not an absolute address.

    The last variable allocated would be at Stk + 0, and others may be at Stk + 1, or Stk + 2, 4, 8, 10 etc...
    Each variable would be a fixed number of bytes offset from the stackpointer. If the local variables were pushed on the stack, then the offset of previously pushed variables would change, which would require a whole different mechanism to deal with.

    Technically, once a subroutine is entered and the stackpointer established for that sub's data, it shouldn't change for that sub, but only increase (actually decrease in value, but "increasing" stack usage) when calling another sub (or the same sub recursively), to establish a reference point for that current sub. When a sub exits, the local allocation for local variables is deallocated in one shot (stackpointer is incremented by the amount allocated), and the values that were pushed as part of the call (arguments and return address) are popped.
    "Anyone can do any amount of work, provided it isn't the work he is supposed to be doing at that moment" Robert Benchley, 1930

  5. #5

    Thread Starter
    Hyperactive Member
    Join Date
    Feb 2017
    Posts
    442

    Re: Stack and Code Efficiency

    Thanks All for input.
    Was not worried about any specific function, just an overall approach to every function I write to get as much speed as possible for a specific APP.

    passel:
    Your response was the type of detail of was looking for. In regard to:
    as a technical point, local variables are not pushed on to the stack. They are allocated on the stack.
    I can agree with the distinction you make in terminology.
    Can you elaborate on this a bit more.
    From my understanding the stack order is based on the processor -- x86 series is what I am working with) .
    So allocated order (without confirming) may be (in bottom up order):

    Function parameters
    Function return value
    Local variables
    Stack Pointer.

    Now the question I have is if we are allocating the stack variables at the time the function is entered, in what context does a push
    and pop to the stack take place within a function?

  6. #6
    VB-aholic & Lovin' It LaVolpe's Avatar
    Join Date
    Oct 2007
    Location
    Beside Waldo
    Posts
    18,525

    Re: Stack and Code Efficiency

    x86... generally speaking
    - Parameters are pushed onto the stack in reverse order (stdCall,CDecl); different calling conventions have different rules.
    - All parameters are DWord aligned, minimum of 4 bytes each.
    - In stdCall, all pushed parameters are popped when sub/function exits; different rules can apply for other calling conventions
    - Return value is passed into a register.
    - Local variables are allocated on the stack by adjusting the stack pointer to make room for them.
    - The stack pointer adjusts via pushes, pops and/or add/subtract executions on the esp register.

    Typically one pop for each push. If subtracting esp to make room, a complimentary add is called to restore. Push/pops can happen on demand or automatically via calling a subroutine within the compiled code. For each call to a sub/function (internal or external), the location for the next execution is pushed as a "return address" (for lack of a better term) and popped when called routine exits.

    FYI: I am not an ASM guru, so my terminology may be off a bit

    I think if you find any decent tutorial on assembly, this will all make more sense to you.
    Typical stack might look like following, from last to first placed on the stack
    : temporary stuff pushed; popped when no longer needed
    : local variables as needed, esp adjusted on exit
    : copy of register values as needed, popped on exit
    : params, popped on exit (stdCall)
    : caller return address, popped on exit automatically via ret instruction

    ... last pushed, first popped
    Last edited by LaVolpe; Nov 12th, 2019 at 02:11 PM.
    Insomnia is just a byproduct of, "It can't be done"

    Classics Enthusiast? Here's my 1969 Mustang Mach I Fastback. Her sister '67 Coupe has been adopted

    Newbie? Novice? Bored? Spend a few minutes browsing the FAQ section of the forum.
    Read the HitchHiker's Guide to Getting Help on the Forums.
    Here is the list of TAGs you can use to format your posts
    Here are VB6 Help Files online


    {Alpha Image Control} {Memory Leak FAQ} {Unicode Open/Save Dialog} {Resource Image Viewer/Extractor}
    {VB and DPI Tutorial} {Manifest Creator} {UserControl Button Template} {stdPicture Render Usage}

  7. #7
    Hyperactive Member
    Join Date
    Feb 2019
    Posts
    447

    Re: Stack and Code Efficiency

    How much is your time worth compared to gaining 0.01% of speed? I would identify the bottlenecks first, then optimize those. In your first example, it's DB interaction. You can use a profiler like CodeSmart, or the free and open source(but requires more work) Visual Basic Profiler. Scroll to the bottom of the page to "Profiling EXEs" to see instructions. It shows the time that it takes for each routine to execute in CPU cycles. The top of the page is for measuring ActiveX DLL's in a web server. You only need to download Profiler.dll. The full source link is on top of the page, it's written in VC6 and Assembly. I tell it to start capturing timing information by calling Instrument in Form_Load/Sub Main, and stop it by calling Report/Disconnect in Form_Unload. The output can be viewed by using DebugView, which you can export to Excel/LibreOffice Calc for easy viewing.

  8. #8

    Thread Starter
    Hyperactive Member
    Join Date
    Feb 2017
    Posts
    442

    Re: Stack and Code Efficiency

    Thanks for responding.

    (1)
    Found this excellent reference:
    https://users.ece.cmu.edu/~koopman/s...ers/index.html

    (2)
    qvb6: Will check out the Profiler as appears best way to get the timing info I need.
    .

  9. #9
    Super Moderator Shaggy Hiker's Avatar
    Join Date
    Aug 2002
    Location
    Idaho
    Posts
    34,293

    Re: Stack and Code Efficiency

    Optimizing code can save you a few cycles here and there. Improving the algorithm can save you thousands of cycles. Therefore, when it comes to optimizing, look to the algorithm first. Only when that can't be improved further should you look to optimization. Algorithm optimization is far more complex, too, since there aren't many solid rules with general applicability. Finding the bottlenecks is the first step, then try to think of ways to remove those bottlenecks entirely. For example, if a calculation is causing trouble, can you perform the calculation some other time? An example of this was the lookup tables used for trig calculations before floating point units were ubiquitous. During startup, you created tables of trig functions for the inputs you want. Then, when you need to perform such a costly calculation, you would look up the value in an array, which was FAR faster than the calculation. Effectively, the cost of doing the calculation had moved to program startup. It was paid one time for the life of the program.
    My usual boring signature: Nothing

  10. #10

    Thread Starter
    Hyperactive Member
    Join Date
    Feb 2017
    Posts
    442

    Re: Stack and Code Efficiency

    Shaggy Hiker:
    Thanks for the comment and reminder.
    Try and do as posted in my normal coding - NOT - that it can't always be improved.

    Optimizing code can save you a few cycles here and there. Improving the algorithm can save you thousands of cycles.
    They kinda go hand in hand though.
    As per my example if a using a constant on the heap is slower than using a local variable
    then coding a local variable in each procedure over a heap call --- in total throughout the program
    (not just one function) "should" yield a Net improvement in performace.

    Your Point is well taken.
    Object of post was to see if I could gain some knowledge over something where I know enough to be dangerous.
    Last edited by vb6forever; Nov 12th, 2019 at 04:08 PM.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Featured


Click Here to Expand Forum to Full Width