/* Copyright (C) 2021-2024 Free Software Foundation, Inc.
   Contributed by Oracle.

   This file is part of GNU Binutils.

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 3, or (at your option)
   any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, 51 Franklin Street - Fifth Floor, Boston,
   MA 02110-1301, USA.  */

#include "config.h"
#include "DbeSession.h"
#include "FileData.h"
#include "StringBuilder.h"
#include "i18n.h"
#include "util.h"
#include "IOActivity.h"
#include "MetricList.h"
#include "Application.h"
#include "Experiment.h"
#include "DbeView.h"
#include "Exp_Layout.h"
#include "i18n.h"

IOActivity::IOActivity (DbeView *_dbev)
{
  dbev = _dbev;
  fDataHash = NULL;
  fDataTotal = NULL;
  fDataObjs = NULL;
  fDataObjsFile = NULL;
  hasFile = false;
  fDataObjsVfd = NULL;
  hasVfd = false;
  fDataObjsCallStack = NULL;
  hasCallStack = false;
  fDataCalStkMap = NULL;
  fDataVfdMap = NULL;
  hist_data_file_all = NULL;
  hist_data_vfd_all = NULL;
  hist_data_callstack_all = NULL;
}

void
IOActivity::reset ()
{
  int numExps = dbeSession->nexps ();
  FileData *fData = NULL;
  DefaultMap<int64_t, FileData*>* fDataMap;
  for (int k = 0; k < numExps; k++)
    {
      Experiment *exp = dbeSession->get_exp (k);
      fDataMap = exp->getFDataMap ();
      if (fDataMap == NULL)
	continue;

      fDataObjs = fDataMap->values ();
      if (fDataObjs == NULL)
	continue;
      int numFiles = fDataObjs->size ();
      for (int j = 0; j < numFiles; j++)
	{
	  fData = fDataObjs->fetch (j);
	  fData->init ();
	}
    }

  delete fDataHash;
  fDataHash = NULL;
  delete fDataTotal;
  fDataTotal = NULL;

  delete fDataObjsFile;
  fDataObjsFile = NULL;
  hasFile = false;

  delete fDataObjsVfd;
  fDataObjsVfd = NULL;
  hasVfd = false;

  delete fDataObjsCallStack;
  fDataObjsCallStack = NULL;
  hasCallStack = false;

  delete fDataObjs;
  fDataObjs = NULL;
  delete fDataCalStkMap;
  fDataCalStkMap = NULL;
  delete fDataVfdMap;
  fDataVfdMap = NULL;

  // These three pointers are deleted by DbeView
  // They are named iofile_data, iovfd_data, and iocs_data
  hist_data_file_all = NULL;
  hist_data_vfd_all = NULL;
  hist_data_callstack_all = NULL;
}

