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 ALPAKA_OS_WINDOWS || ALPAKA_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 ALPAKA_OS_LINUX || ALPAKA_OS_IOS
19# include <sys/param.h>
20# include <sys/types.h>
21# include <unistd.h>
22
23# include <cstdint>
24# if ALPAKA_OS_IOS
25# include <sys/sysctl.h>
26# endif
27#endif
28
29#if ALPAKA_OS_LINUX
30# include <fstream>
31#endif
32
33#include <cstdint>
34#include <cstring>
35#include <stdexcept>
36#include <string>
37
38#if ALPAKA_ARCH_X86
39# if ALPAKA_COMP_GNUC || ALPAKA_COMP_CLANG || ALPAKA_COMP_PGI
40# include <cpuid.h>
41# elif ALPAKA_COMP_MSVC || defined(ALPAKA_COMP_MSVC_EMULATED)
42# include <intrin.h>
43# endif
44#endif
45
46namespace alpaka::onHost
47{
48 constexpr int NO_CPUID = 0;
49 constexpr int UNKNOWN_CPU = 0;
50 constexpr int UNKNOWN_COMPILER = 1;
51#if ALPAKA_ARCH_X86
52# if ALPAKA_COMP_GNUC || ALPAKA_COMP_CLANG || ALPAKA_COMP_PGI
53 inline auto cpuid(std::uint32_t level, std::uint32_t subfunction, std::uint32_t ex[4]) -> void
54 {
55 __cpuid_count(level, subfunction, ex[0], ex[1], ex[2], ex[3]);
56 }
57
58# elif ALPAKA_COMP_MSVC || defined(ALPAKA_COMP_MSVC_EMULATED)
59 inline auto cpuid(std::uint32_t level, std::uint32_t subfunction, std::uint32_t ex[4]) -> void
60 {
61 __cpuidex(reinterpret_cast<int*>(ex), level, subfunction);
62 }
63# else
64 inline auto cpuid(std::uint32_t, std::uint32_t, std::uint32_t ex[4]) -> void
65 {
66 ex[0] = ex[2] = ex[3] = NO_CPUID;
67 ex[1] = UNKNOWN_COMPILER;
68 }
69# endif
70#else
71 inline auto cpuid(std::uint32_t, std::uint32_t, std::uint32_t ex[4]) -> void
72 {
73 ex[0] = ex[2] = ex[3] = NO_CPUID;
74 ex[1] = UNKNOWN_CPU;
75 }
76#endif
77 //! \return The name of the CPU the code is running on.
78 inline auto getCpuName() -> std::string
79 {
80 // Get extended ids.
81 std::uint32_t ex[4] = {0};
82 cpuid(0x8000'0000, 0, ex);
83 std::uint32_t const nExIds(ex[0]);
84
85 if(!nExIds)
86 {
87 switch(ex[1])
88 {
90 return "<unknown: compiler>";
91 case UNKNOWN_CPU:
92 return "<unknown: CPU>";
93 default:
94 return "<unknown>";
95 }
96 }
97#if ALPAKA_ARCH_X86
98 // Get the information associated with each extended ID.
99 char cpuBrandString[0x40] = {0};
100 for(std::uint32_t i(0x8000'0000); i <= nExIds; ++i)
101 {
102 cpuid(i, 0, ex);
103
104 // Interpret CPU brand string and cache information.
105 if(i == 0x8000'0002)
106 {
107 std::memcpy(cpuBrandString, ex, sizeof(ex));
108 }
109 else if(i == 0x8000'0003)
110 {
111 std::memcpy(cpuBrandString + 16, ex, sizeof(ex));
112 }
113 else if(i == 0x8000'0004)
114 {
115 std::memcpy(cpuBrandString + 32, ex, sizeof(ex));
116 }
117 }
118 return std::string(cpuBrandString);
119#else
120 return std::string("unknown");
121#endif
122 }
123
124 //! \return Pagesize in bytes used by the system.
125 inline size_t getPageSize()
126 {
127#if ALPAKA_OS_WINDOWS || ALPAKA_OS_CYGWIN
128 SYSTEM_INFO si;
129 GetSystemInfo(&si);
130 return si.dwPageSize;
131#elif ALPAKA_OS_LINUX || ALPAKA_OS_IOS
132# if defined(_SC_PAGESIZE)
133 return static_cast<std::size_t>(sysconf(_SC_PAGESIZE));
134# else
135 // this is legacy and only used as fallback
136 return static_cast<size_t>(getpagesize());
137# endif
138#else
139# error "getPageSize not implemented for this system!"
140 return 0;
141#endif
142 }
143
144 //! \return The total number of bytes of global memory.
145 //! Adapted from David Robert Nadeau:
146 //! http://nadeausoftware.com/articles/2012/09/c_c_tip_how_get_physical_memory_size_system
147 inline auto getGlobalMemCapacityBytes() -> std::size_t
148 {
149#if ALPAKA_OS_WINDOWS
150 MEMORYSTATUSEX status;
151 status.dwLength = sizeof(status);
152 GlobalMemoryStatusEx(&status);
153 return static_cast<std::size_t>(status.ullTotalPhys);
154
155#elif ALPAKA_OS_CYGWIN
156 // New 64-bit MEMORYSTATUSEX isn't available.
157 MEMORYSTATUS status;
158 status.dwLength = sizeof(status);
159 GlobalMemoryStatus(&status);
160 return static_cast<std::size_t>(status.dwTotalPhys);
161
162#elif ALPAKA_OS_LINUX || ALPAKA_OS_IOS
163 // Unix : Prefer sysctl() over sysconf() except sysctl() with HW_REALMEM and HW_PHYSMEM which are not
164 // always reliable
165# if defined(CTL_HW) && (defined(HW_MEMSIZE) || defined(HW_PHYSMEM64))
166 int mib[2]
167 = {CTL_HW,
168# if defined(HW_MEMSIZE) // OSX
169 HW_MEMSIZE
170# elif defined(HW_PHYSMEM64) // NetBSD, OpenBSD.
171 HW_PHYSMEM64
172# endif
173 };
174 std::uint64_t size(0);
175 std::size_t sizeLen{sizeof(size)};
176 if(sysctl(mib, 2, &size, &sizeLen, nullptr, 0) < 0)
177 throw std::logic_error("getGlobalMemCapacityBytes failed calling sysctl!");
178 return static_cast<std::size_t>(size);
179
180# elif defined(_SC_AIX_REALMEM) // AIX.
181 return static_cast<std::size_t>(sysconf(_SC_AIX_REALMEM)) * static_cast<std::size_t>(1024);
182
183# elif defined(_SC_PHYS_PAGES) // Linux, FreeBSD, OpenBSD, Solaris.
184 return static_cast<std::size_t>(sysconf(_SC_PHYS_PAGES)) * getPageSize();
185
186# elif defined(CTL_HW) \
187 && (defined(HW_PHYSMEM) || defined(HW_REALMEM)) // FreeBSD, DragonFly BSD, NetBSD, OpenBSD, and OSX.
188 int mib[2]
189 = {CTL_HW,
190# if defined(HW_REALMEM) // FreeBSD.
191 HW_REALMEM
192# elif defined(HW_PYSMEM) // Others.
193 HW_PHYSMEM
194# endif
195 };
196 std::uint32_t size(0);
197 std::size_t const sizeLen{sizeof(size)};
198 if(sysctl(mib, 2, &size, &sizeLen, nullptr, 0) < 0)
199 throw std::logic_error("getGlobalMemCapacityBytes failed calling sysctl!");
200 return static_cast<std::size_t>(size);
201# endif
202
203#else
204# error "getGlobalMemCapacityBytes not implemented for this system!"
205#endif
206 }
207
208 //! \return The free number of bytes of global memory.
209 //! \throws std::logic_error if not implemented on the system and std::runtime_error on other errors.
210 inline auto getFreeGlobalMemBytes() -> std::size_t
211 {
212#if ALPAKA_OS_WINDOWS
213 MEMORYSTATUSEX status;
214 status.dwLength = sizeof(status);
215 GlobalMemoryStatusEx(&status);
216 return static_cast<std::size_t>(status.ullAvailPhys);
217#elif ALPAKA_OS_LINUX
218# if defined(_SC_AVPHYS_PAGES)
219 return static_cast<std::size_t>(sysconf(_SC_AVPHYS_PAGES)) * getPageSize();
220# else
221 // this is legacy and only used as fallback
222 return static_cast<std::size_t>(get_avphys_pages()) * getPageSize();
223# endif
224#elif ALPAKA_OS_IOS
225 int free_pages = 0;
226 std::size_t len = sizeof(free_pages);
227 if(sysctlbyname("vm.page_free_count", &free_pages, &len, nullptr, 0) < 0)
228 {
229 throw std::logic_error("getFreeGlobalMemSizeBytes failed calling sysctl(vm.page_free_count)!");
230 }
231
232 return static_cast<std::size_t>(free_pages) * getPageSize();
233#else
234# error "getFreeGlobalMemSizeBytes not implemented for this system!"
235#endif
236 }
237
238} // namespace alpaka::onHost
Functionality which is usable on the host CPU controller thread.
Definition api.hpp:40
auto cpuid(std::uint32_t, std::uint32_t, std::uint32_t ex[4]) -> void
Definition sysInfo.hpp:71
constexpr int NO_CPUID
Definition sysInfo.hpp:48
auto getFreeGlobalMemBytes() -> std::size_t
Definition sysInfo.hpp:210
auto getCpuName() -> std::string
Definition sysInfo.hpp:78
size_t getPageSize()
Definition sysInfo.hpp:125
constexpr int UNKNOWN_COMPILER
Definition sysInfo.hpp:50
constexpr int UNKNOWN_CPU
Definition sysInfo.hpp:49
auto getGlobalMemCapacityBytes() -> std::size_t
Definition sysInfo.hpp:147