alpaka
Abstraction Library for Parallel Kernel Acceleration
SysInfo.hpp
Go to the documentation of this file.
1 /* Copyright 2022 Benjamin Worpitz, Daniel Vollmer, Erik Zenker, RenĂ© Widera, Bernhard Manfred Gruber, Andrea Bocci
2  * SPDX-License-Identifier: MPL-2.0
3  */
4 
5 #pragma once
6 
8 
9 #if BOOST_OS_WINDOWS || BOOST_OS_CYGWIN
10 # ifndef NOMINMAX
11 # define NOMINMAX
12 # endif
13 # ifndef WIN32_LEAN_AND_MEAN
14 # define WIN32_LEAN_AND_MEAN
15 # endif
16 // We could use some more macros to reduce the number of sub-headers included, but this would restrict user code.
17 # include <windows.h>
18 #elif BOOST_OS_UNIX || BOOST_OS_MACOS
19 # include <sys/param.h>
20 # include <sys/types.h>
21 # include <unistd.h>
22 
23 # include <cstdint>
24 # if BOOST_OS_BSD || BOOST_OS_MACOS
25 # include <sys/sysctl.h>
26 # endif
27 #endif
28 
29 #if BOOST_OS_LINUX
30 # include <fstream>
31 #endif
32 
33 #include <cstring>
34 #include <stdexcept>
35 #include <string>
36 
37 #if BOOST_ARCH_X86
38 # if BOOST_COMP_GNUC || BOOST_COMP_CLANG || BOOST_COMP_PGI
39 # include <cpuid.h>
40 # elif BOOST_COMP_MSVC || defined(BOOST_COMP_MSVC_EMULATED)
41 # include <intrin.h>
42 # endif
43 #endif
44 
46 {
47  constexpr int NO_CPUID = 0;
48  constexpr int UNKNOWN_CPU = 0;
49  constexpr int UNKNOWN_COMPILER = 1;
50 #if BOOST_ARCH_X86
51 # if BOOST_COMP_GNUC || BOOST_COMP_CLANG || BOOST_COMP_PGI
52  inline auto cpuid(std::uint32_t level, std::uint32_t subfunction, std::uint32_t ex[4]) -> void
53  {
54  __cpuid_count(level, subfunction, ex[0], ex[1], ex[2], ex[3]);
55  }
56 
57 # elif BOOST_COMP_MSVC || defined(BOOST_COMP_MSVC_EMULATED)
58  inline auto cpuid(std::uint32_t level, std::uint32_t subfunction, std::uint32_t ex[4]) -> void
59  {
60  __cpuidex(reinterpret_cast<int*>(ex), level, subfunction);
61  }
62 # else
63  inline auto cpuid(std::uint32_t, std::uint32_t, std::uint32_t ex[4]) -> void
64  {
65  ex[0] = ex[2] = ex[3] = NO_CPUID;
66  ex[1] = UNKNOWN_COMPILER;
67  }
68 # endif
69 #else
70  inline auto cpuid(std::uint32_t, std::uint32_t, std::uint32_t ex[4]) -> void
71  {
72  ex[0] = ex[2] = ex[3] = NO_CPUID;
73  ex[1] = UNKNOWN_CPU;
74  }
75 #endif
76  //! \return The name of the CPU the code is running on.
77  inline auto getCpuName() -> std::string
78  {
79  // Get extended ids.
80  std::uint32_t ex[4] = {0};
81  cpuid(0x8000'0000, 0, ex);
82  std::uint32_t const nExIds(ex[0]);
83 
84  if(!nExIds)
85  {
86  switch(ex[1])
87  {
88  case UNKNOWN_COMPILER:
89  return "<unknown: compiler>";
90  case UNKNOWN_CPU:
91  return "<unknown: CPU>";
92  default:
93  return "<unknown>";
94  }
95  }
96 #if BOOST_ARCH_X86
97  // Get the information associated with each extended ID.
98  char cpuBrandString[0x40] = {0};
99  for(std::uint32_t i(0x8000'0000); i <= nExIds; ++i)
100  {
101  cpuid(i, 0, ex);
102 
103  // Interpret CPU brand string and cache information.
104  if(i == 0x8000'0002)
105  {
106  std::memcpy(cpuBrandString, ex, sizeof(ex));
107  }
108  else if(i == 0x8000'0003)
109  {
110  std::memcpy(cpuBrandString + 16, ex, sizeof(ex));
111  }
112  else if(i == 0x8000'0004)
113  {
114  std::memcpy(cpuBrandString + 32, ex, sizeof(ex));
115  }
116  }
117  return std::string(cpuBrandString);
118 #else
119  return std::string("unknown");
120 #endif
121  }
122 
123  //! \return Pagesize in bytes used by the system.
124  inline size_t getPageSize()
125  {
126 #if BOOST_OS_WINDOWS || BOOST_OS_CYGWIN
127  SYSTEM_INFO si;
128  GetSystemInfo(&si);
129  return si.dwPageSize;
130 #elif BOOST_OS_UNIX || BOOST_OS_MACOS
131 # if defined(_SC_PAGESIZE)
132  return static_cast<std::size_t>(sysconf(_SC_PAGESIZE));
133 # else
134  // this is legacy and only used as fallback
135  return = static_cast<size_t>(getpagesize());
136 # endif
137 #else
138 # error "getPageSize not implemented for this system!"
139  return 0;
140 #endif
141  }
142 
143  //! \return The total number of bytes of global memory.
144  //! Adapted from David Robert Nadeau:
145  //! http://nadeausoftware.com/articles/2012/09/c_c_tip_how_get_physical_memory_size_system
146  inline auto getTotalGlobalMemSizeBytes() -> std::size_t
147  {
148 #if BOOST_OS_WINDOWS
149  MEMORYSTATUSEX status;
150  status.dwLength = sizeof(status);
151  GlobalMemoryStatusEx(&status);
152  return static_cast<std::size_t>(status.ullTotalPhys);
153 
154 #elif BOOST_OS_CYGWIN
155  // New 64-bit MEMORYSTATUSEX isn't available.
156  MEMORYSTATUS status;
157  status.dwLength = sizeof(status);
158  GlobalMemoryStatus(&status);
159  return static_cast<std::size_t>(status.dwTotalPhys);
160 
161 #elif BOOST_OS_UNIX || BOOST_OS_MACOS
162  // Unix : Prefer sysctl() over sysconf() except sysctl() with HW_REALMEM and HW_PHYSMEM which are not
163  // always reliable
164 # if defined(CTL_HW) && (defined(HW_MEMSIZE) || defined(HW_PHYSMEM64))
165  int mib[2]
166  = { CTL_HW,
167 # if defined(HW_MEMSIZE) // OSX
168  HW_MEMSIZE
169 # elif defined(HW_PHYSMEM64) // NetBSD, OpenBSD.
170  HW_PHYSMEM64
171 # endif
172  };
173  std::uint64_t size(0);
174  std::size_t sizeLen{sizeof(size)};
175  if(sysctl(mib, 2, &size, &sizeLen, nullptr, 0) < 0)
176  throw std::logic_error("getTotalGlobalMemSizeBytes failed calling sysctl!");
177  return static_cast<std::size_t>(size);
178 
179 # elif defined(_SC_AIX_REALMEM) // AIX.
180  return static_cast<std::size_t>(sysconf(_SC_AIX_REALMEM)) * static_cast<std::size_t>(1024);
181 
182 # elif defined(_SC_PHYS_PAGES) // Linux, FreeBSD, OpenBSD, Solaris.
183  return static_cast<std::size_t>(sysconf(_SC_PHYS_PAGES)) * getPageSize();
184 
185 # elif defined(CTL_HW) \
186  && (defined(HW_PHYSMEM) || defined(HW_REALMEM)) // FreeBSD, DragonFly BSD, NetBSD, OpenBSD, and OSX.
187  int mib[2]
188  = { CTL_HW,
189 # if defined(HW_REALMEM) // FreeBSD.
190  HW_REALMEM
191 # elif defined(HW_PYSMEM) // Others.
192  HW_PHYSMEM
193 # endif
194  };
195  std::uint32_t size(0);
196  std::size_t const sizeLen{sizeof(size)};
197  if(sysctl(mib, 2, &size, &sizeLen, nullptr, 0) < 0)
198  throw std::logic_error("getTotalGlobalMemSizeBytes failed calling sysctl!");
199  return static_cast<std::size_t>(size);
200 # endif
201 
202 #else
203 # error "getTotalGlobalMemSizeBytes not implemented for this system!"
204 #endif
205  }
206 
207  //! \return The free number of bytes of global memory.
208  //! \throws std::logic_error if not implemented on the system and std::runtime_error on other errors.
209  inline auto getFreeGlobalMemSizeBytes() -> std::size_t
210  {
211 #if BOOST_OS_WINDOWS
212  MEMORYSTATUSEX status;
213  status.dwLength = sizeof(status);
214  GlobalMemoryStatusEx(&status);
215  return static_cast<std::size_t>(status.ullAvailPhys);
216 #elif BOOST_OS_LINUX
217 # if defined(_SC_AVPHYS_PAGES)
218  return static_cast<std::size_t>(sysconf(_SC_AVPHYS_PAGES)) * getPageSize();
219 # else
220  // this is legacy and only used as fallback
221  return static_cast<std::size_t>(get_avphys_pages()) * getPageSize();
222 # endif
223 #elif BOOST_OS_MACOS
224  int free_pages = 0;
225  std::size_t len = sizeof(free_pages);
226  if(sysctlbyname("vm.page_free_count", &free_pages, &len, nullptr, 0) < 0)
227  {
228  throw std::logic_error("getFreeGlobalMemSizeBytes failed calling sysctl(vm.page_free_count)!");
229  }
230 
231  return static_cast<std::size_t>(free_pages) * getPageSize();
232 #else
233 # error "getFreeGlobalMemSizeBytes not implemented for this system!"
234 #endif
235  }
236 
237 } // namespace alpaka::cpu::detail
The CPU device.
Definition: SysInfo.hpp:46
constexpr int NO_CPUID
Definition: SysInfo.hpp:47
constexpr int UNKNOWN_CPU
Definition: SysInfo.hpp:48
auto getTotalGlobalMemSizeBytes() -> std::size_t
Definition: SysInfo.hpp:146
constexpr int UNKNOWN_COMPILER
Definition: SysInfo.hpp:49
auto cpuid(std::uint32_t, std::uint32_t, std::uint32_t ex[4]) -> void
Definition: SysInfo.hpp:70
auto getFreeGlobalMemSizeBytes() -> std::size_t
Definition: SysInfo.hpp:209
size_t getPageSize()
Definition: SysInfo.hpp:124
auto getCpuName() -> std::string
Definition: SysInfo.hpp:77
ALPAKA_FN_HOST auto memcpy(TQueue &queue, alpaka::detail::DevGlobalImplGeneric< TTag, TTypeDst > &viewDst, TViewSrc const &viewSrc) -> void