Real Software Forums

The forum for Real Studio and other Real Software products.
[ REAL Software Website | Board Index ]
It is currently Mon Oct 20, 2014 10:41 pm
xojo

All times are UTC - 5 hours




Post new topic Reply to topic  [ 13 posts ] 
Author Message
 Post subject: OS X and Thread Bug?
PostPosted: Mon Mar 20, 2006 5:31 am 
Offline

Joined: Wed Mar 08, 2006 6:53 pm
Posts: 60
I originally had code within the action event of a button, which called 15 different methods; approximately 1,100 lines of code. However this process caused the watchcursor to appear on Classic Mac, which could not be hidden due to bug in RB, so all the code from the button and the 15 methods were placed in one thread which the button now calls instead. For some reason there is a significant amount of more time used for X when the thread is used? Why?


X, Classic Mode 9.2.2, XP tested on dual 867Mhz G4, with 1.25GB memory.

Classic 9.0 tested on single processor 350 Mhz G4, with 1.25GB memory.

Note: VirtualPC runs slower than actual PC (thats why I like to use it)

Note: Average time is expressed in decimal values of less than a second.


(1) Thread (button action code & 15 methods):

Pro: No WatchCursor on computer running Classic (not Classic Mode)

XP (VirtualPC) = .92
Classic 9.0 = .40
Classic Mode 9.2.2 = .19
X = .62


(2) Button Action Code + 15 Methods:

Con: WatchCursor on computer running Classic (not Classic Mode)

XP (VirtualPC) = .80
Classic 9.0 = .35
Classic Mode 9.2.2 = .15
X = .36


Edit: Had VirtualPC figures switched (now fixed)

_________________
Banned yet another time.


Last edited by seventypages[Banned] on Mon Mar 20, 2006 9:45 am, edited 1 time in total.

Top
 Profile  
 
 Post subject:
PostPosted: Mon Mar 20, 2006 8:46 am 
Offline

Joined: Sat Oct 01, 2005 6:52 pm
Posts: 1024
Non-threaded code can hog the processor while threads must share. That accounts for longer processing times often noticed with threads. The advantage of the thread is that other activities can take place while the thread is running such as progress updates and user inputs. As a result, the user experiences a more responsive computer.


Top
 Profile  
 
 Post subject:
PostPosted: Mon Mar 20, 2006 10:03 am 
Offline

Joined: Wed Mar 08, 2006 6:53 pm
Posts: 60
Does RB have "real" multi-thread capacity? According to Neuberg's book (yes, I know it old) this does not actually occur unless you have multi-processor computer and the language is coded to take advantage of this; i.e., threads don't actually run at the same time, but instead short pieces of each thread are run at a time to give the appearance that the threads are actually running at the same time (sort of a start and stop rountine).

Surprising that the thread runs so much slower on a dual processor 867Mhz Mac G4 running 10.2.8 than it does on a G4 with a single 350Mhz processor running 9.0? This must mean RB does not actually run multiple threads at the same time as two processors should get the job done faster. The difference between Classic Mode and X running at the same time on the same computer is amazing!

That sort of sucks as I'll have to use 1,100 lines of code for the thread version to prevent a watchcursor in Classic Mac OS due to defect in RB, and then I'll have to duplicate the same code within the original methods for use with OS X; 1,100 extra lines of code (as maintaining 2 seperate versions will likely even be more work).

_________________
Banned yet another time.


Top
 Profile  
 
 Post subject:
PostPosted: Mon Mar 20, 2006 11:38 am 
Offline
User avatar

Joined: Wed Sep 28, 2005 8:39 am
Posts: 9341
Location: St Augusta, MN
seventypages wrote:
Does RB have "real" multi-thread capacity?


No, it has cooperative threads, which cannot (by definition) be used on multiple processors.

Quote:
According to Neuberg's book (yes, I know it old) this does not actually occur unless you have multi-processor computer and the language is coded to take advantage of this; i.e., threads don't actually run at the same time, but instead short pieces of each thread are run at a time to give the appearance that the threads are actually running at the same time (sort of a start and stop rountine).


Which is also true of preemptive threads as well. The only time two threads execute at the same time is when multiple processors (or processor cores) are involved. Just an FYI.

Quote:
Surprising that the thread runs so much slower on a dual processor 867Mhz Mac G4 running 10.2.8 than it does on a G4 with a single 350Mhz processor running 9.0?


Not at all -- my guess is that you haven't modified the thread priority at all. So what's happening is that you've taken code which used to use 100% of the CPU, and now it only uses 50% of the CPU.

Quote:
That sort of sucks as I'll have to use 1,100 lines of code for the thread version to prevent a watchcursor in Classic Mac OS due to defect in RB


