1 // Copyright (c) 2009, Google Inc.
2 // All rights reserved.
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are
8 // * Redistributions of source code must retain the above copyright
9 // notice, this list of conditions and the following disclaimer.
10 // * Redistributions in binary form must reproduce the above
11 // copyright notice, this list of conditions and the following disclaimer
12 // in the documentation and/or other materials provided with the
14 // * Neither the name of Google Inc. nor the names of its
15 // contributors may be used to endorse or promote products derived from
16 // this software without specific prior written permission.
18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 // Author: Andrew Fikes
34 #include "stack_trace_table.h"
35 #include <string.h> // for NULL, memset
36 #include "base/spinlock.h" // for SpinLockHolder
37 #include "common.h" // for StackTrace
38 #include "internal_logging.h" // for ASSERT, Log
39 #include "page_heap_allocator.h" // for PageHeapAllocator
40 #include "static_vars.h" // for Static
44 bool StackTraceTable::Bucket::KeyEqual(uintptr_t h
,
45 const StackTrace
& t
) const {
46 const bool eq
= (this->hash
== h
&& this->trace
.depth
== t
.depth
);
47 for (int i
= 0; eq
&& i
< t
.depth
; ++i
) {
48 if (this->trace
.stack
[i
] != t
.stack
[i
]) {
55 StackTraceTable::StackTraceTable()
59 table_(new Bucket
*[kHashTableSize
]()) {
60 memset(table_
, 0, kHashTableSize
* sizeof(Bucket
*));
63 StackTraceTable::~StackTraceTable() {
67 void StackTraceTable::AddTrace(const StackTrace
& t
) {
72 // Hash function borrowed from base/heap-profile-table.cc
74 for (int i
= 0; i
< t
.depth
; ++i
) {
75 h
+= reinterpret_cast<uintptr_t>(t
.stack
[i
]);
82 const int idx
= h
% kHashTableSize
;
84 Bucket
* b
= table_
[idx
];
85 while (b
!= NULL
&& !b
->KeyEqual(h
, t
)) {
90 b
->trace
.size
+= t
.size
; // keep cumulative size
92 depth_total_
+= t
.depth
;
94 b
= Static::bucket_allocator()->New();
96 Log(kLog
, __FILE__
, __LINE__
,
97 "tcmalloc: could not allocate bucket", sizeof(*b
));
103 b
->next
= table_
[idx
];
109 void** StackTraceTable::ReadStackTracesAndClear() {
114 // Allocate output array
115 const int out_len
= bucket_total_
* 3 + depth_total_
+ 1;
116 void** out
= new void*[out_len
];
118 Log(kLog
, __FILE__
, __LINE__
,
119 "tcmalloc: allocation failed for stack traces",
120 out_len
* sizeof(*out
));
126 for (int i
= 0; i
< kHashTableSize
; ++i
) {
127 Bucket
* b
= table_
[i
];
129 out
[idx
++] = reinterpret_cast<void*>(static_cast<uintptr_t>(b
->count
));
130 out
[idx
++] = reinterpret_cast<void*>(b
->trace
.size
); // cumulative size
131 out
[idx
++] = reinterpret_cast<void*>(b
->trace
.depth
);
132 for (int d
= 0; d
< b
->trace
.depth
; ++d
) {
133 out
[idx
++] = b
->trace
.stack
[d
];
138 out
[idx
++] = static_cast<uintptr_t>(0);
139 ASSERT(idx
== out_len
);
145 SpinLockHolder
h(Static::pageheap_lock());
146 for (int i
= 0; i
< kHashTableSize
; ++i
) {
147 Bucket
* b
= table_
[i
];
149 Bucket
* next
= b
->next
;
150 Static::bucket_allocator()->Delete(b
);
159 } // namespace tcmalloc