ArrayHandle.hxx 13.1 KB
Newer Older
1 2 3 4 5 6 7 8
//============================================================================
//  Copyright (c) Kitware, Inc.
//  All rights reserved.
//  See LICENSE.txt for details.
//  This software is distributed WITHOUT ANY WARRANTY; without even
//  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
//  PURPOSE.  See the above copyright notice for more information.
//
9
//  Copyright 2014 National Technology & Engineering Solutions of Sandia, LLC (NTESS).
10 11 12
//  Copyright 2014 UT-Battelle, LLC.
//  Copyright 2014 Los Alamos National Security.
//
13
//  Under the terms of Contract DE-NA0003525 with NTESS,
14 15 16 17 18 19 20
//  the U.S. Government retains certain rights in this software.
//
//  Under the terms of Contract DE-AC52-06NA25396 with Los Alamos National
//  Laboratory (LANL), the U.S. Government retains certain rights in
//  this software.
//============================================================================

21 22 23 24
namespace vtkm
{
namespace cont
{
25

26 27
template <typename T, typename S>
ArrayHandle<T, S>::ArrayHandle()
28 29 30 31 32 33
  : Internals(new InternalStruct)
{
  this->Internals->ControlArrayValid = false;
  this->Internals->ExecutionArrayValid = false;
}

34 35
template <typename T, typename S>
ArrayHandle<T, S>::ArrayHandle(const ArrayHandle<T, S>& src)
36
  : Internals(src.Internals)
37 38
{
}
39

40
template <typename T, typename S>
41
ArrayHandle<T, S>::ArrayHandle(ArrayHandle<T, S>&& src) noexcept
42
  : Internals(std::move(src.Internals))
43 44
{
}
45

46 47
template <typename T, typename S>
ArrayHandle<T, S>::ArrayHandle(const typename ArrayHandle<T, S>::StorageType& storage)
48 49 50 51 52 53 54
  : Internals(new InternalStruct)
{
  this->Internals->ControlArray = storage;
  this->Internals->ControlArrayValid = true;
  this->Internals->ExecutionArrayValid = false;
}

55
template <typename T, typename S>
56
ArrayHandle<T, S>::ArrayHandle(typename ArrayHandle<T, S>::StorageType&& storage) noexcept
57 58 59 60 61 62 63
  : Internals(new InternalStruct)
{
  this->Internals->ControlArray = std::move(storage);
  this->Internals->ControlArrayValid = true;
  this->Internals->ExecutionArrayValid = false;
}

64 65
template <typename T, typename S>
ArrayHandle<T, S>::~ArrayHandle()
66 67 68
{
}

69 70
template <typename T, typename S>
ArrayHandle<T, S>& ArrayHandle<T, S>::operator=(const ArrayHandle<T, S>& src)
71 72 73 74 75
{
  this->Internals = src.Internals;
  return *this;
}

76
template <typename T, typename S>
77
ArrayHandle<T, S>& ArrayHandle<T, S>::operator=(ArrayHandle<T, S>&& src) noexcept
78 79 80 81 82
{
  this->Internals = std::move(src.Internals);
  return *this;
}

83 84
template <typename T, typename S>
typename ArrayHandle<T, S>::StorageType& ArrayHandle<T, S>::GetStorage()
85 86 87 88 89 90 91 92
{
  this->SyncControlArray();
  if (this->Internals->ControlArrayValid)
  {
    return this->Internals->ControlArray;
  }
  else
  {
93
    throw vtkm::cont::ErrorInternal(
94 95 96 97
      "ArrayHandle::SyncControlArray did not make control array valid.");
  }
}

98 99
template <typename T, typename S>
const typename ArrayHandle<T, S>::StorageType& ArrayHandle<T, S>::GetStorage() const
100 101 102 103 104 105 106 107
{
  this->SyncControlArray();
  if (this->Internals->ControlArrayValid)
  {
    return this->Internals->ControlArray;
  }
  else
  {
108
    throw vtkm::cont::ErrorInternal(
109 110 111 112
      "ArrayHandle::SyncControlArray did not make control array valid.");
  }
}

113 114
template <typename T, typename S>
typename ArrayHandle<T, S>::PortalControl ArrayHandle<T, S>::GetPortalControl()
115 116 117 118 119 120 121 122 123 124 125 126
{
  this->SyncControlArray();
  if (this->Internals->ControlArrayValid)
  {
    // If the user writes into the iterator we return, then the execution
    // array will become invalid. Play it safe and release the execution
    // resources. (Use the const version to preserve the execution array.)
    this->ReleaseResourcesExecutionInternal();
    return this->Internals->ControlArray.GetPortal();
  }
  else
  {
127
    throw vtkm::cont::ErrorInternal(
128
      "ArrayHandle::SyncControlArray did not make control array valid.");
129 130 131
  }
}

132 133
template <typename T, typename S>
typename ArrayHandle<T, S>::PortalConstControl ArrayHandle<T, S>::GetPortalConstControl() const
134 135 136 137 138 139 140 141
{
  this->SyncControlArray();
  if (this->Internals->ControlArrayValid)
  {
    return this->Internals->ControlArray.GetPortalConst();
  }
  else
  {
142
    throw vtkm::cont::ErrorInternal(
143
      "ArrayHandle::SyncControlArray did not make control array valid.");
144 145 146
  }
}

147 148
template <typename T, typename S>
vtkm::Id ArrayHandle<T, S>::GetNumberOfValues() const
149 150 151 152 153 154 155 156 157 158 159 160 161 162 163
{
  if (this->Internals->ControlArrayValid)
  {
    return this->Internals->ControlArray.GetNumberOfValues();
  }
  else if (this->Internals->ExecutionArrayValid)
  {
    return this->Internals->ExecutionArray->GetNumberOfValues();
  }
  else
  {
    return 0;
  }
}

164 165
template <typename T, typename S>
void ArrayHandle<T, S>::Shrink(vtkm::Id numberOfValues)
166
{
167
  VTKM_ASSERT(numberOfValues >= 0);
168

169
  if (numberOfValues > 0)
170
  {
171 172 173
    vtkm::Id originalNumberOfValues = this->GetNumberOfValues();

    if (numberOfValues < originalNumberOfValues)
174
    {
175 176 177 178 179 180 181 182
      if (this->Internals->ControlArrayValid)
      {
        this->Internals->ControlArray.Shrink(numberOfValues);
      }
      if (this->Internals->ExecutionArrayValid)
      {
        this->Internals->ExecutionArray->Shrink(numberOfValues);
      }
183
    }
184
    else if (numberOfValues == originalNumberOfValues)
185
    {
186
      // Nothing to do.
187
    }
188 189
    else // numberOfValues > originalNumberOfValues
    {
190
      throw vtkm::cont::ErrorBadValue("ArrayHandle::Shrink cannot be used to grow array.");
191 192 193
    }

    VTKM_ASSERT(this->GetNumberOfValues() == numberOfValues);
194
  }
195
  else // numberOfValues == 0
196
  {
197 198 199 200
    // If we are shrinking to 0, there is nothing to save and we might as well
    // free up memory. Plus, some storage classes expect that data will be
    // deallocated when the size goes to zero.
    this->Allocate(0);
201 202 203
  }
}

204 205 206 207
template <typename T, typename S>
template <typename DeviceAdapterTag>
typename ArrayHandle<T, S>::template ExecutionTypes<DeviceAdapterTag>::PortalConst
  ArrayHandle<T, S>::PrepareForInput(DeviceAdapterTag) const
208 209 210
{
  VTKM_IS_DEVICE_ADAPTER_TAG(DeviceAdapterTag);

211
  if (!this->Internals->ControlArrayValid && !this->Internals->ExecutionArrayValid)
212
  {
213 214 215 216
    // Want to use an empty array.
    // Set up ArrayHandle state so this actually works.
    this->Internals->ControlArray.Allocate(0);
    this->Internals->ControlArrayValid = true;
217 218 219 220
  }

  this->PrepareForDevice(DeviceAdapterTag());
  typename ExecutionTypes<DeviceAdapterTag>::PortalConst portal =
221 222
    this->Internals->ExecutionArray->PrepareForInput(!this->Internals->ExecutionArrayValid,
                                                     DeviceAdapterTag());
223 224 225 226 227 228

  this->Internals->ExecutionArrayValid = true;

  return portal;
}

229 230 231 232
template <typename T, typename S>
template <typename DeviceAdapterTag>
typename ArrayHandle<T, S>::template ExecutionTypes<DeviceAdapterTag>::Portal
ArrayHandle<T, S>::PrepareForOutput(vtkm::Id numberOfValues, DeviceAdapterTag)
233 234 235 236 237 238 239 240 241 242
{
  VTKM_IS_DEVICE_ADAPTER_TAG(DeviceAdapterTag);

  // Invalidate any control arrays.
  // Should the control array resource be released? Probably not a good
  // idea when shared with execution.
  this->Internals->ControlArrayValid = false;

  this->PrepareForDevice(DeviceAdapterTag());
  typename ExecutionTypes<DeviceAdapterTag>::Portal portal =
243
    this->Internals->ExecutionArray->PrepareForOutput(numberOfValues, DeviceAdapterTag());
244 245 246 247 248 249 250 251 252 253 254 255 256 257 258

  // We are assuming that the calling code will fill the array using the
  // iterators we are returning, so go ahead and mark the execution array as
  // having valid data. (A previous version of this class had a separate call
  // to mark the array as filled, but that was onerous to call at the the
  // right time and rather pointless since it is basically always the case
  // that the array is going to be filled before anything else. In this
  // implementation the only access to the array is through the iterators
  // returned from this method, so you would have to work to invalidate this
  // assumption anyway.)
  this->Internals->ExecutionArrayValid = true;

  return portal;
}

259 260 261 262
template <typename T, typename S>
template <typename DeviceAdapterTag>
typename ArrayHandle<T, S>::template ExecutionTypes<DeviceAdapterTag>::Portal
  ArrayHandle<T, S>::PrepareForInPlace(DeviceAdapterTag)
263 264 265
{
  VTKM_IS_DEVICE_ADAPTER_TAG(DeviceAdapterTag);

266
  if (!this->Internals->ControlArrayValid && !this->Internals->ExecutionArrayValid)
267
  {
268 269 270 271
    // Want to use an empty array.
    // Set up ArrayHandle state so this actually works.
    this->Internals->ControlArray.Allocate(0);
    this->Internals->ControlArrayValid = true;
272 273 274 275
  }

  this->PrepareForDevice(DeviceAdapterTag());
  typename ExecutionTypes<DeviceAdapterTag>::Portal portal =
276 277
    this->Internals->ExecutionArray->PrepareForInPlace(!this->Internals->ExecutionArrayValid,
                                                       DeviceAdapterTag());
278 279 280 281 282 283 284 285 286 287 288

  this->Internals->ExecutionArrayValid = true;

  // Invalidate any control arrays since their data will become invalid when
  // the execution data is overwritten. Don't actually release the control
  // array. It may be shared as the execution array.
  this->Internals->ControlArrayValid = false;

  return portal;
}

289 290 291
template <typename T, typename S>
template <typename DeviceAdapterTag>
void ArrayHandle<T, S>::PrepareForDevice(DeviceAdapterTag) const
292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310
{
  if (this->Internals->ExecutionArray != nullptr)
  {
    if (this->Internals->ExecutionArray->IsDeviceAdapter(DeviceAdapterTag()))
    {
      // Already have manager for correct device adapter. Nothing to do.
      return;
    }
    else
    {
      // Have the wrong manager. Delete the old one and create a new one
      // of the right type. (BTW, it would be possible for the array handle
      // to hold references to execution arrays on multiple devices. However,
      // there is not a clear use case for that yet and it is unclear what
      // the behavior of "dirty" arrays should be, so it is not currently
      // implemented.)
      this->SyncControlArray();
      // Need to change some state that does not change the logical state from
      // an external point of view.
311 312
      this->Internals->ExecutionArray.reset();
      this->Internals->ExecutionArrayValid = false;
313
    }
314
  }
315 316 317 318 319

  VTKM_ASSERT(this->Internals->ExecutionArray == nullptr);
  VTKM_ASSERT(!this->Internals->ExecutionArrayValid);
  // Need to change some state that does not change the logical state from
  // an external point of view.
320
  this->Internals->ExecutionArray.reset(
321
    new vtkm::cont::internal::ArrayHandleExecutionManager<T, StorageTag, DeviceAdapterTag>(
322
      &this->Internals->ControlArray));
323 324
}

325 326
template <typename T, typename S>
void ArrayHandle<T, S>::SyncControlArray() const
327 328 329 330 331 332 333
{
  if (!this->Internals->ControlArrayValid)
  {
    // Need to change some state that does not change the logical state from
    // an external point of view.
    if (this->Internals->ExecutionArrayValid)
    {
334 335
      this->Internals->ExecutionArray->RetrieveOutputData(&this->Internals->ControlArray);
      this->Internals->ControlArrayValid = true;
336 337 338 339 340 341
    }
    else
    {
      // This array is in the null state (there is nothing allocated), but
      // the calling function wants to do something with the array. Put this
      // class into a valid state by allocating an array of size 0.
342 343
      this->Internals->ControlArray.Allocate(0);
      this->Internals->ControlArrayValid = true;
344 345 346 347
    }
  }
}
}
Sujin Philip's avatar
Sujin Philip committed
348 349 350 351 352 353 354 355 356
} // vtkm::cont

