aboutsummaryrefslogtreecommitdiff
path: root/src/share/vm/services/memRecorder.hpp
blob: 313af97db7fead90c740556df2ea8323df0d0b84 (plain)
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
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
/*
 * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 *
 */

#ifndef SHARE_VM_SERVICES_MEM_RECORDER_HPP
#define SHARE_VM_SERVICES_MEM_RECORDER_HPP

#include "memory/allocation.hpp"
#include "runtime/os.hpp"
#include "services/memPtrArray.hpp"

class MemSnapshot;
class MemTracker;
class MemTrackWorker;

// Fixed size memory pointer array implementation
template <class E, int SIZE> class FixedSizeMemPointerArray :
  public MemPointerArray {
  // This implementation is for memory recorder only
  friend class MemRecorder;

 private:
  E      _data[SIZE];
  int    _size;

 protected:
  FixedSizeMemPointerArray(bool init_elements = false):
   _size(0){
    if (init_elements) {
      for (int index = 0; index < SIZE; index ++) {
        ::new ((void*)&_data[index]) E();
      }
    }
  }

  void* operator new(size_t size, const std::nothrow_t& nothrow_constant) {
    // the instance is part of memRecorder, needs to be tagged with 'otNMTRecorder'
    // to avoid recursion
    return os::malloc(size, (mtNMT | otNMTRecorder));
  }

  void* operator new(size_t size) {
    assert(false, "use nothrow version");
    return NULL;
  }

  void operator delete(void* p) {
    os::free(p, (mtNMT | otNMTRecorder));
  }

  // instance size
  inline size_t instance_size() const {
    return sizeof(FixedSizeMemPointerArray<E, SIZE>);
  }

  debug_only(int capacity() const { return SIZE; })

 public:
  // implementation of public interface
  bool out_of_memory() const { return false; }
  bool is_empty()      const { return _size == 0; }
  bool is_full()             { return length() >= SIZE; }
  int  length()        const { return _size; }

  void clear() {
    _size = 0;
  }

  bool append(MemPointer* ptr) {
    if (is_full()) return false;
    _data[_size ++] = *(E*)ptr;
    return true;
  }

  virtual bool insert_at(MemPointer* p, int pos) {
    assert(false, "append only");
    return false;
  }

  virtual bool remove_at(int pos) {
    assert(false, "not supported");
    return false;
  }

  MemPointer* at(int index) const {
    assert(index >= 0 && index < length(),
      "parameter check");
    return ((E*)&_data[index]);
  }

  void sort(FN_SORT fn) {
    qsort((void*)_data, _size, sizeof(E), fn);
  }

  bool shrink() {
    return false;
  }
};


// This iterator requires pre-sorted MemPointerArray, which is sorted by:
//  1. address
//  2. allocation type
//  3. sequence number
// During the array walking, iterator collapses pointers with the same
// address and allocation type, and only returns the one with highest
// sequence number.
//
// This is read-only iterator, update methods are asserted.
class SequencedRecordIterator : public MemPointerArrayIterator {
 private:
   MemPointerArrayIteratorImpl _itr;
   MemPointer*                 _cur;

 public:
  SequencedRecordIterator(const MemPointerArray* arr):
    _itr(const_cast<MemPointerArray*>(arr)) {
    _cur = next_record();
  }

  SequencedRecordIterator(const SequencedRecordIterator& itr):
    _itr(itr._itr) {
    _cur = next_record();
  }

  // return the pointer at current position
  virtual MemPointer* current() const {
    return _cur;
  };

  // return the next pointer and advance current position
  virtual MemPointer* next() {
    _cur = next_record();
    return _cur;
  }

  // return the next pointer without advancing current position
  virtual MemPointer* peek_next() const {
    assert(false, "not implemented");
    return NULL;

  }
  // return the previous pointer without changing current position
  virtual MemPointer* peek_prev() const {
    assert(false, "not implemented");
    return NULL;
  }

  // remove the pointer at current position
  virtual void remove() {
    assert(false, "read-only iterator");
  };
  // insert the pointer at current position
  virtual bool insert(MemPointer* ptr) {
    assert(false, "read-only iterator");
    return false;
  }

  virtual bool insert_after(MemPointer* ptr) {
    assert(false, "read-only iterator");
    return false;
  }
 private:
  // collapse the 'same kind' of records, and return this 'kind' of
  // record with highest sequence number
  MemPointer* next_record();

  // Test if the two records are the same kind: the same memory block and allocation
  // type.
  inline bool same_kind(const MemPointerRecord* p1, const MemPointerRecord* p2) const {
    return (p1->addr() == p2->addr() &&
      (p1->flags() &MemPointerRecord::tag_masks) ==
      (p2->flags() & MemPointerRecord::tag_masks));
  }
};



#define DEFAULT_RECORDER_PTR_ARRAY_SIZE 512

class MemRecorder : public CHeapObj<mtNMT|otNMTRecorder> {
  friend class MemSnapshot;
  friend class MemTracker;
  friend class MemTrackWorker;

 protected:
  // the array that holds memory records
  MemPointerArray*         _pointer_records;

 private:
  // used for linked list
  MemRecorder*             _next;
  // active recorder can only record a certain generation data
  debug_only(unsigned long _generation;)

 protected:
  _NOINLINE_ MemRecorder();
  ~MemRecorder();

  // record a memory operation
  bool record(address addr, MEMFLAGS flags, size_t size, address caller_pc = 0);

  // linked list support
  inline void set_next(MemRecorder* rec) {
    _next = rec;
  }

  inline MemRecorder* next() const {
    return _next;
  }

  // if the recorder is full
  inline bool is_full() const {
    assert(_pointer_records != NULL, "just check");
    return _pointer_records->is_full();
  }

  // if running out of memory when initializing recorder's internal
  // data
  inline bool out_of_memory() const {
    return (_pointer_records == NULL ||
      _pointer_records->out_of_memory());
  }

  inline void clear() {
    assert(_pointer_records != NULL, "Just check");
    _pointer_records->clear();
  }

  SequencedRecordIterator pointer_itr();

 protected:
  // number of MemRecorder instance
  static volatile jint _instance_count;

 private:
  // sorting function, sort records into following order
  // 1. memory address
  // 2. allocation type
  // 3. sequence number
  static int sort_record_fn(const void* e1, const void* e2);

  debug_only(void check_dup_seq(jint seq) const;)
  debug_only(void set_generation();)
};

#endif // SHARE_VM_SERVICES_MEM_RECORDER_HPP