TestingDeviceAdapter.h 61.9 KB
Newer Older
1 2 3 4 5 6 7 8 9 10
//============================================================================
//  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.
//
//  Copyright 2014 Sandia Corporation.
//  Copyright 2014 UT-Battelle, LLC.
11
//  Copyright 2014 Los Alamos National Security.
12 13 14 15 16 17 18 19
//
//  Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
//  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.
//============================================================================
20 21
#ifndef vtk_m_cont_testing_TestingDeviceAdapter_h
#define vtk_m_cont_testing_TestingDeviceAdapter_h
22

23
#include <vtkm/TypeTraits.h>
24
#include <vtkm/BinaryPredicates.h>
25
#include <vtkm/cont/ArrayHandle.h>
26
#include <vtkm/cont/ArrayHandleConstant.h>
Kenneth Moreland's avatar
Kenneth Moreland committed
27
#include <vtkm/cont/ArrayHandleIndex.h>
28
#include <vtkm/cont/ArrayHandlePermutation.h>
29
#include <vtkm/cont/ArrayHandleZip.h>
30
#include <vtkm/cont/ArrayPortalToIterators.h>
31
#include <vtkm/cont/ErrorControlBadAllocation.h>
32
#include <vtkm/cont/ErrorExecution.h>
33
#include <vtkm/cont/RuntimeDeviceInformation.h>
34
#include <vtkm/cont/StorageBasic.h>
Kenneth Moreland's avatar
Kenneth Moreland committed
35
#include <vtkm/cont/Timer.h>
36
#include <vtkm/cont/DeviceAdapterAlgorithm.h>
37 38 39 40 41

#include <vtkm/cont/internal/DeviceAdapterError.h>

#include <vtkm/cont/testing/Testing.h>

Matt Larsen's avatar
Matt Larsen committed
42 43
#include <vtkm/exec/AtomicArray.h>

44 45
#include <algorithm>
#include <cmath>
46 47 48 49
#include <utility>
#include <vector>

#ifdef _WIN32
50 51
#define WIN32_LEAN_AND_MEAN
#define NOMINMAX
52
#include <windows.h>
53 54
#undef NOMINMAX
#undef WIN32_LEAN_AND_MEAN
55 56 57 58 59 60
#endif

namespace vtkm {
namespace cont {
namespace testing {

61
namespace comparison {
62 63 64 65 66 67 68 69 70
struct MaxValue
{
  template<typename T>
  VTKM_EXEC_CONT_EXPORT T operator()(const T& a,const T& b) const
  {
    return (a > b) ? a : b;
  }
};

71 72
}

73

74
#define ERROR_MESSAGE "Got an error."
75
#define ARRAY_SIZE 1000
76
#define OFFSET 1000
77
#define DIM_SIZE 128
78 79 80 81 82 83 84 85

/// This class has a single static member, Run, that tests the templated
/// DeviceAdapter for conformance.
///
template<class DeviceAdapterTag>
struct TestingDeviceAdapter
{
private:
86
  typedef vtkm::cont::StorageTagBasic StorageTag;
87

88
  typedef vtkm::cont::ArrayHandle<vtkm::Id, StorageTag>
89 90
        IdArrayHandle;

91
  typedef vtkm::cont::ArrayHandle<vtkm::FloatDefault,StorageTag>
92 93 94
      ScalarArrayHandle;

  typedef vtkm::cont::internal::ArrayManagerExecution<
95
      vtkm::Id, StorageTag, DeviceAdapterTag>
96 97
      IdArrayManagerExecution;

98
  typedef vtkm::cont::internal::Storage<vtkm::Id, StorageTag> IdStorage;
99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134

  typedef typename IdArrayHandle::template ExecutionTypes<DeviceAdapterTag>
      ::Portal IdPortalType;
  typedef typename IdArrayHandle::template ExecutionTypes<DeviceAdapterTag>
      ::PortalConst IdPortalConstType;

  typedef vtkm::cont::DeviceAdapterAlgorithm<DeviceAdapterTag>
      Algorithm;

public:
  // Cuda kernels have to be public (in Cuda 4.0).

  struct CopyArrayKernel
  {
    VTKM_CONT_EXPORT
    CopyArrayKernel(const IdPortalConstType &input,
                    const IdPortalType &output)
      : InputArray(input), OutputArray(output) {  }

    VTKM_EXEC_EXPORT void operator()(
        vtkm::Id index,
        const vtkm::exec::internal::ErrorMessageBuffer &) const
    {
      this->OutputArray.Set(index, this->InputArray.Get(index));
    }

    VTKM_CONT_EXPORT void SetErrorMessageBuffer(
        const vtkm::exec::internal::ErrorMessageBuffer &) {  }

    IdPortalConstType InputArray;
    IdPortalType OutputArray;
  };

  struct ClearArrayKernel
  {
    VTKM_CONT_EXPORT
135 136 137 138 139
    ClearArrayKernel(const IdPortalType &array) : Array(array), Dims() {  }

    VTKM_CONT_EXPORT
    ClearArrayKernel(const IdPortalType &array,
                     const vtkm::Id3& dims) : Array(array), Dims(dims) {  }
140 141 142 143 144 145

