The problem (initially posted to Universal Thread 2016-06-28:
I have a VFP9 app that runs against Sql Server. When I run the forms inside the FoxPro IDE, running against the production Sql Server database located on a central server down the hall (i.e. NOT on my local developer machine), all the forms load up and run very quickly.
However, once compiled into an exe and running from the same developer machine, the forms take about *FIVE* times as long to load up. This is very consistent across all forms. The difference is 1.5 seconds load time in the IDE versus 7 seconds load time when running from an EXE.
Is there a particular reason that forms would run more quickly inside the FoxPro IDE than when compiled into an EXE?
Some background: A basic form in Visual FoxPro 9 my app will create between 30-40 Business Objects when it loads up (yes, those really cool kind of Sql Server Business Objects based on of the West Wind wwBusiness framework). In our system, like most others, an Order has a Customer, and Contact, and ShipToAddress, and vast collection of child items (i.e. cursors), such as LineItems, LaborRecords, MaterialRecords, ShippingTickets, Invoices, etc. So you can see it’s a very robust business/entity model and *every one* of those items I listed has its own formal Business Object to load the respective data and do various pieces of work on the data.
Each business object is a separate PRG: Job.prg, Customer.prg, Contact.prg, JobLineItems.prg, JobShippingTickets.prg, etc… You get the picture. In all, I have about 40-50 of these Businesss Objects, each in a separate prg file).
Each UI form uses a loader function to instantiate each needed Business Object and all other related Business Objects. The loader functions make a simple call like:
loJob = NewObject("Job", "Job.prg")
Well, guess what I learned…. If you call NewObject() in this manner from within the FoxPro IDE, it runs in about .03 seconds. That’s plenty fast enough for me and my users, but my users don’t run the app from my IDE. They use a compiled EXE app running and in that case, the same NewObject() call takes .21 seconds! Please note that is *7* times longer for each call! Now remember that my forms will typically call this function about 30-40 times, so the results is that the forms will load with startup time of around 1 second in the VFP IDE, but it takes 7-8 seconds when running from an EXE. Are you kidding me? What is going on? (BTW – I discovered this using the Coverage Profiler and a good bit of snooping around in the log results.)
So, the offense that I independently discovered here is that NewObject() is really slow when running inside of an EXE, but very fast when running in the IDE. Can’t explain that, but it’s true.
The remedy was to get away from NewObject() (in by BO factory) and use CreateObject() instead, which also requires the prg(s) to be loaded into memory by way of SET PROCEDURE. So, instead of making 50 Set Procedure calls, I wrote a build task which merges all the separate prgs into a single prg and I added that to the project as an included file, then I added a Set Procedure command for this file in the app bootup sequence.
Set Procedure To BusinessObjects Additive
I then changed my BO loader function to use CreateObject() instead of NewObject():
loJob = CreateObject("Job")
And, boom, I now get lightening fast creation of each BO even when running in the compiled EXE, and the form now loads in 1 second or so. Users = Happy.
Now, apparently I am not the only one who has ever discovered this oddity before (maybe you already knew it yourself as well), but as I was honing in on what I though the issue was, and what I thought the remedy would require, I happened to do a little Googling and found a 10-year blog post by some dude named Rick Strahl who had himself dealt with this issue before, and confirmed the same exact results and remedy that I landed on. Here is his post: http://www.west-wind.com/wconnect/weblog/ShowEntry.blog?id=553. You can also see more discussion on this topic at Fox.Wikis.com http://fox.wikis.com/wc.dll?Wiki~NewObject
Wow! This was a fun day. I love killing these little pests.
User Walter Meester posted a reply on UT asking if I had tried using Sys(2450,1) which is a flag which “Specifies how an application searches for data and resources such as functions, procedures, executable files, and so on.” (From the VFP Help.)
0 = Search along path and default locations before searching in the application. (Default)
1 = Search within the application for the specified procedure or UDF before searching the path and default locations.
So, I went back to the NewObject() way, and added the SYS(2450,1) suggested, and did careful, repetitive testing.
Result: Using Sys(2450,1) along with NewObject() does help a little bit when running inside an exe, *BUT*, it is still slower than using SET PROCEDURE along with CreateObject().
There are very distinctive and noticeable speed differences:
- 1st Place: SET PROCEDURE + CreateObject() = 1.4 seconds
- 2nd Place: Sys(2450,1) + NewObject() = 5 Seconds
- 3rd Place: NewObject() alone (leaving Sys(2450) at the default value of 0): 7.2 seconds
I hope this information helps your app performance in some way.
Here are the results I found from the Coverage Profiler for 1st Place and 3rd Place above. (I did not go back and run 2nd Place through the coverage proviler, but you can perceive where it would fall based on the time results listed above.)