void
IOActivity::createHistItemTotals (Hist_data *hist_data, MetricList *mlist,
				  Histable::Type hType, bool empty)
{
  int mIndex;
  Metric *mtr;
  Hist_data::HistItem *hi;
  FileData *fData = NULL;

  if (fDataTotal == NULL)
    {
      fDataTotal = new FileData (TOTAL_FILENAME);
      fDataTotal->setHistType (hType);
      fDataTotal->setVirtualFd (VIRTUAL_FD_TOTAL);
      fDataTotal->id = 0;
    }

  fData = new FileData (fDataTotal);
  fData->setHistType (hType);
  hi = hist_data->append_hist_item (fData);
  Vec_loop (Metric *, mlist->get_items (), mIndex, mtr)
  {
    if (!mtr->is_visible () && !mtr->is_tvisible () && !mtr->is_pvisible ())
      continue;

    Metric::Type mtype = mtr->get_type ();
    ValueTag vType = mtr->get_vtype ();
    hist_data->total->value[mIndex].tag = vType;
    hi->value[mIndex].tag = vType;
    double prec = (double) NANOSEC;
    switch (mtype)
      {
      case BaseMetric::IO_READ_BYTES:
	if (!empty)
	  {
	    hist_data->total->value[mIndex].ll = fDataTotal->getReadBytes ();
	    hi->value[mIndex].ll = fDataTotal->getReadBytes ();
	  }
	else
	  {
	    hist_data->total->value[mIndex].ll = 0;
	    hi->value[mIndex].ll = 0;
	  }
	break;
      case BaseMetric::IO_READ_CNT:
	if (!empty)
	  {
	    hist_data->total->value[mIndex].ll = fDataTotal->getReadCnt ();
	    hi->value[mIndex].ll = fDataTotal->getReadCnt ();
	  }
	else
	  {
	    hist_data->total->value[mIndex].ll = 0;
	    hi->value[mIndex].ll = 0;
	  }
	break;
      case BaseMetric::IO_READ_TIME:
	if (!empty)
	  {
	    hist_data->total->value[mIndex].d =
		    (double) fDataTotal->getReadTime () / prec;
	    hi->value[mIndex].d = hist_data->total->value[mIndex].d;
	  }
	else
	  {
	    hist_data->total->value[mIndex].d = 0.0;
	    hi->value[mIndex].d = 0.0;
	  }
	break;
      case BaseMetric::IO_WRITE_BYTES:
	if (!empty)
	  {
	    hist_data->total->value[mIndex].ll = fDataTotal->getWriteBytes ();
	    hi->value[mIndex].ll = fDataTotal->getWriteBytes ();
	  }
	else
	  {
	    hist_data->total->value[mIndex].ll = 0;
	    hi->value[mIndex].ll = 0;
	  }
	break;
      case BaseMetric::IO_WRITE_CNT:
	if (!empty)
	  {
	    hist_data->total->value[mIndex].ll = fDataTotal->getWriteCnt ();
	    hi->value[mIndex].ll = fDataTotal->getWriteCnt ();
	  }
	else
	  {
	    hist_data->total->value[mIndex].ll = 0;
	    hi->value[mIndex].ll = 0;
	  }
	break;
      case BaseMetric::IO_WRITE_TIME:
	if (!empty)
	  {
	    hist_data->total->value[mIndex].d =
		    (double) fDataTotal->getWriteTime () / prec;
	    hi->value[mIndex].d = hist_data->total->value[mIndex].d;
	  }
	else
	  {
	    hist_data->total->value[mIndex].d = 0.0;
	    hi->value[mIndex].d = 0.0;
	  }
	break;
      case BaseMetric::IO_OTHER_CNT:
	if (!empty)
	  {
	    hist_data->total->value[mIndex].ll = fDataTotal->getOtherCnt ();
	    hi->value[mIndex].ll = fDataTotal->getOtherCnt ();
	  }
	else
	  {
	    hist_data->total->value[mIndex].ll = 0;
	    hi->value[mIndex].ll = 0;
	  }
	break;
      case BaseMetric::IO_OTHER_TIME:
	if (!empty)
	  {
	    hist_data->total->value[mIndex].d =
		    (double) fDataTotal->getOtherTime () / prec;
	    hi->value[mIndex].d = hist_data->total->value[mIndex].d;
	  }
	else
	  {
	    hist_data->total->value[mIndex].d = 0.0;
	    hi->value[mIndex].d = 0.0;
	  }
	break;
      case BaseMetric::IO_ERROR_CNT:
	if (!empty)
	  {
	    hist_data->total->value[mIndex].ll = fDataTotal->getErrorCnt ();
	    hi->value[mIndex].ll = fDataTotal->getErrorCnt ();
	  }
	else
	  {
	    hist_data->total->value[mIndex].ll = 0;
	    hi->value[mIndex].ll = 0;
	  }
	break;
      case BaseMetric::IO_ERROR_TIME:
	if (!empty)
	  {
	    hist_data->total->value[mIndex].d = (double) fDataTotal->getErrorTime () / prec;
	    hi->value[mIndex].d = hist_data->total->value[mIndex].d;
	  }
	else
	  {
	    hist_data->total->value[mIndex].d = 0.0;
	    hi->value[mIndex].d = 0.0;
	  }
	break;
      default:
	break;
      }
  }
}