    VTKM_EXEC_EXPORT void operator()(vtkm::Id index) const
    {
      this->Array.Set(index, OFFSET);
    }

146 147 148 149 150 151 152 153
    VTKM_EXEC_EXPORT void operator()(vtkm::Id3 index) const
    {
      //convert from id3 to id
      vtkm::Id flatIndex =
                  index[0]+ this->Dims[0]*(index[1]+ this->Dims[1]*index[2]);
      this->operator()(flatIndex);
    }

154 155 156 157
    VTKM_CONT_EXPORT void SetErrorMessageBuffer(
        const vtkm::exec::internal::ErrorMessageBuffer &) {  }

    IdPortalType Array;
158
    vtkm::Id3 Dims;
159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176
  };

  struct ClearArrayMapKernel //: public vtkm::exec::WorkletMapField
  {

    // typedef void ControlSignature(Field(Out));
    // typedef void ExecutionSignature(_1);

    template<typename T>
    VTKM_EXEC_EXPORT void operator()(T& value) const
    {
      value = OFFSET;
    }
  };

  struct AddArrayKernel
  {
    VTKM_CONT_EXPORT
177 178 179 180 181 182
    AddArrayKernel(const IdPortalType &array) : Array(array), Dims() {  }

    VTKM_CONT_EXPORT
    AddArrayKernel(const IdPortalType &array,
                     const vtkm::Id3& dims) : Array(array), Dims(dims) {  }

183 184 185 186 187 188

    VTKM_EXEC_EXPORT void operator()(vtkm::Id index) const
    {
      this->Array.Set(index, this->Array.Get(index) + index);
    }

189 190 191 192 193 194 195 196
    VTKM_EXEC_EXPORT void operator()(vtkm::Id3 index) const
    {
      //convert from id3 to id
      vtkm::Id flatIndex =
                  index[0]+ this->Dims[0]*(index[1]+ this->Dims[1]*index[2]);
      this->operator()(flatIndex);
    }

197 198 199 200
    VTKM_CONT_EXPORT void SetErrorMessageBuffer(
        const vtkm::exec::internal::ErrorMessageBuffer &) {  }

    IdPortalType Array;
201
    vtkm::Id3 Dims;
202 203 204 205 206 207 208
  };

  struct OneErrorKernel
  {
    VTKM_EXEC_EXPORT void operator()(vtkm::Id index) const
    {
      if (index == ARRAY_SIZE/2)
209
      {
210
        this->ErrorMessage.RaiseError(ERROR_MESSAGE);
211
      }
212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280
    }

    VTKM_CONT_EXPORT void SetErrorMessageBuffer(
        const vtkm::exec::internal::ErrorMessageBuffer &errorMessage)
    {
      this->ErrorMessage = errorMessage;
    }

    vtkm::exec::internal::ErrorMessageBuffer ErrorMessage;
  };

  struct AllErrorKernel
  {
    VTKM_EXEC_EXPORT void operator()(vtkm::Id vtkmNotUsed(index)) const
    {
      this->ErrorMessage.RaiseError(ERROR_MESSAGE);
    }

    VTKM_CONT_EXPORT void SetErrorMessageBuffer(
        const vtkm::exec::internal::ErrorMessageBuffer &errorMessage)
    {
      this->ErrorMessage = errorMessage;
    }

    vtkm::exec::internal::ErrorMessageBuffer ErrorMessage;
  };

  struct OffsetPlusIndexKernel
  {
    VTKM_CONT_EXPORT
    OffsetPlusIndexKernel(const IdPortalType &array) : Array(array) {  }

    VTKM_EXEC_EXPORT void operator()(vtkm::Id index) const
    {
      this->Array.Set(index, OFFSET + index);
    }

    VTKM_CONT_EXPORT void SetErrorMessageBuffer(
        const vtkm::exec::internal::ErrorMessageBuffer &) {  }

    IdPortalType Array;
  };

  struct MarkOddNumbersKernel
  {
    VTKM_CONT_EXPORT
    MarkOddNumbersKernel(const IdPortalType &array) : Array(array) {  }

    VTKM_EXEC_EXPORT void operator()(vtkm::Id index) const
    {
      this->Array.Set(index, index%2);
    }

    VTKM_CONT_EXPORT void SetErrorMessageBuffer(
        const vtkm::exec::internal::ErrorMessageBuffer &) {  }

    IdPortalType Array;
  };

  struct FuseAll
  {
    template<typename T>
    VTKM_EXEC_EXPORT bool operator()(const T&, const T&) const
    {
      //binary predicates for unique return true if they are the same
      return true;
    }
  };

Matt Larsen's avatar
Matt Larsen committed
281
  template<typename T>
282
  struct AtomicKernel
Matt Larsen's avatar
Matt Larsen committed
283 284 285 286 287 288 289 290
  {
    VTKM_CONT_EXPORT
    AtomicKernel(const vtkm::exec::AtomicArray<T,DeviceAdapterTag> &array)
    : AArray(array)
    {  }

    VTKM_EXEC_EXPORT void operator()(vtkm::Id index) const
    {
291 292
      T value = (T) index;
      this->AArray.Add(0, value);
Matt Larsen's avatar
Matt Larsen committed
293 294 295 296 297 298 299 300
    }

    VTKM_CONT_EXPORT void SetErrorMessageBuffer(
        const vtkm::exec::internal::ErrorMessageBuffer &) {  }

    vtkm::exec::AtomicArray<T,DeviceAdapterTag> AArray;
  };

301
  template<typename T>
302
  struct AtomicCASKernel
303 304 305 306 307 308 309 310 311 312 313 314 315 316
  {
    VTKM_CONT_EXPORT
    AtomicCASKernel(const vtkm::exec::AtomicArray<T,DeviceAdapterTag> &array)
    : AArray(array)
    {  }

    VTKM_EXEC_EXPORT void operator()(vtkm::Id index) const
    {
      T value = (T) index;
      //Get the old value from the array with a no-op
      T oldValue = this->AArray.Add(0,T(0));
      //This creates an atomic add using the CAS operatoin
      T assumed = T(0);
      do
317
      {
318 319 320 321
        assumed = oldValue;
        oldValue = this->AArray.CompareAndSwap(0, (assumed + value) , assumed);

      } while (assumed != oldValue);
322

323 324 325 326 327 328 329 330
    }

    VTKM_CONT_EXPORT void SetErrorMessageBuffer(
        const vtkm::exec::internal::ErrorMessageBuffer &) {  }

    vtkm::exec::AtomicArray<T,DeviceAdapterTag> AArray;
  };

331 332 333 334 335 336 337 338

private:

