1/* Copyright (C) 2021-2024 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 "FileData.h"
24#include "StringBuilder.h"
25#include "i18n.h"
26#include "util.h"
27#include "IOActivity.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
35IOActivity::IOActivity (DbeView *_dbev)
36{
37  dbev = _dbev;
38  fDataHash = NULL;
39  fDataTotal = NULL;
40  fDataObjs = NULL;
41  fDataObjsFile = NULL;
42  hasFile = false;
43  fDataObjsVfd = NULL;
44  hasVfd = false;
45  fDataObjsCallStack = NULL;
46  hasCallStack = false;
47  fDataCalStkMap = NULL;
48  fDataVfdMap = NULL;
49  hist_data_file_all = NULL;
50  hist_data_vfd_all = NULL;
51  hist_data_callstack_all = NULL;
52}
53
54void
55IOActivity::reset ()
56{
57  int numExps = dbeSession->nexps ();
58  FileData *fData = NULL;
59  DefaultMap<int64_t, FileData*>* fDataMap;
60  for (int k = 0; k < numExps; k++)
61    {
62      Experiment *exp = dbeSession->get_exp (k);
63      fDataMap = exp->getFDataMap ();
64      if (fDataMap == NULL)
65	continue;
66
67      fDataObjs = fDataMap->values ();
68      if (fDataObjs == NULL)
69	continue;
70      int numFiles = fDataObjs->size ();
71      for (int j = 0; j < numFiles; j++)
72	{
73	  fData = fDataObjs->fetch (j);
74	  fData->init ();
75	}
76    }
77
78  delete fDataHash;
79  fDataHash = NULL;
80  delete fDataTotal;
81  fDataTotal = NULL;
82
83  delete fDataObjsFile;
84  fDataObjsFile = NULL;
85  hasFile = false;
86
87  delete fDataObjsVfd;
88  fDataObjsVfd = NULL;
89  hasVfd = false;
90
91  delete fDataObjsCallStack;
92  fDataObjsCallStack = NULL;
93  hasCallStack = false;
94
95  delete fDataObjs;
96  fDataObjs = NULL;
97  delete fDataCalStkMap;
98  fDataCalStkMap = NULL;
99  delete fDataVfdMap;
100  fDataVfdMap = NULL;
101
102  // These three pointers are deleted by DbeView
103  // They are named iofile_data, iovfd_data, and iocs_data
104  hist_data_file_all = NULL;
105  hist_data_vfd_all = NULL;
106  hist_data_callstack_all = NULL;
107}
108
109void
110IOActivity::createHistItemTotals (Hist_data *hist_data, MetricList *mlist,
111				  Histable::Type hType, bool empty)
112{
113  int mIndex;
114  Metric *mtr;
115  Hist_data::HistItem *hi;
116  FileData *fData = NULL;
117
118  if (fDataTotal == NULL)
119    {
120      fDataTotal = new FileData (TOTAL_FILENAME);
121      fDataTotal->setHistType (hType);
122      fDataTotal->setVirtualFd (VIRTUAL_FD_TOTAL);
123      fDataTotal->id = 0;
124    }
125
126  fData = new FileData (fDataTotal);
127  fData->setHistType (hType);
128  hi = hist_data->append_hist_item (fData);
129  Vec_loop (Metric *, mlist->get_items (), mIndex, mtr)
130  {
131    if (!mtr->is_visible () && !mtr->is_tvisible () && !mtr->is_pvisible ())
132      continue;
133
134    Metric::Type mtype = mtr->get_type ();
135    ValueTag vType = mtr->get_vtype ();
136    hist_data->total->value[mIndex].tag = vType;
137    hi->value[mIndex].tag = vType;
138    double prec = (double) NANOSEC;
139    switch (mtype)
140      {
141      case BaseMetric::IO_READ_BYTES:
142	if (!empty)
143	  {
144	    hist_data->total->value[mIndex].ll = fDataTotal->getReadBytes ();
145	    hi->value[mIndex].ll = fDataTotal->getReadBytes ();
146	  }
147	else
148	  {
149	    hist_data->total->value[mIndex].ll = 0;
150	    hi->value[mIndex].ll = 0;
151	  }
152	break;
153      case BaseMetric::IO_READ_CNT:
154	if (!empty)
155	  {
156	    hist_data->total->value[mIndex].ll = fDataTotal->getReadCnt ();
157	    hi->value[mIndex].ll = fDataTotal->getReadCnt ();
158	  }
159	else
160	  {
161	    hist_data->total->value[mIndex].ll = 0;
162	    hi->value[mIndex].ll = 0;
163	  }
164	break;
165      case BaseMetric::IO_READ_TIME:
166	if (!empty)
167	  {
168	    hist_data->total->value[mIndex].d =
169		    (double) fDataTotal->getReadTime () / prec;
170	    hi->value[mIndex].d = hist_data->total->value[mIndex].d;
171	  }
172	else
173	  {
174	    hist_data->total->value[mIndex].d = 0.0;
175	    hi->value[mIndex].d = 0.0;
176	  }
177	break;
178      case BaseMetric::IO_WRITE_BYTES:
179	if (!empty)
180	  {
181	    hist_data->total->value[mIndex].ll = fDataTotal->getWriteBytes ();
182	    hi->value[mIndex].ll = fDataTotal->getWriteBytes ();
183	  }
184	else
185	  {
186	    hist_data->total->value[mIndex].ll = 0;
187	    hi->value[mIndex].ll = 0;
188	  }
189	break;
190      case BaseMetric::IO_WRITE_CNT:
191	if (!empty)
192	  {
193	    hist_data->total->value[mIndex].ll = fDataTotal->getWriteCnt ();
194	    hi->value[mIndex].ll = fDataTotal->getWriteCnt ();
195	  }
196	else
197	  {
198	    hist_data->total->value[mIndex].ll = 0;
199	    hi->value[mIndex].ll = 0;
200	  }
201	break;
202      case BaseMetric::IO_WRITE_TIME:
203	if (!empty)
204	  {
205	    hist_data->total->value[mIndex].d =
206		    (double) fDataTotal->getWriteTime () / prec;
207	    hi->value[mIndex].d = hist_data->total->value[mIndex].d;
208	  }
209	else
210	  {
211	    hist_data->total->value[mIndex].d = 0.0;
212	    hi->value[mIndex].d = 0.0;
213	  }
214	break;
215      case BaseMetric::IO_OTHER_CNT:
216	if (!empty)
217	  {
218	    hist_data->total->value[mIndex].ll = fDataTotal->getOtherCnt ();
219	    hi->value[mIndex].ll = fDataTotal->getOtherCnt ();
220	  }
221	else
222	  {
223	    hist_data->total->value[mIndex].ll = 0;
224	    hi->value[mIndex].ll = 0;
225	  }
226	break;
227      case BaseMetric::IO_OTHER_TIME:
228	if (!empty)
229	  {
230	    hist_data->total->value[mIndex].d =
231		    (double) fDataTotal->getOtherTime () / prec;
232	    hi->value[mIndex].d = hist_data->total->value[mIndex].d;
233	  }
234	else
235	  {
236	    hist_data->total->value[mIndex].d = 0.0;
237	    hi->value[mIndex].d = 0.0;
238	  }
239	break;
240      case BaseMetric::IO_ERROR_CNT:
241	if (!empty)
242	  {
243	    hist_data->total->value[mIndex].ll = fDataTotal->getErrorCnt ();
244	    hi->value[mIndex].ll = fDataTotal->getErrorCnt ();
245	  }
246	else
247	  {
248	    hist_data->total->value[mIndex].ll = 0;
249	    hi->value[mIndex].ll = 0;
250	  }
251	break;
252      case BaseMetric::IO_ERROR_TIME:
253	if (!empty)
254	  {
255	    hist_data->total->value[mIndex].d = (double) fDataTotal->getErrorTime () / prec;
256	    hi->value[mIndex].d = hist_data->total->value[mIndex].d;
257	  }
258	else
259	  {
260	    hist_data->total->value[mIndex].d = 0.0;
261	    hi->value[mIndex].d = 0.0;
262	  }
263	break;
264      default:
265	break;
266      }
267  }
268}
269
270void
271IOActivity::computeHistTotals (Hist_data *hist_data, MetricList *mlist)
272{
273  int mIndex;
274  Metric *mtr;
275  Vec_loop (Metric *, mlist->get_items (), mIndex, mtr)
276  {
277    if (!mtr->is_visible () && !mtr->is_tvisible () && !mtr->is_pvisible ())
278      continue;
279
280    Metric::Type mtype = mtr->get_type ();
281    ValueTag vType = mtr->get_vtype ();
282    hist_data->total->value[mIndex].tag = vType;
283    double prec = (double) NANOSEC;
284    switch (mtype)
285      {
286      case BaseMetric::IO_READ_BYTES:
287	hist_data->total->value[mIndex].ll = fDataTotal->getReadBytes ();
288	break;
289      case BaseMetric::IO_READ_CNT:
290	hist_data->total->value[mIndex].ll = fDataTotal->getReadCnt ();
291	break;
292      case BaseMetric::IO_READ_TIME:
293	hist_data->total->value[mIndex].d =
294		(double) fDataTotal->getReadTime () / prec;
295	break;
296      case BaseMetric::IO_WRITE_BYTES:
297	hist_data->total->value[mIndex].ll = fDataTotal->getWriteBytes ();
298	break;
299      case BaseMetric::IO_WRITE_CNT:
300	hist_data->total->value[mIndex].ll = fDataTotal->getWriteCnt ();
301	break;
302      case BaseMetric::IO_WRITE_TIME:
303	hist_data->total->value[mIndex].d =
304		(double) fDataTotal->getWriteTime () / prec;
305	break;
306      case BaseMetric::IO_OTHER_CNT:
307	hist_data->total->value[mIndex].ll = fDataTotal->getOtherCnt ();
308	break;
309      case BaseMetric::IO_OTHER_TIME:
310	hist_data->total->value[mIndex].d =
311		(double) fDataTotal->getOtherTime () / prec;
312	break;
313      case BaseMetric::IO_ERROR_CNT:
314	hist_data->total->value[mIndex].ll = fDataTotal->getErrorCnt ();
315	break;
316      case BaseMetric::IO_ERROR_TIME:
317	hist_data->total->value[mIndex].d =
318		(double) fDataTotal->getErrorTime () / prec;
319	break;
320      default:
321	break;
322      }
323  }
324}
325
326void
327IOActivity::computeHistData (Hist_data *hist_data, MetricList *mlist,
328			     Hist_data::Mode mode, Histable *selObj)
329{
330
331  Hist_data::HistItem *hi = NULL;
332  int numObjs = fDataObjs->size ();
333  int numMetrics = mlist->get_items ()->size ();
334
335  for (int i = 0; i < numObjs; i++)
336    {
337      FileData *fData = fDataObjs->fetch (i);
338      if (mode == Hist_data::ALL)
339	hi = hist_data->append_hist_item (fData);
340      else if (mode == Hist_data::SELF)
341	{
342	  if (fData->id == selObj->id)
343	    hi = hist_data->append_hist_item (fData);
344	  else
345	    continue;
346	}
347
348      for (int mIndex = 0; mIndex < numMetrics; mIndex++)
349	{
350	  Metric *mtr = mlist->get_items ()->fetch (mIndex);
351	  if (!mtr->is_visible () && !mtr->is_tvisible ()
352	      && !mtr->is_pvisible ())
353	    continue;
354
355	  Metric::Type mtype = mtr->get_type ();
356	  ValueTag vType = mtr->get_vtype ();
357	  hi->value[mIndex].tag = vType;
358
359	  double prec = (double) NANOSEC;
360	  switch (mtype)
361	    {
362	    case BaseMetric::IO_READ_BYTES:
363	      hi->value[mIndex].ll = fData->getReadBytes ();
364	      break;
365	    case BaseMetric::IO_READ_CNT:
366	      hi->value[mIndex].ll = fData->getReadCnt ();
367	      break;
368	    case BaseMetric::IO_READ_TIME:
369	      hi->value[mIndex].d = (double) fData->getReadTime () / prec;
370	      break;
371	    case BaseMetric::IO_WRITE_BYTES:
372	      hi->value[mIndex].ll = fData->getWriteBytes ();
373	      break;
374	    case BaseMetric::IO_WRITE_CNT:
375	      hi->value[mIndex].ll = fData->getWriteCnt ();
376	      break;
377	    case BaseMetric::IO_WRITE_TIME:
378	      hi->value[mIndex].d = (double) fData->getWriteTime () / prec;
379	      break;
380	    case BaseMetric::IO_OTHER_CNT:
381	      hi->value[mIndex].ll = fData->getOtherCnt ();
382	      break;
383	    case BaseMetric::IO_OTHER_TIME:
384	      hi->value[mIndex].d = (double) fData->getOtherTime () / prec;
385	      break;
386	    case BaseMetric::IO_ERROR_CNT:
387	      hi->value[mIndex].ll = fData->getErrorCnt ();
388	      break;
389	    case BaseMetric::IO_ERROR_TIME:
390	      hi->value[mIndex].d = (double) fData->getErrorTime () / prec;
391	      break;
392	    default:
393	      break;
394	    }
395	}
396    }
397}
398
399Hist_data *
400IOActivity::compute_metrics (MetricList *mlist, Histable::Type type,
401			     Hist_data::Mode mode, Histable *selObj)
402{
403
404  // it's already there, just return it
405  if (mode == Hist_data::ALL)
406    {
407      if (type == Histable::IOACTFILE && hist_data_file_all)
408	return hist_data_file_all;
409      else if (type == Histable::IOACTVFD && hist_data_vfd_all)
410	return hist_data_vfd_all;
411      else if (type == Histable::IOCALLSTACK && hist_data_callstack_all)
412	return hist_data_callstack_all;
413    }
414
415  bool has_data = false;
416  Hist_data *hist_data = NULL;
417  VMode viewMode = dbev->get_view_mode ();
418
419  switch (type)
420    {
421    case Histable::IOACTVFD:
422      if (!hasVfd)
423	computeData (type);
424
425      // computeData() creates fDataObjsVfd
426      // fDataObjsVfd contains the list of vfd objects
427      if (fDataObjsVfd != NULL)
428	{
429	  // fDataObjs is used in other methods
430	  fDataObjs = fDataObjsVfd;
431	  has_data = true;
432	}
433      else
434	has_data = false;
435
436      if (has_data && mode == Hist_data::ALL && hist_data_vfd_all == NULL)
437	{
438	  hist_data_vfd_all = new Hist_data (mlist, type, mode, true);
439	  hist_data = hist_data_vfd_all;
440	}
441      else if (has_data)
442	hist_data = new Hist_data (mlist, type, mode, false);
443      else
444	{
445	  hist_data = new Hist_data (mlist, type, mode, false);
446	  createHistItemTotals (hist_data, mlist, type, true);
447	  return hist_data;
448	}
449      break;
450    case Histable::IOACTFILE:
451      if (!hasFile)
452	computeData (type);
453
454      // computeData() creates fDataObjsFile
455      // fDataObjsFile contains the list of file objects
456      if (fDataObjsFile != NULL)
457	{
458	  fDataObjs = fDataObjsFile;
459	  has_data = true;
460	}
461      else
462	has_data = false;
463
464      if (has_data && mode == Hist_data::ALL && hist_data_file_all == NULL)
465	{
466	  hist_data_file_all = new Hist_data (mlist, type, mode, true);
467	  hist_data = hist_data_file_all;
468	}
469      else if (has_data)
470	hist_data = new Hist_data (mlist, type, mode, false);
471      else
472	{
473	  hist_data = new Hist_data (mlist, type, mode, false);
474	  createHistItemTotals (hist_data, mlist, type, true);
475	  return hist_data;
476	}
477      break;
478    case Histable::IOCALLSTACK:
479      if (!hasCallStack)
480	computeCallStack (type, viewMode);
481
482      // computeCallStack() creates fDataObjsCallStack
483      // fDataObjsCallStack contains the list of call stack objects
484      if (fDataObjsCallStack != NULL)
485	{
486	  fDataObjs = fDataObjsCallStack;
487	  has_data = true;
488	}
489      else
490	has_data = false;
491
492      if (has_data && (mode == Hist_data::ALL) && (hist_data_callstack_all == NULL))
493	{
494	  hist_data_callstack_all = new Hist_data (mlist, type, mode, true);
495	  hist_data = hist_data_callstack_all;
496	}
497      else if (has_data)
498	hist_data = new Hist_data (mlist, type, mode, false);
499      else
500	{
501	  hist_data = new Hist_data (mlist, type, mode, false);
502	  createHistItemTotals (hist_data, mlist, type, true);
503	  return hist_data;
504	}
505      break;
506    default:
507      fprintf (stderr,
508	    "IOActivity cannot process data due to wrong Histable (type=%d) \n",
509	       type);
510      abort ();
511    }
512
513  if (mode == Hist_data::ALL || (mode == Hist_data::SELF && selObj->id == 0))
514    createHistItemTotals (hist_data, mlist, type, false);
515  else
516    computeHistTotals (hist_data, mlist);
517  computeHistData (hist_data, mlist, mode, selObj);
518
519  // Determine by which metric to sort if any
520  bool rev_sort = mlist->get_sort_rev ();
521  int sort_ind = -1;
522  int nmetrics = mlist->get_items ()->size ();
523  for (int mind = 0; mind < nmetrics; mind++)
524    if (mlist->get_sort_ref_index () == mind)
525      sort_ind = mind;
526
527  hist_data->sort (sort_ind, rev_sort);
528  hist_data->compute_minmax ();
529  return hist_data;
530}
531
532void
533IOActivity::computeData (Histable::Type type)
534{
535  bool has_iodata = false;
536  reset ();
537  int64_t histableId = 0; // It is used by fDataAggr only
538  // fData uses vfd for histable id
539
540  fDataHash = new HashMap<char*, FileData*>;
541  FileData *fData = NULL;
542  FileData *fDataAggr = NULL;
543
544  fDataTotal = new FileData (TOTAL_FILENAME);
545  fDataTotal->setHistType (type);
546  fDataTotal->setVirtualFd (VIRTUAL_FD_TOTAL);
547  fDataTotal->id = histableId++;
548
549  FileData *fDataStdin = new FileData (STDIN_FILENAME);
550  fDataStdin->setFileDes (STDIN_FD);
551  fDataStdin->setHistType (type);
552  fDataStdin->setFsType ("N/A");
553  fDataStdin->id = histableId++;
554
555  FileData *fDataStdout = new FileData (STDOUT_FILENAME);
556  fDataStdout->setFileDes (STDOUT_FD);
557  fDataStdout->setHistType (type);
558  fDataStdout->setFsType ("N/A");
559  fDataStdout->id = histableId++;
560
561  FileData *fDataStderr = new FileData (STDERR_FILENAME);
562  fDataStderr->setFileDes (STDERR_FD);
563  fDataStderr->setHistType (type);
564  fDataStderr->setFsType ("N/A");
565  fDataStderr->id = histableId++;
566
567  FileData *fDataOtherIO = new FileData (OTHERIO_FILENAME);
568  fDataOtherIO->setFileDes (OTHERIO_FD);
569  fDataOtherIO->setHistType (type);
570  fDataOtherIO->setFsType ("N/A");
571  fDataOtherIO->id = histableId++;
572
573  DefaultMap<int64_t, FileData*>* fDataMap;
574  fDataObjsFile = NULL;
575  fDataObjsVfd = NULL;
576
577  // get the list of io events from DbeView
578  int numExps = dbeSession->nexps ();
579
580  for (int k = 0; k < numExps; k++)
581    {
582      DataView *ioPkts = dbev->get_filtered_events (k, DATA_IOTRACE);
583      if (ioPkts == NULL || ioPkts->getSize () <= 0)
584	continue;
585      Experiment *exp = dbeSession->get_exp (k);
586      fDataMap = exp->getFDataMap ();
587      if (fDataMap == NULL)
588	continue;
589      delete fDataVfdMap;
590      fDataVfdMap = new DefaultMap<long, FileData*>;
591
592      long sz = ioPkts->getSize ();
593      for (long i = 0; i < sz; ++i)
594	{
595	  hrtime_t event_duration = ioPkts->getLongValue (PROP_EVT_TIME, i);
596	  int64_t nByte = ioPkts->getLongValue (PROP_IONBYTE, i);
597	  IOTrace_type ioType = (IOTrace_type) ioPkts->getIntValue (PROP_IOTYPE, i);
598	  int64_t vFd = ioPkts->getLongValue (PROP_IOVFD, i);
599	  if (vFd >= 0)
600	    {
601	      fData = fDataMap->get (vFd);
602	      if (fData == NULL)
603		continue;
604	    }
605	  else
606	    continue;
607
608	  if (fDataVfdMap->get (vFd) == NULL)
609	    fDataVfdMap->put (vFd, fData);
610
611	  switch (ioType)
612	    {
613	    case READ_TRACE:
614	      fData->addReadEvent (event_duration, nByte);
615	      // Set the Histable id for IOVFD
616	      fData->id = fData->getVirtualFd ();
617	      fDataTotal->addReadEvent (event_duration, nByte);
618	      fDataTotal->setReadStat (event_duration, nByte);
619	      break;
620	    case WRITE_TRACE:
621	      fData->addWriteEvent (event_duration, nByte);
622	      // Set the Histable id for IOVFD
623	      fData->id = fData->getVirtualFd ();
624	      fDataTotal->addWriteEvent (event_duration, nByte);
625	      fDataTotal->setWriteStat (event_duration, nByte);
626	      break;
627	    case OPEN_TRACE:
628	      fData->addOtherEvent (event_duration);
629	      // Set the Histable id for IOVFD
630	      fData->id = fData->getVirtualFd ();
631	      fDataTotal->addOtherEvent (event_duration);
632	      break;
633	    case CLOSE_TRACE:
634	    case OTHERIO_TRACE:
635	      fData->addOtherEvent (event_duration);
636	      // Set the Histable id for IOVFD
637	      fData->id = fData->getVirtualFd ();
638	      fDataTotal->addOtherEvent (event_duration);
639	      break;
640	    case READ_TRACE_ERROR:
641	    case WRITE_TRACE_ERROR:
642	    case OPEN_TRACE_ERROR:
643	    case CLOSE_TRACE_ERROR:
644	    case OTHERIO_TRACE_ERROR:
645	      fData->addErrorEvent (event_duration);
646	      // Set the Histable id for IOVFD
647	      fData->id = fData->getVirtualFd ();
648	      fDataTotal->addErrorEvent (event_duration);
649	      break;
650
651	    case IOTRACETYPE_LAST:
652	      break;
653	    }
654
655	  if (type == Histable::IOACTFILE)
656	    {
657	      fDataAggr = fDataHash->get (fData->getFileName ());
658	      if (fDataAggr == NULL)
659		{
660		  bool setInfo = false;
661		  if (vFd == VIRTUAL_FD_STDIN)
662		    fDataAggr = fDataStdin;
663		  else if (vFd == VIRTUAL_FD_STDOUT)
664		    fDataAggr = fDataStdout;
665		  else if (vFd == VIRTUAL_FD_STDERR)
666		    fDataAggr = fDataStderr;
667		  else if (vFd == VIRTUAL_FD_OTHERIO)
668		    fDataAggr = fDataOtherIO;
669		  else
670		    {
671		      fDataAggr = new FileData (fData->getFileName ());
672		      setInfo = true;
673		    }
674		  fDataHash->put (fData->getFileName (), fDataAggr);
675
676		  if (setInfo)
677		    {
678		      fDataAggr->setFsType (fData->getFsType ());
679		      fDataAggr->setHistType (type);
680		      // Set the Histable id for aggregated file name
681		      fDataAggr->id = histableId;
682		      fDataAggr->setVirtualFd (histableId);
683		      histableId++;
684		    }
685		}
686
687	      fDataAggr->setFileDesList (fData->getFileDes ());
688	      fDataAggr->setVirtualFds (fData->getVirtualFd ());
689	      switch (ioType)
690		{
691		case READ_TRACE:
692		  fDataAggr->addReadEvent (event_duration, nByte);
693		  break;
694		case WRITE_TRACE:
695		  fDataAggr->addWriteEvent (event_duration, nByte);
696		  break;
697		case OPEN_TRACE:
698		  fDataAggr->addOtherEvent (event_duration);
699		  break;
700		case CLOSE_TRACE:
701		case OTHERIO_TRACE:
702		  fDataAggr->addOtherEvent (event_duration);
703		  break;
704		case READ_TRACE_ERROR:
705		case WRITE_TRACE_ERROR:
706		case OPEN_TRACE_ERROR:
707		case CLOSE_TRACE_ERROR:
708		case OTHERIO_TRACE_ERROR:
709		  fDataAggr->addErrorEvent (event_duration);
710		  break;
711		case IOTRACETYPE_LAST:
712		  break;
713		}
714	    }
715	  has_iodata = true;
716	}
717      if (sz > 0)
718	{
719	  if (fDataObjsVfd == NULL)
720	    fDataObjsVfd = new Vector<FileData*>;
721	  fDataObjsVfd->addAll (fDataVfdMap->values ());
722	  hasVfd = true;
723	}
724    }
725  if (has_iodata && type == Histable::IOACTFILE)
726    {
727      fDataObjsFile = fDataHash->values ()->copy ();
728      hasFile = true;
729    }
730}
731
732void
733IOActivity::computeCallStack (Histable::Type type, VMode viewMode)
734{
735  bool has_data = false;
736  int64_t stackIndex = 0;
737  FileData *fData = NULL;
738  delete fDataCalStkMap;
739  fDataCalStkMap = new DefaultMap<void*, FileData*>;
740  delete fDataTotal;
741  fDataTotal = new FileData (TOTAL_FILENAME);
742  fDataTotal->setHistType (type);
743
744  // There is no call stack for total, use the index for id
745  fDataTotal->id = stackIndex++;
746
747  // get the list of io events from DbeView
748  int numExps = dbeSession->nexps ();
749  for (int k = 0; k < numExps; k++)
750    {
751      DataView *ioPkts = dbev->get_filtered_events (k, DATA_IOTRACE);
752      if (ioPkts == NULL || ioPkts->getSize () <= 0)
753	continue;
754      long sz = ioPkts->getSize ();
755      for (long i = 0; i < sz; ++i)
756	{
757	  hrtime_t event_duration = ioPkts->getLongValue (PROP_EVT_TIME, i);
758	  int64_t nByte = ioPkts->getLongValue (PROP_IONBYTE, i);
759	  void *stackId = getStack (viewMode, ioPkts, i);
760	  IOTrace_type ioType =
761		  (IOTrace_type) ioPkts->getIntValue (PROP_IOTYPE, i);
762	  int64_t vFd = ioPkts->getLongValue (PROP_IOVFD, i);
763
764	  if (stackId != NULL && vFd > 0)
765	    {
766	      fData = fDataCalStkMap->get (stackId);
767	      if (fData == NULL)
768		{
769		  char *stkName = dbe_sprintf (GTXT ("Stack 0x%llx"),
770					       (unsigned long long) stackId);
771		  fData = new FileData (stkName);
772		  fDataCalStkMap->put (stackId, fData);
773		  fData->id = (int64_t) stackId;
774		  fData->setVirtualFd (stackIndex);
775		  stackIndex++;
776		  fData->setHistType (type);
777		}
778	    }
779	  else
780	    continue;
781
782	  switch (ioType)
783	    {
784	    case READ_TRACE:
785	      fData->addReadEvent (event_duration, nByte);
786	      fDataTotal->addReadEvent (event_duration, nByte);
787	      fDataTotal->setReadStat (event_duration, nByte);
788	      break;
789	    case WRITE_TRACE:
790	      fData->addWriteEvent (event_duration, nByte);
791	      fDataTotal->addWriteEvent (event_duration, nByte);
792	      fDataTotal->setWriteStat (event_duration, nByte);
793	      break;
794	    case OPEN_TRACE:
795	      fData->addOtherEvent (event_duration);
796	      fDataTotal->addOtherEvent (event_duration);
797	      break;
798	    case CLOSE_TRACE:
799	    case OTHERIO_TRACE:
800	      fData->addOtherEvent (event_duration);
801	      fDataTotal->addOtherEvent (event_duration);
802	      break;
803	    case READ_TRACE_ERROR:
804	    case WRITE_TRACE_ERROR:
805	    case OPEN_TRACE_ERROR:
806	      fData->addErrorEvent (event_duration);
807	      fDataTotal->addErrorEvent (event_duration);
808	      break;
809	    case CLOSE_TRACE_ERROR:
810	    case OTHERIO_TRACE_ERROR:
811	      fData->addErrorEvent (event_duration);
812	      fDataTotal->addErrorEvent (event_duration);
813	      break;
814	    case IOTRACETYPE_LAST:
815	      break;
816	    }
817	  has_data = true;
818	}
819    }
820  if (has_data)
821    {
822      fDataObjsCallStack = fDataCalStkMap->values ()->copy ();
823      hasCallStack = true;
824    }
825}
826