void
IOActivity::computeHistTotals (Hist_data *hist_data, MetricList *mlist)
{
  int mIndex;
  Metric *mtr;
  Vec_loop (Metric *, mlist->get_items (), mIndex, mtr)
  {
    if (!mtr->is_visible () && !mtr->is_tvisible () && !mtr->is_pvisible ())
      continue;

    Metric::Type mtype = mtr->get_type ();
    ValueTag vType = mtr->get_vtype ();
    hist_data->total->value[mIndex].tag = vType;
    double prec = (double) NANOSEC;
    switch (mtype)
      {
      case BaseMetric::IO_READ_BYTES:
	hist_data->total->value[mIndex].ll = fDataTotal->getReadBytes ();
	break;
      case BaseMetric::IO_READ_CNT:
	hist_data->total->value[mIndex].ll = fDataTotal->getReadCnt ();
	break;
      case BaseMetric::IO_READ_TIME:
	hist_data->total->value[mIndex].d =
		(double) fDataTotal->getReadTime () / prec;
	break;
      case BaseMetric::IO_WRITE_BYTES:
	hist_data->total->value[mIndex].ll = fDataTotal->getWriteBytes ();
	break;
      case BaseMetric::IO_WRITE_CNT:
	hist_data->total->value[mIndex].ll = fDataTotal->getWriteCnt ();
	break;
      case BaseMetric::IO_WRITE_TIME:
	hist_data->total->value[mIndex].d =
		(double) fDataTotal->getWriteTime () / prec;
	break;
      case BaseMetric::IO_OTHER_CNT:
	hist_data->total->value[mIndex].ll = fDataTotal->getOtherCnt ();
	break;
      case BaseMetric::IO_OTHER_TIME:
	hist_data->total->value[mIndex].d =
		(double) fDataTotal->getOtherTime () / prec;
	break;
      case BaseMetric::IO_ERROR_CNT:
	hist_data->total->value[mIndex].ll = fDataTotal->getErrorCnt ();
	break;
      case BaseMetric::IO_ERROR_TIME:
	hist_data->total->value[mIndex].d =
		(double) fDataTotal->getErrorTime () / prec;
	break;
      default:
	break;
      }
  }
}

void
IOActivity::computeHistData (Hist_data *hist_data, MetricList *mlist,
			     Hist_data::Mode mode, Histable *selObj)
{

  Hist_data::HistItem *hi = NULL;
  int numObjs = fDataObjs->size ();
  int numMetrics = mlist->get_items ()->size ();

  for (int i = 0; i < numObjs; i++)
    {
      FileData *fData = fDataObjs->fetch (i);
      if (mode == Hist_data::ALL)
	hi = hist_data->append_hist_item (fData);
      else if (mode == Hist_data::SELF)
	{
	  if (fData->id == selObj->id)
	    hi = hist_data->append_hist_item (fData);
	  else
	    continue;
	}

      for (int mIndex = 0; mIndex < numMetrics; mIndex++)
	{
	  Metric *mtr = mlist->get_items ()->fetch (mIndex);
	  if (!mtr->is_visible () && !mtr->is_tvisible ()
	      && !mtr->is_pvisible ())
	    continue;

	  Metric::Type mtype = mtr->get_type ();
	  ValueTag vType = mtr->get_vtype ();
	  hi->value[mIndex].tag = vType;

	  double prec = (double) NANOSEC;
	  switch (mtype)
	    {
	    case BaseMetric::IO_READ_BYTES:
	      hi->value[mIndex].ll = fData->getReadBytes ();
	      break;
	    case BaseMetric::IO_READ_CNT:
	      hi->value[mIndex].ll = fData->getReadCnt ();
	      break;
	    case BaseMetric::IO_READ_TIME:
	      hi->value[mIndex].d = (double) fData->getReadTime () / prec;
	      break;
	    case BaseMetric::IO_WRITE_BYTES:
	      hi->value[mIndex].ll = fData->getWriteBytes ();
	      break;
	    case BaseMetric::IO_WRITE_CNT:
	      hi->value[mIndex].ll = fData->getWriteCnt ();
	      break;
	    case BaseMetric::IO_WRITE_TIME:
	      hi->value[mIndex].d = (double) fData->getWriteTime () / prec;
	      break;
	    case BaseMetric::IO_OTHER_CNT:
	      hi->value[mIndex].ll = fData->getOtherCnt ();
	      break;
	    case BaseMetric::IO_OTHER_TIME:
	      hi->value[mIndex].d = (double) fData->getOtherTime () / prec;
	      break;
	    case BaseMetric::IO_ERROR_CNT:
	      hi->value[mIndex].ll = fData->getErrorCnt ();
	      break;
	    case BaseMetric::IO_ERROR_TIME:
	      hi->value[mIndex].d = (double) fData->getErrorTime () / prec;
	      break;
	    default:
	      break;
	    }
	}
    }
}