  static VTKM_CONT_EXPORT void TestDeviceAdapterTag()
  {
    std::cout << "-------------------------------------------" << std::endl;
    std::cout << "Testing device adapter tag" << std::endl;

339 340
    typedef vtkm::cont::DeviceAdapterTraits<DeviceAdapterTag> Traits;
    typedef vtkm::cont::DeviceAdapterTraits<
341 342 343
        vtkm::cont::DeviceAdapterTagError> ErrorTraits;

    VTKM_TEST_ASSERT(Traits::GetId() == Traits::GetId(),
344
                     "Device adapter Id does not equal itself.");
345
    VTKM_TEST_ASSERT(Traits::GetId() != ErrorTraits::GetId(),
346
                     "Device adapter Id not distinguishable from others.");
347 348 349 350 351

    VTKM_TEST_ASSERT(Traits::GetName() == Traits::GetName(),
                     "Device adapter Name does not equal itself.");
    VTKM_TEST_ASSERT(Traits::GetName() != ErrorTraits::GetName(),
                     "Device adapter Name not distinguishable from others.");
352 353 354 355 356 357 358 359 360 361 362 363
  }

  // Note: this test does not actually test to make sure the data is available
  // in the execution environment. It tests to make sure data gets to the array
  // and back, but it is possible that the data is not available in the
  // execution environment.
  static VTKM_CONT_EXPORT void TestArrayManagerExecution()
  {
    std::cout << "-------------------------------------------" << std::endl;
    std::cout << "Testing ArrayManagerExecution" << std::endl;

    typedef vtkm::cont::internal::ArrayManagerExecution<
364
        vtkm::Id,StorageTagBasic,DeviceAdapterTag>
365 366
        ArrayManagerExecution;

367
    typedef vtkm::cont::internal::Storage<vtkm::Id,StorageTagBasic> StorageType;
368

369
    // Create original input array.
370 371 372 373 374 375 376 377
    StorageType storage;
    storage.Allocate(ARRAY_SIZE*2);

    StorageType::PortalType portal = storage.GetPortal();
    VTKM_TEST_ASSERT(portal.GetNumberOfValues() == ARRAY_SIZE*2,
                     "Storage portal has unexpected size.");

    for (vtkm::Id index = 0; index < ARRAY_SIZE; index++)
378
    {
379
      portal.Set(index, TestValue(index, vtkm::Id()));
380
    }
381

382
    ArrayManagerExecution manager(&storage);
383

384 385 386 387 388
    // Do an operation just so we know the values are placed in the execution
    // environment and they change. We are only calling on half the array
    // because we are about to shrink.
    Algorithm::Schedule(AddArrayKernel(manager.PrepareForInPlace(true)),
                        ARRAY_SIZE);
389 390

    // Change size.
391 392 393 394 395 396 397 398
    manager.Shrink(ARRAY_SIZE);

    VTKM_TEST_ASSERT(manager.GetNumberOfValues() == ARRAY_SIZE,
                     "Shrink did not set size of array manager correctly.");

    // Get the array back and check its values. We have to get it back into
    // the same storage since some ArrayManagerExecution classes will expect
    // that.
399
    manager.RetrieveOutputData(&storage);
400 401 402 403

    VTKM_TEST_ASSERT(storage.GetNumberOfValues() == ARRAY_SIZE,
                     "Storage has wrong number of values after execution "
                     "array shrink.");
404 405

    // Check array.
406 407 408 409
    StorageType::PortalConstType checkPortal = storage.GetPortalConst();
    VTKM_TEST_ASSERT(checkPortal.GetNumberOfValues() == ARRAY_SIZE,
                     "Storage portal wrong size.");

410
    for (vtkm::Id index = 0; index < ARRAY_SIZE; index++)
411
    {
412 413 414
      VTKM_TEST_ASSERT(
            checkPortal.Get(index) == TestValue(index, vtkm::Id()) + index,
            "Did not get correct values from array.");
415
    }
416 417 418 419 420 421 422 423 424 425 426
  }

