]> Git Repo - binutils.git/blob - gprofng/src/HeapActivity.cc
Automatic date update in version.in
[binutils.git] / gprofng / src / HeapActivity.cc
1 /* Copyright (C) 2021 Free Software Foundation, Inc.
2    Contributed by Oracle.
3
4    This file is part of GNU Binutils.
5
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.
10
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.
15
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.  */
20
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"
34
35 HeapActivity::HeapActivity (DbeView *_dbev)
36 {
37   dbev = _dbev;
38   hDataTotal = NULL;
39   hDataObjs = NULL;
40   hDataObjsCallStack = NULL;
41   hasCallStack = false;
42   hDataCalStkMap = NULL;
43   hist_data_callstack_all = NULL;
44 }
45
46 void
47 HeapActivity::reset ()
48 {
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;
58 }
59
60 void
61 HeapActivity::createHistItemTotals (Hist_data *hist_data, MetricList *mlist,
62                                     Histable::Type hType, bool empty)
63 {
64   int mIndex;
65   Metric *mtr;
66   Hist_data::HistItem *hi;
67   HeapData *hData = NULL;
68   if (hDataTotal == NULL)
69     {
70       hDataTotal = new HeapData (TOTAL_HEAPNAME);
71       hDataTotal->setHistType (hType);
72       hDataTotal->setStackId (TOTAL_STACK_ID);
73       hDataTotal->id = 0;
74     }
75
76   hData = new HeapData (hDataTotal);
77   hData->setHistType (hType);
78   hi = hist_data->append_hist_item (hData);
79
80   Vec_loop (Metric *, mlist->get_items (), mIndex, mtr)
81   {
82     if (!mtr->is_visible () && !mtr->is_tvisible () && !mtr->is_pvisible ())
83       continue;
84
85     Metric::Type mtype = mtr->get_type ();
86     ValueTag vType = mtr->get_vtype ();
87
88     hist_data->total->value[mIndex].tag = vType;
89     hi->value[mIndex].tag = vType;
90     switch (mtype)
91       {
92       case BaseMetric::HEAP_ALLOC_BYTES:
93         if (!empty)
94           {
95             hist_data->total->value[mIndex].ll = hDataTotal->getAllocBytes ();
96             hi->value[mIndex].ll = hDataTotal->getAllocBytes ();
97           }
98         else
99           {
100             hist_data->total->value[mIndex].ll = 0;
101             hi->value[mIndex].ll = 0;
102           }
103         break;
104       case BaseMetric::HEAP_ALLOC_CNT:
105         if (!empty)
106           {
107             hist_data->total->value[mIndex].ll = hDataTotal->getAllocCnt ();
108             hi->value[mIndex].ll = hDataTotal->getAllocCnt ();
109           }
110         else
111           {
112             hist_data->total->value[mIndex].ll = 0;
113             hi->value[mIndex].ll = 0;
114           }
115         break;
116       case BaseMetric::HEAP_LEAK_BYTES:
117         if (!empty)
118           {
119             hist_data->total->value[mIndex].ll = hDataTotal->getLeakBytes ();
120             hi->value[mIndex].ll = hDataTotal->getLeakBytes ();
121           }
122         else
123           {
124             hist_data->total->value[mIndex].ll = 0;
125             hi->value[mIndex].ll = 0;
126           }
127         break;
128       case BaseMetric::HEAP_LEAK_CNT:
129         if (!empty)
130           {
131             hist_data->total->value[mIndex].ll = hDataTotal->getLeakCnt ();
132             hi->value[mIndex].ll = hDataTotal->getLeakCnt ();
133           }
134         else
135           {
136             hist_data->total->value[mIndex].ll = 0;
137             hi->value[mIndex].ll = 0;
138           }
139         break;
140       default:
141         break;
142       }
143   }
144 }
145
146 void
147 HeapActivity::computeHistTotals (Hist_data *hist_data, MetricList *mlist)
148 {
149   int mIndex;
150   Metric *mtr;
151   Vec_loop (Metric *, mlist->get_items (), mIndex, mtr)
152   {
153     if (!mtr->is_visible () && !mtr->is_tvisible () && !mtr->is_pvisible ())
154       continue;
155
156     Metric::Type mtype = mtr->get_type ();
157     ValueTag vType = mtr->get_vtype ();
158
159     hist_data->total->value[mIndex].tag = vType;
160     switch (mtype)
161       {
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;
176       }
177   }
178 }
179
180 void
181 HeapActivity::computeHistData (Hist_data *hist_data, MetricList *mlist,
182                                Hist_data::Mode mode, Histable *selObj)
183 {
184
185   Hist_data::HistItem *hi = NULL;
186
187   int numObjs = hDataObjs->size ();
188   int numMetrics = mlist->get_items ()->size ();
189   for (int i = 0; i < numObjs; i++)
190     {
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)
195         {
196           if (hData->id == selObj->id)
197             hi = hist_data->append_hist_item (hData);
198           else
199             continue;
200         }
201
202       for (int mIndex = 0; mIndex < numMetrics; mIndex++)
203         {
204           Metric *mtr = mlist->get_items ()->fetch (mIndex);
205           if (!mtr->is_visible () && !mtr->is_tvisible ()
206               && !mtr->is_pvisible ())
207             continue;
208
209           Metric::Type mtype = mtr->get_type ();
210           ValueTag vType = mtr->get_vtype ();
211           hi->value[mIndex].tag = vType;
212           switch (mtype)
213             {
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;
228             }
229         }
230     }
231 }
232
233 Hist_data *
234 HeapActivity::compute_metrics (MetricList *mlist, Histable::Type type,
235                                Hist_data::Mode mode, Histable *selObj)
236 {
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;
241
242   bool has_data = false;
243   Hist_data *hist_data = NULL;
244   VMode viewMode = dbev->get_view_mode ();
245   switch (type)
246     {
247     case Histable::HEAPCALLSTACK:
248       if (!hasCallStack)    // It is not computed yet
249         computeCallStack (type, viewMode);
250
251       // computeCallStack() creates hDataObjsCallStack
252       // hDataObjsCallStack contains the list of call stack objects
253       if (hDataObjsCallStack != NULL)
254         {
255           hDataObjs = hDataObjsCallStack;
256           has_data = true;
257         }
258       else
259         has_data = false;
260
261       if (has_data && mode == Hist_data::ALL && hist_data_callstack_all == NULL)
262         {
263           hist_data_callstack_all = new Hist_data (mlist, type, mode, true);
264           hist_data = hist_data_callstack_all;
265         }
266       else if (has_data)
267         hist_data = new Hist_data (mlist, type, mode, false);
268       else
269         {
270           hist_data = new Hist_data (mlist, type, mode, false);
271           createHistItemTotals (hist_data, mlist, type, true);
272           return hist_data;
273         }
274       break;
275     default:
276       fprintf (stderr,
277                "HeapActivity cannot process data due to wrong Histable (type=%d) \n",
278                type);
279       abort ();
280     }
281
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);
287
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 ();
292
293   for (int mind = 0; mind < nmetrics; mind++)
294     if (mlist->get_sort_ref_index () == mind)
295       sort_ind = mind;
296
297   hist_data->sort (sort_ind, rev_sort);
298   hist_data->compute_minmax ();
299
300   return hist_data;
301 }
302
303 void
304 HeapActivity::computeCallStack (Histable::Type type, VMode viewMode)
305 {
306   bool has_data = false;
307   reset ();
308   uint64_t stackIndex = 0;
309   HeapData *hData = NULL;
310
311   delete hDataCalStkMap;
312   hDataCalStkMap = new DefaultMap<uint64_t, HeapData*>;
313
314   delete hDataTotal;
315   hDataTotal = new HeapData (TOTAL_HEAPNAME);
316   hDataTotal->setHistType (type);
317
318   // There is no call stack for total, use the index for id
319   hDataTotal->id = stackIndex++;
320
321   // get the list of io events from DbeView
322   int numExps = dbeSession->nexps ();
323
324   for (int k = 0; k < numExps; k++)
325     {
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);
329
330       DataView *heapPkts = dbev->get_filtered_events (k, DATA_HEAP);
331       if (heapPkts == NULL)
332         continue;
333
334       Experiment *exp = dbeSession->get_exp (k);
335       long sz = heapPkts->getSize ();
336       int pid = 0;
337       int userExpId = 0;
338       if (sz > 0)
339         {
340           pid = exp->getPID ();
341           userExpId = exp->getUserExpId ();
342         }
343       for (long i = 0; i < sz; ++i)
344         {
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 ();
353
354           switch (heapType)
355             {
356             case MMAP_TRACE:
357             case MALLOC_TRACE:
358             case REALLOC_TRACE:
359               if (stackId != 0)
360                 {
361                   hData = hDataCalStkMap->get (stackId);
362                   if (hData == NULL)
363                     {
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);
372                     }
373                 }
374               else
375                 continue;
376
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)
383                 {
384                   hData->addLeakEvent (leaked);
385                   hDataTotal->addLeakEvent (leaked);
386                   hDataTotal->setLeakStat (leaked);
387                 }
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;
398             }
399           has_data = true;
400         }
401     }
402
403   if (has_data)
404     {
405       hDataObjsCallStack = hDataCalStkMap->values ()->copy ();
406       hasCallStack = true;
407     }
408 }
This page took 0.046154 seconds and 4 git commands to generate.