Set Affinity to uniprocessor still needed? (run exe on 1 core only)

Hi all,

In the C5/C6 days I used:
imagecfg -u myapp.exe
to set the affinity of myapp.exe to uniprocessor (1 core only).

I still use this behavior also in my C10 applications.

I can’t remember exactly why it has/had to be used.
Is it still necessary, can it hurt?

Best regards
Jeffrey

It was done because C5 could not handle multi-processor machines where 2 threads really were running simultaneously and would crash. IIRC I mainly saw it in the TopSpeed driver.

I do not do this currently in 10 or 11.

Another way is to call SetProcessorAffinity at the start of the program.

C6 introduced “true” threading.

There was also a free template floating around which made binding to a cpu core quick and easy, cant remember who wrote it though.

The IceTips code is wrong as is noted in the comments. It would work in a 2 processor system, which was common at the time. Today my old PC has 8 cores (16 logical), a new PC can have easily have 16 to 24 cores.

I’ll post my old code for any using <= C5.5 that want it built in. It may go a bit overboard finding a random Processor from the Mask allowed. Most code simply took #1 or #2. I think C5 will need a LIB with SetProcessAffinityMask() as it was not in Win32.LIB.

    Module('WinAPI')
        GetLastError(),PASCAL,LONG,DLL(1)
        GetCurrentProcess(),PASCAL,LONG,DLL(1)
        GetProcessAffinityMask(long hProcess, *LONG lpProcessAffinityMask, *LONG lpSystemAffinityMask),PASCAL,BOOL,DLL(1)
        SetProcessAffinityMask(long hProcess, LONG lpProcessAffinityMask),PASCAL,BOOL,DLL(1)
    End    
!----------------------------------------
AffinityFix          PROCEDURE 
ProMask     LONG        !Affinity Process Mask
SysMask     LONG        !Affinity System Mask
SetProMask  LONG        !Affinity Process Mask I set
bRtn        LONG        !Bool return from function
BitCnt      LONG,AUTO
BitHigh     LONG,AUTO
BitCls      CLASS
CountBits       PROCEDURE(LONG inBitMap),LONG
RandomBit       PROCEDURE(LONG inBitMap),LONG
            END
  CODE
    bRtn = GetProcessAffinityMask(GetCurrentProcess(), ProMask, SysMask)    !0=failed     !http://msdn.microsoft.com/en-us/library/ms683213(VS.85).aspx
?    DBg('AffinityFix','Get bRtn=' & bRtn & ' ProMask=' & ProMask & ' SysMask=' & SysMask )
    IF bRtn=0
        DBg('AffinityFix','Get Mask failed '& GetLastError() )
        RETURN
    END
    IF ProMask <= 2 THEN RETURN.             !1b or 10b(2) is fine, that's CPU 1 or 2

    BitCnt = BitCls.CountBits(ProMask)
    IF BitCnt < 2 THEN RETURN.               !Only 1 processor in my affinity mask so leave it. Could have been set by ImageCfg.
    BitCnt = BitCls.CountBits(SysMask)
    IF BitCnt < 2 THEN RETURN.               !System has only 1 processor in mask
    SetProMask = BitCls.RandomBit(SysMask)
    bRtn = SetProcessAffinityMask(GetCurrentProcess(),SetProMask)
        DBg('AffinityFix','Set(' & SetProMask & ') bRtn=' & bRtn & ' prior ProMask=' & ProMask & ' SysMask=' & SysMask & choose(bRtn>0,'','  Err=' & GetLastError()))
    bRtn = GetProcessAffinityMask(GetCurrentProcess(), ProMask, SysMask)
    DBg('AffinityFix','ReGet bRtn=' & bRtn & ' now ProMask=' & ProMask & ' SysMask=' & SysMask )
    RETURN

BitCls.CountBits       PROCEDURE(LONG inBitMap)!,LONG
BeeCnt     LONG,AUTO
bitNdx     LONG,AUTO
    CODE
    BeeCnt = 0
    LOOP bitNdx = 1 to 32
         IF BAND(inBitMap,1) THEN BeeCnt += 1.  !Bit is on, count it
         inBitMap = BSHIFT(inBitMap,-1)         !Shift Right, low bits fall off
    WHILE inBitMap                              !Stop Loop If Mask = Zero
    RETURN BeeCnt

BitCls.RandomBit       PROCEDURE(LONG inBitMap)!,LONG
BeeCnt      LONG,AUTO
bitOnNdx    LONG,AUTO
OneBitOn    LONG,AUTO
bitsFound   LONG,DIM(32),AUTO   !stick the bits I find on into this array
RandomBit   LONG,AUTO
    CODE
    BeeCnt = 0
    RandomBit = 0
    CLEAR(bitsFound[])
    OneBitOn = 1
    LOOP bitOnNdx = 1 to 32
         IF BAND(inBitMap,OneBitOn) THEN
             BeeCnt += 1
             bitsFound[BeeCnt] = OneBitOn
         END
         OneBitOn = BSHIFT(OneBitOn,1)
    WHILE inBitMap >= OneBitOn
    IF BeeCnt THEN
       bitOnNdx = random(1,BeeCnt)
       IF bitOnNdx THEN RandomBit = bitsFound[bitOnNdx].
    END
    RETURN RandomBit

This will need review and testing for systems with more than 32 processors.

Hi all,

I removed the affinity to uniprocessor, so my C10 application is running multi-core now. I have noticed that some complex forms with a lot of tabs and controls are running very fast now. When running on 1 core, the opening of the form sometimes (but too often) took a lot of time and my laptop fan was spinning a lot. With multi-core all is very fast and no noise of my laptop fan.

Best regards
Jeffrey

1 Like

With improvements made over time, the affinity is no longer needed.

If you run some apps which tie themselves to core0 or core1, in todays multi core multi processor, its a way to manually avoid those two busy cores.

Sure windows does a good job of load balancing the workload across multiple cores, but I’ve yet to see if windows will move a cpu intensive thread onto a core which has a light workload, or a core better suited for the type of work its doing.