Vowpal Wabbit
memory.h
Go to the documentation of this file.
1 #pragma once
2 #include <cstdlib>
3 #include <cstdio>
4 #include <iostream>
5 #include <memory>
6 #include "vw_exception.h"
7 
8 template <class T>
9 T* calloc_or_throw(size_t nmemb)
10 {
11  if (nmemb == 0)
12  return nullptr;
13 
14  void* data = calloc(nmemb, sizeof(T));
15  if (data == nullptr)
16  {
17  const char* msg = "internal error: memory allocation failed!\n";
18  // use low-level function since we're already out of memory.
19  fputs(msg, stderr);
20  THROW_OR_RETURN(msg, nullptr);
21  }
22  return (T*)data;
23 }
24 
25 template <class T>
27 {
28  return *calloc_or_throw<T>(1);
29 }
30 
31 using free_fn = void (*)(void*);
32 
33 template <class T>
34 using free_ptr = std::unique_ptr<T, free_fn>;
35 
36 template <class T>
37 void destroy_free(void* temp)
38 {
39  ((T*)temp)->~T();
40  free(temp);
41 }
42 
43 template <class T, typename... Args>
45 {
46  T* temp = calloc_or_throw<T>(1);
47  new (temp) T(std::forward<Args>(args)...);
48  return std::unique_ptr<T, free_fn>(temp, destroy_free<T>);
49 }
50 
51 #ifdef MADV_MERGEABLE
52 template <class T>
53 T* calloc_mergable_or_throw(size_t nmemb)
54 {
55  if (nmemb == 0)
56  return nullptr;
57  size_t length = nmemb * sizeof(T);
58  void* data;
59  if (0 != posix_memalign(&data, sysconf(_SC_PAGE_SIZE), length))
60  {
61  const char* msg = "internal error: memory allocation failed!\n";
62  fputs(msg, stderr);
63  THROW(msg);
64  }
65  if (data == nullptr)
66  {
67  const char* msg = "internal error: memory allocation failed!\n";
68  fputs(msg, stderr);
69  THROW(msg);
70  }
71  memset(data, 0, length);
72  // mark weight vector as KSM sharable
73  // it allows to save memory if you run multiple instances of the same model
74  // see more https://www.kernel.org/doc/Documentation/vm/ksm.txt
75  // you need to have Linux kernel >= 2.6.32 and KSM enabled
76  // to check is KSM enabled run the command
77  // $ grep KSM /boot/config-`uname -r`
78  // if KSM is enabled you should see:
79  // >> CONFIG_KSM=y
80  // you can enable ksmd with sudo "echo 1 > /sys/kernel/mm/ksm/run"
81  // mark address space as a candidate for merging
82 
83  if (0 != madvise(data, length, MADV_MERGEABLE))
84  {
85  const char* msg = "internal warning: marking memory as ksm mergeable failed!\n";
86  fputs(msg, stderr);
87  }
88  return (T*)data;
89 }
90 #else
91 #define calloc_mergable_or_throw calloc_or_throw
92 #endif
93 
94 inline void free_it(void* ptr)
95 {
96  if (ptr != nullptr)
97  free(ptr);
98 }
T * calloc_or_throw(size_t nmemb)
Definition: memory.h:9
void free_it(void *ptr)
Definition: memory.h:94
free_ptr< T > scoped_calloc_or_throw(Args &&... args)
Definition: memory.h:44
std::unique_ptr< T, free_fn > free_ptr
Definition: memory.h:34
void destroy_free(void *temp)
Definition: memory.h:37
#define calloc_mergable_or_throw
Definition: memory.h:91
void(*)(void *) free_fn
Definition: memory.h:31
#define THROW_OR_RETURN(...)
Definition: vw_exception.h:208
#define THROW(args)
Definition: vw_exception.h:181