I've put the following demo together based on my understanding of what im supposed to be doing (perhaps im not on the right track i dont know as this is my first year with OSX), but it's not quite working, whereas the Windows equivalent works perfectly.
TO TEST that my code is locked onto a particular core i call CPUID to retrieve the APIC ID unique to each logical core, which is simply:
Code: Select all
! xor ecx, ecx
! mov eax, 0xB ;cpu topology leaf
! cpuid
mov APICID, edx
wikipedia wrote:Unlike most other CPUID leaves, leaf Bh will return different values in EDX depending on which logical processor the CPUID instruction runs; the value returned in EDX is actually the x2APIC id of the logical processor.
ANYWAY! I tested on Windows (using winapi) and YES, as expected it returns a unique id for each core - just a low number like 1, 2 etc.
But then I tried it on OSX (using pthread api), and it's not quite working as i would expect... the SET and GET affinity functions are both successful, yet when retrieving the CPU APIC ID on my 4-core system i get results like "0,0,0,1", "3,3,3,3", "0,0,0,0", "1,1,1,2" etc (it should be returning something like "0,1,2,3", maybe not in order but each unique), so it does sort of seem to be switching, but just not exactly to the requirement!
Anyway ive spent the last two days on this but im stuck so must ask for help! Does anyone have any ideas?
Code: Select all
EnableExplicit
#THREAD_AFFINITY_POLICY = 4
#THREAD_AFFINITY_POLICY_COUNT = 1
ImportC ""
thread_policy_get.i (machthread, flavor, *policy, *count, *getdefault)
thread_policy_set.i (machthread, flavor, *policy, count)
pthread_self.i()
pthread_mach_thread_np.i(thread)
sysctlbyname(sysname.i, *count, *countlen, other, other2)
EndImport
Global CPUCnt
Procedure.i GetCPUCount()
Protected count, count_len = SizeOf(count), *bufname
*bufname = AllocateMemory(512)
PokeS(*bufname, "hw.logicalcpu", -1, #PB_Ascii)
If sysctlbyname(*bufname, @count, @count_len, #Null, 0) <> 0: count = 1: EndIf
If count = 0: count = 1: EndIf
ProcedureReturn count
EndProcedure
Procedure.l SingleCoreAffinityMask(corenum) ;first corenum is 0 which returns 1, core 1 returns 2, core 2 returns 4, etc
ProcedureReturn 1 << corenum
EndProcedure
Procedure SetThreadCPUAffinity(hThread, CPUCore)
Protected cpubits = SingleCoreAffinityMask(CPUCore) ;set new core
If thread_policy_set(hThread, #THREAD_AFFINITY_POLICY, @cpubits, #THREAD_AFFINITY_POLICY_COUNT) = 0
ProcedureReturn cpubits
Else
ProcedureReturn 0
EndIf
EndProcedure
Procedure.l GetThreadCPUAffinity(hThread)
Protected count, cpubits, getdefault
getdefault = #False: count = 1
If thread_policy_get(hThread, #THREAD_AFFINITY_POLICY, @cpubits, @count, @getdefault) = 0
ProcedureReturn cpubits
Else
ProcedureReturn 0
EndIf
EndProcedure
;Return the unique APIC ID that each logical CPU has
Procedure.i GetAPICID()
DisableDebugger
EnableASM
Protected result.l
! xor ecx, ecx
! mov eax, 0xB
! cpuid
mov result, edx
DisableASM
ProcedureReturn result
EnableDebugger
EndProcedure
;The main thread which sets its affinity to each CPU one at a time
Procedure CPUThread(threadval.i)
Protected CPU.i, hThread = pthread_mach_thread_np(pthread_self())
For CPU = 0 To CPUCnt-1
Debug "Trying logical core #" + Str(CPU) + "... (Set/Get = 0 on error)"
Debug " SETAFFINITY=" + Str( SetThreadCPUAffinity(hThread, CPU) )
Debug " GETAFFINITY=" + Str(GetThreadCPUAffinity(hThread))
Debug " CPU APIC ID=" + Str(GetAPICID()) + " (can be 0 but should be unique on each core)"
Next CPU
EndProcedure
CPUCnt = GetCPUCount()
Debug "Logical CPU Count = " + Str(CPUCnt)
CreateThread(@CPUThread(), #Null)
MessageRequester("OK","Done")