Przemyslaw Czerpak wrote:
> The results are much worse then in my Linux box.
> It can be caused be few reasons:
> 1. the cost of task switching is probably much higher in OS2 then
>    in Linux because it has to reload memory descriptors for each
>    thread - it's forced by TLS format.
I don't know

> 2. The cost of simultaneous memory allocation very high. Here other
>    MM should help.
It could be, I'm not sure of the quality of GCC runtime on OS/2

> 3. The overhead caused by freezing thread in critical section is very high.
You're using mutexes for critical sections, in OS/2 there is a
DosEnterCritSection() call which stops task switching until after a
DosExitCritSection() is called.

BUT you must not call other APIs while inside a critical section, otherwise a
deadlock may occur.

Now, if you don't call other functions inside critical sections (even C
runtime ones) we could try to use them to see if speed changes.

>    In all tests there are only two Harbour mutexes which are used (I do not
>    count thread start/stop synchronization because this code is called only
>    ones):
>       1-st inside hb_dynsymFind() which is used by these tests:
>          [ x := &( "f1(" + str(i) + ")" ) ].............................50.81
>          [ bc := &( "{|x|f1(x)}" ); eval( bc, i ) ]....................142.90
>       2-nd inside garbage.c used to add/remove each new GC block to linked
>            list. It's used by tests which allocates/deallocates new GC items 
>            in each loop:

Here if allocation occurs it could deadlock if using DosEnterCritSection()

>    This are the most expensive tests and please look at the difference for
>    the same tests but when existing codeblocks are reused.
>    Codeblock create in each loop and then evaluated:
>       [ eval( { || i % 16 } ) ].....................................138.32
>    Codeblock create in outside the loop and evaluated:
>       [ eval( bc := { || i % 16 } ) ].................................1.02

Terrific!

>    I'll add also test for creating and coping empty array to easier see this
>    overhead.
>    The code covered by critical section inside garbage.c is minimal:
>          HB_GC_LOCK
>          hb_gc[Un]Link( &s_pCurrBlock, pAlloc );
>          HB_GC_UNLOCK
>    and hb_gc[Un]Link() is very simple and short, f.e. hb_gcLink() look:
> 
>          static void hb_gcLink( HB_GARBAGE_PTR *pList, HB_GARBAGE_PTR pAlloc )
>          {
>             if( *pList )
>             {
>                pAlloc->pNext = *pList;
>                pAlloc->pPrev = (*pList)->pPrev;
>                pAlloc->pPrev->pNext = pAlloc;
>                (*pList)->pPrev = pAlloc;
>             }
>             else
>                *pList = pAlloc->pNext = pAlloc->pPrev = pAlloc;
>          }
>    It's only few machine instructions.

This could work with DosEnterCritSection() since it is not calling other APIs.

>    This suggests that the whole overhead is caused by very huge cost
>    of critical sections in OS2. Because it's such simple and short code
>    which should be executed extremely fast then we can try to use our own
>    spinlocks instead of OS level semaphores which seems to be not efficient
>    enough. The code covered by critical section is probably less then 1%
>    of whole code executed in LOOP but kills the performance in OS2. 

The only fear is that OS/2 critical sections could not scale well on real
multi-cpus

>    It's
>    probably caused by series of two locks (MM probably also has its own
>    critical section) which exploits some bad synchronization behavior in
>    OS2 or just simply mutexes are such expensive in this system.

I think the second answer could be the one.

>    If you are interested then I can implement small ASM inline function
>    for OS2 GCC builds and we can compare the results.
> 
It could be an interesting thing if you don't care wasting some time to
speedup OS/2 :) (you're nearly becoming an OS/2 user, after all :D) but I
won't be able to do more test before next monday morning.

Plese see this link, which deals with mutexes on OS/2 SMP kernels and uses
faster mutexes to scale better.

http://www.edm2.com/0507/smp.html

Thanks a lot.

Maurilio.

PS.

Disables thread switching for the current process.

#define INCL_DOSPROCESS
#include <os2.h>

APIRET    ulrc;  /*  Return Code. */

ulrc = DosEnterCritSec();

ulrc (APIRET) - returns
Return Code.

DosEnterCritSec returns one of the following values:

0 NO_ERROR
309 ERROR_INVALID_THREADID
484 ERROR_CRITSEC_OVERFLOW

For a full list of error codes, see Errors.

DosEnterCritSec causes all other threads in the process to block themselves
and give up their time slice. After a DosEnterCritSec request is made, no
functions should be called that depend on another thread to do processing
until DosExitCritSec has completed. Great care should be taken when using
compiler runtime functions and other OS/2 functions after a DosEnterCritSec
request has been made, since the underlying processing of the called function
may require processing by another thread and thus cause a deadlock.

A thread can also execute code without having to give up time slices to other
threads in its process if it requests a priority class that is higher than
those of the other threads. A thread's priority is examined with
DosGetInfoBlocks, and changed with DosSetPriority.

A count is maintained of the number of times DosEnterCritSec is issued without
a corresponding DosExitCritSec. The count is incremented by DosEnterCritSec
and decremented by DosExitCritSec. Normal thread dispatching is not restored
until the count is zero. The outstanding DosEnterCritSec count is maintained
in a word. If an overflow occurs, the count is set to the maximum value, no
operation is performed, and the request returns with ERROR_CRITSEC_OVERFLOW.

If a signal occurs, thread 1 begins execution to process the signal even
though another thread in the process has a DosEnterCritSec active. Thread 1 of
a process is its initial thread of execution, not a thread created with
DosCreateThread. Any processing done by thread 1 to satisfy the signal must
not include accessing the critical resource intended to be protected by
DosEnterCritSec.

Note: This function is very powerful and must be used with caution! It should
be used only in a most cooperative environment where the state of all threads
in known. While in the critical section, do not call other compiler runtime or
OS/2 functions that could start another thread that it would depend on running
before being able to return.


DosQueryThreadContext can be used to obtain the context of other threads in
the process once they have been blocked by DosEnterCritSec.

ERROR_INVALID_THREADID is returned when an invalid attempt is made to enter a
critical section of code in a signal handler or exception handler.

ERROR_INVALID_THREADID is also returned when a dynamic link library (DLL)
routine incorrectly issues DosEnterCritSec.

This example shows how a thread enters and exits a critical section of code.

 #define INCL_DOSPROCESS      /* Process values */
 #define INCL_DOSERRORS       /* Error values */
 #include <os2.h>
 #include <stdio.h>

 int main(VOID)
   {
   APIRET  rc = NO_ERROR;    /* Return code */

    rc = DosEnterCritSec();

    if (rc != NO_ERROR) {
        printf("DosEnterCritSec error: return code = %u\n",rc);
        return 1;
    }
      /***********************************************/
      /* Add critical section code here.  While this */
      /* code is running, all other threads are      */
      /* stopped.  CALL NO LIBRARY OR OS/2 FUNCTIONS */
      /* HERE UNLESS YOU KNOW THEY DO NOT REQUIRE    */
      /* ACTION BY ANOTHER THREAD IN THE PROCESS.    */
      /***********************************************/

    rc =  DosExitCritSec();

    if (rc != NO_ERROR) {
        printf("DosExitCritSec error: return code = %u\n",rc);
        return 1;
    }

    return NO_ERROR;
    }




-- 
 __________
|  |  | |__| Maurilio Longo
|_|_|_|____| farmaconsult s.r.l.


_______________________________________________
Harbour mailing list
Harbour@harbour-project.org
http://lists.harbour-project.org/mailman/listinfo/harbour

Reply via email to