ChooseCudaDevice.h 3.75 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 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
//
//  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.
//============================================================================
#ifndef vtk_m_cont_cuda_ChooseCudaDevice_h
#define vtk_m_cont_cuda_ChooseCudaDevice_h

#include <vtkm/cont/ErrorExecution.h>

#include <cuda.h>
#include <algorithm>
#include <vector>

namespace vtkm{
namespace cuda{
namespace cont {

namespace {
struct compute_info
{
36 37 38 39
  compute_info(cudaDeviceProp prop, int index)
  {
    this->Index = index;
    this->Major = prop.major;
40

41 42 43 44
    this->MemorySize = prop.totalGlobalMem;
    this->Performance = prop.multiProcessorCount *
        prop.maxThreadsPerMultiProcessor *
        (prop.clockRate / 100000.0f);
45

46 47 48 49 50 51
    //9999 is equal to emulation make sure it is a super bad device
    if(this->Major >= 9999)
    {
      this->Major = -1;
      this->Performance = -1;
    }
52 53
  }

54 55
  //sort from fastest to slowest
  bool operator<(const compute_info other) const
56
  {
57 58 59 60 61 62 63 64 65
    //if we are both SM2 or greater check performance
    //if we both the same SM level check performance
    if( (this->Major >= 2 && other.Major >= 2) ||
        (this->Major == other.Major) )
    {
      return betterPerfomance(other);
    }
    //prefer the greater SM otherwise
    return this->Major > other.Major;
66 67
  }

68
  bool betterPerfomance(const compute_info other) const
69
  {
70 71 72
    if ( this->Performance == other.Performance)
    {
      if( this->MemorySize == other.MemorySize )
73
      {
74 75 76
        //prefer first device over second device
        //this will be subjective I bet
        return this->Index < other.Index;
77
      }
78 79 80
      return this->MemorySize > other.MemorySize;
    }
    return this->Performance > other.Performance;
81 82
  }

83
  int GetIndex() const { return Index; }
84 85

private:
86 87 88 89
  int Index;
  int Major;
  size_t MemorySize;
  float Performance;
90 91 92 93 94 95 96 97 98 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 135 136 137 138 139 140 141 142 143 144 145
};

}

///Returns the fastest cuda device id that the current system has
///A result of zero means no cuda device has been found
static int FindFastestDeviceId()
{
  //get the number of devices and store information
  int numberOfDevices=0;
  cudaGetDeviceCount(&numberOfDevices);

  std::vector<compute_info> devices;
  for(int i=0; i < numberOfDevices; ++i)
    {
    cudaDeviceProp properties;
    cudaGetDeviceProperties(&properties, i);
    if(properties.computeMode != cudaComputeModeProhibited)
      {
      //only add devices that have compute mode allowed
      devices.push_back( compute_info(properties,i) );
      }
    }

  //sort from fastest to slowest
  std::sort(devices.begin(),devices.end());

  int device=0;
  if(devices.size()> 0)
    {
    device = devices.front().GetIndex();
    }
  return device;
}


//choose a cuda compute device. This can't be used if you are setting
//up open gl interop
static void SetCudaDevice(int id)
{
  cudaError_t cError = cudaSetDevice(id);
  if(cError != cudaSuccess)
    {
    std::string cuda_error_msg(
                 "Unable to bind to the given cuda device. Error: ");
    cuda_error_msg.append(cudaGetErrorString(cError));
    throw vtkm::cont::ErrorExecution(cuda_error_msg);
    }
}


}
}
} //namespace

#endif