1 /** @file
2 
3   A brief file description
4 
5   @section license License
6 
7   Licensed to the Apache Software Foundation (ASF) under one
8   or more contributor license agreements.  See the NOTICE file
9   distributed with this work for additional information
10   regarding copyright ownership.  The ASF licenses this file
11   to you under the Apache License, Version 2.0 (the
12   "License"); you may not use this file except in compliance
13   with the License.  You may obtain a copy of the License at
14 
15       http://www.apache.org/licenses/LICENSE-2.0
16 
17   Unless required by applicable law or agreed to in writing, software
18   distributed under the License is distributed on an "AS IS" BASIS,
19   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20   See the License for the specific language governing permissions and
21   limitations under the License.
22  */
23 
24 #include "tscore/ink_assert.h"
25 #include "tscore/ink_atomic.h"
26 #include "tscore/ink_resource.h"
27 #include <execinfo.h>
28 
29 int res_track_memory          = 0; // Disabled by default
30 uint64_t ssl_memory_allocated = 0;
31 uint64_t ssl_memory_freed     = 0;
32 
33 std::map<const char *, Resource *> ResourceTracker::_resourceMap;
34 ink_mutex ResourceTracker::resourceLock = PTHREAD_MUTEX_INITIALIZER;
35 
36 /**
37  * Individual resource to keep track of.  A map of these are in the ResourceTracker.
38  */
39 class Resource
40 {
41 public:
Resource()42   Resource() { _name[0] = '\0'; }
43   void increment(const int64_t size);
44   int64_t
getValue() const45   getValue() const
46   {
47     return _value;
48   }
49   int64_t
getIncrement() const50   getIncrement() const
51   {
52     return _incrementCount;
53   }
54   int64_t
getDecrement() const55   getDecrement() const
56   {
57     return _decrementCount;
58   }
59   void
setSymbol(const void * symbol)60   setSymbol(const void *symbol)
61   {
62     _symbol = symbol;
63   }
64   void
setName(const char * name)65   setName(const char *name)
66   {
67     strncpy(_name, name, sizeof(_name));
68     _name[sizeof(_name) - 1] = '\0';
69   }
70   void
setName(const void * symbol,const char * name)71   setName(const void *symbol, const char *name)
72   {
73     Dl_info info;
74     dladdr(const_cast<void *>(symbol), &info);
75     snprintf(_name, sizeof(_name), "%s/%s", name, info.dli_sname);
76   }
77   const char *
getName() const78   getName() const
79   {
80     return _name;
81   }
82   const void *
getSymbol() const83   getSymbol() const
84   {
85     return _symbol;
86   }
87 
88 private:
89   int64_t _incrementCount = 0;
90   int64_t _decrementCount = 0;
91   int64_t _value          = 0;
92   const void *_symbol     = nullptr;
93   char _name[128];
94 };
95 
96 void
increment(const int64_t size)97 Resource::increment(const int64_t size)
98 {
99   ink_atomic_increment(&_value, size);
100   if (size >= 0) {
101     ink_atomic_increment(&_incrementCount, 1);
102   } else {
103     ink_atomic_increment(&_decrementCount, 1);
104   }
105 }
106 
107 void
increment(const char * name,const int64_t size)108 ResourceTracker::increment(const char *name, const int64_t size)
109 {
110   Resource &resource      = lookup(name);
111   const char *lookup_name = resource.getName();
112   if (lookup_name[0] == '\0') {
113     resource.setName(name);
114   }
115   resource.increment(size);
116 }
117 
118 void
increment(const void * symbol,const int64_t size,const char * name)119 ResourceTracker::increment(const void *symbol, const int64_t size, const char *name)
120 {
121   Resource &resource = lookup(static_cast<const char *>(symbol));
122   if (resource.getSymbol() == nullptr && name != nullptr) {
123     resource.setName(symbol, name);
124     resource.setSymbol(symbol);
125   }
126   resource.increment(size);
127 }
128 
129 Resource &
lookup(const char * name)130 ResourceTracker::lookup(const char *name)
131 {
132   Resource *resource = nullptr;
133   ink_mutex_acquire(&resourceLock);
134   std::map<const char *, Resource *>::iterator it = _resourceMap.find(name);
135   if (it != _resourceMap.end()) {
136     resource = it->second;
137   } else {
138     // create a new entry
139     resource           = new Resource;
140     _resourceMap[name] = resource;
141   }
142   ink_mutex_release(&resourceLock);
143   ink_release_assert(resource != nullptr);
144   return *resource;
145 }
146 
147 void
dump(FILE * fd)148 ResourceTracker::dump(FILE *fd)
149 {
150   if (!res_track_memory) {
151     return;
152   }
153   int64_t total = 0;
154 
155   ink_mutex_acquire(&resourceLock);
156   if (!_resourceMap.empty()) {
157     fprintf(fd, "\n%-10s | %-10s | %-20s | %-10s | %-50s\n", "Allocs", "Frees", "Size In-use", "Avg Size", "Location");
158     fprintf(fd, "-----------|------------|----------------------|------------|"
159                 "--------------------------------------------------------------------\n");
160     for (std::map<const char *, Resource *>::const_iterator it = _resourceMap.begin(); it != _resourceMap.end(); ++it) {
161       const Resource &resource = *it->second;
162       int64_t average_size     = 0;
163       if (resource.getIncrement() - resource.getDecrement() > 0) {
164         average_size = resource.getValue() / (resource.getIncrement() - resource.getDecrement());
165       }
166       fprintf(fd, "%10" PRId64 " | %10" PRId64 " | %20" PRId64 " | %10" PRId64 " | %-50s\n", resource.getIncrement(),
167               resource.getDecrement(), resource.getValue(), average_size, resource.getName());
168       total += resource.getValue();
169     }
170     fprintf(fd, "                          %20" PRId64 " |            | %-50s\n", total, "TOTAL");
171     fprintf(fd, "--------------------------------------------------------------"
172                 "--------------------------------------------------------------------\n");
173   }
174 
175   ink_mutex_release(&resourceLock);
176 
177   if (res_track_memory >= 2) {
178     fprintf(fd, "\n%-20s | %-20s | %-20s | %-20s\n", "Total Allocated", "Total Freed", "Currently Allocated", "Type");
179     fprintf(fd, "---------------------|----------------------|----------------------|----------------------\n");
180     fprintf(fd, "%20" PRId64 " | %20" PRId64 " | %20" PRId64 " | %-50s\n", ssl_memory_allocated, ssl_memory_freed,
181             ssl_memory_allocated - ssl_memory_freed, "SSL Allocated Memory");
182     fprintf(fd, "---------------------|----------------------|----------------------|----------------------\n");
183   }
184 }
185