alpaka
Abstraction Library for Parallel Kernel Acceleration
Loading...
Searching...
No Matches
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 {
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
auto getCpuName() -> std::string
Definition SysInfo.hpp:77