Skip to content

Commit

Permalink
Implement GetCurrentProcessCpuCount for Unix and merge NumberOfProces…
Browse files Browse the repository at this point in the history
…ors implementations. (dotnet#11742)

* Implement GetCurrentProcessCpuCount for Unix and merge NumberOfProcessors implementations.

* Split GetCurrentProcessCpuCount in PAL and non-PAL parts

* gcenv.unix.cpp: GetCurrentProcessAffinityMask: revert, GetCurrentProcessCpuCount: add implementation

* bugfix: #if instead of #ifdef HAVE_SCHED_GETAFFINITY

* Remove PAL_GetCurrentProcessCpuCount

* gcenv.unix: implement GetCurrentProcessAffinityMask, GetCurrentProcessCpuCount

* numa.cpp: initialize g_cpuToAffinity[i].Number when numa.h is missing

* cleanup

* mscorwks_unixexports.src: Add GetProcessAffinityMask

* PR feedback

* Add GetProcessAffinityMask to mscordac_unixexports.src
  • Loading branch information
tmds authored and janvorli committed May 29, 2017
1 parent c08d7df commit ee454e1
Show file tree
Hide file tree
Showing 8 changed files with 120 additions and 50 deletions.
1 change: 1 addition & 0 deletions src/dlls/mscordac/mscordac_unixexports.src
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ GetLastError
GetLongPathNameW
GetModuleFileNameW
GetProcAddress
GetProcessAffinityMask
GetProcessHeap
GetShortPathNameW
GetStdHandle
Expand Down
1 change: 1 addition & 0 deletions src/dlls/mscoree/mscorwks_unixexports.src
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ GetFileType
GetFullPathNameW
GetLongPathNameW
GetProcAddress
GetProcessAffinityMask
GetStdHandle
GetSystemInfo
GetTempFileNameW
Expand Down
1 change: 1 addition & 0 deletions src/gc/unix/config.h.in
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,6 @@
#cmakedefine01 HAVE_SCHED_GETCPU
#cmakedefine01 HAVE_PTHREAD_CONDATTR_SETCLOCK
#cmakedefine01 HAVE_MACH_ABSOLUTE_TIME
#cmakedefine01 HAVE_SCHED_GETAFFINITY

#endif // __CONFIG_H__
2 changes: 2 additions & 0 deletions src/gc/unix/configure.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -52,4 +52,6 @@ check_cxx_source_runs("
}
" HAVE_MACH_ABSOLUTE_TIME)

check_library_exists(c sched_getaffinity "" HAVE_SCHED_GETAFFINITY)

configure_file(${CMAKE_CURRENT_SOURCE_DIR}/config.h.in ${CMAKE_CURRENT_BINARY_DIR}/config.h)
96 changes: 92 additions & 4 deletions src/gc/unix/gcenv.unix.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -404,6 +404,18 @@ size_t GCToOSInterface::GetLargestOnDieCacheSize(bool trueSize)
return 0;
}

/*++
Function:
GetFullAffinityMask
Get affinity mask for the specified number of processors with all
the processors enabled.
--*/
static uintptr_t GetFullAffinityMask(int cpuCount)
{
return ((uintptr_t)1 << (cpuCount)) - 1;
}

// Get affinity mask of the current process
// Parameters:
// processMask - affinity mask for the specified process
Expand All @@ -417,18 +429,94 @@ size_t GCToOSInterface::GetLargestOnDieCacheSize(bool trueSize)
// A process affinity mask is a subset of the system affinity mask. A process is only allowed
// to run on the processors configured into a system. Therefore, the process affinity mask cannot
// specify a 1 bit for a processor when the system affinity mask specifies a 0 bit for that processor.
bool GCToOSInterface::GetCurrentProcessAffinityMask(uintptr_t* processMask, uintptr_t* systemMask)
bool GCToOSInterface::GetCurrentProcessAffinityMask(uintptr_t* processAffinityMask, uintptr_t* systemAffinityMask)
{
// TODO(segilles) processor detection
return false;
if (g_logicalCpuCount > 64)
{
*processAffinityMask = 0;
*systemAffinityMask = 0;
return true;
}

uintptr_t systemMask = GetFullAffinityMask(g_logicalCpuCount);

#if HAVE_SCHED_GETAFFINITY

int pid = getpid();
cpu_set_t cpuSet;
int st = sched_getaffinity(pid, sizeof(cpu_set_t), &cpuSet);
if (st == 0)
{
uintptr_t processMask = 0;

for (int i = 0; i < g_logicalCpuCount; i++)
{
if (CPU_ISSET(i, &cpuSet))
{
processMask |= ((uintptr_t)1) << i;
}
}

*processAffinityMask = processMask;
*systemAffinityMask = systemMask;
return true;
}
else if (errno == EINVAL)
{
// There are more processors than can fit in a cpu_set_t
// return zero in both masks.
*processAffinityMask = 0;
*systemAffinityMask = 0;
return true;
}
else
{
// We should not get any of the errors that the sched_getaffinity can return since none
// of them applies for the current thread, so this is an unexpected kind of failure.
return false;
}

#else // HAVE_SCHED_GETAFFINITY

// There is no API to manage thread affinity, so let's return both affinity masks
// with all the CPUs on the system set.
*systemAffinityMask = systemMask;
*processAffinityMask = systemMask;
return true;

#endif // HAVE_SCHED_GETAFFINITY
}

