GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/context/context_mm.cpp Lines: 58 62 93.5 %
Date: 2021-05-22 Branches: 36 100 36.0 %

Line Exec Source
1
/******************************************************************************
2
 * Top contributors (to current version):
3
 *   Clark Barrett, Andres Noetzli, Morgan Deters
4
 *
5
 * This file is part of the cvc5 project.
6
 *
7
 * Copyright (c) 2009-2021 by the authors listed in the file AUTHORS
8
 * in the top-level source directory and their institutional affiliations.
9
 * All rights reserved.  See the file COPYING in the top-level source
10
 * directory for licensing information.
11
 * ****************************************************************************
12
 *
13
 * Implementation of Context Memory Manager
14
 */
15
16
#include <cstdlib>
17
#include <deque>
18
#include <limits>
19
#include <new>
20
#include <ostream>
21
#include <vector>
22
23
#ifdef CVC5_VALGRIND
24
#include <valgrind/memcheck.h>
25
#endif /* CVC5_VALGRIND */
26
27
#include "base/check.h"
28
#include "base/output.h"
29
#include "context/context_mm.h"
30
31
namespace cvc5 {
32
namespace context {
33
34
#ifndef CVC5_DEBUG_CONTEXT_MEMORY_MANAGER
35
36
435208
void ContextMemoryManager::newChunk() {
37
38
  // Increment index to chunk list
39
435208
  ++d_indexChunkList;
40
435208
  Assert(d_chunkList.size() == d_indexChunkList)
41
      << "Index should be at the end of the list";
42
43
  // Create new chunk if no free chunk available
44
435208
  if(d_freeChunks.empty()) {
45
87638
    d_chunkList.push_back((char*)malloc(chunkSizeBytes));
46
87638
    if(d_chunkList.back() == NULL) {
47
      throw std::bad_alloc();
48
    }
49
50
#ifdef CVC5_VALGRIND
51
    VALGRIND_MAKE_MEM_NOACCESS(d_chunkList.back(), chunkSizeBytes);
52
#endif /* CVC5_VALGRIND */
53
  }
54
  // If there is a free chunk, use that
55
  else {
56
347570
    d_chunkList.push_back(d_freeChunks.back());
57
347570
    d_freeChunks.pop_back();
58
  }
59
  // Set up the current chunk pointers
60
435208
  d_nextFree = d_chunkList.back();
61
435208
  d_endChunk = d_nextFree + chunkSizeBytes;
62
435208
}
63
64
65
2149738
ContextMemoryManager::ContextMemoryManager() : d_indexChunkList(0) {
66
  // Create initial chunk
67
2149738
  d_chunkList.push_back((char*)malloc(chunkSizeBytes));
68
2149738
  d_nextFree = d_chunkList.back();
69
2149738
  if(d_nextFree == NULL) {
70
    throw std::bad_alloc();
71
  }
72
2149738
  d_endChunk = d_nextFree + chunkSizeBytes;
73
74
#ifdef CVC5_VALGRIND
75
  VALGRIND_CREATE_MEMPOOL(this, 0, false);
76
  VALGRIND_MAKE_MEM_NOACCESS(d_nextFree, chunkSizeBytes);
77
  d_allocations.push_back(std::vector<char*>());
78
#endif /* CVC5_VALGRIND */
79
2149738
}
80
81
82
6449214
ContextMemoryManager::~ContextMemoryManager() {
83
#ifdef CVC5_VALGRIND
84
  VALGRIND_DESTROY_MEMPOOL(this);
85
#endif /* CVC5_VALGRIND */
86
87
  // Delete all chunks
88
6449214
  while(!d_chunkList.empty()) {
89
2149738
    free(d_chunkList.back());
90
2149738
    d_chunkList.pop_back();
91
  }
92
45955
  while(!d_freeChunks.empty()) {
93
45955
    free(d_freeChunks.back());
94
45955
    d_freeChunks.pop_back();
95
  }
96
2149738
}
97
98
99
88325097
void* ContextMemoryManager::newData(size_t size) {
100
  // Use next available free location in current chunk
101
88325097
  void* res = (void*)d_nextFree;
102
88325097
  d_nextFree += size;
103
  // Check if the request is too big for the chunk
104
88325097
  if(d_nextFree > d_endChunk) {
105
435208
    newChunk();
106
435208
    res = (void*)d_nextFree;
107
435208
    d_nextFree += size;
108
435208
    AlwaysAssert(d_nextFree <= d_endChunk)
109
        << "Request is bigger than memory chunk size";
110
  }
111
176650194
  Debug("context") << "ContextMemoryManager::newData(" << size
112
88325097
                   << ") returning " << res << " at level "
113
88325097
                   << d_chunkList.size() << std::endl;
114
115
#ifdef CVC5_VALGRIND
116
  VALGRIND_MEMPOOL_ALLOC(this, static_cast<char*>(res), size);
117
  d_allocations.back().push_back(static_cast<char*>(res));
118
#endif /* CVC5_VALGRIND */
119
120
88325097
  return res;
121
}
122
123
124
2609153
void ContextMemoryManager::push() {
125
#ifdef CVC5_VALGRIND
126
  d_allocations.push_back(std::vector<char*>());
127
#endif /* CVC5_VALGRIND */
128
129
  // Store current state on the stack
130
2609153
  d_nextFreeStack.push_back(d_nextFree);
131
2609153
  d_endChunkStack.push_back(d_endChunk);
132
2609153
  d_indexChunkListStack.push_back(d_indexChunkList);
133
2609153
}
134
135
136
2609153
void ContextMemoryManager::pop() {
137
#ifdef CVC5_VALGRIND
138
  for (auto allocation : d_allocations.back())
139
  {
140
    VALGRIND_MEMPOOL_FREE(this, allocation);
141
  }
142
  d_allocations.pop_back();
143
#endif /* CVC5_VALGRIND */
144
145
2609153
  Assert(d_nextFreeStack.size() > 0 && d_endChunkStack.size() > 0);
146
147
  // Restore state from stack
148
2609153
  d_nextFree = d_nextFreeStack.back();
149
2609153
  d_nextFreeStack.pop_back();
150
2609153
  d_endChunk = d_endChunkStack.back();
151
2609153
  d_endChunkStack.pop_back();
152
153
  // Free all the new chunks since the last push
154
3479569
  while(d_indexChunkList > d_indexChunkListStack.back()) {
155
435208
    d_freeChunks.push_back(d_chunkList.back());
156
#ifdef CVC5_VALGRIND
157
    VALGRIND_MAKE_MEM_NOACCESS(d_chunkList.back(), chunkSizeBytes);
158
#endif /* CVC5_VALGRIND */
159
435208
    d_chunkList.pop_back();
160
435208
    --d_indexChunkList;
161
  }
162
2609153
  d_indexChunkListStack.pop_back();
163
164
  // Delete excess free chunks
165
2692519
  while(d_freeChunks.size() > maxFreeChunks) {
166
41683
    free(d_freeChunks.front());
167
41683
    d_freeChunks.pop_front();
168
  }
169
2609153
}
170
#else
171
172
unsigned ContextMemoryManager::getMaxAllocationSize()
173
{
174
  return std::numeric_limits<unsigned>::max();
175
}
176
177
#endif /* CVC5_DEBUG_CONTEXT_MEMORY_MANAGER */
178
179
}  // namespace context
180
28200
}  // namespace cvc5