1 /* Copyright (C) 2021 Free Software Foundation, Inc.
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)
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. */
22 #include "DbeSession.h"
24 #include "StringBuilder.h"
27 #include "HeapActivity.h"
28 #include "MetricList.h"
29 #include "Application.h"
30 #include "Experiment.h"
32 #include "Exp_Layout.h"
35 HeapActivity::HeapActivity (DbeView
*_dbev
)
40 hDataObjsCallStack
= NULL
;
42 hDataCalStkMap
= NULL
;
43 hist_data_callstack_all
= NULL
;
47 HeapActivity::reset ()
51 delete hDataObjsCallStack
;
52 hDataObjsCallStack
= NULL
;
55 delete hDataCalStkMap
;
56 hDataCalStkMap
= NULL
;
57 hist_data_callstack_all
= NULL
;
61 HeapActivity::createHistItemTotals (Hist_data
*hist_data
, MetricList
*mlist
,
62 Histable::Type hType
, bool empty
)
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
);
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 ())
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
;
92 case BaseMetric::HEAP_ALLOC_BYTES
:
95 hist_data
->total
->value
[mIndex
].ll
= hDataTotal
->getAllocBytes ();
96 hi
->value
[mIndex
].ll
= hDataTotal
->getAllocBytes ();
100 hist_data
->total
->value
[mIndex
].ll
= 0;
101 hi
->value
[mIndex
].ll
= 0;
104 case BaseMetric::HEAP_ALLOC_CNT
:
107 hist_data
->total
->value
[mIndex
].ll
= hDataTotal
->getAllocCnt ();
108 hi
->value
[mIndex
].ll
= hDataTotal
->getAllocCnt ();
112 hist_data
->total
->value
[mIndex
].ll
= 0;
113 hi
->value
[mIndex
].ll
= 0;
116 case BaseMetric::HEAP_LEAK_BYTES
:
119 hist_data
->total
->value
[mIndex
].ll
= hDataTotal
->getLeakBytes ();
120 hi
->value
[mIndex
].ll
= hDataTotal
->getLeakBytes ();
124 hist_data
->total
->value
[mIndex
].ll
= 0;
125 hi
->value
[mIndex
].ll
= 0;
128 case BaseMetric::HEAP_LEAK_CNT
:
131 hist_data
->total
->value
[mIndex
].ll
= hDataTotal
->getLeakCnt ();
132 hi
->value
[mIndex
].ll
= hDataTotal
->getLeakCnt ();
136 hist_data
->total
->value
[mIndex
].ll
= 0;
137 hi
->value
[mIndex
].ll
= 0;
147 HeapActivity::computeHistTotals (Hist_data
*hist_data
, MetricList
*mlist
)
151 Vec_loop (Metric
*, mlist
->get_items (), mIndex
, mtr
)
153 if (!mtr
->is_visible () && !mtr
->is_tvisible () && !mtr
->is_pvisible ())
156 Metric::Type mtype
= mtr
->get_type ();
157 ValueTag vType
= mtr
->get_vtype ();
159 hist_data
->total
->value
[mIndex
].tag
= vType
;
162 case BaseMetric::HEAP_ALLOC_BYTES
:
163 hist_data
->total
->value
[mIndex
].ll
= hDataTotal
->getAllocBytes ();
165 case BaseMetric::HEAP_ALLOC_CNT
:
166 hist_data
->total
->value
[mIndex
].ll
= hDataTotal
->getAllocCnt ();
168 case BaseMetric::HEAP_LEAK_BYTES
:
169 hist_data
->total
->value
[mIndex
].ll
= hDataTotal
->getLeakBytes ();
171 case BaseMetric::HEAP_LEAK_CNT
:
172 hist_data
->total
->value
[mIndex
].ll
= hDataTotal
->getLeakCnt ();
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
);
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 ())
209 Metric::Type mtype
= mtr
->get_type ();
210 ValueTag vType
= mtr
->get_vtype ();
211 hi
->value
[mIndex
].tag
= vType
;
214 case BaseMetric::HEAP_ALLOC_BYTES
:
215 hi
->value
[mIndex
].ll
= hData
->getAllocBytes ();
217 case BaseMetric::HEAP_ALLOC_CNT
:
218 hi
->value
[mIndex
].ll
= hData
->getAllocCnt ();
220 case BaseMetric::HEAP_LEAK_BYTES
:
221 hi
->value
[mIndex
].ll
= hData
->getLeakBytes ();
223 case BaseMetric::HEAP_LEAK_CNT
:
224 hi
->value
[mIndex
].ll
= hData
->getLeakCnt ();
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 ();
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
;
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
;
267 hist_data
= new Hist_data (mlist
, type
, mode
, false);
270 hist_data
= new Hist_data (mlist
, type
, mode
, false);
271 createHistItemTotals (hist_data
, mlist
, type
, true);
277 "HeapActivity cannot process data due to wrong Histable (type=%d) \n",
282 if (mode
== Hist_data::ALL
|| (mode
== Hist_data::SELF
&& selObj
->id
== 0))
283 createHistItemTotals (hist_data
, mlist
, type
, false);
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 ();
291 int nmetrics
= mlist
->get_items ()->size ();
293 for (int mind
= 0; mind
< nmetrics
; mind
++)
294 if (mlist
->get_sort_ref_index () == mind
)
297 hist_data
->sort (sort_ind
, rev_sort
);
298 hist_data
->compute_minmax ();
304 HeapActivity::computeCallStack (Histable::Type type
, VMode viewMode
)
306 bool has_data
= false;
308 uint64_t stackIndex
= 0;
309 HeapData
*hData
= NULL
;
311 delete hDataCalStkMap
;
312 hDataCalStkMap
= new DefaultMap
<uint64_t, HeapData
*>;
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
)
334 Experiment
*exp
= dbeSession
->get_exp (k
);
335 long sz
= heapPkts
->getSize ();
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 ();
361 hData
= hDataCalStkMap
->get (stackId
);
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
);
371 hData
->setHistType (type
);
377 hData
->addAllocEvent (nByte
);
378 hDataTotal
->addAllocEvent (nByte
);
379 hDataTotal
->setAllocStat (nByte
);
380 hDataTotal
->setPeakMemUsage (heapSize
, hData
->getStackId (),
381 timestamp
, pid
, userExpId
);
384 hData
->addLeakEvent (leaked
);
385 hDataTotal
->addLeakEvent (leaked
);
386 hDataTotal
->setLeakStat (leaked
);
392 hData
= new HeapData (TOTAL_HEAPNAME
);
393 hDataTotal
->setPeakMemUsage (heapSize
, hData
->getStackId (),
394 timestamp
, pid
, userExpId
);
405 hDataObjsCallStack
= hDataCalStkMap
->values ()->copy ();