namespace vtkm
{
namespace cont
{
namespace internal
{

357 358 359 360 361 362
namespace detail
{
template <typename ArrayHandle>
inline void VTKM_CONT StorageSerialization(diy::BinaryBuffer& bb,
                                           const ArrayHandle& obj,
                                           std::false_type)
Sujin Philip's avatar
Sujin Philip committed
363 364 365 366
{
  vtkm::Id count = obj.GetNumberOfValues();
  diy::save(bb, count);

367
  diy::save(bb, vtkm::Id(0)); //not a basic storage
Sujin Philip's avatar
Sujin Philip committed
368 369 370 371 372 373
  auto portal = obj.GetPortalConstControl();
  for (vtkm::Id i = 0; i < count; ++i)
  {
    diy::save(bb, portal.Get(i));
  }
}
374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394

template <typename ArrayHandle>
inline void VTKM_CONT StorageSerialization(diy::BinaryBuffer& bb,
                                           const ArrayHandle& obj,
                                           std::true_type)
{
  vtkm::Id count = obj.GetNumberOfValues();
  diy::save(bb, count);

  diy::save(bb, vtkm::Id(1)); //is basic storage
  diy::save(bb, obj.GetStorage().GetArray(), static_cast<std::size_t>(count));
}
}

template <typename T, typename S>
inline void VTKM_CONT ArrayHandleDefaultSerialization(diy::BinaryBuffer& bb,
                                                      const vtkm::cont::ArrayHandle<T, S>& obj)
{
  using is_basic = typename std::is_same<S, vtkm::cont::StorageTagBasic>::type;
  detail::StorageSerialization(bb, obj, is_basic{});
}
Sujin Philip's avatar
Sujin Philip committed
395 396 397 398 399 400 401 402 403 404 405 406 407 408
}
}
} // vtkm::cont::internal

namespace diy
{

template <typename T>
VTKM_CONT void Serialization<vtkm::cont::ArrayHandle<T>>::load(BinaryBuffer& bb,
                                                               vtkm::cont::ArrayHandle<T>& obj)
{
  vtkm::Id count = 0;
  diy::load(bb, count);
  obj.Allocate(count);
409 410 411 412 413 414 415 416

  vtkm::Id input_was_basic_storage = 0;
  diy::load(bb, input_was_basic_storage);
  if (input_was_basic_storage)
  {
    diy::load(bb, obj.GetStorage().GetArray(), static_cast<std::size_t>(count));
  }
  else
Sujin Philip's avatar
Sujin Philip committed
417
  {
418 419 420 421 422 423 424
    auto portal = obj.GetPortalControl();
    for (vtkm::Id i = 0; i < count; ++i)
    {
      T val{};
      diy::load(bb, val);
      portal.Set(i, val);
    }
Sujin Philip's avatar
Sujin Philip committed
425
  }
426
}
Sujin Philip's avatar
Sujin Philip committed
427
} // diy