Or you could just disable the auto wait cursor with a single line of code:

#pragma DisableAutoWaitCursor


Or, you could add about another XXX lines of very well-placed code to make your method MP thread safe, and deal with the hard-to-track crashes when you forgot a place. Preemptive threads aren't a panacea to speed issues like you make them sound. Cooperative threads are very powerful due to the fact you don't have to care about thread safety (for the most part). Preemptive threads are a very, very difficult thing for even an experienced programmer to get right due to safety issues, and aren't something that will ever be just a simple "switch" to turn on and off.


Top
 Profile  
 
 Post subject:
PostPosted: Mon Mar 20, 2006 2:35 pm 
Offline

Joined: Wed Mar 08, 2006 6:53 pm
Posts: 60
Quote:
Or you could just disable the auto wait cursor with a single line of code:

#pragma DisableAutoWaitCursor



There is a bug in Realbasic. The watchcursor cannot be disabled on Classic builds using this pragma (see my other post). I think something could have gone wrong when the global nature of the autowaitcursor was removed from RB?

My original problem was that I had code within the action event of a button. Among this code were 15 calls to 15 seperate methods which were called in a certain order. I installed the above pragma at the top of the action event of the button and at the top of each method, but the watchcursor still showed on Classic (not Classic Mode of X). There was no other code running at the same time to produce the watchcursor.

So I instead moved all the code from action event of the button and from the 15 methods and installed it in a single thread which is now called from the action event of a button. Because the code is running in a thread there is no watchcursor on Mac Classic (the above pragma was not needed, but I did install the DisableBackgroundTasks so the application does not yield to other applications).

So in both cases the same code is running in the same linear fashion; the only difference is that instead of using 15 different methods to make the code easier to read, its now in one huge block inside a thread. I don't understand why the same exact thread would run so much slower since even if the newer computer is only using one of its single 867Mhz processors to process the code, this should be faster than a single 350Mhz processor. So perhaps there is some kind of bottleneck/bug in RB in the way threads are completed within Max OS X or perhaps related to double processor systems?

Due to the watchcursor bug I don't see any alternative to adding both the thread of 1,100 lines because this removes the watchcursor for Classic Mac; and adding the original 1,100 lines of code within the 15 methods and button action event as this runs significantly faster on X.

Windows can use the nonthread method. X Classic Mode will have have to use the threaded procedure even though the watchcursor is not a problem here and the nonthreaded procedure runs faster since I'd rather not try installing what probably is toolbox call to determine if the OS is real Classic or X Classic Mode.

Quote:
Not at all -- my guess is that you haven't modified the thread priority at all. So what's happening is that you've taken code which used to use 100% of the CPU, and now it only uses 50% of the CPU.


By thread priority you mean you mean the thread should not yield to other applications? I added the DisableBackgroundTasks to both the action event of the button and the thread.

So by moving the code to the thread its getting a lower priority than if it was in multiple methods and the action event of a button; thus its given a lessor amount of the CPU's attention?

_________________
Banned yet another time.


Top
 Profile  
 
 Post subject:
PostPosted: Mon Mar 20, 2006 3:31 pm 
Offline
User avatar

Joined: Wed Sep 28, 2005 8:39 am
Posts: 9341
Location: St Augusta, MN
seventypages wrote:
There is a bug in Realbasic. The watchcursor cannot be disabled on Classic builds using this pragma (see my other post). I think something could have gone wrong when the global nature of the autowaitcursor was removed from RB?


Um... so if you put this code in a Classic build, it does or does not work?

#pragma DisableAutoWaitCursor
for i as Integer = 0 to 1000000
dim r as Double = rnd
next i


You should see no wait cursor.

Quote:
So perhaps there is some kind of bottleneck/bug in RB in the way threads are completed within Max OS X or perhaps related to double processor systems?


No, threads behave slower because you're not using the entire CPU time to execute the code within the thread. You're only using *part* of the CPU time to do it. So it'll run slower.

Quote:
By thread priority you mean you mean the thread should not yield to other applications?


No. I mean the Thread.Priority property on the thread class. Priority has nothing to do with yielding to other applications in the system and everything to do with yielding to other threads in your application.

Quote:
I added the DisableBackgroundTasks to both the action event of the button and the thread.


Which means that threads won't yield any time back to any thread, which essentially negates the usefulness of the thread. You shouldn't be disabling background tasks in threads.

Quote:
So by moving the code to the thread its getting a lower priority than if it was in multiple methods and the action event of a button; thus its given a lessor amount of the CPU's attention?


Correct.

You may want to check out the series of blog postings I did about threads a while back.

http://ramblings.aaronballman.com/?p=420
http://ramblings.aaronballman.com/?p=421
http://ramblings.aaronballman.com/?p=424

