1 //============================================================================
2 // Copyright (c) Kitware, Inc.
3 // All rights reserved.
4 // See LICENSE.txt for details.
5 //
6 // This software is distributed WITHOUT ANY WARRANTY; without even
7 // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
8 // PURPOSE. See the above copyright notice for more information.
9 //============================================================================
10
11 #include <vtkm/cont/internal/ArrayPortalFromIterators.h>
12 #include <vtkm/cont/internal/Buffer.h>
13
14 #include <vtkm/cont/serial/DeviceAdapterSerial.h>
15
16 #include <vtkm/cont/testing/Testing.h>
17
18 namespace
19 {
20
21 using T = vtkm::FloatDefault;
22 constexpr vtkm::Id ARRAY_SIZE = 20;
23
24 using PortalType = vtkm::cont::internal::ArrayPortalFromIterators<T*>;
25 using PortalTypeConst = vtkm::cont::internal::ArrayPortalFromIterators<const T*>;
26
27 struct TestMetaData
28 {
29 vtkm::Id Value = 0;
30 };
31
32 constexpr vtkm::Id METADATA_VALUE = 42;
33
CheckMetaData(const vtkm::cont::internal::Buffer & buffer)34 bool CheckMetaData(const vtkm::cont::internal::Buffer& buffer)
35 {
36 return buffer.GetMetaData<TestMetaData>().Value == METADATA_VALUE;
37 }
38
MakePortal(void * buffer,vtkm::Id numValues)39 PortalType MakePortal(void* buffer, vtkm::Id numValues)
40 {
41 return PortalType(static_cast<T*>(buffer),
42 static_cast<T*>(buffer) + static_cast<std::size_t>(numValues));
43 };
44
MakePortal(const void * buffer,vtkm::Id numValues)45 PortalTypeConst MakePortal(const void* buffer, vtkm::Id numValues)
46 {
47 return PortalTypeConst(static_cast<const T*>(buffer),
48 static_cast<const T*>(buffer) + static_cast<std::size_t>(numValues));
49 };
50
VectorDeleter(void * container)51 void VectorDeleter(void* container)
52 {
53 std::vector<T>* v = reinterpret_cast<std::vector<T>*>(container);
54 delete v;
55 }
56
VectorReallocator(void * & memory,void * & container,vtkm::BufferSizeType oldSize,vtkm::BufferSizeType newSize)57 void VectorReallocator(void*& memory,
58 void*& container,
59 vtkm::BufferSizeType oldSize,
60 vtkm::BufferSizeType newSize)
61 {
62 std::vector<T>* v = reinterpret_cast<std::vector<T>*>(container);
63 VTKM_TEST_ASSERT(v->size() == static_cast<std::size_t>(oldSize));
64 VTKM_TEST_ASSERT(v->empty() || (memory == v->data()));
65
66 v->resize(static_cast<std::size_t>(newSize));
67 memory = v->data();
68 }
69 struct VectorDeleter
70 {
71 std::shared_ptr<std::vector<T>> Data;
72
VectorDeleter__anon0ec9fcfe0111::VectorDeleter73 VectorDeleter(vtkm::Id numValues)
74 : Data(new std::vector<T>(static_cast<size_t>(numValues)))
75 {
76 }
77
78 template <typename U>
operator ()__anon0ec9fcfe0111::VectorDeleter79 void operator()(U* p)
80 {
81 if (this->Data)
82 {
83 VTKM_TEST_ASSERT(reinterpret_cast<T*>(p) == this->Data->data());
84 this->Data.reset();
85 }
86 }
87 };
88
89
DoTest()90 void DoTest()
91 {
92 constexpr vtkm::Id BUFFER_SIZE = ARRAY_SIZE * static_cast<vtkm::Id>(sizeof(T));
93 constexpr vtkm::cont::DeviceAdapterTagSerial device;
94
95 vtkm::cont::internal::Buffer buffer;
96
97 {
98 TestMetaData metadata;
99 metadata.Value = METADATA_VALUE;
100 buffer.SetMetaData(metadata);
101 VTKM_TEST_ASSERT(CheckMetaData(buffer));
102 }
103
104 std::cout << "Copy uninitialized buffer" << std::endl;
105 {
106 vtkm::cont::internal::Buffer copy;
107 copy.DeepCopyFrom(buffer);
108 VTKM_TEST_ASSERT(copy.GetNumberOfBytes() == 0);
109 VTKM_TEST_ASSERT(CheckMetaData(copy));
110 }
111
112 std::cout << "Initialize buffer" << std::endl;
113 {
114 vtkm::cont::Token token;
115 buffer.SetNumberOfBytes(BUFFER_SIZE, vtkm::CopyFlag::Off, token);
116 }
117
118 VTKM_TEST_ASSERT(buffer.GetNumberOfBytes() == BUFFER_SIZE);
119
120 std::cout << "Copy sized but uninitialized buffer" << std::endl;
121 {
122 vtkm::cont::internal::Buffer copy;
123 copy.DeepCopyFrom(buffer);
124 VTKM_TEST_ASSERT(copy.GetNumberOfBytes() == BUFFER_SIZE);
125 VTKM_TEST_ASSERT(CheckMetaData(copy));
126 VTKM_TEST_ASSERT(!copy.IsAllocatedOnHost());
127 VTKM_TEST_ASSERT(!copy.IsAllocatedOnDevice(device));
128 }
129
130 std::cout << "Fill up values on host" << std::endl;
131 {
132 vtkm::cont::Token token;
133 SetPortal(MakePortal(buffer.WritePointerHost(token), ARRAY_SIZE));
134 }
135 VTKM_TEST_ASSERT(buffer.IsAllocatedOnHost());
136 VTKM_TEST_ASSERT(!buffer.IsAllocatedOnDevice(device));
137
138 std::cout << "Check values on host" << std::endl;
139 {
140 vtkm::cont::Token token;
141 CheckPortal(MakePortal(buffer.ReadPointerHost(token), ARRAY_SIZE));
142 }
143 VTKM_TEST_ASSERT(buffer.IsAllocatedOnHost());
144 VTKM_TEST_ASSERT(!buffer.IsAllocatedOnDevice(device));
145
146 std::cout << "Copy buffer with host data" << std::endl;
147 {
148 vtkm::cont::Token token;
149 vtkm::cont::internal::Buffer copy;
150 copy.DeepCopyFrom(buffer);
151 VTKM_TEST_ASSERT(copy.GetNumberOfBytes() == BUFFER_SIZE);
152 VTKM_TEST_ASSERT(CheckMetaData(copy));
153 VTKM_TEST_ASSERT(copy.IsAllocatedOnHost());
154 VTKM_TEST_ASSERT(!copy.IsAllocatedOnDevice(device));
155 CheckPortal(MakePortal(buffer.ReadPointerHost(token), ARRAY_SIZE));
156 }
157
158 std::cout << "Check values on device" << std::endl;
159 {
160 vtkm::cont::Token token;
161 CheckPortal(MakePortal(buffer.ReadPointerDevice(device, token), ARRAY_SIZE));
162 }
163 VTKM_TEST_ASSERT(buffer.IsAllocatedOnHost());
164 VTKM_TEST_ASSERT(buffer.IsAllocatedOnDevice(device));
165
166 std::cout << "Resize array and access write on device" << std::endl;
167 {
168 vtkm::cont::Token token;
169 buffer.SetNumberOfBytes(BUFFER_SIZE / 2, vtkm::CopyFlag::On, token);
170 VTKM_TEST_ASSERT(buffer.GetNumberOfBytes() == BUFFER_SIZE / 2);
171 CheckPortal(MakePortal(buffer.WritePointerDevice(device, token), ARRAY_SIZE / 2));
172 }
173 VTKM_TEST_ASSERT(!buffer.IsAllocatedOnHost());
174 VTKM_TEST_ASSERT(buffer.IsAllocatedOnDevice(device));
175
176 std::cout << "Resize array and access write on host" << std::endl;
177 // Note that this is a weird corner case where the array was resized while saving the data
178 // and then requested on another device.
179 {
180 vtkm::cont::Token token;
181 buffer.SetNumberOfBytes(BUFFER_SIZE * 2, vtkm::CopyFlag::On, token);
182 VTKM_TEST_ASSERT(buffer.GetNumberOfBytes() == BUFFER_SIZE * 2);
183 // Although the array is twice ARRAY_SIZE, the valid values are only ARRAY_SIZE/2
184 CheckPortal(MakePortal(buffer.WritePointerHost(token), ARRAY_SIZE / 2));
185 }
186 VTKM_TEST_ASSERT(buffer.IsAllocatedOnHost());
187 VTKM_TEST_ASSERT(!buffer.IsAllocatedOnDevice(device));
188
189 std::cout << "Reset with device data" << std::endl;
190 std::vector<T> v(ARRAY_SIZE);
191 void* devicePointer = v.data();
192 SetPortal(MakePortal(devicePointer, ARRAY_SIZE));
193 buffer.Reset(vtkm::cont::internal::BufferInfo(device,
194 devicePointer,
195 new std::vector<T>(std::move(v)),
196 BUFFER_SIZE,
197 VectorDeleter,
198 VectorReallocator));
199 VTKM_TEST_ASSERT(buffer.GetNumberOfBytes() == BUFFER_SIZE);
200 VTKM_TEST_ASSERT(!buffer.IsAllocatedOnHost());
201 VTKM_TEST_ASSERT(buffer.IsAllocatedOnDevice(device));
202
203 std::cout << "Make sure device pointer is as expected" << std::endl;
204 {
205 vtkm::cont::Token token;
206 VTKM_TEST_ASSERT(buffer.WritePointerDevice(device, token) == devicePointer);
207 }
208
209 std::cout << "Copy buffer with device data" << std::endl;
210 {
211 vtkm::cont::Token token;
212 vtkm::cont::internal::Buffer copy;
213 copy.DeepCopyFrom(buffer);
214 VTKM_TEST_ASSERT(copy.GetNumberOfBytes() == BUFFER_SIZE);
215 VTKM_TEST_ASSERT(CheckMetaData(copy));
216 VTKM_TEST_ASSERT(!copy.IsAllocatedOnHost());
217 VTKM_TEST_ASSERT(copy.IsAllocatedOnDevice(device));
218 CheckPortal(MakePortal(buffer.ReadPointerDevice(device, token), ARRAY_SIZE));
219 }
220
221 std::cout << "Pull data to host" << std::endl;
222 {
223 vtkm::cont::Token token;
224 CheckPortal(MakePortal(buffer.ReadPointerHost(token), ARRAY_SIZE));
225 }
226 }
227
228 } // anonymous namespace
229
UnitTestBuffer(int argc,char * argv[])230 int UnitTestBuffer(int argc, char* argv[])
231 {
232 return vtkm::cont::testing::Testing::Run(DoTest, argc, argv);
233 }
234