  static VTKM_CONT_EXPORT void TestOutOfMemory()
  {
    // Only test out of memory with 64 bit ids.  If there are 32 bit ids on
    // a 64 bit OS (common), it is simply too hard to get a reliable allocation
    // that is too much memory.
#ifdef VTKM_USE_64BIT_IDS
    std::cout << "-------------------------------------------" << std::endl;
    std::cout << "Testing Out of Memory" << std::endl;
    try
427
    {
428
      std::cout << "Do array allocation that should fail." << std::endl;
429
      vtkm::cont::internal::Storage<
430 431 432 433 434
          vtkm::Vec<vtkm::Float32, 4>, StorageTagBasic> supportArray;
      vtkm::cont::internal::ArrayManagerExecution<
          vtkm::Vec<vtkm::Float32, 4>, StorageTagBasic, DeviceAdapterTag>
          bigManager(&supportArray);

435
      const vtkm::Id bigSize = 0x7FFFFFFFFFFFFFFFLL;
436
      bigManager.PrepareForOutput(bigSize);
437 438
      // It does not seem reasonable to get here.  The previous call should fail.
      VTKM_TEST_FAIL("A ridiculously sized allocation succeeded.  Either there "
439 440 441 442
                     "was a failure that was not reported but should have been "
                     "or the width of vtkm::Id is not large enough to express all "
                     "array sizes.");
    }
443
    catch (vtkm::cont::ErrorControlBadAllocation error)
444
    {
445
      std::cout << "Got the expected error: " << error.GetMessage() << std::endl;
446
    }
447
#else
448
    std::cout << "--------- Skipping out of memory test" << std::endl;
449 450 451
#endif
  }

Kenneth Moreland's avatar
Kenneth Moreland committed
452 453 454 455 456
  VTKM_CONT_EXPORT
  static void TestTimer()
  {
    std::cout << "-------------------------------------------" << std::endl;
    std::cout << "Testing Timer" << std::endl;
457

Kenneth Moreland's avatar
Kenneth Moreland committed
458
    vtkm::cont::Timer<DeviceAdapterTag> timer;
459

460 461
    std::cout << "Timer started. Sleeping..." << std::endl;

Kenneth Moreland's avatar
Kenneth Moreland committed
462 463 464 465 466
#ifndef _WIN32
    sleep(1);
#else
    Sleep(1000);
#endif
467

468 469
    std::cout << "Woke up. Check time." << std::endl;

Kenneth Moreland's avatar
Kenneth Moreland committed
470
    vtkm::Float64 elapsedTime = timer.GetElapsedTime();
471

Kenneth Moreland's avatar
Kenneth Moreland committed
472
    std::cout << "Elapsed time: " << elapsedTime << std::endl;
473

Kenneth Moreland's avatar
Kenneth Moreland committed
474 475 476 477 478
    VTKM_TEST_ASSERT(elapsedTime > 0.999,
                     "Timer did not capture full second wait.");
    VTKM_TEST_ASSERT(elapsedTime < 2.0,
                     "Timer counted too far or system really busy.");
  }
479

480 481 482 483 484 485 486 487 488 489 490 491
  VTKM_CONT_EXPORT
  static void TestRuntime()
  {
    std::cout << "-------------------------------------------" << std::endl;
    std::cout << "Testing RuntimeDeviceInformation" << std::endl;

    vtkm::cont::RuntimeDeviceInformation<DeviceAdapterTag> runtime;
    const bool valid_runtime = runtime.Exists();

    VTKM_TEST_ASSERT(valid_runtime, "runtime detection failed for device");
  }

492 493 494 495 496 497
  static VTKM_CONT_EXPORT void TestAlgorithmSchedule()
  {
    std::cout << "-------------------------------------------" << std::endl;
    std::cout << "Testing single value Scheduling with vtkm::Id" << std::endl;

    {
498
      std::cout << "Allocating execution array" << std::endl;
499
      IdStorage storage;
500
      IdArrayManagerExecution manager(&storage);
501

502
      std::cout << "Running clear." << std::endl;
503
      Algorithm::Schedule(ClearArrayKernel(manager.PrepareForOutput(1)), 1);
504

505
      std::cout << "Running add." << std::endl;
506
      Algorithm::Schedule(AddArrayKernel(manager.PrepareForInPlace(false)), 1);
507

508
      std::cout << "Checking results." << std::endl;
509
      manager.RetrieveOutputData(&storage);
510

511
      for (vtkm::Id index = 0; index < 1; index++)
512
      {
513
        vtkm::Id value = storage.GetPortalConst().Get(index);
514 515
        VTKM_TEST_ASSERT(value == index + OFFSET,
                         "Got bad value for single value scheduled kernel.");
516 517 518 519 520 521 522
      }
    } //release memory

    std::cout << "-------------------------------------------" << std::endl;
    std::cout << "Testing Schedule with vtkm::Id" << std::endl;

    {
523
      std::cout << "Allocating execution array" << std::endl;
524
      IdStorage storage;
525
      IdArrayManagerExecution manager(&storage);
526

527
      std::cout << "Running clear." << std::endl;
528 529
      Algorithm::Schedule(ClearArrayKernel(manager.PrepareForOutput(ARRAY_SIZE)),
                          ARRAY_SIZE);
530

531
      std::cout << "Running add." << std::endl;
532 533
      Algorithm::Schedule(AddArrayKernel(manager.PrepareForInPlace(false)),
                          ARRAY_SIZE);
534

535
      std::cout << "Checking results." << std::endl;
536
      manager.RetrieveOutputData(&storage);
537

538
      for (vtkm::Id index = 0; index < ARRAY_SIZE; index++)
539
      {
540
        vtkm::Id value = storage.GetPortalConst().Get(index);
541 542
        VTKM_TEST_ASSERT(value == index + OFFSET,
                         "Got bad value for scheduled kernels.");
543 544 545
      }
    } //release memory

546 547 548 549 550 551 552 553 554
    std::cout << "-------------------------------------------" << std::endl;
    std::cout << "Testing Schedule with a vary large Id value" << std::endl;

    {
      std::cout << "Allocating execution array" << std::endl;
      IdStorage storage;
      IdArrayManagerExecution manager(&storage);

      std::cout << "Running clear." << std::endl;
555

556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576
      //size is selected to be larger than the CUDA backend can launch in a
      //single invocation when compiled for SM_2 support
      const vtkm::Id size = 8400000;
      Algorithm::Schedule(ClearArrayKernel(manager.PrepareForOutput(size)),
                          size);

      std::cout << "Running add." << std::endl;
      Algorithm::Schedule(AddArrayKernel(manager.PrepareForInPlace(false)),
                          size);

      std::cout << "Checking results." << std::endl;
      manager.RetrieveOutputData(&storage);

      for (vtkm::Id index = 0; index < size; index++)
      {
        vtkm::Id value = storage.GetPortalConst().Get(index);
        VTKM_TEST_ASSERT(value == index + OFFSET,
                         "Got bad value for scheduled kernels.");
      }
    } //release memory

577 578 579 580 581
    //verify that the schedule call works with id3
    std::cout << "-------------------------------------------" << std::endl;
    std::cout << "Testing Schedule with vtkm::Id3" << std::endl;

    {
582
      std::cout << "Allocating execution array" << std::endl;
583
      IdStorage storage;
584
      IdArrayManagerExecution manager(&storage);
585
      vtkm::Id3 maxRange(DIM_SIZE);
586

587
      std::cout << "Running clear." << std::endl;
588 589
      Algorithm::Schedule(
            ClearArrayKernel(manager.PrepareForOutput(
590
                               DIM_SIZE * DIM_SIZE * DIM_SIZE), maxRange),
591
            maxRange);
592

593
      std::cout << "Running add." << std::endl;
594
      Algorithm::Schedule(AddArrayKernel(manager.PrepareForInPlace(false), maxRange),
595
                          maxRange);
596

597
      std::cout << "Checking results." << std::endl;
598
      manager.RetrieveOutputData(&storage);
599

600 601
      const vtkm::Id maxId = DIM_SIZE * DIM_SIZE * DIM_SIZE;
      for (vtkm::Id index = 0; index < maxId; index++)
602
      {
603
        vtkm::Id value = storage.GetPortalConst().Get(index);
604 605
        VTKM_TEST_ASSERT(value == index + OFFSET,
                         "Got bad value for scheduled vtkm::Id3 kernels.");
606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628
      }
    } //release memory
  }

