llmemory.h 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293
  1. /**
  2. * @file llmemory.h
  3. * @brief Memory allocation/deallocation header-stuff goes here.
  4. *
  5. * $LicenseInfo:firstyear=2002&license=viewergpl$
  6. *
  7. * Copyright (c) 2002-2009, Linden Research, Inc.
  8. *
  9. * Second Life Viewer Source Code
  10. * The source code in this file ("Source Code") is provided by Linden Lab
  11. * to you under the terms of the GNU General Public License, version 2.0
  12. * ("GPL"), unless you have obtained a separate licensing agreement
  13. * ("Other License"), formally executed by you and Linden Lab. Terms of
  14. * the GPL can be found in doc/GPL-license.txt in this distribution, or
  15. * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
  16. *
  17. * There are special exceptions to the terms and conditions of the GPL as
  18. * it is applied to this Source Code. View the full text of the exception
  19. * in the file doc/FLOSS-exception.txt in this software distribution, or
  20. * online at
  21. * http://secondlifegrid.net/programs/open_source/licensing/flossexception
  22. *
  23. * By copying, modifying or distributing this software, you acknowledge
  24. * that you have read and understood your obligations described above,
  25. * and agree to abide by those obligations.
  26. *
  27. * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
  28. * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
  29. * COMPLETENESS OR PERFORMANCE.
  30. * $/LicenseInfo$
  31. */
  32. #ifndef LL_MEMORY_H
  33. #define LL_MEMORY_H
  34. #include <set>
  35. #include <string.h> // For memcpy()
  36. #if !LL_WINDOWS
  37. # include <stdint.h>
  38. #endif
  39. #if LL_JEMALLOC
  40. # include "jemalloc/jemalloc.h"
  41. #elif !LL_WINDOWS
  42. # include <stdlib.h>
  43. #endif
  44. #include "llerror.h"
  45. #include "hbtracy.h"
  46. // Utilities and macros used for SSE2 optimized maths
  47. #if LL_DEBUG
  48. void ll_assert_aligned_error();
  49. # define ll_assert_aligned(ptr,alignment) \
  50. if (LL_UNLIKELY(reinterpret_cast<uintptr_t>(ptr) % (U32)alignment != 0)) \
  51. ll_assert_aligned_error()
  52. #else
  53. # define ll_assert_aligned(ptr,alignment)
  54. #endif
  55. // Purely static class
  56. class LLMemory
  57. {
  58. LLMemory() = delete;
  59. ~LLMemory() = delete;
  60. protected:
  61. LOG_CLASS(LLMemory);
  62. public:
  63. // These two methods must only be called from the main thread. Called from
  64. // indra/newview/llappviewer*.cpp:
  65. static void initClass();
  66. static void cleanupClass();
  67. // Return the resident set size of the current process, in bytes, or zero
  68. // if not known.
  69. static U64 getCurrentRSS();
  70. static void updateMemoryInfo(bool trim_heap = false);
  71. static void logMemoryInfo();
  72. static U32 getMaxPhysicalMemKB() { return sMaxPhysicalMemInKB; }
  73. static U32 getMaxVirtualMemKB() { return sMaxVirtualMemInKB; }
  74. static U32 getAvailablePhysicalMemKB() { return sAvailPhysicalMemInKB; }
  75. static U32 getAvailableVirtualMemKB() { return sAvailVirtualMemInKB; }
  76. static U32 getAllocatedMemKB() { return sAllocatedMemInKB; }
  77. static U32 getAllocatedPageSizeKB() { return sAllocatedPageSizeInKB; }
  78. static void allocationFailed(size_t size = 0);
  79. static void resetFailedAllocation() { sFailedAllocation = false; }
  80. LL_INLINE static bool hasFailedAllocation() { return sFailedAllocation; }
  81. LL_INLINE static bool gotFailedAllocation() { return sFailedAllocationOnce; }
  82. // The four methods below used to be part of LLMemoryInfo (in llsys.h/cpp),
  83. // which I removed to merge here, since they did not even relate with the
  84. // global system info, but instead with the memory consumption of the
  85. // viewer itself... HB
  86. static U32 getPhysicalMemoryKB(); // Memory size in KiloBytes
  87. // Get the available memory infomation in KiloBytes.
  88. static void getMaxMemoryKB(U32& max_physical_mem_kb,
  89. U32& max_virtual_mem_kb);
  90. static void getAvailableMemoryKB(U32& avail_physical_mem_kb,
  91. U32& avail_virtual_mem_kb);
  92. static std::string getInfo();
  93. private:
  94. static bool sFailedAllocation;
  95. static bool sFailedAllocationOnce;
  96. static U32 sMaxPhysicalMemInKB;
  97. static U32 sMaxVirtualMemInKB;
  98. static U32 sAvailPhysicalMemInKB;
  99. static U32 sAvailVirtualMemInKB;
  100. static U32 sAllocatedMemInKB;
  101. static U32 sAllocatedPageSizeInKB;
  102. };
  103. // Generic aligned memory management. Note that other, usage-specific functions
  104. // are used to allocate (pooled) memory for images, vertex buffers and volumes.
  105. // See: llimage/llimage.h, llrender/llvertexbuffer.h and llmath/llvolume.h. HB
  106. // NOTE: since the memory functions below use void* pointers instead of char*
  107. // (because void* is the type used by malloc and jemalloc), strict aliasing is
  108. // not possible on structures allocated with them. Make sure you forbid your
  109. // compiler to optimize with strict aliasing assumption (i.e. for gcc, DO use
  110. // the -fno-strict-aliasing option) ! HB
  111. // IMPORTANT: returned hunk MUST be freed with ll_aligned_free_16().
  112. LL_INLINE void* ll_aligned_malloc_16(size_t size, bool track_failure = true)
  113. {
  114. if (LL_UNLIKELY(size <= 0)) return NULL;
  115. void* ptr;
  116. #if LL_JEMALLOC || LL_MIMALLOC || LL_DARWIN
  117. // With jemalloc, mimalloc or macOS, all malloc() calls are 16-bytes
  118. // aligned.
  119. ptr = malloc(size);
  120. #elif LL_WINDOWS
  121. ptr = _aligned_malloc(size, 16);
  122. #else
  123. if (LL_UNLIKELY(posix_memalign(&ptr, 16, size) != 0))
  124. {
  125. // Out of memory
  126. if (track_failure)
  127. {
  128. LLMemory::allocationFailed(size);
  129. }
  130. return NULL;
  131. }
  132. #endif
  133. if (LL_UNLIKELY(ptr == NULL && track_failure))
  134. {
  135. LLMemory::allocationFailed(size);
  136. }
  137. LL_TRACY_ALLOC(ptr, size, trc_mem_align16);
  138. return ptr;
  139. }
  140. LL_INLINE void ll_aligned_free_16(void* p) noexcept
  141. {
  142. LL_TRACY_FREE(p, trc_mem_align16);
  143. if (LL_LIKELY(p))
  144. {
  145. #if LL_JEMALLOC || LL_MIMALLOC || LL_DARWIN
  146. // With jemalloc, mimalloc or macOS, all malloc() calls are 16-bytes
  147. // aligned.
  148. free(p);
  149. #elif LL_WINDOWS
  150. _aligned_free(p);
  151. #else
  152. free(p); // posix_memalign() is compatible with free()
  153. #endif
  154. }
  155. }
  156. // IMPORTANT: returned hunk MUST be freed with ll_aligned_free_16().
  157. LL_INLINE void* ll_aligned_realloc_16(void* ptr, size_t size, size_t old_size)
  158. {
  159. if (LL_UNLIKELY(size == old_size && ptr))
  160. {
  161. return ptr;
  162. }
  163. LL_TRACY_FREE(ptr, trc_mem_align16);
  164. void* ret;
  165. #if LL_JEMALLOC || LL_MIMALLOC || LL_DARWIN
  166. // With jemalloc, mimalloc or macOS, all realloc() calls are 16-bytes
  167. // aligned.
  168. ret = realloc(ptr, size);
  169. #elif LL_WINDOWS
  170. ret = _aligned_realloc(ptr, size, 16);
  171. #else
  172. if (LL_LIKELY(posix_memalign(&ret, 16, size) == 0))
  173. {
  174. if (LL_LIKELY(ptr))
  175. {
  176. // FIXME: memcpy is SLOW
  177. memcpy(ret, ptr, old_size < size ? old_size : size);
  178. free(ptr);
  179. }
  180. LL_TRACY_ALLOC(ret, size, trc_mem_align16);
  181. return ret;
  182. }
  183. LLMemory::allocationFailed(size);
  184. return NULL;
  185. #endif
  186. if (LL_UNLIKELY(ret == NULL))
  187. {
  188. LLMemory::allocationFailed(size);
  189. }
  190. LL_TRACY_ALLOC(ret, size, trc_mem_align16);
  191. return ret;
  192. }
  193. LL_INLINE void* ll_aligned_malloc(size_t size, int align)
  194. {
  195. if (LL_UNLIKELY(size <= 0)) return NULL;
  196. void* addr;
  197. #if LL_JEMALLOC
  198. addr = mallocx(size, MALLOCX_ALIGN((size_t)align) | MALLOCX_TCACHE_NONE);
  199. #elif LL_WINDOWS
  200. addr = _aligned_malloc(size, align);
  201. #else
  202. addr = malloc(size + (align - 1) + sizeof(void*));
  203. if (LL_LIKELY(addr))
  204. {
  205. char* aligned = ((char*)addr) + sizeof(void*);
  206. aligned += align - ((uintptr_t)aligned & (align - 1));
  207. ((void**)aligned)[-1] = addr;
  208. addr = (void*)aligned;
  209. }
  210. #endif
  211. if (LL_UNLIKELY(addr == NULL))
  212. {
  213. LLMemory::allocationFailed(size);
  214. }
  215. LL_TRACY_ALLOC(addr, size, trc_mem_align);
  216. return addr;
  217. }
  218. LL_INLINE void ll_aligned_free(void* addr) noexcept
  219. {
  220. LL_TRACY_FREE(addr, trc_mem_align);
  221. if (LL_LIKELY(addr))
  222. {
  223. #if LL_JEMALLOC
  224. dallocx(addr, 0);
  225. #elif LL_WINDOWS
  226. _aligned_free(addr);
  227. #else
  228. free(((void**)addr)[-1]);
  229. #endif
  230. }
  231. }
  232. // Copy words 16-bytes blocks from src to dst. Source and destination MUST NOT
  233. // OVERLAP. Source and dest must be 16-byte aligned and size must be multiple
  234. // of 16.
  235. void ll_memcpy_nonaliased_aligned_16(char* __restrict dst,
  236. const char* __restrict src, size_t bytes);
  237. // To reduce the sources verbosity and typing, you may use this macro in the
  238. // public methods declaration block for alignas(16) classes. HB
  239. #define LL_ALIGNED16_NEW_DELETE \
  240. LL_INLINE void* operator new(size_t size) \
  241. { return ll_aligned_malloc_16(size); } \
  242. LL_INLINE void* operator new[](size_t size) \
  243. { return ll_aligned_malloc_16(size); } \
  244. LL_INLINE void operator delete(void* ptr) noexcept \
  245. { ll_aligned_free_16(ptr); } \
  246. LL_INLINE void operator delete[](void* ptr) noexcept \
  247. { ll_aligned_free_16(ptr); }
  248. // Handy conversion macro. HB
  249. #define BYTES2MEGABYTES(x) ((x) >> 20)
  250. #endif // LL_MEMORY_H