Hist_data *
IOActivity::compute_metrics (MetricList *mlist, Histable::Type type,
			     Hist_data::Mode mode, Histable *selObj)
{

  // it's already there, just return it
  if (mode == Hist_data::ALL)
    {
      if (type == Histable::IOACTFILE && hist_data_file_all)
	return hist_data_file_all;
      else if (type == Histable::IOACTVFD && hist_data_vfd_all)
	return hist_data_vfd_all;
      else if (type == Histable::IOCALLSTACK && hist_data_callstack_all)
	return hist_data_callstack_all;
    }

  bool has_data = false;
  Hist_data *hist_data = NULL;
  VMode viewMode = dbev->get_view_mode ();

  switch (type)
    {
    case Histable::IOACTVFD:
      if (!hasVfd)
	computeData (type);

      // computeData() creates fDataObjsVfd
      // fDataObjsVfd contains the list of vfd objects
      if (fDataObjsVfd != NULL)
	{
	  // fDataObjs is used in other methods
	  fDataObjs = fDataObjsVfd;
	  has_data = true;
	}
      else
	has_data = false;

      if (has_data && mode == Hist_data::ALL && hist_data_vfd_all == NULL)
	{
	  hist_data_vfd_all = new Hist_data (mlist, type, mode, true);
	  hist_data = hist_data_vfd_all;
	}
      else if (has_data)
	hist_data = new Hist_data (mlist, type, mode, false);
      else
	{
	  hist_data = new Hist_data (mlist, type, mode, false);
	  createHistItemTotals (hist_data, mlist, type, true);
	  return hist_data;
	}
      break;
    case Histable::IOACTFILE:
      if (!hasFile)
	computeData (type);

      // computeData() creates fDataObjsFile
      // fDataObjsFile contains the list of file objects
      if (fDataObjsFile != NULL)
	{
	  fDataObjs = fDataObjsFile;
	  has_data = true;
	}
      else
	has_data = false;

      if (has_data && mode == Hist_data::ALL && hist_data_file_all == NULL)
	{
	  hist_data_file_all = new Hist_data (mlist, type, mode, true);
	  hist_data = hist_data_file_all;
	}
      else if (has_data)
	hist_data = new Hist_data (mlist, type, mode, false);
      else
	{
	  hist_data = new Hist_data (mlist, type, mode, false);
	  createHistItemTotals (hist_data, mlist, type, true);
	  return hist_data;
	}
      break;
    case Histable::IOCALLSTACK:
      if (!hasCallStack)
	computeCallStack (type, viewMode);

      // computeCallStack() creates fDataObjsCallStack
      // fDataObjsCallStack contains the list of call stack objects
      if (fDataObjsCallStack != NULL)
	{
	  fDataObjs = fDataObjsCallStack;
	  has_data = true;
	}
      else
	has_data = false;

      if (has_data && (mode == Hist_data::ALL) && (hist_data_callstack_all == NULL))
	{
	  hist_data_callstack_all = new Hist_data (mlist, type, mode, true);
	  hist_data = hist_data_callstack_all;
	}
      else if (has_data)
	hist_data = new Hist_data (mlist, type, mode, false);
      else
	{
	  hist_data = new Hist_data (mlist, type, mode, false);
	  createHistItemTotals (hist_data, mlist, type, true);
	  return hist_data;
	}
      break;
    default:
      fprintf (stderr,
	    "IOActivity cannot process data due to wrong Histable (type=%d) \n",
	       type);
      abort ();
    }

  if (mode == Hist_data::ALL || (mode == Hist_data::SELF && selObj->id == 0))
    createHistItemTotals (hist_data, mlist, type, false);
  else
    computeHistTotals (hist_data, mlist);
  computeHistData (hist_data, mlist, mode, selObj);

  // Determine by which metric to sort if any
  bool rev_sort = mlist->get_sort_rev ();
  int sort_ind = -1;
  int nmetrics = mlist->get_items ()->size ();
  for (int mind = 0; mind < nmetrics; mind++)
    if (mlist->get_sort_ref_index () == mind)
      sort_ind = mind;

  hist_data->sort (sort_ind, rev_sort);
  hist_data->compute_minmax ();
  return hist_data;
}

