blob: e78872761f8e77373ef8557a54f6d1c95f9d7255 [file] [log] [blame]
/*
* Copyright (c) 2011-2013 Apple Inc. All rights reserved.
*
* @APPLE_APACHE_LICENSE_HEADER_START@
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* @APPLE_APACHE_LICENSE_HEADER_END@
*/
/*
* IMPORTANT: This header file describes INTERNAL interfaces to libdispatch
* which are subject to change in future releases of Mac OS X. Any applications
* relying on these interfaces WILL break.
*/
#ifndef __DISPATCH_SHIMS_HW_CONFIG__
#define __DISPATCH_SHIMS_HW_CONFIG__
#ifdef __SIZEOF_POINTER__
#define DISPATCH_SIZEOF_PTR __SIZEOF_POINTER__
#elif defined(_WIN64)
#define DISPATCH_SIZEOF_PTR 8
#elif defined(_WIN32)
#define DISPATCH_SIZEOF_PTR 4
#elif defined(_MSC_VER)
#error "could not determine pointer size as a constant int for MSVC"
#elif defined(__LP64__) || defined(__LLP64__)
#define DISPATCH_SIZEOF_PTR 8
#elif defined(__ILP32__)
#define DISPATCH_SIZEOF_PTR 4
#else
#error "could not determine pointer size as a constant int"
#endif // __SIZEOF_POINTER__
typedef enum {
_dispatch_hw_config_logical_cpus,
_dispatch_hw_config_physical_cpus,
_dispatch_hw_config_active_cpus,
} _dispatch_hw_config_t;
#if !defined(DISPATCH_HAVE_HW_CONFIG_COMMPAGE) && \
defined(_COMM_PAGE_LOGICAL_CPUS) && \
defined(_COMM_PAGE_PHYSICAL_CPUS) && defined(_COMM_PAGE_ACTIVE_CPUS)
#define DISPATCH_HAVE_HW_CONFIG_COMMPAGE 1
#endif
#if DISPATCH_HAVE_HW_CONFIG_COMMPAGE
DISPATCH_ALWAYS_INLINE
static inline uint32_t
_dispatch_hw_get_config(_dispatch_hw_config_t c)
{
uintptr_t p;
switch (c) {
case _dispatch_hw_config_logical_cpus:
p = _COMM_PAGE_LOGICAL_CPUS; break;
case _dispatch_hw_config_physical_cpus:
p = _COMM_PAGE_PHYSICAL_CPUS; break;
case _dispatch_hw_config_active_cpus:
p = _COMM_PAGE_ACTIVE_CPUS; break;
}
return *(uint8_t*)p;
}
#define dispatch_hw_config(c) \
_dispatch_hw_get_config(_dispatch_hw_config_##c)
#define DISPATCH_HW_CONFIG()
#define _dispatch_hw_config_init()
#else // DISPATCH_HAVE_HW_CONFIG_COMMPAGE
extern struct _dispatch_hw_configs_s {
uint32_t logical_cpus;
uint32_t physical_cpus;
uint32_t active_cpus;
} _dispatch_hw_config;
#define DISPATCH_HW_CONFIG() struct _dispatch_hw_configs_s _dispatch_hw_config
#define dispatch_hw_config(c) (_dispatch_hw_config.c)
DISPATCH_ALWAYS_INLINE
static inline uint32_t
_dispatch_hw_get_config(_dispatch_hw_config_t c)
{
uint32_t val = 1;
#if defined(__linux__) && HAVE_SYSCONF
switch (c) {
case _dispatch_hw_config_logical_cpus:
case _dispatch_hw_config_physical_cpus:
return (uint32_t)sysconf(_SC_NPROCESSORS_CONF);
case _dispatch_hw_config_active_cpus:
{
#ifdef __USE_GNU
// Prefer pthread_getaffinity_np because it considers
// scheduler cpu affinity. This matters if the program
// is restricted to a subset of the online cpus (eg via numactl).
cpu_set_t cpuset;
if (pthread_getaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset) == 0)
return (uint32_t)CPU_COUNT(&cpuset);
#endif
return (uint32_t)sysconf(_SC_NPROCESSORS_ONLN);
}
}
#elif defined(_WIN32)
PSYSTEM_LOGICAL_PROCESSOR_INFORMATION slpiInfo = NULL;
PSYSTEM_LOGICAL_PROCESSOR_INFORMATION slpiCurrent = NULL;
DWORD dwProcessorLogicalCount = 0;
DWORD dwProcessorPackageCount = 0;
DWORD dwProcessorCoreCount = 0;
DWORD dwSize = 0;
while (true) {
DWORD dwResult;
if (GetLogicalProcessorInformation(slpiInfo, &dwSize))
break;
dwResult = GetLastError();
if (slpiInfo)
free(slpiInfo);
if (dwResult == ERROR_INSUFFICIENT_BUFFER) {
slpiInfo = (PSYSTEM_LOGICAL_PROCESSOR_INFORMATION)malloc(dwSize);
dispatch_assert(slpiInfo);
} else {
slpiInfo = NULL;
dwSize = 0;
break;
}
}
for (slpiCurrent = slpiInfo;
dwSize >= sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION);
slpiCurrent++, dwSize -= sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION)) {
switch (slpiCurrent->Relationship) {
case RelationProcessorCore:
++dwProcessorCoreCount;
dwProcessorLogicalCount += __popcnt64(slpiCurrent->ProcessorMask);
break;
case RelationProcessorPackage:
++dwProcessorPackageCount;
break;
case RelationNumaNode:
case RelationCache:
case RelationGroup:
case RelationAll:
break;
}
}
free(slpiInfo);
switch (c) {
case _dispatch_hw_config_logical_cpus:
return dwProcessorLogicalCount;
case _dispatch_hw_config_physical_cpus:
return dwProcessorPackageCount;
case _dispatch_hw_config_active_cpus:
return dwProcessorCoreCount;
}
#else
const char *name = NULL;
int r;
#if defined(__APPLE__)
switch (c) {
case _dispatch_hw_config_logical_cpus:
name = "hw.logicalcpu_max"; break;
case _dispatch_hw_config_physical_cpus:
name = "hw.physicalcpu_max"; break;
case _dispatch_hw_config_active_cpus:
name = "hw.activecpu"; break;
}
#elif defined(__FreeBSD__)
(void)c; name = "kern.smp.cpus";
#endif
if (name) {
size_t valsz = sizeof(val);
r = sysctlbyname(name, &val, &valsz, NULL, 0);
(void)dispatch_assume_zero(r);
dispatch_assert(valsz == sizeof(uint32_t));
} else {
#if HAVE_SYSCONF && defined(_SC_NPROCESSORS_ONLN)
r = (int)sysconf(_SC_NPROCESSORS_ONLN);
if (r > 0) val = (uint32_t)r;
#endif
}
#endif
return val;
}
#define dispatch_hw_config_init(c) \
_dispatch_hw_get_config(_dispatch_hw_config_##c)
static inline void
_dispatch_hw_config_init(void)
{
dispatch_hw_config(logical_cpus) = dispatch_hw_config_init(logical_cpus);
dispatch_hw_config(physical_cpus) = dispatch_hw_config_init(physical_cpus);
dispatch_hw_config(active_cpus) = dispatch_hw_config_init(active_cpus);
}
#undef dispatch_hw_config_init
#endif // DISPATCH_HAVE_HW_CONFIG_COMMPAGE
#endif /* __DISPATCH_SHIMS_HW_CONFIG__ */