Faiss
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Friends
GpuIndex.cu
1 /**
2  * Copyright (c) 2015-present, Facebook, Inc.
3  * All rights reserved.
4  *
5  * This source code is licensed under the BSD+Patents license found in the
6  * LICENSE file in the root directory of this source tree.
7  */
8 
9 
10 #include "GpuIndex.h"
11 #include "../FaissAssert.h"
12 #include "GpuResources.h"
13 #include "utils/DeviceUtils.h"
14 #include <stdio.h>
15 
16 namespace faiss { namespace gpu {
17 
18 // Default size for which we page add or search
19 constexpr size_t kAddPageSize = (size_t) 256 * 1024 * 1024;
20 constexpr size_t kSearchPageSize = (size_t) 256 * 1024 * 1024;
21 
22 // Or, maximum number of vectors to consider per page of add or search
23 constexpr size_t kAddVecSize = (size_t) 512 * 1024;
24 
25 // Use a smaller search size, as precomputed code usage on IVFPQ
26 // requires substantial amounts of memory
27 // FIXME: parameterize based on algorithm need
28 constexpr size_t kSearchVecSize = (size_t) 32 * 1024;
29 
30 GpuIndex::GpuIndex(GpuResources* resources,
31  int dims,
32  faiss::MetricType metric,
33  GpuIndexConfig config) :
34  Index(dims, metric),
35  resources_(resources),
36  device_(config.device),
37  memorySpace_(config.memorySpace) {
38  FAISS_THROW_IF_NOT_FMT(device_ < getNumDevices(),
39  "Invalid GPU device %d", device_);
40 
41  FAISS_THROW_IF_NOT_MSG(dims > 0, "Invalid number of dimensions");
42 
43 #ifdef FAISS_UNIFIED_MEM
44  FAISS_THROW_IF_NOT_FMT(
45  memorySpace_ == MemorySpace::Device ||
46  (memorySpace_ == MemorySpace::Unified &&
47  getFullUnifiedMemSupport(device_)),
48  "Device %d does not support full CUDA 8 Unified Memory (CC 6.0+)",
49  config.device);
50 #else
51  FAISS_THROW_IF_NOT_MSG(memorySpace_ == MemorySpace::Device,
52  "Must compile with CUDA 8+ for Unified Memory support");
53 #endif
54 
55  FAISS_ASSERT(resources_);
56  resources_->initializeForDevice(device_);
57 }
58 
59 void
60 GpuIndex::add(Index::idx_t n, const float* x) {
61  addInternal_(n, x, nullptr);
62 }
63 
64 void
66  const float* x,
67  const Index::idx_t* ids) {
68  addInternal_(n, x, ids);
69 }
70 
71 void
73  const float* x,
74  const Index::idx_t* ids) {
75  DeviceScope scope(device_);
76 
77  FAISS_THROW_IF_NOT_MSG(this->is_trained, "Index not trained");
78 
79  if (n > 0) {
80  size_t totalSize = n * (size_t) this->d * sizeof(float);
81 
82  if (totalSize > kAddPageSize || n > kAddVecSize) {
83  // How many vectors fit into kAddPageSize?
84  size_t maxNumVecsForPageSize =
85  kAddPageSize / ((size_t) this->d * sizeof(float));
86 
87  // Always add at least 1 vector, if we have huge vectors
88  maxNumVecsForPageSize = std::max(maxNumVecsForPageSize, (size_t) 1);
89 
90  size_t tileSize = std::min((size_t) n, maxNumVecsForPageSize);
91  tileSize = std::min(tileSize, kSearchVecSize);
92 
93  for (size_t i = 0; i < n; i += tileSize) {
94  size_t curNum = std::min(tileSize, n - i);
95 
96  addImpl_(curNum,
97  x + i * (size_t) this->d,
98  ids ? ids + i : nullptr);
99  }
100  } else {
101  addImpl_(n, x, ids);
102  }
103  }
104 }
105 
106 void
108  const float* x,
109  Index::idx_t k,
110  float* distances,
111  Index::idx_t* labels) const {
112  DeviceScope scope(device_);
113 
114  FAISS_THROW_IF_NOT_MSG(this->is_trained, "Index not trained");
115 
116  if (n > 0) {
117  size_t totalSize = n * (size_t) this->d * sizeof(float);
118 
119  if ((totalSize > kSearchPageSize) || (n > kSearchVecSize)) {
120  // How many vectors fit into kSearchPageSize?
121  // Just consider `x`, not the size of `distances` or `labels`
122  // since they should be small, relatively speaking
123  size_t maxNumVecsForPageSize =
124  kSearchPageSize / ((size_t) this->d * sizeof(float));
125 
126  // Always search at least 1 vector, if we have huge vectors
127  maxNumVecsForPageSize = std::max(maxNumVecsForPageSize, (size_t) 1);
128 
129  size_t tileSize = std::min((size_t) n, maxNumVecsForPageSize);
130  tileSize = std::min(tileSize, kSearchVecSize);
131 
132  for (size_t i = 0; i < n; i += tileSize) {
133  size_t curNum = std::min(tileSize, n - i);
134 
135  searchImpl_(curNum,
136  x + i * (size_t) this->d,
137  k,
138  distances + i * k,
139  labels + i * k);
140  }
141  } else {
142  searchImpl_(n, x, k, distances, labels);
143  }
144  }
145 }
146 
147 } } // namespace
void search(faiss::Index::idx_t n, const float *x, faiss::Index::idx_t k, float *distances, faiss::Index::idx_t *labels) const override
Definition: GpuIndex.cu:107
virtual void searchImpl_(faiss::Index::idx_t n, const float *x, faiss::Index::idx_t k, float *distances, faiss::Index::idx_t *labels) const =0
Overridden to actually perform the search.
void addInternal_(Index::idx_t n, const float *x, const Index::idx_t *ids)
Definition: GpuIndex.cu:72
void add_with_ids(Index::idx_t n, const float *x, const Index::idx_t *ids) override
Definition: GpuIndex.cu:65
int d
vector dimension
Definition: Index.h:66
const int device_
The GPU device we are resident on.
Definition: GpuIndex.h:93
long idx_t
all indices are this type
Definition: Index.h:64
virtual void addImpl_(Index::idx_t n, const float *x, const Index::idx_t *ids)=0
Overridden to actually perform the add.
void add(faiss::Index::idx_t, const float *x) override
Definition: GpuIndex.cu:60
bool is_trained
set if the Index does not require training, or if training is done already
Definition: Index.h:71
MetricType
Some algorithms support both an inner product version and a L2 search version.
Definition: Index.h:45