Automatic date update in version.in
[binutils-gdb.git] / gprofng / src / HeapActivity.cc
blobd25fe162ab995f17e78250aabb57fe38461a80e6
1 /* Copyright (C) 2021-2024 Free Software Foundation, Inc.
2 Contributed by Oracle.
4 This file is part of GNU Binutils.
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3, or (at your option)
9 any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, 51 Franklin Street - Fifth Floor, Boston,
19 MA 02110-1301, USA. */
21 #include "config.h"
22 #include "DbeSession.h"
23 #include "HeapData.h"
24 #include "StringBuilder.h"
25 #include "i18n.h"
26 #include "util.h"
27 #include "HeapActivity.h"
28 #include "MetricList.h"
29 #include "Application.h"
30 #include "Experiment.h"
31 #include "DbeView.h"
32 #include "Exp_Layout.h"
33 #include "i18n.h"
35 HeapActivity::HeapActivity (DbeView *_dbev)
37 dbev = _dbev;
38 hDataTotal = NULL;
39 hDataObjs = NULL;
40 hDataObjsCallStack = NULL;
41 hasCallStack = false;
42 hDataCalStkMap = NULL;
43 hist_data_callstack_all = NULL;
46 void
47 HeapActivity::reset ()
49 delete hDataTotal;
50 hDataTotal = NULL;
51 delete hDataObjsCallStack;
52 hDataObjsCallStack = NULL;
53 hasCallStack = false;
54 hDataObjs = NULL;
55 delete hDataCalStkMap;
56 hDataCalStkMap = NULL;
57 hist_data_callstack_all = NULL;
60 void
61 HeapActivity::createHistItemTotals (Hist_data *hist_data, MetricList *mlist,
62 Histable::Type hType, bool empty)
64 int mIndex;
65 Metric *mtr;
66 Hist_data::HistItem *hi;
67 HeapData *hData = NULL;
68 if (hDataTotal == NULL)
70 hDataTotal = new HeapData (TOTAL_HEAPNAME);
71 hDataTotal->setHistType (hType);
72 hDataTotal->setStackId (TOTAL_STACK_ID);
73 hDataTotal->id = 0;
76 hData = new HeapData (hDataTotal);
77 hData->setHistType (hType);
78 hi = hist_data->append_hist_item (hData);
80 Vec_loop (Metric *, mlist->get_items (), mIndex, mtr)
82 if (!mtr->is_visible () && !mtr->is_tvisible () && !mtr->is_pvisible ())
83 continue;
85 Metric::Type mtype = mtr->get_type ();
86 ValueTag vType = mtr->get_vtype ();
88 hist_data->total->value[mIndex].tag = vType;
89 hi->value[mIndex].tag = vType;
90 switch (mtype)
92 case BaseMetric::HEAP_ALLOC_BYTES:
93 if (!empty)
95 hist_data->total->value[mIndex].ll = hDataTotal->getAllocBytes ();
96 hi->value[mIndex].ll = hDataTotal->getAllocBytes ();
98 else
100 hist_data->total->value[mIndex].ll = 0;
101 hi->value[mIndex].ll = 0;
103 break;
104 case BaseMetric::HEAP_ALLOC_CNT:
105 if (!empty)
107 hist_data->total->value[mIndex].ll = hDataTotal->getAllocCnt ();
108 hi->value[mIndex].ll = hDataTotal->getAllocCnt ();
110 else
112 hist_data->total->value[mIndex].ll = 0;
113 hi->value[mIndex].ll = 0;
115 break;
116 case BaseMetric::HEAP_LEAK_BYTES:
117 if (!empty)
119 hist_data->total->value[mIndex].ll = hDataTotal->getLeakBytes ();
120 hi->value[mIndex].ll = hDataTotal->getLeakBytes ();
122 else
124 hist_data->total->value[mIndex].ll = 0;
125 hi->value[mIndex].ll = 0;
127 break;
128 case BaseMetric::HEAP_LEAK_CNT:
129 if (!empty)
131 hist_data->total->value[mIndex].ll = hDataTotal->getLeakCnt ();
132 hi->value[mIndex].ll = hDataTotal->getLeakCnt ();
134 else
136 hist_data->total->value[mIndex].ll = 0;
137 hi->value[mIndex].ll = 0;
139 break;
140 default:
141 break;
146 void
147 HeapActivity::computeHistTotals (Hist_data *hist_data, MetricList *mlist)
149 int mIndex;
150 Metric *mtr;
151 Vec_loop (Metric *, mlist->get_items (), mIndex, mtr)
153 if (!mtr->is_visible () && !mtr->is_tvisible () && !mtr->is_pvisible ())
154 continue;
156 Metric::Type mtype = mtr->get_type ();
157 ValueTag vType = mtr->get_vtype ();
159 hist_data->total->value[mIndex].tag = vType;
160 switch (mtype)
162 case BaseMetric::HEAP_ALLOC_BYTES:
163 hist_data->total->value[mIndex].ll = hDataTotal->getAllocBytes ();
164 break;
165 case BaseMetric::HEAP_ALLOC_CNT:
166 hist_data->total->value[mIndex].ll = hDataTotal->getAllocCnt ();
167 break;
168 case BaseMetric::HEAP_LEAK_BYTES:
169 hist_data->total->value[mIndex].ll = hDataTotal->getLeakBytes ();
170 break;
171 case BaseMetric::HEAP_LEAK_CNT:
172 hist_data->total->value[mIndex].ll = hDataTotal->getLeakCnt ();
173 break;
174 default:
175 break;
180 void
181 HeapActivity::computeHistData (Hist_data *hist_data, MetricList *mlist,
182 Hist_data::Mode mode, Histable *selObj)
185 Hist_data::HistItem *hi = NULL;
187 int numObjs = hDataObjs->size ();
188 int numMetrics = mlist->get_items ()->size ();
189 for (int i = 0; i < numObjs; i++)
191 HeapData *hData = hDataObjs->fetch (i);
192 if (mode == Hist_data::ALL)
193 hi = hist_data->append_hist_item (hData);
194 else if (mode == Hist_data::SELF)
196 if (hData->id == selObj->id)
197 hi = hist_data->append_hist_item (hData);
198 else
199 continue;
202 for (int mIndex = 0; mIndex < numMetrics; mIndex++)
204 Metric *mtr = mlist->get_items ()->fetch (mIndex);
205 if (!mtr->is_visible () && !mtr->is_tvisible ()
206 && !mtr->is_pvisible ())
207 continue;
209 Metric::Type mtype = mtr->get_type ();
210 ValueTag vType = mtr->get_vtype ();
211 hi->value[mIndex].tag = vType;
212 switch (mtype)
214 case BaseMetric::HEAP_ALLOC_BYTES:
215 hi->value[mIndex].ll = hData->getAllocBytes ();
216 break;
217 case BaseMetric::HEAP_ALLOC_CNT:
218 hi->value[mIndex].ll = hData->getAllocCnt ();
219 break;
220 case BaseMetric::HEAP_LEAK_BYTES:
221 hi->value[mIndex].ll = hData->getLeakBytes ();
222 break;
223 case BaseMetric::HEAP_LEAK_CNT:
224 hi->value[mIndex].ll = hData->getLeakCnt ();
225 break;
226 default:
227 break;
233 Hist_data *
234 HeapActivity::compute_metrics (MetricList *mlist, Histable::Type type,
235 Hist_data::Mode mode, Histable *selObj)
237 // it's already there, just return it
238 if (mode == Hist_data::ALL && type == Histable::HEAPCALLSTACK
239 && hist_data_callstack_all != NULL)
240 return hist_data_callstack_all;
242 bool has_data = false;
243 Hist_data *hist_data = NULL;
244 VMode viewMode = dbev->get_view_mode ();
245 switch (type)
247 case Histable::HEAPCALLSTACK:
248 if (!hasCallStack) // It is not computed yet
249 computeCallStack (type, viewMode);
251 // computeCallStack() creates hDataObjsCallStack
252 // hDataObjsCallStack contains the list of call stack objects
253 if (hDataObjsCallStack != NULL)
255 hDataObjs = hDataObjsCallStack;
256 has_data = true;
258 else
259 has_data = false;
261 if (has_data && mode == Hist_data::ALL && hist_data_callstack_all == NULL)
263 hist_data_callstack_all = new Hist_data (mlist, type, mode, true);
264 hist_data = hist_data_callstack_all;
266 else if (has_data)
267 hist_data = new Hist_data (mlist, type, mode, false);
268 else
270 hist_data = new Hist_data (mlist, type, mode, false);
271 createHistItemTotals (hist_data, mlist, type, true);
272 return hist_data;
274 break;
275 default:
276 fprintf (stderr,
277 "HeapActivity cannot process data due to wrong Histable (type=%d) \n",
278 type);
279 abort ();
282 if (mode == Hist_data::ALL || (mode == Hist_data::SELF && selObj->id == 0))
283 createHistItemTotals (hist_data, mlist, type, false);
284 else
285 computeHistTotals (hist_data, mlist);
286 computeHistData (hist_data, mlist, mode, selObj);
288 // Determine by which metric to sort if any
289 bool rev_sort = mlist->get_sort_rev ();
290 int sort_ind = -1;
291 int nmetrics = mlist->get_items ()->size ();
293 for (int mind = 0; mind < nmetrics; mind++)
294 if (mlist->get_sort_ref_index () == mind)
295 sort_ind = mind;
297 hist_data->sort (sort_ind, rev_sort);
298 hist_data->compute_minmax ();
300 return hist_data;
303 void
304 HeapActivity::computeCallStack (Histable::Type type, VMode viewMode)
306 bool has_data = false;
307 reset ();
308 uint64_t stackIndex = 0;
309 HeapData *hData = NULL;
311 delete hDataCalStkMap;
312 hDataCalStkMap = new DefaultMap<uint64_t, HeapData*>;
314 delete hDataTotal;
315 hDataTotal = new HeapData (TOTAL_HEAPNAME);
316 hDataTotal->setHistType (type);
318 // There is no call stack for total, use the index for id
319 hDataTotal->id = stackIndex++;
321 // get the list of io events from DbeView
322 int numExps = dbeSession->nexps ();
324 for (int k = 0; k < numExps; k++)
326 // Investigate the performance impact of processing the heap events twice.
327 // This is a 2*n performance issue
328 dbev->get_filtered_events (k, DATA_HEAPSZ);
330 DataView *heapPkts = dbev->get_filtered_events (k, DATA_HEAP);
331 if (heapPkts == NULL)
332 continue;
334 Experiment *exp = dbeSession->get_exp (k);
335 long sz = heapPkts->getSize ();
336 int pid = 0;
337 int userExpId = 0;
338 if (sz > 0)
340 pid = exp->getPID ();
341 userExpId = exp->getUserExpId ();
343 for (long i = 0; i < sz; ++i)
345 uint64_t nByte = heapPkts->getULongValue (PROP_HSIZE, i);
346 uint64_t stackId = (uint64_t) getStack (viewMode, heapPkts, i);
347 Heap_type heapType = (Heap_type) heapPkts->getIntValue (PROP_HTYPE, i);
348 uint64_t leaked = heapPkts->getULongValue (PROP_HLEAKED, i);
349 int64_t heapSize = heapPkts->getLongValue (PROP_HCUR_ALLOCS, i);
350 hrtime_t packetTimestamp = heapPkts->getLongValue (PROP_TSTAMP, i);
351 hrtime_t timestamp = packetTimestamp - exp->getStartTime () +
352 exp->getRelativeStartTime ();
354 switch (heapType)
356 case MMAP_TRACE:
357 case MALLOC_TRACE:
358 case REALLOC_TRACE:
359 if (stackId != 0)
361 hData = hDataCalStkMap->get (stackId);
362 if (hData == NULL)
364 char *stkName = dbe_sprintf (GTXT ("Stack 0x%llx"),
365 (unsigned long long) stackId);
366 hData = new HeapData (stkName);
367 hDataCalStkMap->put (stackId, hData);
368 hData->id = (int64_t) stackId;
369 hData->setStackId (stackIndex);
370 stackIndex++;
371 hData->setHistType (type);
374 else
375 continue;
377 hData->addAllocEvent (nByte);
378 hDataTotal->addAllocEvent (nByte);
379 hDataTotal->setAllocStat (nByte);
380 hDataTotal->setPeakMemUsage (heapSize, hData->getStackId (),
381 timestamp, pid, userExpId);
382 if (leaked > 0)
384 hData->addLeakEvent (leaked);
385 hDataTotal->addLeakEvent (leaked);
386 hDataTotal->setLeakStat (leaked);
388 break;
389 case MUNMAP_TRACE:
390 case FREE_TRACE:
391 if (hData == NULL)
392 hData = new HeapData (TOTAL_HEAPNAME);
393 hDataTotal->setPeakMemUsage (heapSize, hData->getStackId (),
394 timestamp, pid, userExpId);
395 break;
396 case HEAPTYPE_LAST:
397 break;
399 has_data = true;
403 if (has_data)
405 hDataObjsCallStack = hDataCalStkMap->values ()->copy ();
406 hasCallStack = true;