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