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