1 // -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
2 // Copyright 2009 Google Inc. All Rights Reserved.
3 // Author: fikes@google.com (Andrew Fikes)
4 //
5 // Use of this source code is governed by a BSD-style license that can
6 // be found in the LICENSE file.
7 
8 
9 #include "config_for_unittests.h"
10 #include <stdio.h>   // for puts()
11 #include "stack_trace_table.h"
12 #include "base/logging.h"
13 #include "base/spinlock.h"
14 #include "static_vars.h"
15 
16 #undef ARRAYSIZE   // may be defined on, eg, windows
17 #define ARRAYSIZE(a)  ( sizeof(a) / sizeof(*(a)) )
18 
CheckTracesAndReset(tcmalloc::StackTraceTable * table,const uintptr_t * expected,int len)19 static void CheckTracesAndReset(tcmalloc::StackTraceTable* table,
20                         const uintptr_t* expected, int len) {
21   void** entries = table->ReadStackTracesAndClear();
22   for (int i = 0; i < len; ++i) {
23     CHECK_EQ(reinterpret_cast<uintptr_t>(entries[i]), expected[i]);
24   }
25   delete[] entries;
26 }
27 
AddTrace(tcmalloc::StackTraceTable * table,const tcmalloc::StackTrace & t)28 static void AddTrace(tcmalloc::StackTraceTable* table,
29                      const tcmalloc::StackTrace& t) {
30   // Normally we'd need this lock, but since the test is single-threaded
31   // we don't.  I comment it out on windows because the DLL-decl thing
32   // is really annoying in this case.
33 #ifndef _MSC_VER
34   SpinLockHolder h(tcmalloc::Static::pageheap_lock());
35 #endif
36   table->AddTrace(t);
37 }
38 
main(int argc,char ** argv)39 int main(int argc, char **argv) {
40   tcmalloc::StackTraceTable table;
41 
42   // Empty table
43   CHECK_EQ(table.depth_total(), 0);
44   CHECK_EQ(table.bucket_total(), 0);
45   static const uintptr_t k1[] = {0};
46   CheckTracesAndReset(&table, k1, ARRAYSIZE(k1));
47 
48   tcmalloc::StackTrace t1;
49   t1.size = static_cast<uintptr_t>(1024);
50   t1.depth = static_cast<uintptr_t>(2);
51   t1.stack[0] = reinterpret_cast<void*>(1);
52   t1.stack[1] = reinterpret_cast<void*>(2);
53 
54 
55   tcmalloc::StackTrace t2;
56   t2.size = static_cast<uintptr_t>(512);
57   t2.depth = static_cast<uintptr_t>(2);
58   t2.stack[0] = reinterpret_cast<void*>(2);
59   t2.stack[1] = reinterpret_cast<void*>(1);
60 
61   // Table w/ just t1
62   AddTrace(&table, t1);
63   CHECK_EQ(table.depth_total(), 2);
64   CHECK_EQ(table.bucket_total(), 1);
65   static const uintptr_t k2[] = {1, 1024, 2, 1, 2, 0};
66   CheckTracesAndReset(&table, k2, ARRAYSIZE(k2));
67 
68   // Table w/ t1, t2
69   AddTrace(&table, t1);
70   AddTrace(&table, t2);
71   CHECK_EQ(table.depth_total(), 4);
72   CHECK_EQ(table.bucket_total(), 2);
73   static const uintptr_t k3[] = {1, 1024, 2, 1, 2, 1,  512, 2, 2, 1, 0};
74   CheckTracesAndReset(&table, k3, ARRAYSIZE(k3));
75 
76   // Table w/ 2 x t1, 1 x t2
77   AddTrace(&table, t1);
78   AddTrace(&table, t2);
79   AddTrace(&table, t1);
80   CHECK_EQ(table.depth_total(), 4);
81   CHECK_EQ(table.bucket_total(), 2);
82   static const uintptr_t k4[] = {2, 2048, 2, 1, 2, 1,  512, 2, 2, 1, 0};
83   CheckTracesAndReset(&table, k4, ARRAYSIZE(k4));
84 
85   // Same stack as t1, but w/ different size
86   tcmalloc::StackTrace t3;
87   t3.size = static_cast<uintptr_t>(2);
88   t3.depth = static_cast<uintptr_t>(2);
89   t3.stack[0] = reinterpret_cast<void*>(1);
90   t3.stack[1] = reinterpret_cast<void*>(2);
91 
92   // Table w/ t1, t3
93   AddTrace(&table, t1);
94   AddTrace(&table, t3);
95   CHECK_EQ(table.depth_total(), 2);
96   CHECK_EQ(table.bucket_total(), 1);
97   static const uintptr_t k5[] = {2, 1026, 2, 1, 2, 0};
98   CheckTracesAndReset(&table, k5, ARRAYSIZE(k5));
99 
100   puts("PASS");
101   return 0;
102 }
103