blob: 5888dc0415911db9cd0f8e20454e9ca5802fcc4a [file] [log] [blame]
Austin Schuh745610d2015-09-06 18:19:50 -07001// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
2// Copyright (c) 2009, Google Inc.
3// All rights reserved.
4//
5// Redistribution and use in source and binary forms, with or without
6// modification, are permitted provided that the following conditions are
7// met:
8//
9// * Redistributions of source code must retain the above copyright
10// notice, this list of conditions and the following disclaimer.
11// * Redistributions in binary form must reproduce the above
12// copyright notice, this list of conditions and the following disclaimer
13// in the documentation and/or other materials provided with the
14// distribution.
15// * Neither the name of Google Inc. nor the names of its
16// contributors may be used to endorse or promote products derived from
17// this software without specific prior written permission.
18//
19// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30
31// ---
32// Author: Andrew Fikes
33
34#include <config.h>
35#include "stack_trace_table.h"
36#include <string.h> // for NULL, memset
37#include "base/spinlock.h" // for SpinLockHolder
38#include "common.h" // for StackTrace
39#include "internal_logging.h" // for ASSERT, Log
40#include "page_heap_allocator.h" // for PageHeapAllocator
41#include "static_vars.h" // for Static
42
43namespace tcmalloc {
44
Austin Schuh745610d2015-09-06 18:19:50 -070045StackTraceTable::StackTraceTable()
46 : error_(false),
47 depth_total_(0),
48 bucket_total_(0),
Brian Silverman20350ac2021-11-17 18:19:55 -080049 head_(nullptr) {
Austin Schuh745610d2015-09-06 18:19:50 -070050}
51
52StackTraceTable::~StackTraceTable() {
Brian Silverman20350ac2021-11-17 18:19:55 -080053 ASSERT(head_ == nullptr);
Austin Schuh745610d2015-09-06 18:19:50 -070054}
55
56void StackTraceTable::AddTrace(const StackTrace& t) {
57 if (error_) {
58 return;
59 }
60
Brian Silverman20350ac2021-11-17 18:19:55 -080061 depth_total_ += t.depth;
62 bucket_total_++;
63 Entry* entry = allocator_.allocate(1);
64 if (entry == nullptr) {
65 Log(kLog, __FILE__, __LINE__,
66 "tcmalloc: could not allocate bucket", sizeof(*entry));
67 error_ = true;
Austin Schuh745610d2015-09-06 18:19:50 -070068 } else {
Brian Silverman20350ac2021-11-17 18:19:55 -080069 entry->trace = t;
70 entry->next = head_;
71 head_ = entry;
Austin Schuh745610d2015-09-06 18:19:50 -070072 }
73}
74
75void** StackTraceTable::ReadStackTracesAndClear() {
Brian Silverman20350ac2021-11-17 18:19:55 -080076 void** out = nullptr;
Austin Schuh745610d2015-09-06 18:19:50 -070077
Austin Schuh745610d2015-09-06 18:19:50 -070078 const int out_len = bucket_total_ * 3 + depth_total_ + 1;
Brian Silverman20350ac2021-11-17 18:19:55 -080079 if (!error_) {
80 // Allocate output array
81 out = new (std::nothrow_t{}) void*[out_len];
82 if (out == nullptr) {
83 Log(kLog, __FILE__, __LINE__,
84 "tcmalloc: allocation failed for stack traces",
85 out_len * sizeof(*out));
Austin Schuh745610d2015-09-06 18:19:50 -070086 }
87 }
Brian Silverman20350ac2021-11-17 18:19:55 -080088
89 if (out) {
90 // Fill output array
91 int idx = 0;
92 Entry* entry = head_;
93 while (entry != NULL) {
94 out[idx++] = reinterpret_cast<void*>(uintptr_t{1}); // count
95 out[idx++] = reinterpret_cast<void*>(entry->trace.size); // cumulative size
96 out[idx++] = reinterpret_cast<void*>(entry->trace.depth);
97 for (int d = 0; d < entry->trace.depth; ++d) {
98 out[idx++] = entry->trace.stack[d];
99 }
100 entry = entry->next;
101 }
102 out[idx++] = NULL;
103 ASSERT(idx == out_len);
104 }
Austin Schuh745610d2015-09-06 18:19:50 -0700105
106 // Clear state
107 error_ = false;
108 depth_total_ = 0;
109 bucket_total_ = 0;
Brian Silverman20350ac2021-11-17 18:19:55 -0800110
Austin Schuh745610d2015-09-06 18:19:50 -0700111 SpinLockHolder h(Static::pageheap_lock());
Brian Silverman20350ac2021-11-17 18:19:55 -0800112 Entry* entry = head_;
113 while (entry != nullptr) {
114 Entry* next = entry->next;
115 allocator_.deallocate(entry, 1);
116 entry = next;
Austin Schuh745610d2015-09-06 18:19:50 -0700117 }
Brian Silverman20350ac2021-11-17 18:19:55 -0800118 head_ = nullptr;
Austin Schuh745610d2015-09-06 18:19:50 -0700119
120 return out;
121}
122
123} // namespace tcmalloc