I think that's all of them. Those should give you a bit more of an understanding of what threads are, how they work and the APIs you use with them.


Top
 Profile  
 
 Post subject:
PostPosted: Mon Mar 20, 2006 10:35 pm 
Offline

Joined: Wed Mar 08, 2006 6:53 pm
Posts: 60
Quote:
#pragma DisableAutoWaitCursor
for ias Integer =0to 1000000
dim ras Double = rnd
next i


That code will not actually run in 5.5.5; I assume you mean:

Dim i as integer
Dim r as double

#pragma DisableAutoWaitCursor
for i = 0 to 1000000
r = rnd
next i


Yes, this particle code, in the action event of a button, generates a watchcursor without the pragama, and with the pragma inserted no watchcursor is generated. The watchcursor is generated on both Classic (9.0) and Classic Mode (9.2.2).

So I removed all my code from the thread and inserted into the action event of a button, including the DisableAutoWaitCursor pragma. The watchcursor is still generated on Classic (9.0). The watchcursor is never generated on Classic mode (9.2.2) regardless of if the pragma is included or not. X and XP are also not effected. There is no other code executing at the same time.

The problem here is that the above loop does not emulate the code I am using. Although there are a couple tiny loops (probably can’t measure the time they take as they’re too small) 99.9% of the code consists of series of If-ElseIf-End statements, case statements, and references to control properties. Many of the If statements do not have a simple format, for example

If condition and condition and condition then

If condition and condition or condition and condition or condition and condition then

If condition and condition and condition or condition then

Probably the best example of what is being done would be Adobe Illustrator’s multi-panel save preview window in which say 4 different versions of a document can be viewed in mutli-paned window at once. In my application the processor intense code performs a series of tests, sets control and window properties based on computations, and then each object that is to be modified is updated at the end of the code block. Adobe illustrator’s preview window is slightly different in that it computes and illustrates one configuration at a time (showing a progressbar for each preview pane) whereas mine first computes all changes and then updates everything.

So far the only way to get rid of the watchcursor on Classic is to place the code inside a thread; however, running the code in a thread on X makes it twice a slow so I only way I can see to overcome this to use the thread for Classic and Classic Mode and use nonthreaded code for X and XP, which means I must duplicate 1,100 lines of code.

This is really weird though that the same thread runs slower on a faster processor; it also runs slower in X than in Classic mode when both are runing on the same machine.

Quote:
Which means that threads won't yield any time back to any thread, which essentially negates the usefulness of the thread. You shouldn't be disabling background tasks in threads.


According to 5.5.5’s LR #Pragma Directives: DisableBackgroundTasks states:

“It prevents REALbasic from calling the WaitNextEvent toolbox routine, so it never yields time ot any other applications. It therefore, can speed up processor-intense operations but prevents REALbasic from displaying the Watch cursor, may halt normal background updating of interface elements, and prevents other threads from executing.”

I don’t see any information pertaining to threads in this. Please note I am only running one thread at a time - the application only contains one instance of a thread class in the main window. Are you saying that because this is used the main application thread will not yield time to the instance of the thread class in the main window - if though the main application thread is not performing any tasks.

[quote]
No. I mean the Thread.Priority property on the thread class. Priority has nothing to do with yielding to other applications in the system and everything to do with yielding to other threads in your application.
[quote]

Thanks for the links I saved them as pdf’s); however, a good percentage of the articles do not apply to RB 5.5.5 as the thread class has no priority property and the app class has no yieldtonextthread property, etc...

_________________
Banned yet another time.


Top
 Profile  
 
 Post subject:
PostPosted: Mon Mar 20, 2006 10:45 pm 
Offline
User avatar

Joined: Wed Sep 28, 2005 8:39 am
Posts: 9341
Location: St Augusta, MN
seventypages wrote:
“It prevents REALbasic from calling the WaitNextEvent toolbox routine, so it never yields time ot any other applications. It therefore, can speed up processor-intense operations but prevents REALbasic from displaying the Watch cursor, may halt normal background updating of interface elements, and prevents other threads from executing.”

I don’t see any information pertaining to threads in this. Please note I am only running one thread at a time - the application only contains one instance of a thread class in the main window. Are you saying that because this is used the main application thread will not yield time to the instance of the thread class in the main window - if though the main application thread is not performing any tasks.


Uh... "prevents other threads from executing" would pertain to threads. ;-) You have TWO threads running. The main application, and the worker thread. By disabling background tasks, one or the other won't be running until background tasks are turned on. And this is a bad thing.


Top
 Profile  
 
 Post subject:
PostPosted: Mon Mar 20, 2006 10:57 pm 
Offline