void
IOActivity::computeData (Histable::Type type)
{
  bool has_iodata = false;
  reset ();
  int64_t histableId = 0; // It is used by fDataAggr only
  // fData uses vfd for histable id

  fDataHash = new HashMap<char*, FileData*>;
  FileData *fData = NULL;
  FileData *fDataAggr = NULL;

  fDataTotal = new FileData (TOTAL_FILENAME);
  fDataTotal->setHistType (type);
  fDataTotal->setVirtualFd (VIRTUAL_FD_TOTAL);
  fDataTotal->id = histableId++;

  FileData *fDataStdin = new FileData (STDIN_FILENAME);
  fDataStdin->setFileDes (STDIN_FD);
  fDataStdin->setHistType (type);
  fDataStdin->setFsType ("N/A");
  fDataStdin->id = histableId++;

  FileData *fDataStdout = new FileData (STDOUT_FILENAME);
  fDataStdout->setFileDes (STDOUT_FD);
  fDataStdout->setHistType (type);
  fDataStdout->setFsType ("N/A");
  fDataStdout->id = histableId++;

  FileData *fDataStderr = new FileData (STDERR_FILENAME);
  fDataStderr->setFileDes (STDERR_FD);
  fDataStderr->setHistType (type);
  fDataStderr->setFsType ("N/A");
  fDataStderr->id = histableId++;

  FileData *fDataOtherIO = new FileData (OTHERIO_FILENAME);
  fDataOtherIO->setFileDes (OTHERIO_FD);
  fDataOtherIO->setHistType (type);
  fDataOtherIO->setFsType ("N/A");
  fDataOtherIO->id = histableId++;

  DefaultMap<int64_t, FileData*>* fDataMap;
  fDataObjsFile = NULL;
  fDataObjsVfd = NULL;

  // get the list of io events from DbeView
  int numExps = dbeSession->nexps ();

  for (int k = 0; k < numExps; k++)
    {
      DataView *ioPkts = dbev->get_filtered_events (k, DATA_IOTRACE);
      if (ioPkts == NULL || ioPkts->getSize () <= 0)
	continue;
      Experiment *exp = dbeSession->get_exp (k);
      fDataMap = exp->getFDataMap ();
      if (fDataMap == NULL)
	continue;
      delete fDataVfdMap;
      fDataVfdMap = new DefaultMap<long, FileData*>;

      long sz = ioPkts->getSize ();
      for (long i = 0; i < sz; ++i)
	{
	  hrtime_t event_duration = ioPkts->getLongValue (PROP_EVT_TIME, i);
	  int64_t nByte = ioPkts->getLongValue (PROP_IONBYTE, i);
	  IOTrace_type ioType = (IOTrace_type) ioPkts->getIntValue (PROP_IOTYPE, i);
	  int64_t vFd = ioPkts->getLongValue (PROP_IOVFD, i);
	  if (vFd >= 0)
	    {
	      fData = fDataMap->get (vFd);
	      if (fData == NULL)
		continue;
	    }
	  else
	    continue;

	  if (fDataVfdMap->get (vFd) == NULL)
	    fDataVfdMap->put (vFd, fData);

	  switch (ioType)
	    {
	    case READ_TRACE:
	      fData->addReadEvent (event_duration, nByte);
	      // Set the Histable id for IOVFD
	      fData->id = fData->getVirtualFd ();
	      fDataTotal->addReadEvent (event_duration, nByte);
	      fDataTotal->setReadStat (event_duration, nByte);
	      break;
	    case WRITE_TRACE:
	      fData->addWriteEvent (event_duration, nByte);
	      // Set the Histable id for IOVFD
	      fData->id = fData->getVirtualFd ();
	      fDataTotal->addWriteEvent (event_duration, nByte);
	      fDataTotal->setWriteStat (event_duration, nByte);
	      break;
	    case OPEN_TRACE:
	      fData->addOtherEvent (event_duration);
	      // Set the Histable id for IOVFD
	      fData->id = fData->getVirtualFd ();
	      fDataTotal->addOtherEvent (event_duration);
	      break;
	    case CLOSE_TRACE:
	    case OTHERIO_TRACE:
	      fData->addOtherEvent (event_duration);
	      // Set the Histable id for IOVFD
	      fData->id = fData->getVirtualFd ();
	      fDataTotal->addOtherEvent (event_duration);
	      break;
	    case READ_TRACE_ERROR:
	    case WRITE_TRACE_ERROR:
	    case OPEN_TRACE_ERROR:
	    case CLOSE_TRACE_ERROR:
	    case OTHERIO_TRACE_ERROR:
	      fData->addErrorEvent (event_duration);
	      // Set the Histable id for IOVFD
	      fData->id = fData->getVirtualFd ();
	      fDataTotal->addErrorEvent (event_duration);
	      break;

	    case IOTRACETYPE_LAST:
	      break;
	    }

	  if (type == Histable::IOACTFILE)
	    {
	      fDataAggr = fDataHash->get (fData->getFileName ());
	      if (fDataAggr == NULL)
		{
		  bool setInfo = false;
		  if (vFd == VIRTUAL_FD_STDIN)
		    fDataAggr = fDataStdin;
		  else if (vFd == VIRTUAL_FD_STDOUT)
		    fDataAggr = fDataStdout;
		  else if (vFd == VIRTUAL_FD_STDERR)
		    fDataAggr = fDataStderr;
		  else if (vFd == VIRTUAL_FD_OTHERIO)
		    fDataAggr = fDataOtherIO;
		  else
		    {
		      fDataAggr = new FileData (fData->getFileName ());
		      setInfo = true;
		    }
		  fDataHash->put (fData->getFileName (), fDataAggr);

		  if (setInfo)
		    {
		      fDataAggr->setFsType (fData->getFsType ());
		      fDataAggr->setHistType (type);
		      // Set the Histable id for aggregated file name
		      fDataAggr->id = histableId;
		      fDataAggr->setVirtualFd (histableId);
		      histableId++;
		    }
		}

	      fDataAggr->setFileDesList (fData->getFileDes ());
	      fDataAggr->setVirtualFds (fData->getVirtualFd ());
	      switch (ioType)
		{
		case READ_TRACE:
		  fDataAggr->addReadEvent (event_duration, nByte);
		  break;
		case WRITE_TRACE:
		  fDataAggr->addWriteEvent (event_duration, nByte);
		  break;
		case OPEN_TRACE:
		  fDataAggr->addOtherEvent (event_duration);
		  break;
		case CLOSE_TRACE:
		case OTHERIO_TRACE:
		  fDataAggr->addOtherEvent (event_duration);
		  break;
		case READ_TRACE_ERROR:
		case WRITE_TRACE_ERROR:
		case OPEN_TRACE_ERROR:
		case CLOSE_TRACE_ERROR:
		case OTHERIO_TRACE_ERROR:
		  fDataAggr->addErrorEvent (event_duration);
		  break;
		case IOTRACETYPE_LAST:
		  break;
		}
	    }
	  has_iodata = true;
	}
      if (sz > 0)
	{
	  if (fDataObjsVfd == NULL)
	    fDataObjsVfd = new Vector<FileData*>;
	  fDataObjsVfd->addAll (fDataVfdMap->values ());
	  hasVfd = true;
	}
    }
  if (has_iodata && type == Histable::IOACTFILE)
    {
      fDataObjsFile = fDataHash->values ()->copy ();
      hasFile = true;
    }
}

