File: mem.hpp

package info (click to toggle)
macaulay2 1.21%2Bds-3
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 133,096 kB
  • sloc: cpp: 110,377; ansic: 16,306; javascript: 4,193; makefile: 3,821; sh: 3,580; lisp: 764; yacc: 590; xml: 177; python: 140; perl: 114; lex: 65; awk: 3
file content (189 lines) | stat: -rw-r--r-- 4,900 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
// (c) 1995  Michael E. Stillman
#ifndef _mem_hh_
#define _mem_hh_

#include <cassert>
#include "newdelete.hpp"
// for spinLock:
#include "../system/mutex.h"
class buffer;

// 2*2^NDOUBLES = Largest stash size.
const int NDOUBLES = 25;
// const int slab_size = 2040;
const int slab_size = 2032;
// const int slab_size = 262134;
const char bad_pattern = '\245';
const int word_size =
    static_cast<int>(sizeof(void *));  // g++-4.8.0 complains without the cast.

extern size_t engine_allocated;
extern size_t engine_highwater;

// Each type should include something like the following:
#if 0
// // in .hpp file:
// friend void i_stashes();
// static stash *mystash;
// void *operator new(size_t size) { return mystash->new_elem(); }
// void operator delete(void *p) { mystash->delete_elem(p); }
// // in .cc file
// stash *matrix_rec::mystash;
// // in object.cc in i_stashes:
// matrix_rec::mystash = new stash("matrix", sizeof(matrix_rec));
#endif

class slab : public our_new_delete
{
  friend class stash;
  static int n_slabs;
  slab *next;
  char s[slab_size];

  slab() : next(NULL) { n_slabs++; }
  ~slab() { n_slabs--; }
};

class stash : public our_new_delete
{
 public:
  stash(const char *s, size_t len);
  ~stash();

  void *new_elem();
  void delete_elem(void *p);

  void text_out(buffer &o) const;  // Display statistics about this stash.
  static void stats(buffer &o);

 private:
  const char *name;
  size_t element_size;  // In bytes
  // n_per_slab provides the number of elements of element_size in each slab.
  // If 0, elements are new'ed directly.
  int n_per_slab;

  // List of slabs
  // Uses slab::next to indicate next element in list
  // This will be 0 if n_per_slab is 0.
  slab *slabs;

  // Free list for this stash.
  // Currently: if n_per_slab is 0, then elements are deleted'd directly.
  // Note that this essentially a list of the elements from various slabs.
  // a pointer to the next element in the list is in the first sizeof(void*)
  // bytes.
  void *free_list;

  // statistics
  size_t n_allocs;
  size_t n_inuse;
  size_t highwater;
  size_t n_frees;

  // private routines
  void chop_slab();

  // spinlock for modifying member lists
  spinLock list_spinlock;
};

inline void *stash::new_elem()
// Allocate space for an object from this stash.
{
  return newarray_clear(char, element_size);
  acquireSpinLock(&list_spinlock);
  n_allocs++;
  n_inuse++;
  if (n_inuse > highwater) highwater = n_inuse;
  if (free_list == NULL)
    {
      if (n_per_slab == 0)
        {
          void *result = newarray_clear(char, element_size);
          // allocated_amount += element_size;
          releaseSpinLock(&list_spinlock);
          return result;
        }
      chop_slab();
    }
  assert(free_list != NULL);  // chop_slab should not let this happen.
  void *result = free_list;
  free_list = *(reinterpret_cast<void **>(free_list));
  releaseSpinLock(&list_spinlock);
  return result;
}

inline void stash::delete_elem(void *p)
// Delete the object 'p', placing it on the free list for this stash.
{
  if (p == NULL) return;
  freemem(p);
  return;
  //  if (trace_bad_deletes)
  //    {
  //      for (void *q = free_list; q != NULL; q = *(reinterpret_cast<void
  //      **>(q)))
  //    if (q == p)
  //      assert(0);
  //    }

  n_inuse--;
  n_frees++;
  if (n_per_slab == 0)
    {
      //      deleted_amount += element_size;
      char *q = reinterpret_cast<char *>(p);
      freemem(q);
      return;
    }
  acquireSpinLock(&list_spinlock);
  memset(p, 0, element_size);  // we clear this element because it's free, and
                               // it may contain words that look like pointers
                               // to gc
  *(reinterpret_cast<void **>(p)) = free_list;
  free_list = p;
  releaseSpinLock(&list_spinlock);
}

/**
The doubling stash essentially is a list of stashes of different sizes.
The sizes start at 2 and run to 2*2^NDOUBLES
**/

class doubling_stash : public our_new_delete
{
  doubling_stash(const doubling_stash &) { assert(0); }
  void operator=(const doubling_stash &) { assert(0); }
 public:
  doubling_stash();
  ~doubling_stash();
  // Get a new element of given size.  Essentially this just dispatches to the
  // correct stash
  void *new_elem(size_t size);
  // Delete an element of a given size.  Essentially this just deletes an
  // element
  void delete_elem(void *p);
  // return the allocated size.
  size_t allocated_size(void *p);

 private:
  stash *doubles[NDOUBLES];
  size_t double_size[NDOUBLES];
};

extern doubling_stash *doubles;

static inline void engine_alloc(size_t n)
{
  engine_allocated += n;
  if (engine_allocated > engine_highwater) engine_highwater = engine_allocated;
}

static inline void engine_dealloc(size_t n) { engine_allocated -= n; }
#endif

// Local Variables:
// compile-command: "make -C $M2BUILDDIR/Macaulay2/e "
// indent-tabs-mode: nil
// End: