Project
Loading...
Searching...
No Matches
GPUExternalAllocator.cxx
Go to the documentation of this file.
1// Copyright 2019-2020 CERN and copyright holders of ALICE O2.
2// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders.
3// All rights not expressly granted are reserved.
4//
5// This software is distributed under the terms of the GNU General Public
6// License v3 (GPL Version 3), copied verbatim in the file "COPYING".
7//
8// In applying this license CERN does not waive the privileges and immunities
9// granted to it by virtue of its status as an Intergovernmental Organization
10// or submit itself to any jurisdiction.
11
12#if defined(TRK_HAS_CUDA_TRACKING)
13#include <cuda_runtime.h>
14#elif defined(TRK_HAS_HIP_TRACKING)
15#include <hip/hip_runtime.h>
16#endif
17
19
20#include <algorithm>
21#include <stdexcept>
22#include <string>
23
24namespace
25{
26#if defined(TRK_HAS_CUDA_TRACKING)
27void checkGpuError(cudaError_t error, const char* call)
28{
29 if (error != cudaSuccess) {
30 throw std::runtime_error(std::string(call) + ": " + cudaGetErrorString(error));
31 }
32}
33#elif defined(TRK_HAS_HIP_TRACKING)
34void checkGpuError(hipError_t error, const char* call)
35{
36 if (error != hipSuccess) {
37 throw std::runtime_error(std::string(call) + ": " + hipGetErrorString(error));
38 }
39}
40#endif
41} // namespace
42
43namespace o2::trk
44{
45
50
52{
53 const auto type = static_cast<MemoryType>(getType());
54 const bool useHost = (type & static_cast<MemoryType>(o2::gpu::GPUMemoryResource::MEMORY_HOST)) != 0;
55 const bool useStack = (type & static_cast<MemoryType>(o2::gpu::GPUMemoryResource::MEMORY_STACK)) != 0;
56
57 void* ptr = useHost ? allocateHost(size) : allocateDevice(size);
58
59 std::lock_guard<std::mutex> guard(mMutex);
60 const uint64_t tag = (useStack && !mTagStack.empty()) ? mTagStack.back() : 0;
61 mAllocations.emplace(ptr, AllocationMeta{useHost ? AllocationSpace::Host : AllocationSpace::Device, tag, useStack});
62 if (useStack) {
63 mTaggedAllocations[tag].push_back(ptr);
64 }
65
66 return ptr;
67}
68
70{
71 if (!ptr) {
72 return;
73 }
74
75 AllocationMeta meta;
76 {
77 std::lock_guard<std::mutex> guard(mMutex);
78 const auto found = mAllocations.find(ptr);
79 if (found == mAllocations.end()) {
80 return;
81 }
82 meta = found->second;
83 mAllocations.erase(found);
84 if (meta.stacked) {
85 removeFromTagLocked(meta.tag, ptr);
86 }
87 }
88
89 freeAllocation(ptr, meta.space);
90}
91
93{
94 std::lock_guard<std::mutex> guard(mMutex);
95 mTagStack.push_back(tag);
96}
97
99{
100 std::vector<std::pair<void*, AllocationSpace>> toFree;
101 {
102 std::lock_guard<std::mutex> guard(mMutex);
103 if (mTagStack.empty() || mTagStack.back() != tag) {
104 throw std::runtime_error("GPUExternalAllocator tag stack mismatch");
105 }
106
107 const auto tagged = mTaggedAllocations.find(tag);
108 if (tagged != mTaggedAllocations.end()) {
109 toFree.reserve(tagged->second.size());
110 for (void* ptr : tagged->second) {
111 const auto found = mAllocations.find(ptr);
112 if (found != mAllocations.end()) {
113 toFree.emplace_back(ptr, found->second.space);
114 mAllocations.erase(found);
115 }
116 }
117 mTaggedAllocations.erase(tagged);
118 }
119
120 mTagStack.pop_back();
121 }
122
123 for (const auto& [ptr, space] : toFree) {
124 freeAllocation(ptr, space);
125 }
126}
127
129{
130 std::vector<std::pair<void*, AllocationSpace>> toFree;
131 {
132 std::lock_guard<std::mutex> guard(mMutex);
133 toFree.reserve(mAllocations.size());
134 for (const auto& [ptr, meta] : mAllocations) {
135 toFree.emplace_back(ptr, meta.space);
136 }
137 mAllocations.clear();
138 mTaggedAllocations.clear();
139 mTagStack.clear();
140 }
141
142 for (const auto& [ptr, space] : toFree) {
143 freeAllocation(ptr, space);
144 }
145}
146
147void* GPUExternalAllocator::allocateHost(size_t size)
148{
149 void* ptr = nullptr;
150#if defined(TRK_HAS_CUDA_TRACKING)
151 checkGpuError(cudaHostAlloc(&ptr, size, cudaHostAllocPortable), "cudaHostAlloc");
152#elif defined(TRK_HAS_HIP_TRACKING)
153 checkGpuError(hipHostMalloc(&ptr, size, hipHostMallocPortable), "hipHostMalloc");
154#else
155 throw std::runtime_error("GPUExternalAllocator built without a GPU backend");
156#endif
157 return ptr;
158}
159
160void* GPUExternalAllocator::allocateDevice(size_t size)
161{
162 void* ptr = nullptr;
163#if defined(TRK_HAS_CUDA_TRACKING)
164 checkGpuError(cudaMalloc(&ptr, size), "cudaMalloc");
165#elif defined(TRK_HAS_HIP_TRACKING)
166 checkGpuError(hipMalloc(&ptr, size), "hipMalloc");
167#else
168 throw std::runtime_error("GPUExternalAllocator built without a GPU backend");
169#endif
170 return ptr;
171}
172
173void GPUExternalAllocator::freeAllocation(void* ptr, AllocationSpace space)
174{
175 if (!ptr) {
176 return;
177 }
178
179#if defined(TRK_HAS_CUDA_TRACKING)
180 if (space == AllocationSpace::Host) {
181 checkGpuError(cudaFreeHost(ptr), "cudaFreeHost");
182 } else {
183 checkGpuError(cudaFree(ptr), "cudaFree");
184 }
185#elif defined(TRK_HAS_HIP_TRACKING)
186 if (space == AllocationSpace::Host) {
187 checkGpuError(hipHostFree(ptr), "hipHostFree");
188 } else {
189 checkGpuError(hipFree(ptr), "hipFree");
190 }
191#else
192 (void)space;
193#endif
194}
195
196void GPUExternalAllocator::removeFromTagLocked(uint64_t tag, void* ptr)
197{
198 const auto tagged = mTaggedAllocations.find(tag);
199 if (tagged == mTaggedAllocations.end()) {
200 return;
201 }
202
203 auto& entries = tagged->second;
204 entries.erase(std::remove(entries.begin(), entries.end(), ptr), entries.end());
205 if (entries.empty()) {
206 mTaggedAllocations.erase(tagged);
207 }
208}
209
210} // namespace o2::trk
TBranch * ptr
Type getType() const noexcept
void * allocate(size_t size) override
void pushTagOnStack(uint64_t tag) override
void deallocate(char *ptr, size_t size) override
void popTagOffStack(uint64_t tag) override
GLsizeiptr size
Definition glcorearb.h:659
GLint GLint GLsizei GLint GLenum GLenum type
Definition glcorearb.h:275
typedef void(APIENTRYP PFNGLCULLFACEPROC)(GLenum mode)