Impala
Impalaistheopensource,nativeanalyticdatabaseforApacheHadoop.
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
free-pool.h
Go to the documentation of this file.
1 // Copyright 2012 Cloudera Inc.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 
16 #ifndef IMPALA_RUNTIME_FREE_POOL_H
17 #define IMPALA_RUNTIME_FREE_POOL_H
18 
19 #include <stdio.h>
20 #include <string.h>
21 #include <string>
22 #include "common/logging.h"
23 #include "runtime/mem-pool.h"
24 #include "util/bit-util.h"
25 
26 DECLARE_bool(disable_mem_pools);
27 
28 namespace impala {
29 
43 class FreePool {
44  public:
47  FreePool(MemPool* mem_pool)
48  : mem_pool_(mem_pool),
49  net_allocations_(0) {
50  memset(&lists_, 0, sizeof(lists_));
51  }
52 
54  uint8_t* Allocate(int size) {
56  if (FLAGS_disable_mem_pools) return reinterpret_cast<uint8_t*>(malloc(size));
57 
59  if (size == 0) return reinterpret_cast<uint8_t*>(0x1);
60 
62  int free_list_idx = BitUtil::Log2(size);
63  DCHECK_LT(free_list_idx, NUM_LISTS);
64 
65  FreeListNode* allocation = lists_[free_list_idx].next;
66  if (allocation == NULL) {
67  // There wasn't an existing allocation of the right size, allocate a new one.
68  size = 1 << free_list_idx;
69  allocation = reinterpret_cast<FreeListNode*>(
70  mem_pool_->Allocate(size + sizeof(FreeListNode)));
71  } else {
72  // Remove this allocation from the list.
73  lists_[free_list_idx].next = allocation->next;
74  }
75  DCHECK(allocation != NULL);
76  // Set the back node to point back to the list it came from so know where
77  // to add it on Free().
78  allocation->list = &lists_[free_list_idx];
79  return reinterpret_cast<uint8_t*>(allocation) + sizeof(FreeListNode);
80  }
81 
82  void Free(uint8_t* ptr) {
84  if (FLAGS_disable_mem_pools) {
85  free(ptr);
86  return;
87  }
88  if (ptr == NULL || reinterpret_cast<int64_t>(ptr) == 0x1) return;
89  FreeListNode* node = reinterpret_cast<FreeListNode*>(ptr - sizeof(FreeListNode));
90  FreeListNode* list = node->list;
91 #ifndef NDEBUG
92  CheckValidAllocation(list, ptr);
93 #endif
94  // Add node to front of list.
95  node->next = list->next;
96  list->next = node;
97  }
98 
102  uint8_t* Reallocate(uint8_t* ptr, int size) {
103  if (FLAGS_disable_mem_pools) {
104  return reinterpret_cast<uint8_t*>(realloc(reinterpret_cast<void*>(ptr), size));
105  }
106  if (ptr == NULL || reinterpret_cast<int64_t>(ptr) == 0x1) return Allocate(size);
107  FreeListNode* node = reinterpret_cast<FreeListNode*>(ptr - sizeof(FreeListNode));
108  FreeListNode* list = node->list;
109 #ifndef NDEBUG
110  CheckValidAllocation(list, ptr);
111 #endif
112  int bucket_idx = (list - &lists_[0]);
113  // This is the actual size of ptr.
114  int allocation_size = 1 << bucket_idx;
115 
116  // If it's already big enough, just return the ptr.
117  if (allocation_size >= size) return ptr;
118 
119  // Make a new one. Since Allocate() already rounds up to powers of 2, this effectively
120  // doubles for the caller.
121  uint8_t* new_ptr = Allocate(size);
122  memcpy(new_ptr, ptr, allocation_size);
123  Free(ptr);
124  return new_ptr;
125  }
126 
128  int64_t net_allocations() const { return net_allocations_; }
129 
130  private:
131  static const int NUM_LISTS = 64;
132 
133  struct FreeListNode {
135  union {
136  FreeListNode* next; // Used when it is in the free list
137  FreeListNode* list; // Used when it is being used by the caller.
138  };
139  };
140 
141  void CheckValidAllocation(FreeListNode* computed_list_ptr, uint8_t* allocation) const {
142  // On debug, check that list is valid.
143  bool found = false;
144  for (int i = 0; i < NUM_LISTS && !found; ++i) {
145  if (computed_list_ptr == &lists_[i]) found = true;
146  }
147  DCHECK(found) << "Could not find list for ptr: "
148  << reinterpret_cast<void*>(allocation)
149  << ". Allocation could have already been freed." << std::endl
150  << DebugString();
151  }
152 
153  std::string DebugString() const {
154  std::stringstream ss;
155  ss << "FreePool: " << this << std::endl;
156  for (int i = 0; i < NUM_LISTS; ++i) {
157  FreeListNode* n = lists_[i].next;
158  if (n == NULL) continue;
159  ss << i << ": ";
160  while (n != NULL) {
161  uint8_t* ptr = reinterpret_cast<uint8_t*>(n);
162  ptr += sizeof(FreeListNode);
163  ss << reinterpret_cast<void*>(ptr);
164  n = n->next;
165  if (n != NULL) ss << "->";
166  }
167  ss << std::endl;
168  }
169  return ss.str();
170  }
171 
174 
179 
182 };
183 
184 }
185 
186 #endif
int64_t net_allocations_
Diagnostic counter that tracks (# Allocates - # Frees)
Definition: free-pool.h:181
MemTracker * mem_tracker()
Definition: free-pool.h:127
FreeListNode lists_[NUM_LISTS]
Definition: free-pool.h:178
uint8_t * Reallocate(uint8_t *ptr, int size)
Definition: free-pool.h:102
uint8_t * Allocate(int size)
Allocates a buffer of size.
Definition: free-pool.h:54
static const int NUM_LISTS
Definition: free-pool.h:131
MemTracker * mem_tracker()
Definition: mem-pool.h:151
void Free(uint8_t *ptr)
Definition: free-pool.h:82
std::string DebugString() const
Definition: free-pool.h:153
FreePool(MemPool *mem_pool)
Definition: free-pool.h:47
This class is thread-safe.
Definition: mem-tracker.h:61
void CheckValidAllocation(FreeListNode *computed_list_ptr, uint8_t *allocation) const
Definition: free-pool.h:141
DECLARE_bool(disable_mem_pools)
int64_t net_allocations() const
Definition: free-pool.h:128
MemPool * mem_pool_
MemPool to allocate from. Unowned.
Definition: free-pool.h:173
uint8_t * Allocate(int size)
Definition: mem-pool.h:92
static int Log2(uint64_t x)
Definition: bit-util.h:135