void
IOActivity::computeCallStack (Histable::Type type, VMode viewMode)
{
  bool has_data = false;
  int64_t stackIndex = 0;
  FileData *fData = NULL;
  delete fDataCalStkMap;
  fDataCalStkMap = new DefaultMap<void*, FileData*>;
  delete fDataTotal;
  fDataTotal = new FileData (TOTAL_FILENAME);
  fDataTotal->setHistType (type);

  // There is no call stack for total, use the index for id
  fDataTotal->id = stackIndex++;

  // get the list of io events from DbeView
  int numExps = dbeSession->nexps ();
  for (int k = 0; k < numExps; k++)
    {
      DataView *ioPkts = dbev->get_filtered_events (k, DATA_IOTRACE);
      if (ioPkts == NULL || ioPkts->getSize () <= 0)
	continue;
      long sz = ioPkts->getSize ();
      for (long i = 0; i < sz; ++i)
	{
	  hrtime_t event_duration = ioPkts->getLongValue (PROP_EVT_TIME, i);
	  int64_t nByte = ioPkts->getLongValue (PROP_IONBYTE, i);
	  void *stackId = getStack (viewMode, ioPkts, i);
	  IOTrace_type ioType =
		  (IOTrace_type) ioPkts->getIntValue (PROP_IOTYPE, i);
	  int64_t vFd = ioPkts->getLongValue (PROP_IOVFD, i);

	  if (stackId != NULL && vFd > 0)
	    {
	      fData = fDataCalStkMap->get (stackId);
	      if (fData == NULL)
		{
		  char *stkName = dbe_sprintf (GTXT ("Stack 0x%llx"),
					       (unsigned long long) stackId);
		  fData = new FileData (stkName);
		  fDataCalStkMap->put (stackId, fData);
		  fData->id = (int64_t) stackId;
		  fData->setVirtualFd (stackIndex);
		  stackIndex++;
		  fData->setHistType (type);
		}
	    }
	  else
	    continue;

	  switch (ioType)
	    {
	    case READ_TRACE:
	      fData->addReadEvent (event_duration, nByte);
	      fDataTotal->addReadEvent (event_duration, nByte);
	      fDataTotal->setReadStat (event_duration, nByte);
	      break;
	    case WRITE_TRACE:
	      fData->addWriteEvent (event_duration, nByte);
	      fDataTotal->addWriteEvent (event_duration, nByte);
	      fDataTotal->setWriteStat (event_duration, nByte);
	      break;
	    case OPEN_TRACE:
	      fData->addOtherEvent (event_duration);
	      fDataTotal->addOtherEvent (event_duration);
	      break;
	    case CLOSE_TRACE:
	    case OTHERIO_TRACE:
	      fData->addOtherEvent (event_duration);
	      fDataTotal->addOtherEvent (event_duration);
	      break;
	    case READ_TRACE_ERROR:
	    case WRITE_TRACE_ERROR:
	    case OPEN_TRACE_ERROR:
	      fData->addErrorEvent (event_duration);
	      fDataTotal->addErrorEvent (event_duration);
	      break;
	    case CLOSE_TRACE_ERROR:
	    case OTHERIO_TRACE_ERROR:
	      fData->addErrorEvent (event_duration);
	      fDataTotal->addErrorEvent (event_duration);
	      break;
	    case IOTRACETYPE_LAST:
	      break;
	    }
	  has_data = true;
	}
    }
  if (has_data)
    {
      fDataObjsCallStack = fDataCalStkMap->values ()->copy ();
      hasCallStack = true;
    }
}
