Rick Strahl's Weblog
Rick Strahl's FoxPro and Web Connection Weblog
White Papers | Products | Message Board | News |

Slow SET PROCEDURE TO and NEWOBJECT()


5 comments
September 30, 2006 •

I’ve been doing some performance testing in Web Connection earlier today and as I was running through some of the stress routines I noticed that one of my samples was running noticeably slower than many others. Web Connection requests are typically pretty quick – usually somewhere around 100th of a second or even less so for many requests the FoxPro timer resolution doesn’t even register a time at all <s>…

 

But one of the requests was taking quite a bit longer than any of the others and to top it off this is a real simple request. It turns out that the slowdown is caused by an explicit SET PROCEDURE TO command…

 

This is one thing that’s bugged me about VFP for some time: Loading of libraries is pretty slow and in Web code you certainly would want to put any SET PROCEDURE TO code into your server’s startup code (that is with Web Connection – can’t do that with ASP/COM since there’s no persistence).

 

So you might say, yeah I never do that, but if you’re using NEWOBJECT() you maybe surprised to find that NEWOBJECT Is nearly as slow as loading a library from scratch. Try this code with a PRG

 

SET PROCEDURE TO

CLOSE ALL

 

Sec = SECONDS()

 

#DEFINE TYPE 0

 

lcLibrary = "wwPop3"

 

#IF Type = 0

      SET PROCEDURE TO (lcLibrary)

#ENDIF

 

FOR  x = 1 TO 1000

  *** Preloaded

  #IF Type = 0

     loPop3 = CREATEOBJECT(lcLibrary)

  #ENDIF

 

  *** Load every time

  #IF Type = 1

        SET PROCEDURE TO (lcLibrary)

        loPop3 = CREATEOBJECT(lcLibrary)

  #ENDIF

 

  *** NewObject

  #IF Type = 2

        loPop3 = NewObject(lcLibrary,lcLibrary + ".prg")

  #ENDIF

     

  *** 'Manual' check

  #IF Type = 3

        IF ATC(lcLibrary,SET("PROCEDURE") ) < 1

          SET PROCEDURE TO (lcLibrary)

        ENDIF

        loPop3 = CREATEOBJECT(lcLibrary)

  #ENDIF 

ENDFOR

 

? SECONDS() - Sec

RETURN

 

NewObject is nearly 10 times slower that the ‘manual’ check shown on the bottom which is a pretty painful perf hit. That should make you think twice about using NEWOBJECT vs. SET PROCEDURE or SET CLASSLIB and then using plain CREATEOBJECT.

 

The problem is that NEWOBJECT() has to perform all sorts of checks for files and file locations I suspect, vs. the manual code assuming the code exists in the procedure stack only. So there’s no checking for a file inside of an APP/EXE vs. disk etc. Still 90% of the time the latter is probably way more efficient.

 

This is probably not a big issue in normal apps but in Web apps, that take 0.01 of a second having NEWOBJECT() or SET PROCEDURE can often double the request time which is rather significant.

Posted in:

Feedback for this Weblog Entry


Re: Slow SET PROCEDURE TO and NEWOBJECT()



Sylvain Bujold
October 03, 2006

I haven't run the test but is there any changes if you add ADDITIVE to the SET PROC for Type=1 ?

We had similar problems a while ago with a customer using a Novell Client. In their case though the hit kept getting longer and longer over time, up to 14 seconds a hit! Loaded those libraries at server startup only and it fixed problem.

Re: Slow SET PROCEDURE TO and NEWOBJECT()



Rick Strahl
October 04, 2006

Hmmm... ADDITIVE improves performance by about 25%, but it's still much slower (about 12 times slower) than the manual approach.

NEWOBJECT() is slowest, with SET PROCEDURE TO without ADDITIVE about the same.

re: Slow SET PROCEDURE TO and NEWOBJECT()



Matt Slay
June 28, 2016

Wow... almost 10 years later and today I was researching slow client app form load times on forms that use 30-40 Business Objects to present data field and grids to the user.

40 BOs were taking 7-8 seconds to new up when the form launched while running in an EXE, but only 1-2 seconds when running the same code from within the VFP IDE.

I blogged about my discovery, research, and remedy. Link below. In the post I also give props to Rick for blogging about this a decade ago.

http://mattslay.com/foxpro-newobject-fast-here-slow-there/

Re: Slow SET PROCEDURE TO and NEWOBJECT()



Mike Yearwood
12 days ago

I suggest avoiding set procedure. Put customer.prg in a folder in your development path and add it to the exe. Just call it like this:

loCustomer=Customer(1,2,3)

Customer.prg lparameters one, two, three RETURN CreateObject('Customer',one,two,three)

define class customer procedure init lparameters one, two, three endproc enddefine

Re: Slow SET PROCEDURE TO and NEWOBJECT()



Rick Strahl
11 days ago

@Mike - That might work for you, but it doesn't work for me. I never run an EXE in development, so your project inclusion loading would not work for me. Plus the fact that you have to add your non-direct referenced dependencies explicitly into the project, which is a pain in the ass.

My approach is every class declares its dependencies at the top:

*** Dependencies
SET PROCEDURE TO wwUtils ADDITIVE
SET PROCEDURE TO wwApi ADDITIVE
SET PROCEDURE TO wwSql ADDITIVE

*** this library
SET PROCEDURE TO wwBusinessObject ADDITIVE

Then to load the library I can simply do:

*** At app startup - or in `MyApp_Load.prg`
DO wwBusinessObject
DO wwDotnetBridge 

*** Now use any class declared

The benefit is you have code based configuration - you can easily tell what dependencies your app has by looking at MyApp_Load.prg and as a bonus all your dependencies automatically get puled into the project. If you start a new project you can copy/customize the list without manually adding files to your project file.

This works both for compiled and PRG files and you can run the PRG from the Command Window both running the app or loading only the libraries.

 
© Rick Strahl, West Wind Technologies, 2003 - 2024