| Taskflow: A General-purpose Task-parallel Programming System

Loading...
Searching...
No Matches
os.hpp
1#pragma once
2
3#include <cstdlib>
4#include <cstdio>
5#include <string>
6#include <thread>
7#include <new>
8
9#define TF_OS_LINUX 0
10#define TF_OS_DRAGONFLY 0
11#define TF_OS_FREEBSD 0
12#define TF_OS_NETBSD 0
13#define TF_OS_OPENBSD 0
14#define TF_OS_DARWIN 0
15#define TF_OS_WINDOWS 0
16#define TF_OS_CNK 0
17#define TF_OS_HURD 0
18#define TF_OS_SOLARIS 0
19#define TF_OS_UNIX 0
20
21#ifdef _WIN32
22#undef TF_OS_WINDOWS
23#define TF_OS_WINDOWS 1
24#endif
25
26#ifdef __CYGWIN__
27#undef TF_OS_WINDOWS
28#define TF_OS_WINDOWS 1
29#endif
30
31#if (defined __APPLE__ && defined __MACH__)
32#undef TF_OS_DARWIN
33#define TF_OS_DARWIN 1
34#endif
35
36// in some ppc64 linux installations, only the second condition is met
37#if (defined __linux)
38#undef TF_OS_LINUX
39#define TF_OS_LINUX 1
40#elif (defined __linux__)
41#undef TF_OS_LINUX
42#define TF_OS_LINUX 1
43#else
44#endif
45
46#if (defined __DragonFly__)
47#undef TF_OS_DRAGONFLY
48#define TF_OS_DRAGONFLY 1
49#endif
50
51#if (defined __FreeBSD__)
52#undef TF_OS_FREEBSD
53#define TF_OS_FREEBSD 1
54#endif
55
56#if (defined __NetBSD__)
57#undef TF_OS_NETBSD
58#define TF_OS_NETBSD 1
59#endif
60
61#if (defined __OpenBSD__)
62#undef TF_OS_OPENBSD
63#define TF_OS_OPENBSD 1
64#endif
65
66#if (defined __bgq__)
67#undef TF_OS_CNK
68#define TF_OS_CNK 1
69#endif
70
71#if (defined __GNU__)
72#undef TF_OS_HURD
73#define TF_OS_HURD 1
74#endif
75
76#if (defined __sun)
77#undef TF_OS_SOLARIS
78#define TF_OS_SOLARIS 1
79#endif
80
81#if (1 != \
82 TF_OS_LINUX + TF_OS_DRAGONFLY + TF_OS_FREEBSD + TF_OS_NETBSD + \
83 TF_OS_OPENBSD + TF_OS_DARWIN + TF_OS_WINDOWS + TF_OS_HURD + \
84 TF_OS_SOLARIS)
85#define TF_OS_UNKNOWN 1
86#endif
87
88#if TF_OS_LINUX || TF_OS_DRAGONFLY || TF_OS_FREEBSD || TF_OS_NETBSD || \
89 TF_OS_OPENBSD || TF_OS_DARWIN || TF_OS_HURD || TF_OS_SOLARIS
90#undef TF_OS_UNIX
91#define TF_OS_UNIX 1
92#endif
93
94// ------------------------------------------------------------------------------------------------
95// Number of bits used by the OS for user-space virtual addresses
96// Used as the default PtrBits for TaggedHead64 to leave the remaining
97// high bits free for the ABA version counter.
98// ------------------------------------------------------------------------------------------------
99//
100// No standard C++ mechanism exposes the VA width; we derive it from
101// architecture-specific predefined macros. Override by defining
102// TF_POINTER_BITS before including this header if your environment
103// differs (e.g. x86-64 with LA57 5-level paging uses 57 bits).
104
105#if defined(TF_POINTER_BITS)
106 // user-defined override — accepted as-is
107
108#elif defined(__x86_64__) || defined(_M_X64) || defined(_M_AMD64)
109 // 4-level paging: 48 bits. If your kernel enables LA57 (5-level paging,
110 // 57-bit VA), compile with -DTF_POINTER_BITS=57. Note that only 7 bits
111 // remain for the ABA tag in that case; TaggedHead128 is a better choice.
112 #define TF_POINTER_BITS 48
113
114#elif defined(__aarch64__) || defined(_M_ARM64)
115 #define TF_POINTER_BITS 48 // ARMv8 48-bit VA (TTBR0 range)
116
117#elif defined(__riscv) && __riscv_xlen == 64
118 #define TF_POINTER_BITS 48 // SV48 worst case; SV39 gives 25 free bits
119
120#else
121 #define TF_POINTER_BITS (sizeof(void*) * CHAR_BIT) // 32-bit or unknown
122#endif
123
124
125// ------------------------------------------------------------------------------------------------
126// Cache line size detection.
127//
128// Underestimating causes false sharing (hurts performance).
129// Overestimating wastes memory.
130// 64B is correct for the vast majority of modern server/desktop CPUs.
131// ------------------------------------------------------------------------------------------------
132
133#if defined(__i386__) || defined(__x86_64__) || \
134 defined(_M_IX86) || defined(_M_AMD64)
135 // All modern x86/x86_64 CPUs (Intel, AMD) since Pentium 4.
136 #define TF_CACHELINE_SIZE 64
137
138#elif defined(__aarch64__) || defined(__arm64__) || defined(_M_ARM64)
139 // 64-bit ARM: Apple Silicon (M1/M2/M3), AWS Graviton, Qualcomm Oryon, etc.
140 #define TF_CACHELINE_SIZE 64
141
142#elif defined(__arm__) || defined(_M_ARM)
143 // 32-bit ARM — cache line size depends on the ARM architecture revision.
144 #if defined(__ARM_ARCH_5T__) || \
145 defined(__ARM_ARCH_5TE__) || \
146 defined(__ARM_ARCH_6__)
147 #define TF_CACHELINE_SIZE 32
148 #else
149 // ARMv7-A (Cortex-A5/A7/A8/A9/A15) and later 32-bit ARM.
150 #define TF_CACHELINE_SIZE 64
151 #endif
152
153#elif defined(__powerpc64__) || defined(__ppc64__)
154 // IBM POWER7/8/9/10 and PowerPC64 (e.g., original Xbox 360-era G5).
155 #define TF_CACHELINE_SIZE 128
156
157#elif defined(__powerpc__) || defined(__ppc__)
158 // Older 32-bit PowerPC (G3/G4 era embedded systems).
159 #define TF_CACHELINE_SIZE 32
160
161#elif defined(__s390x__) || defined(__zarch__)
162 // IBM Z (z13 and later). Unusually large at 256B.
163 #define TF_CACHELINE_SIZE 256
164
165#elif defined(__riscv)
166 // RISC-V: SiFive U74, Alibaba T-Head, etc.
167 #define TF_CACHELINE_SIZE 64
168
169#elif defined(__mips__) || defined(__mips64)
170 // MIPS32/MIPS64 (embedded and networking SoCs).
171 #define TF_CACHELINE_SIZE 64
172
173#elif defined(__sparc__) || defined(__sparc64__)
174 // Oracle/Fujitsu SPARC.
175 #define TF_CACHELINE_SIZE 64
176
177#elif defined(__loongarch64)
178 // LoongArch (Loongson 3A5000 and later).
179 #define TF_CACHELINE_SIZE 64
180
181#elif defined(__alpha__)
182 // DEC/Compaq Alpha.
183 #define TF_CACHELINE_SIZE 64
184
185#endif
186
187#ifndef TF_CACHELINE_SIZE
188 // Conservative fallback. If we land here, the architecture is unknown.
189 // 64B is correct for virtually all modern CPUs. Overestimating wastes
190 // a small amount of space; underestimating causes false sharing.
191 #define TF_CACHELINE_SIZE 64
192#endif
193
194 namespace tf {
195
218 template <typename T>
219 class CachelineAligned {
220 public:
224 alignas (TF_CACHELINE_SIZE) T data;
225
239 T& get() { return data; }
240
254 const T& get() const { return data; }
255};
256
274 inline std::string get_env(const std::string& str) {
275#ifdef _MSC_VER
276 char *ptr = nullptr;
277 size_t len = 0;
278
279 if(_dupenv_s(&ptr, &len, str.c_str()) == 0 && ptr != nullptr) {
280 std::string res(ptr, len);
281 std::free(ptr);
282 return res;
283 }
284 return "";
285
286#else
287 auto ptr = std::getenv(str.c_str());
288 return ptr ? ptr : "";
289#endif
290}
291
310 inline bool has_env(const std::string& str) {
311#ifdef _MSC_VER
312 char *ptr = nullptr;
313 size_t len = 0;
314
315 if(_dupenv_s(&ptr, &len, str.c_str()) == 0 && ptr != nullptr) {
316 std::string res(ptr, len);
317 std::free(ptr);
318 return true;
319 }
320 return false;
321
322#else
323 auto ptr = std::getenv(str.c_str());
324 return ptr ? true : false;
325#endif
326}
327
328
329} // end of namespace tf -----------------------------------------------------
330
331
332
333
334
335
336
337
338
tf::CachelineAligned
class to ensure cacheline-aligned storage for an object.
Definition os.hpp:219
tf::CachelineAligned::get
T & get()
accesses the underlying object
Definition os.hpp:239
tf::CachelineAligned::get
const T & get() const
accesses the underlying object as a constant reference
Definition os.hpp:254
tf::CachelineAligned::data
T data
The stored object, aligned to twice the cacheline size.
Definition os.hpp:224
tf
taskflow namespace
Definition small_vector.hpp:20
tf::get_env
std::string get_env(const std::string &str)
retrieves the value of an environment variable
Definition os.hpp:274
tf::has_env
bool has_env(const std::string &str)
checks whether an environment variable is defined
Definition os.hpp:310