Announcement

Collapse
No announcement yet.

Performance Speed on WinXP

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • Performance Speed on WinXP

    Good evening, community.

    I fear that my question is fairly global. But that is exactly the reason why I don't know where to search for the problem.
    I have a PBWin created application that manages two worker-threads permanently during runtime.
    Both threads change their individual icon in the main-window's statusbar always after 60 loops.
    The synchronisation is done by using Window's CRITICALSECTION.
    Normally the programm performes very fast, indicated by the fast change of the thread's icons, mentioned above.
    But on some XP-machines the application works with reasonable reduced -speed. The speed is alway steady: either fast or slow on some machines.
    This seems not to be related to the CPU-speed. I have one user with a
    2.1 GHZ-CPU, but the application performes very slowly.
    I'm using GFX-Tools, but don't know if there is a relationship to the question.
    During runtime there should be no contact to the main-disk, because all data is loaded before into the processor.
    The problem doesn't occour on WIn98 and on Vista as far as I have seen.
    Interesting: On one XP-machine the programme starts to hurry, if one opens IE; after closing IE, it again creeps.
    Additionally I should mention, that the running programme only uses 1% of CPU-capacity.
    Where do I have to start searching?

    Thanks for help and greetings from Germany
    Heinz Grandjean
    Last edited by Heinz Grandjean; 25 Feb 2008, 03:48 PM.
    Heinz Grandjean
    http://www.estwgj.com/

  • #2
    First thing I lreaned about threads (from a very good book by an expert) is don't modify the GUI from worker threads.

    The books author referred to the main thread (processes primary thread) as the GUI thread, where all GUI code should be. He recommended avoiding modifying the GUI from worker threads, since it adds a lot of overhead which can slow things down.

    The thing about Windows is that when GUI elements are created (dialogs, windows, controls), they must be accessed from the same thread. This means that when a worker thread makes call to an API function or message, which affects a GUI element (window), Windows must do a context switch and switch to the windows creation thread, act on the window and then swap back to the worker thread.

    Likely the speed problems you have may be the result of this situation.

    Another consideration is how often a GUI object is modified. If a loop runs 60 times per second and each loop sets a GUI objects state, this can slow things down a lot. One technique that helps is to only update the GUI elements at loner intervals. For example, by changing code to only modify the GUI say every 10th of a second (for your 60 intervals/second loop, this would be once every six intervals) you lessen the oberhead needed to modify the GUI. The end user sees no difference between changes are made quick enough for the human eye, but slow enough so they don't notice it.
    Chris Boss
    Computer Workshop
    Developer of "EZGUI"
    http://cwsof.com
    http://twitter.com/EZGUIProGuy

    Comment


    • #3
      You can get around the thread switch by POSTING a message to your main window and letting the GUI thread handle the update when the GUI thread already has the time slice...

      Code:
      %PWM_UPDATE_ICON = %WM_USER + 1 
      
      FUNCTION MainWindowProc ...
      
           CASE %PWM_UPDATE_ICON 
           do it. 
           You can use lparam and wparam to pass info 
      
      
      FUNCTION THreadFunction...
      
         DO WHILE...
            INCR nLoop 
            IF nLoop MOD 60 = 0 THEN
                PostMessage hWndMain, %PWM_UPDATE_ICON, somewParam, someLparam
            END IF 
           ....  yadda, yadda.
      Now there is no forced thread switching... the system 'catches up' whenever Windows goes back to service the GUI thread.


      MCM
      Michael Mattias
      Tal Systems (retired)
      Port Washington WI USA
      [email protected]
      http://www.talsystems.com

      Comment


      • #4
        Apologizes for late answering and many thanks for the help.

        Paradoxically I did all the thread-managing that You suggested in Your answers. I have learned a lot from the forum and carefully read Beverigde/Wiener's guide to threads. That confirms me that the problem seems to lay elsewhere. I think I found it: To garantee proper context-switching between the both worker-threads and the main-dialog, the first statement in each thread's "do loop" -structure was "Sleep 1".
        I changed the threads executing the "sleep 1" statemant only once in 100 circles and now everything is very fast, even on slow -machines.
        Four questions arise from that:
        1) Is the execution- speed of "sleep 1" ("sleep 0" seems not to work) differently executed on different XP-machines? (This had been discussed in other threads here! But where?)
        2) Could the bespoked delay depend on the context-switching overhang?
        3) Is context-switching executed differently on different XP-machines?
        4) Is there a way to gain control about the context-switching -speed?

        Thanks and greetings from Germany
        Heinz Grandjean
        Heinz Grandjean
        http://www.estwgj.com/

        Comment


        • #5
          Using SLEEP can be tricky, especially with threads.

          While I haven't come across problems with XP on different systems yet, there is a problem with Vista.

          I have a simple sample program which runs well using two worker threads communicating to the main GUI thread (primary thread) updating a graphic control (Canvas) many times a second. It draws a simple animated graphic in each control.

          It works fine on XP Home, but on Vista Home basic the threads don't run equally. One thread slows down terribly. Vista is obviously handling the switching between threads differently than does XP.

          Maybe XP runs differently because of the hardware or something on different systems. I don't know, but it is possible.
          Chris Boss
          Computer Workshop
          Developer of "EZGUI"
          http://cwsof.com
          http://twitter.com/EZGUIProGuy

          Comment


          • #6
            There is one thing about Threads to consider and that is their priority. There are multiple levels of priority, starting with the primary thread (process) and then the worker threads.

            If the priorities are set differently because of the operating system, then you will see speed differences.

            Also consider that Windows has become a hog because of all sorts of services running in the background. It is likely worse on Vista.

            Because of this, different PC's may have different software loaded which is running in the background and this will significantly impact the speed of threads.

            Unless two PC's are absolutely identical (hardware and software) you can not guarantee the same speed for running an app or its threads.
            Chris Boss
            Computer Workshop
            Developer of "EZGUI"
            http://cwsof.com
            http://twitter.com/EZGUIProGuy

            Comment


            • #7
              Yes, thank You, I understand.
              Would it be possible, to stop other background-running. The question could be: How to identify non friendly threads of other programms and how to set them to sleep until the own programm's realtime loops have finished.
              Maybe a certain: Shut down everybody around during my own, most important execution time???
              Heinz Grandjean
              http://www.estwgj.com/

              Comment


              • #8
                HEH good luck,

                Sorry...Knee-Jerk reaction

                Just out of curiosity Chris, is Vista home working differently from system to system as far as you can tell? (I only have a small sample to work from, but sure there are differences from flavor to flavor of Vista)
                Engineer's Motto: If it aint broke take it apart and fix it

                "If at 1st you don't succeed... call it version 1.0"

                "Half of Programming is coding"....."The other 90% is DEBUGGING"

                "Document my code????" .... "WHYYY??? do you think they call it CODE? "

                Comment


                • #9
                  >Would it be possible, to stop other background-running

                  In theory, sure.

                  However, that would be on your way to the unemployment line.

                  You "can" give your own program essentially exclusive use of the processor by setting the thread priority to a large value. But the caution in the doc is a wise one:

                  When manipulating priorities, be very careful to ensure that a high-priority thread does not consume all of the available CPU time. A thread with a base priority level above 11 interferes with the normal operation of the operating system. Using REALTIME_PRIORITY_CLASS may cause disk caches to not flush, hang the mouse, and so on.
                  Michael Mattias
                  Tal Systems (retired)
                  Port Washington WI USA
                  [email protected]
                  http://www.talsystems.com

                  Comment


                  • #10
                    How could I have forgotten this?

                    Poor application performance is almost always caused not by the hardware, not by the operating system, not by the compiler, and not even by inferior technique: it's caused by poor design.


                    MCM
                    Michael Mattias
                    Tal Systems (retired)
                    Port Washington WI USA
                    [email protected]
                    http://www.talsystems.com

                    Comment


                    • #11
                      I only have one Vista machine which I tested this on.

                      I am using the default priority for the worker threads as well.
                      Chris Boss
                      Computer Workshop
                      Developer of "EZGUI"
                      http://cwsof.com
                      http://twitter.com/EZGUIProGuy

                      Comment


                      • #12
                        >I am using the default priority for the worker threads as well

                        In my production apps I always set the priority down for worker threads.*

                        Otherwise I feel guilty, because if it really is a "background task" why the heck am I giving it the same priority as my user interface?

                        * You can use SetThreadPriority() against the handle returned by THREAD CREATE. You have to do it that way because my three-year old new feature suggestion for a THREAD SET PRIORITY 'native' feature is apparently still 'under consideration.'
                        Michael Mattias
                        Tal Systems (retired)
                        Port Washington WI USA
                        [email protected]
                        http://www.talsystems.com

                        Comment


                        • #13
                          Good evening community!

                          Mr. Mattias said:
                          Poor application performance is almost always caused not by the hardware, not by the operating system, not by the compiler, and not even by inferior technique: it's caused by poor design.

                          My answer: Oh,yes, that's the reason, why I'm asking for help.

                          Additionally:
                          Otherwise I feel guilty, because if it really is a "background task" why the heck am I giving it the same priority as my user interface?

                          My answer: This is an emotional argument and quite logical, if the technical
                          priorities are clear; but - on my side looking for the technical background - it's still emotional. But i will try this too.

                          Additionally:
                          You can use SetThreadPriority() against the handle returned by THREAD CREATE. You have to do it that way because my three-year old new feature suggestion for a THREAD SET PRIORITY 'native' feature is apparently still 'under consideration.'

                          This argument discusses priority inside an application and it's well underlined by Mr. Mattias' professionality.
                          But I have learned just in that thread here, that problems related to context-switching derive from parallel (outside) applications....

                          I would be interested - in all respect - how to handle the quantity of sleep statements inside the two parallel -executing threads of "my" application in relationship to all the other "enemy"-CPU's loads.
                          Is there a way to find out proper values?

                          Greetings and thanks for help,

                          Heinz Grandjean
                          Heinz Grandjean
                          http://www.estwgj.com/

                          Comment


                          • #14
                            Heinz,
                            If you are asking what I think you are asking.
                            "How many threads, at what priority are too much?"

                            Unfortunately the answer is "It Depends"

                            A thought I had was if all priorities are equal, then if I read somewhere was correct that each thread gets 20ms to complete or release then the question is...each thread in Windows? or does my process = a 20ms time slice and I delegate to each thread I created?

                            Sure you could have a tight loop (no sleeps) but then the CPU strikes depending on how long your process has its time slice, so you have to carefully balance how intensive "Background" is vs god knows how many other apps begging for the time slice you do not give up (whether you are finished or not)

                            the core answer unless someone can correct me is...test on multiple machines, and a number you can live with that you give up your time-slice to other processes
                            Engineer's Motto: If it aint broke take it apart and fix it

                            "If at 1st you don't succeed... call it version 1.0"

                            "Half of Programming is coding"....."The other 90% is DEBUGGING"

                            "Document my code????" .... "WHYYY??? do you think they call it CODE? "

                            Comment


                            • #15
                              Heinz,
                              Is the execution- speed of "sleep 1" ("sleep 0" seems not to work) differently executed on different XP-machines? (This had been discussed in other threads here! But where?)
                              Yes. Timeslices vary. The usual starting time slice is around 15 to 16ms (it's acually 15.625, that's 1/64th of a second, but is then averaged to the nearest whole millisecond).
                              If you SLEEP 0 then you give up your timeslice immediately but return immediately if no other process wants it.
                              If you SLEEP 1 then you give up your timeslice immediately but even if nothing else wants it you will not return for 16 msec. That time will then go to CPU IDLE time.

                              Certain other processes can change this. The timeslices can drop to 1ms each under certain circumstances when other, unrelated programs, do things.
                              To see what timeslice you have, write a program something like this:

                              Code:
                              DECLARE FUNCTION QueryPerformanceFrequency LIB "KERNEL32.DLL" ALIAS "QueryPerformanceFrequency" (lpFrequency AS QUAD) AS LONG
                              DECLARE FUNCTION QueryPerformanceCounter   LIB "KERNEL32.DLL" ALIAS "QueryPerformanceCounter" (lpPerformanceCount AS QUAD) AS LONG
                              
                              FUNCTION PBMAIN () AS LONG
                              
                              LOCAL freq, count0, count1 AS QUAD
                              
                              QueryPerformanceFrequency freq   'Get timer frequency.
                              
                              QueryPerformanceCounter count0   'read the timer at the start of the test
                              
                              DO
                                  SLEEP 1
                                  count0=count1
                                  QueryPerformanceCounter count1
                                  LOCATE 1,1
                                  PRINT FORMAT$(1000*(count1-count0)/freq,"######0.000");"msec              "  'print the elapsed time
                                  
                              LOOP UNTIL INSTAT
                              
                              END FUNCTION
                              As you increase the SLEEP value from 1 to 20 in steps of 1ms you'll see what happens to the actual SLEEP time you get.

                              Now, while that program is running with the SLEEP set to 1msec, try running the following code and look at what happens to the SLEEP time in the first program.

                              Code:
                              REM use a TIMER TO 0.001s
                              
                              $INCLUDE "WIN32API.INC"
                              DECLARE FUNCTION test( BYVAL uID AS LONG, BYVAL uMsg AS LONG, _
                                                       BYVAL dwUser AS LONG, BYVAL dw1 AS LONG, BYVAL dw2 AS LONG) AS LONG
                              
                              GLOBAL COUNT AS LONG
                              
                              FUNCTION WINMAIN (BYVAL hInstance     AS LONG, _
                                                BYVAL hPrevInstance AS LONG, _
                                                BYVAL lpCmdLine           AS ASCIIZ PTR, _
                                                BYVAL iCmdShow      AS LONG) AS LONG
                              
                              'start the timer
                              '1=milliseconds between triggers, 0=maximum timer resolution, test=the routine to call
                              TimerHandle& = timeSetEvent ( BYVAL 1, BYVAL 0, CODEPTR(test), BYVAL 0&, BYVAL %TIME_PERIODIC)
                              
                              PRINT "press a key to end."
                              DO
                                 LOCATE 10,10
                                 PRINT "Time=";FORMAT$(count&/1000,"#######.###");"secs."
                                 SLEEP 1
                                 LOOP UNTIL INSTAT
                              
                                 timeKillEvent TimerHandle&
                              
                              END FUNCTION
                              
                              FUNCTION test ( BYVAL uID AS LONG, BYVAL uMsg AS LONG, _
                                                      BYVAL dwUser AS LONG, BYVAL dw1 AS LONG, BYVAL dw2 AS LONG) AS LONG
                              'this is the routine that is run everytime the timer triggers
                              
                                    INCR COUNT
                              END FUNCTION
                              Paul.

                              Comment


                              • #16
                                Originally posted by Chris Boss View Post
                                First thing I lreaned about threads (from a very good book by an expert) is don't modify the GUI from worker threads.
                                Chris,

                                Do you remember the book? I'd like to pick it up if I don't have it.

                                Brian

                                Comment


                                • #17
                                  The book is:

                                  Multithreading Applications in Win32
                                  by Jim Beveridge and Robert Wiener
                                  Published by Addison Wesley Developers Press
                                  Copyright 1997

                                  Here it is on Amazon:

                                  Chris Boss
                                  Computer Workshop
                                  Developer of "EZGUI"
                                  http://cwsof.com
                                  http://twitter.com/EZGUIProGuy

                                  Comment


                                  • #18
                                    the core answer unless someone can correct me is...test on multiple machines, and a number you can live with
                                    Code:
                                      === USER OPTIONS===
                                       User Display name  [John Q Public               ]
                                    [b]   Loop Delay           [    ][/b]
                                    
                                     ===================
                                    Michael Mattias
                                    Tal Systems (retired)
                                    Port Washington WI USA
                                    [email protected]
                                    http://www.talsystems.com

                                    Comment


                                    • #19
                                      .. problems related to context-switching derive from parallel (outside) applications
                                      Those aren't problems, that's what Windows is designed to do... provide multi-tasking.

                                      BTW, setting the priority is system-wide, not just relative to other threads of your application. If some other application has set its priority above "normal" that's a problem with the other software.

                                      Also, Windows DOES give more time to the thread owning the current active Window. (Buried in the doc for the SetActiveWindow function).

                                      I have said many many times optimization is always application-specific. If you have some application giving you difficulty, the first step is to use the PROFILE function (see in compiler's help file) to identify the procedures taking the most time. Then you can put your effort into optimizing the true "time-hogs" and not waste time tinkering around the margins.

                                      Before you start playing with system priorities, you need to take a close look at your application and make sure your own house is in order.



                                      MCM
                                      Last edited by Michael Mattias; 29 Feb 2008, 08:01 AM.
                                      Michael Mattias
                                      Tal Systems (retired)
                                      Port Washington WI USA
                                      [email protected]
                                      http://www.talsystems.com

                                      Comment

                                      Working...
                                      X