04008c8439b294c40e670b4ea71471fa71ef9d69vboxsync/* $Id$ */
04008c8439b294c40e670b4ea71471fa71ef9d69vboxsync/** @file
5b281ba489ca18f0380d7efc7a5108b606cce449vboxsync * IPRT - Multiprocessor, Windows.
04008c8439b294c40e670b4ea71471fa71ef9d69vboxsync */
04008c8439b294c40e670b4ea71471fa71ef9d69vboxsync
04008c8439b294c40e670b4ea71471fa71ef9d69vboxsync/*
c58f1213e628a545081c70e26c6b67a841cff880vboxsync * Copyright (C) 2006-2011 Oracle Corporation
04008c8439b294c40e670b4ea71471fa71ef9d69vboxsync *
04008c8439b294c40e670b4ea71471fa71ef9d69vboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
04008c8439b294c40e670b4ea71471fa71ef9d69vboxsync * available from http://www.virtualbox.org. This file is free software;
04008c8439b294c40e670b4ea71471fa71ef9d69vboxsync * you can redistribute it and/or modify it under the terms of the GNU
04008c8439b294c40e670b4ea71471fa71ef9d69vboxsync * General Public License (GPL) as published by the Free Software
04008c8439b294c40e670b4ea71471fa71ef9d69vboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
04008c8439b294c40e670b4ea71471fa71ef9d69vboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
04008c8439b294c40e670b4ea71471fa71ef9d69vboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
04008c8439b294c40e670b4ea71471fa71ef9d69vboxsync *
04008c8439b294c40e670b4ea71471fa71ef9d69vboxsync * The contents of this file may alternatively be used under the terms
04008c8439b294c40e670b4ea71471fa71ef9d69vboxsync * of the Common Development and Distribution License Version 1.0
04008c8439b294c40e670b4ea71471fa71ef9d69vboxsync * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
04008c8439b294c40e670b4ea71471fa71ef9d69vboxsync * VirtualBox OSE distribution, in which case the provisions of the
04008c8439b294c40e670b4ea71471fa71ef9d69vboxsync * CDDL are applicable instead of those of the GPL.
04008c8439b294c40e670b4ea71471fa71ef9d69vboxsync *
04008c8439b294c40e670b4ea71471fa71ef9d69vboxsync * You may elect to license modified versions of this file under the
04008c8439b294c40e670b4ea71471fa71ef9d69vboxsync * terms and conditions of either the GPL or the CDDL or both.
04008c8439b294c40e670b4ea71471fa71ef9d69vboxsync */
04008c8439b294c40e670b4ea71471fa71ef9d69vboxsync
04008c8439b294c40e670b4ea71471fa71ef9d69vboxsync
04008c8439b294c40e670b4ea71471fa71ef9d69vboxsync/*******************************************************************************
04008c8439b294c40e670b4ea71471fa71ef9d69vboxsync* Header Files *
04008c8439b294c40e670b4ea71471fa71ef9d69vboxsync*******************************************************************************/
04008c8439b294c40e670b4ea71471fa71ef9d69vboxsync#define LOG_GROUP RTLOGGROUP_SYSTEM
04008c8439b294c40e670b4ea71471fa71ef9d69vboxsync#include <Windows.h>
e09c51deede0562a56286bbc2ec85800a1f4ed71vboxsync
04008c8439b294c40e670b4ea71471fa71ef9d69vboxsync#include <iprt/mp.h>
e09c51deede0562a56286bbc2ec85800a1f4ed71vboxsync#include "internal/iprt.h"
e09c51deede0562a56286bbc2ec85800a1f4ed71vboxsync
04008c8439b294c40e670b4ea71471fa71ef9d69vboxsync#include <iprt/assert.h>
e09c51deede0562a56286bbc2ec85800a1f4ed71vboxsync#include <iprt/cpuset.h>
e09c51deede0562a56286bbc2ec85800a1f4ed71vboxsync#include <iprt/ldr.h>
30b7df5362e14427bd0962b31aa72ec2247ca9c3vboxsync#include <iprt/mem.h>
04008c8439b294c40e670b4ea71471fa71ef9d69vboxsync
04008c8439b294c40e670b4ea71471fa71ef9d69vboxsync
c2ac210bd84591123bb8803712887e2b016cb78fvboxsyncAssertCompile(MAXIMUM_PROCESSORS <= RTCPUSET_MAX_CPUS);
c2ac210bd84591123bb8803712887e2b016cb78fvboxsync
c2ac210bd84591123bb8803712887e2b016cb78fvboxsync
04008c8439b294c40e670b4ea71471fa71ef9d69vboxsync/** @todo RTmpCpuId(). */
04008c8439b294c40e670b4ea71471fa71ef9d69vboxsync
04008c8439b294c40e670b4ea71471fa71ef9d69vboxsyncRTDECL(int) RTMpCpuIdToSetIndex(RTCPUID idCpu)
04008c8439b294c40e670b4ea71471fa71ef9d69vboxsync{
04008c8439b294c40e670b4ea71471fa71ef9d69vboxsync return idCpu < MAXIMUM_PROCESSORS ? idCpu : -1;
04008c8439b294c40e670b4ea71471fa71ef9d69vboxsync}
04008c8439b294c40e670b4ea71471fa71ef9d69vboxsync
04008c8439b294c40e670b4ea71471fa71ef9d69vboxsync
04008c8439b294c40e670b4ea71471fa71ef9d69vboxsyncRTDECL(RTCPUID) RTMpCpuIdFromSetIndex(int iCpu)
04008c8439b294c40e670b4ea71471fa71ef9d69vboxsync{
04008c8439b294c40e670b4ea71471fa71ef9d69vboxsync return (unsigned)iCpu < MAXIMUM_PROCESSORS ? iCpu : NIL_RTCPUID;
04008c8439b294c40e670b4ea71471fa71ef9d69vboxsync}
04008c8439b294c40e670b4ea71471fa71ef9d69vboxsync
04008c8439b294c40e670b4ea71471fa71ef9d69vboxsync
04008c8439b294c40e670b4ea71471fa71ef9d69vboxsyncRTDECL(RTCPUID) RTMpGetMaxCpuId(void)
04008c8439b294c40e670b4ea71471fa71ef9d69vboxsync{
04008c8439b294c40e670b4ea71471fa71ef9d69vboxsync return MAXIMUM_PROCESSORS - 1;
04008c8439b294c40e670b4ea71471fa71ef9d69vboxsync}
04008c8439b294c40e670b4ea71471fa71ef9d69vboxsync
04008c8439b294c40e670b4ea71471fa71ef9d69vboxsync
04008c8439b294c40e670b4ea71471fa71ef9d69vboxsyncRTDECL(bool) RTMpIsCpuOnline(RTCPUID idCpu)
04008c8439b294c40e670b4ea71471fa71ef9d69vboxsync{
04008c8439b294c40e670b4ea71471fa71ef9d69vboxsync RTCPUSET Set;
04008c8439b294c40e670b4ea71471fa71ef9d69vboxsync return RTCpuSetIsMember(RTMpGetOnlineSet(&Set), idCpu);
04008c8439b294c40e670b4ea71471fa71ef9d69vboxsync}
04008c8439b294c40e670b4ea71471fa71ef9d69vboxsync
04008c8439b294c40e670b4ea71471fa71ef9d69vboxsync
2a560b28131ee7efa5b73a9e9cbfdb08eae28624vboxsyncRTDECL(bool) RTMpIsCpuPossible(RTCPUID idCpu)
04008c8439b294c40e670b4ea71471fa71ef9d69vboxsync{
04008c8439b294c40e670b4ea71471fa71ef9d69vboxsync RTCPUSET Set;
04008c8439b294c40e670b4ea71471fa71ef9d69vboxsync return RTCpuSetIsMember(RTMpGetSet(&Set), idCpu);
04008c8439b294c40e670b4ea71471fa71ef9d69vboxsync}
04008c8439b294c40e670b4ea71471fa71ef9d69vboxsync
04008c8439b294c40e670b4ea71471fa71ef9d69vboxsync
04008c8439b294c40e670b4ea71471fa71ef9d69vboxsyncRTDECL(PRTCPUSET) RTMpGetSet(PRTCPUSET pSet)
04008c8439b294c40e670b4ea71471fa71ef9d69vboxsync{
04008c8439b294c40e670b4ea71471fa71ef9d69vboxsync RTCPUID idCpu = RTMpGetCount();
04008c8439b294c40e670b4ea71471fa71ef9d69vboxsync RTCpuSetEmpty(pSet);
04008c8439b294c40e670b4ea71471fa71ef9d69vboxsync while (idCpu-- > 0)
04008c8439b294c40e670b4ea71471fa71ef9d69vboxsync RTCpuSetAdd(pSet, idCpu);
04008c8439b294c40e670b4ea71471fa71ef9d69vboxsync return pSet;
04008c8439b294c40e670b4ea71471fa71ef9d69vboxsync}
04008c8439b294c40e670b4ea71471fa71ef9d69vboxsync
04008c8439b294c40e670b4ea71471fa71ef9d69vboxsync
04008c8439b294c40e670b4ea71471fa71ef9d69vboxsyncRTDECL(RTCPUID) RTMpGetCount(void)
04008c8439b294c40e670b4ea71471fa71ef9d69vboxsync{
04008c8439b294c40e670b4ea71471fa71ef9d69vboxsync SYSTEM_INFO SysInfo;
04008c8439b294c40e670b4ea71471fa71ef9d69vboxsync GetSystemInfo(&SysInfo);
04008c8439b294c40e670b4ea71471fa71ef9d69vboxsync Assert((RTCPUID)SysInfo.dwNumberOfProcessors == SysInfo.dwNumberOfProcessors);
04008c8439b294c40e670b4ea71471fa71ef9d69vboxsync return SysInfo.dwNumberOfProcessors;
04008c8439b294c40e670b4ea71471fa71ef9d69vboxsync}
04008c8439b294c40e670b4ea71471fa71ef9d69vboxsync
e09c51deede0562a56286bbc2ec85800a1f4ed71vboxsync
f1958d2f336573471dde3a866c66783221ab7fdbvboxsyncRTDECL(RTCPUID) RTMpGetCoreCount(void)
f1958d2f336573471dde3a866c66783221ab7fdbvboxsync{
e09c51deede0562a56286bbc2ec85800a1f4ed71vboxsync /*
e09c51deede0562a56286bbc2ec85800a1f4ed71vboxsync * Resolve the API dynamically (one try) as it requires XP w/ sp3 or later.
23a1e55fcdecaaa825c4d9283002a41ac7c25e75vboxsync */
e09c51deede0562a56286bbc2ec85800a1f4ed71vboxsync typedef BOOL (WINAPI *PFNGETLOGICALPROCINFO)(PSYSTEM_LOGICAL_PROCESSOR_INFORMATION, PDWORD);
e09c51deede0562a56286bbc2ec85800a1f4ed71vboxsync static PFNGETLOGICALPROCINFO s_pfnGetLogicalProcInfo = (PFNGETLOGICALPROCINFO)~(uintptr_t)0;
e09c51deede0562a56286bbc2ec85800a1f4ed71vboxsync if (s_pfnGetLogicalProcInfo == (PFNGETLOGICALPROCINFO)~(uintptr_t)0)
e09c51deede0562a56286bbc2ec85800a1f4ed71vboxsync s_pfnGetLogicalProcInfo = (PFNGETLOGICALPROCINFO)RTLdrGetSystemSymbol("kernel32.dll", "GetLogicalProcessorInformation");
e09c51deede0562a56286bbc2ec85800a1f4ed71vboxsync
23a1e55fcdecaaa825c4d9283002a41ac7c25e75vboxsync /*
23a1e55fcdecaaa825c4d9283002a41ac7c25e75vboxsync * Sadly, on XP and Server 2003, even if the API is present, it does not tell us
23a1e55fcdecaaa825c4d9283002a41ac7c25e75vboxsync * how many physical cores there are (any package will look like a single core).
23a1e55fcdecaaa825c4d9283002a41ac7c25e75vboxsync * That is worse than not using the API at all, so just skip it unless it's Vista+.
23a1e55fcdecaaa825c4d9283002a41ac7c25e75vboxsync */
23a1e55fcdecaaa825c4d9283002a41ac7c25e75vboxsync bool fIsVistaOrLater = false;
23a1e55fcdecaaa825c4d9283002a41ac7c25e75vboxsync OSVERSIONINFOEX OSInfoEx = { 0 };
23a1e55fcdecaaa825c4d9283002a41ac7c25e75vboxsync OSInfoEx.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
23a1e55fcdecaaa825c4d9283002a41ac7c25e75vboxsync if ( GetVersionEx((LPOSVERSIONINFO) &OSInfoEx)
23a1e55fcdecaaa825c4d9283002a41ac7c25e75vboxsync && (OSInfoEx.dwPlatformId == VER_PLATFORM_WIN32_NT)
23a1e55fcdecaaa825c4d9283002a41ac7c25e75vboxsync && (OSInfoEx.dwMajorVersion >= 6))
23a1e55fcdecaaa825c4d9283002a41ac7c25e75vboxsync fIsVistaOrLater = true;
23a1e55fcdecaaa825c4d9283002a41ac7c25e75vboxsync
23a1e55fcdecaaa825c4d9283002a41ac7c25e75vboxsync if (s_pfnGetLogicalProcInfo && fIsVistaOrLater)
f1958d2f336573471dde3a866c66783221ab7fdbvboxsync {
e09c51deede0562a56286bbc2ec85800a1f4ed71vboxsync /*
e09c51deede0562a56286bbc2ec85800a1f4ed71vboxsync * Query the information. This unfortunately requires a buffer, so we
e09c51deede0562a56286bbc2ec85800a1f4ed71vboxsync * start with a guess and let windows advice us if it's too small.
e09c51deede0562a56286bbc2ec85800a1f4ed71vboxsync */
b57a5b02e2215fe4653328ceb8cc9975d557dad9vboxsync DWORD cbSysProcInfo = _4K;
e09c51deede0562a56286bbc2ec85800a1f4ed71vboxsync PSYSTEM_LOGICAL_PROCESSOR_INFORMATION paSysInfo = NULL;
e09c51deede0562a56286bbc2ec85800a1f4ed71vboxsync BOOL fRc = FALSE;
e09c51deede0562a56286bbc2ec85800a1f4ed71vboxsync do
e09c51deede0562a56286bbc2ec85800a1f4ed71vboxsync {
e09c51deede0562a56286bbc2ec85800a1f4ed71vboxsync cbSysProcInfo = RT_ALIGN_32(cbSysProcInfo, 256);
e09c51deede0562a56286bbc2ec85800a1f4ed71vboxsync void *pv = RTMemRealloc(paSysInfo, cbSysProcInfo);
e09c51deede0562a56286bbc2ec85800a1f4ed71vboxsync if (!pv)
e09c51deede0562a56286bbc2ec85800a1f4ed71vboxsync break;
e09c51deede0562a56286bbc2ec85800a1f4ed71vboxsync paSysInfo = (PSYSTEM_LOGICAL_PROCESSOR_INFORMATION)pv;
e09c51deede0562a56286bbc2ec85800a1f4ed71vboxsync fRc = s_pfnGetLogicalProcInfo(paSysInfo, &cbSysProcInfo);
e09c51deede0562a56286bbc2ec85800a1f4ed71vboxsync } while (!fRc && GetLastError() == ERROR_INSUFFICIENT_BUFFER);
9cd42f2598c236d3c5e47f3e5bf21d4e96f001edvboxsync if (fRc)
f1958d2f336573471dde3a866c66783221ab7fdbvboxsync {
e09c51deede0562a56286bbc2ec85800a1f4ed71vboxsync /*
e09c51deede0562a56286bbc2ec85800a1f4ed71vboxsync * Parse the result.
e09c51deede0562a56286bbc2ec85800a1f4ed71vboxsync */
e09c51deede0562a56286bbc2ec85800a1f4ed71vboxsync uint32_t cCores = 0;
e09c51deede0562a56286bbc2ec85800a1f4ed71vboxsync uint32_t i = cbSysProcInfo / sizeof(paSysInfo[0]);
e09c51deede0562a56286bbc2ec85800a1f4ed71vboxsync while (i-- > 0)
e09c51deede0562a56286bbc2ec85800a1f4ed71vboxsync if (paSysInfo[i].Relationship == RelationProcessorCore)
e09c51deede0562a56286bbc2ec85800a1f4ed71vboxsync cCores++;
e09c51deede0562a56286bbc2ec85800a1f4ed71vboxsync
e09c51deede0562a56286bbc2ec85800a1f4ed71vboxsync RTMemFree(paSysInfo);
e09c51deede0562a56286bbc2ec85800a1f4ed71vboxsync Assert(cCores > 0);
e09c51deede0562a56286bbc2ec85800a1f4ed71vboxsync return cCores;
f1958d2f336573471dde3a866c66783221ab7fdbvboxsync }
e09c51deede0562a56286bbc2ec85800a1f4ed71vboxsync
e09c51deede0562a56286bbc2ec85800a1f4ed71vboxsync RTMemFree(paSysInfo);
f1958d2f336573471dde3a866c66783221ab7fdbvboxsync }
e09c51deede0562a56286bbc2ec85800a1f4ed71vboxsync
e09c51deede0562a56286bbc2ec85800a1f4ed71vboxsync /* If we don't have the necessary API or if it failed, return the same
e09c51deede0562a56286bbc2ec85800a1f4ed71vboxsync value as the generic implementation. */
e09c51deede0562a56286bbc2ec85800a1f4ed71vboxsync return RTMpGetCount();
f1958d2f336573471dde3a866c66783221ab7fdbvboxsync}
04008c8439b294c40e670b4ea71471fa71ef9d69vboxsync
e09c51deede0562a56286bbc2ec85800a1f4ed71vboxsync
04008c8439b294c40e670b4ea71471fa71ef9d69vboxsyncRTDECL(PRTCPUSET) RTMpGetOnlineSet(PRTCPUSET pSet)
04008c8439b294c40e670b4ea71471fa71ef9d69vboxsync{
04008c8439b294c40e670b4ea71471fa71ef9d69vboxsync SYSTEM_INFO SysInfo;
04008c8439b294c40e670b4ea71471fa71ef9d69vboxsync GetSystemInfo(&SysInfo);
1b396f7f5a76d66e62fc9d8e66dcbe8e7bf72039vboxsync/** @todo port to W2K8 / W7 w/ > 64 CPUs & grouping. */
04008c8439b294c40e670b4ea71471fa71ef9d69vboxsync return RTCpuSetFromU64(pSet, SysInfo.dwActiveProcessorMask);
04008c8439b294c40e670b4ea71471fa71ef9d69vboxsync}
04008c8439b294c40e670b4ea71471fa71ef9d69vboxsync
04008c8439b294c40e670b4ea71471fa71ef9d69vboxsync
04008c8439b294c40e670b4ea71471fa71ef9d69vboxsyncRTDECL(RTCPUID) RTMpGetOnlineCount(void)
04008c8439b294c40e670b4ea71471fa71ef9d69vboxsync{
04008c8439b294c40e670b4ea71471fa71ef9d69vboxsync RTCPUSET Set;
04008c8439b294c40e670b4ea71471fa71ef9d69vboxsync RTMpGetOnlineSet(&Set);
04008c8439b294c40e670b4ea71471fa71ef9d69vboxsync return RTCpuSetCount(&Set);
04008c8439b294c40e670b4ea71471fa71ef9d69vboxsync}
04008c8439b294c40e670b4ea71471fa71ef9d69vboxsync
04bce18d27791abed8346aba0de41c53a2acd81avboxsync
04bce18d27791abed8346aba0de41c53a2acd81avboxsyncRTDECL(RTCPUID) RTMpGetOnlineCoreCount(void)
04bce18d27791abed8346aba0de41c53a2acd81avboxsync{
04bce18d27791abed8346aba0de41c53a2acd81avboxsync /** @todo this isn't entirely correct. */
04bce18d27791abed8346aba0de41c53a2acd81avboxsync return RTMpGetCoreCount();
04bce18d27791abed8346aba0de41c53a2acd81avboxsync}
04bce18d27791abed8346aba0de41c53a2acd81avboxsync