  static VTKM_CONT_EXPORT void TestStreamCompact()
  {
    std::cout << "-------------------------------------------" << std::endl;
    std::cout << "Testing Stream Compact" << std::endl;

    //test the version of compact that takes in input and uses it as a stencil
    //and uses the index of each item as the value to place in the result vector
    IdArrayHandle array;
    IdArrayHandle result;

    //construct the index array

    Algorithm::Schedule(
          MarkOddNumbersKernel(array.PrepareForOutput(ARRAY_SIZE,
                                                      DeviceAdapterTag())),
          ARRAY_SIZE);

    Algorithm::StreamCompact(array, result);
    VTKM_TEST_ASSERT(result.GetNumberOfValues() == array.GetNumberOfValues()/2,
629
                     "result of compacation has an incorrect size");
630 631

    for (vtkm::Id index = 0; index < result.GetNumberOfValues(); index++)
632
    {
633 634
      const vtkm::Id value = result.GetPortalConstControl().Get(index);
      VTKM_TEST_ASSERT(value == (index*2)+1,
635 636
                       "Incorrect value in compaction results.");
    }
637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659
  }

  static VTKM_CONT_EXPORT void TestStreamCompactWithStencil()
  {
    std::cout << "-------------------------------------------" << std::endl;
    std::cout << "Testing Stream Compact with stencil" << std::endl;

    IdArrayHandle array;
    IdArrayHandle stencil;
    IdArrayHandle result;

    //construct the index array
    Algorithm::Schedule(
          OffsetPlusIndexKernel(array.PrepareForOutput(ARRAY_SIZE,
                                                       DeviceAdapterTag())),
          ARRAY_SIZE);
    Algorithm::Schedule(
          MarkOddNumbersKernel(stencil.PrepareForOutput(ARRAY_SIZE,
                                                        DeviceAdapterTag())),
          ARRAY_SIZE);

    Algorithm::StreamCompact(array,stencil,result);
    VTKM_TEST_ASSERT(result.GetNumberOfValues() == array.GetNumberOfValues()/2,
660
                     "result of compacation has an incorrect size");
661 662

    for (vtkm::Id index = 0; index < result.GetNumberOfValues(); index++)
663
    {
664 665
      const vtkm::Id value = result.GetPortalConstControl().Get(index);
      VTKM_TEST_ASSERT(value == (OFFSET + (index*2)+1),
666 667
                       "Incorrect value in compaction result.");
    }
668 669 670 671 672 673 674 675
  }

