1 #ifndef NETGEN_CORE_UTILS_HPP 2 #define NETGEN_CORE_UTILS_HPP 3 4 #include <atomic> 5 #include <chrono> 6 #include <map> 7 #include <ostream> 8 #include <sstream> 9 #include <string> 10 11 #include "ngcore_api.hpp" // for NGCORE_API and CPU arch macros 12 13 #if defined(__APPLE__) && defined(NETGEN_ARCH_ARM64) 14 #include <mach/mach_time.h> 15 #endif 16 17 #ifdef NETGEN_ARCH_AMD64 18 #ifdef WIN32 19 #include <intrin.h> // for __rdtsc() CPU time step counter 20 #else 21 #include <x86intrin.h> // for __rdtsc() CPU time step counter 22 #endif // WIN32 23 #endif // NETGEN_ARCH_AMD64 24 25 namespace ngcore 26 { 27 // MPI rank, nranks TODO: Rename 28 extern NGCORE_API int id, ntasks; 29 30 NGCORE_API std::string Demangle(const char* typeinfo); 31 32 template<typename T> GetName(const T & obj)33 std::string GetName(const T& obj) 34 { return Demangle(typeid(obj).name()); } 35 36 #if defined(__GNUC__) likely(bool x)37 inline bool likely (bool x) { return bool(__builtin_expect(long(x), 1L)); } unlikely(bool x)38 inline bool unlikely (bool x) { return bool(__builtin_expect(long(x), 0L)); } 39 #else likely(bool x)40 inline bool likely (bool x) { return x; } unlikely(bool x)41 inline bool unlikely (bool x) { return x; } 42 #endif 43 44 using TClock = std::chrono::system_clock; 45 extern NGCORE_API const std::chrono::time_point<TClock> wall_time_start; 46 47 // Time in seconds since program start WallTime()48 inline double WallTime () noexcept 49 { 50 std::chrono::time_point<TClock> now = TClock::now(); 51 std::chrono::duration<double> elapsed_seconds = now-wall_time_start; 52 return elapsed_seconds.count(); 53 } 54 55 // High precision clock counter register 56 using TTimePoint = size_t; 57 extern NGCORE_API double seconds_per_tick; 58 GetTimeCounter()59 inline TTimePoint GetTimeCounter() noexcept 60 { 61 #if defined(__APPLE__) && defined(NETGEN_ARCH_ARM64) 62 return mach_absolute_time(); 63 #elif defined(NETGEN_ARCH_AMD64) 64 return __rdtsc(); 65 #elif defined(NETGEN_ARCH_ARM64) && defined(__GNUC__) 66 // __GNUC__ is also defined by CLANG. Use inline asm to read Generic Timer 67 unsigned long long tics; 68 __asm __volatile("mrs %0, CNTVCT_EL0" : "=&r" (tics)); 69 return tics; 70 #else 71 #warning "Unsupported CPU architecture" 72 return 0; 73 #endif 74 } 75 76 template <class T> ToString(const T & t)77 inline std::string ToString (const T& t) 78 { 79 std::stringstream ss; 80 ss << t; 81 return ss.str(); 82 } 83 84 template<typename T1, typename T2> operator <<(std::ostream & ost,const std::map<T1,T2> & map)85 std::ostream& operator << (std::ostream& ost, const std::map<T1,T2>& map) 86 { 87 for(auto& val : map) 88 ost << "\n" << val.first << ": " << val.second; 89 return ost; 90 } 91 92 template <class T> Swap(T & a,T & b)93 NETGEN_INLINE void Swap (T & a, T & b) 94 { 95 T temp = std::move(a); 96 a = std::move(b); 97 b = std::move(temp); 98 } 99 100 // checks if string starts with sequence StartsWith(const std::string & str,const std::string & start)101 inline bool StartsWith(const std::string& str, const std::string& start) 102 { 103 if(start.size() > str.size()) 104 return false; 105 return std::equal(start.begin(), start.end(), str.begin()); 106 } 107 108 // checks if string ends with sequence EndsWith(const std::string & str,const std::string & end)109 inline bool EndsWith(const std::string& str, const std::string& end) 110 { 111 if(end.size() > str.size()) 112 return false; 113 return std::equal(end.rbegin(), end.rend(), str.rbegin()); 114 } 115 116 template<typename T> AsAtomic(T & d)117 NETGEN_INLINE std::atomic<T> & AsAtomic (T & d) 118 { 119 return reinterpret_cast<std::atomic<T>&> (d); 120 } 121 AtomicAdd(double & sum,double val)122 NETGEN_INLINE double AtomicAdd( double & sum, double val ) 123 { 124 std::atomic<double> & asum = AsAtomic(sum); 125 double current = asum.load(); 126 while (!asum.compare_exchange_weak(current, current + val)) 127 ; 128 return current; 129 } 130 131 template<typename T> AtomicMin(T & minval,T val)132 NETGEN_INLINE T AtomicMin( T & minval, T val ) 133 { 134 std::atomic<T> & aminval = AsAtomic(minval); 135 T current = aminval.load(); 136 while (!aminval.compare_exchange_weak(current, std::min(current, val))) 137 ; 138 return current; 139 } 140 141 template<typename T> AtomicMax(T & maxval,T val)142 NETGEN_INLINE T AtomicMax( T & maxval, T val ) 143 { 144 std::atomic<T> & amaxval = AsAtomic(maxval); 145 T current = amaxval.load(); 146 while (!amaxval.compare_exchange_weak(current, std::max(current, val))) 147 ; 148 return current; 149 } 150 151 namespace detail 152 { 153 template<typename T> 154 struct IndexTypeHelper 155 { 156 private: 157 template<typename T2> checkngcore::detail::IndexTypeHelper158 static constexpr auto check(T2* t) -> typename T2::index_type { return *t; } 159 static constexpr size_t check(...); 160 161 public: 162 using type = decltype(check((T*) nullptr)); // NOLINT 163 }; 164 165 } // namespace detail 166 167 // Get index type of object. If object has a typedef index_type it is this type, else size_t 168 template<typename T> 169 using index_type = typename detail::IndexTypeHelper<T>::type; 170 171 class MyMutex 172 { 173 std::atomic<bool> m; 174 public: MyMutex()175 MyMutex() { m.store(false, std::memory_order_relaxed); } lock()176 void lock() 177 { 178 bool should = false; 179 while (!m.compare_exchange_weak(should, true)) 180 { 181 should = false; 182 #ifdef NETGEN_ARCH_AMD64 183 _mm_pause(); 184 #endif // NETGEN_ARCH_AMD64 185 } 186 } unlock()187 void unlock() 188 { 189 m = false; 190 } 191 }; 192 193 class MyLock 194 { 195 MyMutex & mutex; 196 public: MyLock(MyMutex & amutex)197 MyLock (MyMutex & amutex) : mutex(amutex) { mutex.lock(); } ~MyLock()198 ~MyLock () { mutex.unlock(); } 199 }; 200 201 202 } // namespace ngcore 203 204 #endif // NETGEN_CORE_UTILS_HPP 205