// Get number of processors assigned to the current process
// Return:
// The number of processors
uint32_t GCToOSInterface::GetCurrentProcessCpuCount()
{
return g_logicalCpuCount;
uintptr_t pmask, smask;

if (!GetCurrentProcessAffinityMask(&pmask, &smask))
return 1;

pmask &= smask;

int count = 0;
while (pmask)
{
pmask &= (pmask - 1);
count++;
}

// GetProcessAffinityMask can return pmask=0 and smask=0 on systems with more
// than 64 processors, which would leave us with a count of 0. Since the GC
// expects there to be at least one processor to run on (and thus at least one
// heap), we'll return 64 here if count is 0, since there are likely a ton of
// processors available in that case. The GC also cannot (currently) handle
// the case where there are more than 64 processors, so we will return a
// maximum of 64 here.
if (count == 0 || count > 64)
count = 64;

return count;
}

// Return the size of the user-mode portion of the virtual address space of this process.
Expand Down
24 changes: 4 additions & 20 deletions src/pal/src/misc/sysinfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -94,13 +94,10 @@ SET_DEFAULT_DEBUG_CHANNEL(MISC);
#endif
#endif // __APPLE__

/*++
Function:
GetNumberOfProcessors

Return number of processors available for the current process
--*/
int GetNumberOfProcessors()
DWORD
PALAPI
PAL_GetLogicalCpuCountFromOS()
{
int nrcpus = 0;

Expand Down Expand Up @@ -170,7 +167,7 @@ GetSystemInfo(
lpSystemInfo->dwPageSize = pagesize;
lpSystemInfo->dwActiveProcessorMask_PAL_Undefined = 0;

nrcpus = GetNumberOfProcessors();
nrcpus = PAL_GetLogicalCpuCountFromOS();
TRACE("dwNumberOfProcessors=%d\n", nrcpus);
lpSystemInfo->dwNumberOfProcessors = nrcpus;

Expand Down Expand Up @@ -387,19 +384,6 @@ PAL_HasGetCurrentProcessorNumber()
return HAVE_SCHED_GETCPU;
}

DWORD
PALAPI
PAL_GetLogicalCpuCountFromOS()
{
DWORD numLogicalCores = 0;

#if HAVE_SYSCONF
numLogicalCores = sysconf(_SC_NPROCESSORS_ONLN);
#endif

return numLogicalCores;
}

size_t
PALAPI
PAL_GetLogicalProcessorCacheSizeFromOS()
Expand Down
18 changes: 15 additions & 3 deletions src/pal/src/numa/numa.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,6 @@ using namespace CorUnix;
typedef cpuset_t cpu_set_t;
#endif

int GetNumberOfProcessors();

// CPU affinity descriptor
struct CpuAffinity
{
Expand Down Expand Up @@ -208,11 +206,17 @@ NUMASupportInitialize()
#endif // HAVE_NUMA_H
{
// No NUMA
g_cpuCount = GetNumberOfProcessors();
g_cpuCount = PAL_GetLogicalCpuCountFromOS();
g_groupCount = 1;
g_highestNumaNode = 0;

AllocateLookupArrays();

for (int i = 0; i < g_cpuCount; i++)
{
g_cpuToAffinity[i].Number = i;
g_cpuToAffinity[i].Group = 0;
}
}

return TRUE;
Expand Down Expand Up @@ -599,6 +603,14 @@ GetProcessAffinityMask(
*lpProcessAffinityMask = processMask;
*lpSystemAffinityMask = systemMask;
}
else if (errno == EINVAL)
{
// There are more processors than can fit in a cpu_set_t
// return zero in both masks.
*lpProcessAffinityMask = 0;
*lpSystemAffinityMask = 0;
success = TRUE;
}
else
{
// We should not get any of the errors that the sched_getaffinity can return since none
Expand Down
27 changes: 4 additions & 23 deletions src/utilcode/util.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1248,9 +1248,6 @@ DWORD LCM(DWORD u, DWORD v)
return m_threadUseAllCpuGroups;
}

//******************************************************************************
// Returns the number of processors that a process has been configured to run on
//******************************************************************************
//******************************************************************************
// Returns the number of processors that a process has been configured to run on
//******************************************************************************
Expand All @@ -1269,27 +1266,20 @@ int GetCurrentProcessCpuCount()
if (cCPUs != 0)
return cCPUs;

#ifndef FEATURE_PAL

DWORD_PTR pmask, smask;

if (!GetProcessAffinityMask(GetCurrentProcess(), &pmask, &smask))
return 1;

if (pmask == 1)
return 1;

pmask &= smask;

int count = 0;
while (pmask)
{
if (pmask & 1)
count++;

pmask >>= 1;
pmask &= (pmask - 1);
count++;
}

// GetProcessAffinityMask can return pmask=0 and smask=0 on systems with more
// than 64 processors, which would leave us with a count of 0. Since the GC
// expects there to be at least one processor to run on (and thus at least one
Expand All @@ -1303,15 +1293,6 @@ int GetCurrentProcessCpuCount()
cCPUs = count;

return count;

#else // !FEATURE_PAL

SYSTEM_INFO sysInfo;
::GetSystemInfo(&sysInfo);
cCPUs = sysInfo.dwNumberOfProcessors;
return sysInfo.dwNumberOfProcessors;

#endif // !FEATURE_PAL
}

DWORD_PTR GetCurrentProcessCpuMask()
Expand Down

0 comments on commit ee454e1

Please sign in to comment.