  static VTKM_CONT_EXPORT void TestOrderedUniqueValues()
  {
    std::cout << "-------------------------------------------------" << std::endl;
    std::cout << "Testing Sort, Unique, LowerBounds and UpperBounds" << std::endl;
    vtkm::Id testData[ARRAY_SIZE];
    for(vtkm::Id i=0; i < ARRAY_SIZE; ++i)
676
    {
677
      testData[i]= OFFSET+(i % 50);
678
    }
679

680
    IdArrayHandle input = vtkm::cont::make_ArrayHandle(testData, ARRAY_SIZE);
681

682
    //make a deep copy of input and place it into temp
683 684
    IdArrayHandle temp;
    Algorithm::Copy(input,temp);
685

686 687 688
    Algorithm::Sort(temp);
    Algorithm::Unique(temp);

689 690 691
    IdArrayHandle handle;
    IdArrayHandle handle1;

692 693 694 695 696 697 698 699 700 701 702 703 704
    //verify lower and upper bounds work
    Algorithm::LowerBounds(temp,input,handle);
    Algorithm::UpperBounds(temp,input,handle1);

    // Check to make sure that temp was resized correctly during Unique.
    // (This was a discovered bug at one point.)
    temp.GetPortalConstControl();  // Forces copy back to control.
    temp.ReleaseResourcesExecution(); // Make sure not counting on execution.
    VTKM_TEST_ASSERT(
          temp.GetNumberOfValues() == 50,
          "Unique did not resize array (or size did not copy to control).");

    for(vtkm::Id i=0; i < ARRAY_SIZE; ++i)
705
    {
706 707 708 709
      vtkm::Id value = handle.GetPortalConstControl().Get(i);
      vtkm::Id value1 = handle1.GetPortalConstControl().Get(i);
      VTKM_TEST_ASSERT(value == i % 50, "Got bad value (LowerBounds)");
      VTKM_TEST_ASSERT(value1 >= i % 50, "Got bad value (UpperBounds)");
710
    }
711 712 713 714 715 716 717 718 719 720 721 722 723 724

    std::cout << "Testing Sort, Unique, LowerBounds and UpperBounds with random values"
              << std::endl;
    //now test it works when the id are not incrementing
    const vtkm::Id RANDOMDATA_SIZE = 6;
    vtkm::Id randomData[RANDOMDATA_SIZE];
    randomData[0]=500;  // 2 (lower), 3 (upper)
    randomData[1]=955;  // 3 (lower), 4 (upper)
    randomData[2]=955;  // 3 (lower), 4 (upper)
    randomData[3]=120;  // 0 (lower), 1 (upper)
    randomData[4]=320;  // 1 (lower), 2 (upper)
    randomData[5]=955;  // 3 (lower), 4 (upper)

    //change the control structure under the handle
725
    input = vtkm::cont::make_ArrayHandle(randomData, RANDOMDATA_SIZE);
726 727
    Algorithm::Copy(input,handle);
    VTKM_TEST_ASSERT(handle.GetNumberOfValues() == RANDOMDATA_SIZE,
728
                     "Handle incorrect size after setting new control data");
729 730 731

    Algorithm::Copy(input,handle1);
    VTKM_TEST_ASSERT(handle.GetNumberOfValues() == RANDOMDATA_SIZE,
732
                     "Handle incorrect size after setting new control data");
733 734 735

    Algorithm::Copy(handle,temp);
    VTKM_TEST_ASSERT(temp.GetNumberOfValues() == RANDOMDATA_SIZE,
736
                     "Copy failed");
737 738 739 740 741 742
    Algorithm::Sort(temp);
    Algorithm::Unique(temp);
    Algorithm::LowerBounds(temp,handle);
    Algorithm::UpperBounds(temp,handle1);

    VTKM_TEST_ASSERT(handle.GetNumberOfValues() == RANDOMDATA_SIZE,
743
                     "LowerBounds returned incorrect size");
744

745 746 747 748
    std::copy(
          vtkm::cont::ArrayPortalToIteratorBegin(handle.GetPortalConstControl()),
          vtkm::cont::ArrayPortalToIteratorEnd(handle.GetPortalConstControl()),
          randomData);
749 750 751 752 753 754 755 756
    VTKM_TEST_ASSERT(randomData[0] == 2, "Got bad value - LowerBounds");
    VTKM_TEST_ASSERT(randomData[1] == 3, "Got bad value - LowerBounds");
    VTKM_TEST_ASSERT(randomData[2] == 3, "Got bad value - LowerBounds");
    VTKM_TEST_ASSERT(randomData[3] == 0, "Got bad value - LowerBounds");
    VTKM_TEST_ASSERT(randomData[4] == 1, "Got bad value - LowerBounds");
    VTKM_TEST_ASSERT(randomData[5] == 3, "Got bad value - LowerBounds");

    VTKM_TEST_ASSERT(handle1.GetNumberOfValues() == RANDOMDATA_SIZE,
757
                     "UppererBounds returned incorrect size");
758

759 760 761 762
    std::copy(
          vtkm::cont::ArrayPortalToIteratorBegin(handle1.GetPortalConstControl()),
          vtkm::cont::ArrayPortalToIteratorEnd(handle1.GetPortalConstControl()),
          randomData);
763 764 765 766 767 768 769 770
    VTKM_TEST_ASSERT(randomData[0] == 3, "Got bad value - UpperBound");
    VTKM_TEST_ASSERT(randomData[1] == 4, "Got bad value - UpperBound");
    VTKM_TEST_ASSERT(randomData[2] == 4, "Got bad value - UpperBound");
    VTKM_TEST_ASSERT(randomData[3] == 1, "Got bad value - UpperBound");
    VTKM_TEST_ASSERT(randomData[4] == 2, "Got bad value - UpperBound");
    VTKM_TEST_ASSERT(randomData[5] == 4, "Got bad value - UpperBound");
  }

771
  static VTKM_CONT_EXPORT void TestSort()
772 773
  {
    std::cout << "-------------------------------------------------" << std::endl;
774
    std::cout << "Sort" << std::endl;
775 776
    vtkm::Id testData[ARRAY_SIZE];
    for(vtkm::Id i=0; i < ARRAY_SIZE; ++i)
777
    {
778
      testData[i]= OFFSET+((ARRAY_SIZE-i) % 50);
779
    }
780

781
    IdArrayHandle unsorted = vtkm::cont::make_ArrayHandle(testData, ARRAY_SIZE);
782 783
    IdArrayHandle sorted;
    Algorithm::Copy(unsorted, sorted);
784

785
    //Validate the standard inplace sort is correct
786 787 788
    Algorithm::Sort(sorted);

    for (vtkm::Id i = 0; i < ARRAY_SIZE-1; ++i)
789
    {
790 791 792
      vtkm::Id sorted1 = sorted.GetPortalConstControl().Get(i);
      vtkm::Id sorted2 = sorted.GetPortalConstControl().Get(i+1);
      VTKM_TEST_ASSERT(sorted1 <= sorted2, "Values not properly sorted.");
793
    }
794 795 796
  }