Joined: Fri Dec 16, 2005 10:19 pm
Posts: 493
The point of a thread is to let other things happen while it is running. The point of disabling background tasks is to prevent other things from running. Both at once acts like normal code with background tasks disabled. The threadedness has little or no effect.

_________________
- Craig Macomber -
See my rb apps at:
http://www.spincraftsoftware.com/
Lead Programmer for Fragmented Galaxy, an MMORTS:
http://f-g.wikidot.com/


Top
 Profile  
 
 Post subject:
PostPosted: Tue Mar 21, 2006 12:59 am 
Offline

Joined: Wed Mar 08, 2006 6:53 pm
Posts: 60
Having removed the disablebackgroundtasks pragma and inserted the disableautowait cursor I get the following test results:

(1) Thread (code in thread called by button; both button action event and thread have pragma):

Pro: No WatchCursor on Classic 9.0
Con: Slower

XP (VirtualPC) = .82
Classic 9.0 = .53
Classic Mode 9.2.2 = .26
X = .75


(2) Button (code inside action event of button, with pragma)

Con: WatchCursor on Classic
Pro: Faster

XP (VirtualPC) = .79
Classic 9.0 = .32
Classic Mode 9.2.2 = .13
X = .35

The watchcursor still persists and the only way to get rid of it it to use the thread for Classic (and Classic Mode for simplicity); which will require duplication of 1,100 lines of code as the unthreaded is faster for X and XP. There appears to be a bug in RB which allows the watch cursor to be disabled for simple loop, but not for large sections of code which involve multiple blocks of If then and Case statements?

Very strangely if I add MsgBox at the end of the button action event to show the elapsed time of the code the watch cursor never shows.

The basic structure of the code section is:

Pragma

Dim Statements

If Then Block - Possibly Alter Couple Controls

Select Case

If Then Block - Test Input: Return if any tests failed; otherwise execute code below

If Then Block
Select Case
If Then Block
If Then Block
If Then Block
If Then Block
If Then Block
If Then Block
If Then Block
If Then Block
If Then Block
If Then Block
If Then Block
Small Loop
Small Loop - Update Controls

The If Then blocks and Select Case blocks generally test conditions and set properties which are manifest in the final loop which updates the interface accordingly.

Any more tricks?

_________________
Banned yet another time.


Top
 Profile  
 
 Post subject:
PostPosted: Tue Mar 21, 2006 1:02 am 
Offline
User avatar

Joined: Wed Sep 28, 2005 8:39 am
Posts: 9341
Location: St Augusta, MN
No tricks -- I think you may be misunderstanding how the auto wait cursor works.

You have to put the call into every method which you want the wait cursor to be disabled for (I believe -- it's been a LONG time since I've had to deal with Classic). Try putting the pragma at the start of every method being called in the non-threaded version and see if things change for you.


Top
 Profile  
 
 Post subject:
PostPosted: Tue Mar 21, 2006 1:12 am 
Offline

Joined: Wed Mar 08, 2006 6:53 pm
Posts: 60
Quote:
No tricks -- I think you may be misunderstanding how the auto wait cursor works.

You have to put the call into every method which you want the wait cursor to be disabled for (I believe -- it's been a LONG time since I've had to deal with Classic). Try putting the pragma at the start of every method being called in the non-threaded version and see if things change for you.


Yes, In understand that, I already tried that. In the recent test result above there are no methods being called - all the code is dumped into the action event of a button with the pragma at the top.

Also tried global module and a class without any super with the pragma and watch cursor was still present :0(

I am wondering if this has to do with the fact that the disableautowaitcursor was once global and is is not now since Neuberg's book states this should work for the watch cursor (it was global when the book was printed).

_________________
Banned yet another time.


Top
 Profile  
 
 Post subject:
PostPosted: Tue Mar 21, 2006 9:29 pm 
Offline

Joined: Wed Mar 08, 2006 6:53 pm
Posts: 60
Took the extra step of adding the DisableAutoWaitCursor to every conceivable function, sub, method, even if it had nothing to do with the code block, but still got watchcursor so instead this seems to work:

Add new thread class to project and drag instance into window. Then in open event of window run thred. The thread runs continually, but only adds .1 MB (a 10th) of memory usage on Classic.

Either of the following seem to work. I am guessing that the same watch cursor might still be produced but because of the quickness of the thread you never see it - it does not have time to draw it.

I am guessing this watch cursor bug in Rb might be related to 9.0.0 as it does not appear in other versions of th Classic I've tested so far.

Do
App.MouseCursor = ArrowCursor
Loop

or

Do
#Pragma DisableAutoWaitCursor
Loop

_________________
Banned yet another time.


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 13 posts ] 

All times are UTC - 5 hours


Who is online

Users browsing this forum: Google [Bot] and 0 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
Jump to:  
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group