Caffe2 - C++ API
A deep learning, cross platform ML framework
context.h
1 #ifndef CAFFE2_CORE_CONTEXT_H_
2 #define CAFFE2_CORE_CONTEXT_H_
3 
4 #include <cstdlib>
5 #include <ctime>
6 #include <random>
7 #include <unordered_map>
8 
9 #include "caffe2/core/logging.h"
10 #include "caffe2/core/typeid.h"
11 #include "caffe2/proto/caffe2.pb.h"
12 #include "caffe2/utils/math.h"
13 
14 CAFFE2_DECLARE_bool(caffe2_report_cpu_memory_usage);
15 
16 namespace caffe2 {
17 
18 // Use 32-byte alignment should be enough for computation up to AVX512.
19 constexpr size_t gCaffe2Alignment = 32;
20 
21 // A virtual allocator class to do memory allocation and deallocation.
22 struct CPUAllocator {
23  CPUAllocator() {}
24  virtual ~CPUAllocator() noexcept {}
25  virtual void* New(size_t nbytes) = 0;
26  virtual void Delete(void* data) = 0;
27 };
28 
29 // A virtual struct that is used to report Caffe2's memory allocation and
30 // deallocation status
32  public:
33  MemoryAllocationReporter() : allocated_(0) {}
34  void New(void* ptr, size_t nbytes);
35  void Delete(void* ptr);
36 
37  private:
38  std::mutex mutex_;
39  std::unordered_map<void*, size_t> size_table_;
40  size_t allocated_;
41 };
42 
46  void* New(size_t nbytes) override {
47  void* data = nullptr;
48 #ifdef __ANDROID__
49  data = memalign(gCaffe2Alignment, nbytes);
50 #elif defined(_MSC_VER)
51  data = _aligned_malloc(nbytes, gCaffe2Alignment);
52 #else
53  CAFFE_ENFORCE_EQ(posix_memalign(&data, gCaffe2Alignment, nbytes), 0);
54 #endif
55  CHECK(data) << "Failed to allocate " << nbytes << " bytes.";
56  memset(data, 0, nbytes);
57  return data;
58  }
59 #ifdef _MSC_VER
60  void Delete(void* data) override { _aligned_free(data); }
61 #else
62  void Delete(void* data) override { free(data); }
63 #endif
64 };
65 
66 // Get the CPU Alloctor.
67 CPUAllocator* GetCPUAllocator();
68 // Sets the CPU allocator to the given allocator: the caller gives away the
69 // ownership of the pointer.
70 void SetCPUAllocator(CPUAllocator* alloc);
71 
105 class CPUContext final {
106  public:
107  CPUContext() : random_seed_(math::randomNumberSeed()) {}
108  explicit CPUContext(const DeviceOption& option)
109  : random_seed_(
110  option.has_random_seed() ? option.random_seed()
111  : math::randomNumberSeed()) {
112  CAFFE_ENFORCE_EQ(option.device_type(), CPU);
113  }
114 
115  ~CPUContext() noexcept {}
116 
117  inline void SwitchToDevice(int stream_id) {}
118  inline void SwitchToDevice() {
119  SwitchToDevice(0);
120  }
121 
122  inline bool FinishDeviceComputation() { return true; }
123 
124  inline std::mt19937& RandGenerator() {
125  if (!random_generator_.get()) {
126  random_generator_.reset(new std::mt19937(random_seed_));
127  }
128  return *random_generator_.get();
129  }
130 
131  static void* New(size_t nbytes) {
132  void* data = GetCPUAllocator()->New(nbytes);
133  if (FLAGS_caffe2_report_cpu_memory_usage) {
134  reporter_.New(data, nbytes);
135  }
136  return data;
137  }
138 
139  static void Delete(void* data) {
140  if (FLAGS_caffe2_report_cpu_memory_usage) {
141  reporter_.Delete(data);
142  }
143  GetCPUAllocator()->Delete(data);
144  }
145 
146  // Two copy functions that deals with cross-device copies.
147  template <class SrcContext, class DstContext>
148  inline void CopyBytes(size_t nbytes, const void* src, void* dst);
149 
150  template <typename T, class SrcContext, class DstContext>
151  inline void Copy(size_t n, const T* src, T* dst) {
152  if (std::is_fundamental<T>::value) {
153  CopyBytes<SrcContext, DstContext>(n * sizeof(T),
154  static_cast<const void*>(src),
155  static_cast<void*>(dst));
156  } else {
157  for (int i = 0; i < n; ++i) {
158  dst[i] = src[i];
159  }
160  }
161  }
162 
163  template <class SrcContext, class DstContext>
164  inline void
165  CopyItems(const TypeMeta& meta, size_t n, const void* src, void* dst) {
166  if (meta.copy()) {
167  meta.copy()(src, dst, n);
168  } else {
169  CopyBytes<SrcContext, DstContext>(n * meta.itemsize(), src, dst);
170  }
171  }
172 
173  protected:
174  // TODO(jiayq): instead of hard-coding a generator, make it more flexible.
175  int random_seed_{1701};
176  std::unique_ptr<std::mt19937> random_generator_;
177  static MemoryAllocationReporter reporter_;
178 };
179 
180 template<>
181 inline void CPUContext::CopyBytes<CPUContext, CPUContext>(
182  size_t nbytes, const void* src, void* dst) {
183  if (nbytes == 0) {
184  return;
185  }
186  CAFFE_ENFORCE(src);
187  CAFFE_ENFORCE(dst);
188  memcpy(dst, src, nbytes);
189 }
190 
191 } // namespace caffe2
192 
193 #endif // CAFFE2_CORE_CONTEXT_H_
TypedCopy copy() const
Returns the typed copy function pointer for individual iterms.
Definition: typeid.h:133
TypeMeta is a thin class that allows us to store the type of a container such as a blob...
Definition: typeid.h:66
Simple registry implementation in Caffe2 that uses static variables to register object creators durin...
The CPU Context, representing the bare minimum of what a Context class in Caffe2 should implement...
Definition: context.h:105
const size_t & itemsize() const
Returns the size of the item.
Definition: typeid.h:121