  static VTKM_CONT_EXPORT void TestSortWithComparisonObject()
797
  {
798 799 800 801 802 803 804 805
    std::cout << "-------------------------------------------------" << std::endl;
    std::cout << "Sort with comparison object" << std::endl;
    vtkm::Id testData[ARRAY_SIZE];
    for(vtkm::Id i=0; i < ARRAY_SIZE; ++i)
    {
      testData[i]= OFFSET+((ARRAY_SIZE-i) % 50);
    }

806
    //sort the users memory in-place
807
    IdArrayHandle sorted = vtkm::cont::make_ArrayHandle(testData, ARRAY_SIZE);
808
    Algorithm::Sort(sorted);
809

810 811 812 813
    //copy the sorted array into our own memory, if use the same user ptr
    //we would also sort the 'sorted' handle
    IdArrayHandle comp_sorted;
    Algorithm::Copy(sorted, comp_sorted);
814
    Algorithm::Sort(comp_sorted,vtkm::SortGreater());
815

816
    //Validate that sorted and comp_sorted are sorted in the opposite directions
817
    for(vtkm::Id i=0; i < ARRAY_SIZE; ++i)
818
    {
819 820 821
      vtkm::Id sorted1 = sorted.GetPortalConstControl().Get(i);
      vtkm::Id sorted2 = comp_sorted.GetPortalConstControl().Get(ARRAY_SIZE - (i + 1));
      VTKM_TEST_ASSERT(sorted1 == sorted2,
822 823
                       "Got bad sort values when using SortGreater");
    }
824

825
    //validate that sorted and comp_sorted are now equal
826
    Algorithm::Sort(comp_sorted,vtkm::SortLess());
827
    for(vtkm::Id i=0; i < ARRAY_SIZE; ++i)
828
    {
829 830 831
      vtkm::Id sorted1 = sorted.GetPortalConstControl().Get(i);
      vtkm::Id sorted2 = comp_sorted.GetPortalConstControl().Get(i);
      VTKM_TEST_ASSERT(sorted1 == sorted2,
832
                       "Got bad sort values when using SortLess");
833
    }
834 835
  }

836 837 838 839 840 841 842 843 844 845 846
  static VTKM_CONT_EXPORT void TestSortWithFancyArrays()
  {
    std::cout << "-------------------------------------------------" << std::endl;
    std::cout << "Sort of a ArrayHandleZip" << std::endl;

    vtkm::Id testData[ARRAY_SIZE];
    for(vtkm::Id i=0; i < ARRAY_SIZE; ++i)
    {
      testData[i]= OFFSET+((ARRAY_SIZE-i) % 50);
    }

847
    IdArrayHandle unsorted = vtkm::cont::make_ArrayHandle(testData, ARRAY_SIZE);
848 849 850 851 852 853 854
    IdArrayHandle sorted;
    Algorithm::Copy(unsorted, sorted);

    //verify that we can use ArrayHandleZip inplace
    vtkm::cont::ArrayHandleZip< IdArrayHandle, IdArrayHandle> zipped(unsorted, sorted);

    //verify we can use sort with zip handle
855
    Algorithm::Sort(zipped, vtkm::SortGreater());
856 857 858 859 860 861 862 863 864 865 866 867 868
    Algorithm::Sort(zipped);

    for (vtkm::Id i = 0; i < ARRAY_SIZE; ++i)
    {
      vtkm::Pair<vtkm::Id,vtkm::Id> kv_sorted = zipped.GetPortalConstControl().Get(i);
      VTKM_TEST_ASSERT(( OFFSET +  ( i / (ARRAY_SIZE/50)) ) == kv_sorted.first,
                       "ArrayZipHandle improperly sorted");
    }

    std::cout << "-------------------------------------------------" << std::endl;
    std::cout << "Sort of a ArrayHandlePermutation" << std::endl;

    //verify that we can use ArrayHandlePermutation inplace
Kenneth Moreland's avatar
Kenneth Moreland committed
869 870
    vtkm::cont::ArrayHandleIndex index(ARRAY_SIZE);
    vtkm::cont::ArrayHandlePermutation< vtkm::cont::ArrayHandleIndex,
871 872 873
                                        IdArrayHandle> perm(index, sorted);

    //verify we can use a custom operator sort with permutation handle
874
    Algorithm::Sort(perm, vtkm::SortGreater());
875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891
    for (vtkm::Id i = 0; i < ARRAY_SIZE; ++i)
    {
      vtkm::Id sorted_value = perm.GetPortalConstControl().Get(i);
      VTKM_TEST_ASSERT(( OFFSET +  ( (ARRAY_SIZE-(i+1)) / (ARRAY_SIZE/50)) ) == sorted_value,
                       "ArrayZipPermutation improperly sorted");
    }

    //verify we can use the default sort with permutation handle
    Algorithm::Sort(perm);
    for (vtkm::Id i = 0; i < ARRAY_SIZE; ++i)
    {
      vtkm::Id sorted_value = perm.GetPortalConstControl().Get(i);
      VTKM_TEST_ASSERT(( OFFSET +  ( i / (ARRAY_SIZE/50)) ) == sorted_value,
                       "ArrayZipPermutation improperly sorted");
    }
  }

892 893 894 895
  static VTKM_CONT_EXPORT void TestSortByKey()
  {
    std::cout << "-------------------------------------------------" << std::endl;
    std::cout << "Sort by keys" << std::endl;
896

897
    typedef vtkm::Vec<FloatDefault,3> Vec3;
898 899 900
    typedef vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::FloatDefault,3>,StorageTag>
      Vec3ArrayHandle;

901

902
    vtkm::Id testKeys[ARRAY_SIZE];
903
    Vec3 testValues[ARRAY_SIZE];
904

905 906 907
    for(vtkm::Id i=0; i < ARRAY_SIZE; ++i)
      {
      testKeys[i] = ARRAY_SIZE - i;
908
      testValues[i] = TestValue(i, Vec3());
909
      }
910

911 912
    IdArrayHandle keys = vtkm::cont::make_ArrayHandle(testKeys, ARRAY_SIZE);
    Vec3ArrayHandle values = vtkm::cont::make_ArrayHandle(testValues, ARRAY_SIZE);
913

914
    Algorithm::SortByKey(keys,values);
915

916 917 918 919
    for(vtkm::Id i=0; i < ARRAY_SIZE; ++i)
      {
      //keys should be sorted from 1 to ARRAY_SIZE
      //values should be sorted from (ARRAY_SIZE-1) to 0
920 921
      Vec3 sorted_value = values.GetPortalConstControl().Get(i);
      vtkm::Id sorted_key = keys.GetPortalConstControl().Get(i);
922 923

      VTKM_TEST_ASSERT( (sorted_key == (i+1)) , "Got bad SortByKeys key");
924
      VTKM_TEST_ASSERT( test_equal(sorted_value, TestValue(ARRAY_SIZE-1-i, Vec3())),
925 926
                                      "Got bad SortByKeys value");
      }
927

928
    // this will return everything back to what it was before sorting
929
    Algorithm::SortByKey(keys,values,vtkm::SortGreater());
930 931 932 933
    for(vtkm::Id i=0; i < ARRAY_SIZE; ++i)
      {
      //keys should be sorted from ARRAY_SIZE to 1
      //values should be sorted from 0 to (ARRAY_SIZE-1)
934 935
      Vec3 sorted_value = values.GetPortalConstControl().Get(i);
      vtkm::Id sorted_key = keys.GetPortalConstControl().Get(i);
936 937 938

      VTKM_TEST_ASSERT( (sorted_key == (ARRAY_SIZE-i)),
                                      "Got bad SortByKeys key");
939
      VTKM_TEST_ASSERT( test_equal(sorted_value, TestValue(i, Vec3())),
940 941
                                      "Got bad SortByKeys value");
      }
942

943
    //this is here to verify we can sort by vtkm::Vec
944
    Algorithm::SortByKey(values,keys);
945 946 947 948
    for(vtkm::Id i=0; i < ARRAY_SIZE; ++i)
      {
      //keys should be sorted from ARRAY_SIZE to 1
      //values should be sorted from 0 to (ARRAY_SIZE-1)
949 950
      Vec3 sorted_value = values.GetPortalConstControl().Get(i);
      vtkm::Id sorted_key = keys.GetPortalConstControl().Get(i);
951 952 953

      VTKM_TEST_ASSERT( (sorted_key == (ARRAY_SIZE-i)),
                                      "Got bad SortByKeys key");
954
      VTKM_TEST_ASSERT( test_equal(sorted_value, TestValue(i, Vec3())),
955 956 957
                                      "Got bad SortByKeys value");
      }
  }
958 959 960 961 962 963 964

  static VTKM_CONT_EXPORT void TestLowerBoundsWithComparisonObject()
  {
    std::cout << "-------------------------------------------------" << std::endl;
    std::cout << "Testing LowerBounds with comparison object" << std::endl;
    vtkm::Id testData[ARRAY_SIZE];
    for(vtkm::Id i=0; i < ARRAY_SIZE; ++i)
965
    {
966
      testData[i]= OFFSET+(i % 50);
967
    }
968
    IdArrayHandle input = vtkm::cont::make_ArrayHandle(testData, ARRAY_SIZE);
969

Robert Maynard's avatar