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 <errno.h>
23#include <utime.h>
24#include <alloca.h>
25#include <dirent.h>
26#include <ctype.h>
27#include <unistd.h>
28#include <stdio.h>
29#include <stdlib.h>
30#include <sys/param.h>
31#include <set>
32
33#include "util.h"
34#include "CacheMap.h"
35#include "DbeFile.h"
36#include "DbeCacheMap.h"
37#include "DefaultHandler.h"
38#include "DefaultMap2D.h"
39#include "Emsg.h"
40#include "Elf.h"
41#include "SAXParser.h"
42#include "SAXParserFactory.h"
43#include "StringBuilder.h"
44#include "DbeSession.h"
45#include "DbeThread.h"
46#include "Application.h"
47#include "CallStack.h"
48#include "Experiment.h"
49#include "Exp_Layout.h"
50#include "DataStream.h"
51#include "Expression.h"
52#include "Function.h"
53#include "HeapMap.h"
54#include "LoadObject.h"
55#include "Module.h"
56#include "Ovw_data.h"
57#include "PRBTree.h"
58#include "Sample.h"
59#include "SegMem.h"
60#include "StringMap.h"
61#include "UserLabel.h"
62#include "Table.h"
63#include "dbe_types.h"
64#include "FileData.h"
65#include "cc_libcollector.h"
66#include "ExpGroup.h"
67
68int nPush;
69int nPop;
70int pushCnt;
71int popCnt;
72int pushCnt3;
73int popCnt3;
74
75struct Experiment::UIDnode
76{
77  uint64_t uid;
78  uint64_t val;
79  UIDnode *next;
80};
81
82struct Experiment::RawFramePacket
83{
84  uint64_t uid;
85  UIDnode *uidn;
86  UIDnode *uidj;
87  UIDnode *omp_uid;
88  uint32_t omp_state;
89};
90
91static hrtime_t
92parseTStamp (const char *s)
93{
94  hrtime_t ts = (hrtime_t) 0;
95  ts = (hrtime_t) atoi (s) * NANOSEC;
96  s = strchr (s, '.');
97  if (s != NULL)
98    ts += (hrtime_t) atoi (s + 1);
99  return ts;
100}
101
102class Experiment::ExperimentFile
103{
104public:
105
106  enum
107  {
108    EF_NOT_OPENED,
109    EF_OPENED,
110    EF_CLOSED,
111    EF_FAILURE
112  };
113
114  ExperimentFile (Experiment *_exp, const char *_fname);
115  ~ExperimentFile ();
116
117  bool open (bool new_open = false);
118
119  char *
120  get_name ()
121  {
122    return fname;
123  }
124
125  inline int
126  get_status ()
127  {
128    return ef_status;
129  }
130
131  char *fgets ();
132  void close ();
133
134  FILE *fh;
135
136private:
137  Experiment *exp;
138  char *fname;
139  off64_t offset;
140  int bufsz, ef_status;
141  char *buffer;
142};
143
144class Experiment::ExperimentHandler : public DefaultHandler
145{
146public:
147
148  ExperimentHandler (Experiment *_exp);
149  ~ExperimentHandler ();
150
151  void
152  startDocument () { }
153  void endDocument ();
154  void startElement (char *uri, char *localName, char *qName, Attributes *attrs);
155  void endElement (char *uri, char *localName, char *qName);
156  void characters (char *ch, int start, int length);
157
158  void
159  ignorableWhitespace (char*, int, int) { }
160  void
161  error (SAXParseException *e);
162
163private:
164
165  enum Element
166  {
167    EL_NONE,
168    EL_EXPERIMENT,
169    EL_COLLECTOR,
170    EL_SETTING,
171    EL_PROCESS,
172    EL_SYSTEM,
173    EL_EVENT,
174    EL_PROFILE,
175    EL_DATAPTR,
176    EL_PROFDATA,
177    EL_PROFPCKT,
178    EL_FIELD,
179    EL_CPU,
180    EL_STATE,
181    EL_FREQUENCY,
182    EL_POWERM,
183    EL_DTRACEFATAL
184  };
185
186  static int toInt (Attributes *attrs, const char *atr);
187  static char*toStr (Attributes *attrs, const char *atr);
188  void pushElem (Element);
189  void popElem ();
190
191  Experiment *exp;
192  Element curElem;
193  Vector<Element> *stack;
194  Module *dynfuncModule;
195  DataDescriptor *dDscr;
196  PacketDescriptor *pDscr;
197  PropDescr *propDscr;
198  char *text;
199  Cmsg_warn mkind;
200  int mnum;
201  int mec;
202};
203
204
205// HTableSize is the size of smemHTable and instHTable
206// omazur: both HTableSize and the hash function haven't been tuned;
207static const int HTableSize = 8192;
208
209//-------------------------------------------------- Experiment file handler
210
211Experiment::ExperimentFile::ExperimentFile (Experiment *_exp, const char *_fname)
212{
213  exp = _exp;
214  fh = NULL;
215  bufsz = 0;
216  buffer = NULL;
217  ef_status = EF_NOT_OPENED;
218  offset = 0;
219  fname = dbe_sprintf (NTXT ("%s/%s"), exp->expt_name, _fname);
220}
221
222Experiment::ExperimentFile::~ExperimentFile ()
223{
224  close ();
225  free (buffer);
226  free (fname);
227}
228
229bool
230Experiment::ExperimentFile::open (bool new_open)
231{
232  if (fh == NULL)
233    {
234      fh = fopen64 (fname, NTXT ("r"));
235      if (fh == NULL)
236	{
237	  ef_status = EF_FAILURE;
238	  return false;
239	}
240      ef_status = EF_OPENED;
241      if (new_open)
242	offset = 0;
243      if (offset != 0)
244	fseeko64 (fh, offset, SEEK_SET);
245    }
246  return true;
247}
248
249char *
250Experiment::ExperimentFile::fgets ()
251{
252  if (bufsz == 0)
253    {
254      bufsz = 1024;
255      buffer = (char *) malloc (bufsz);
256      if (buffer == NULL)
257	return NULL;
258      buffer[bufsz - 1] = (char) 1; // sentinel
259    }
260  char *res = ::fgets (buffer, bufsz, fh);
261  if (res == NULL)
262    return NULL;
263  while (buffer[bufsz - 1] == (char) 0)
264    {
265      int newsz = bufsz + 1024;
266      char *newbuf = (char *) malloc (newsz);
267      if (newbuf == NULL)
268	return NULL;
269      memcpy (newbuf, buffer, bufsz);
270      free (buffer);
271      buffer = newbuf;
272      buffer[newsz - 1] = (char) 1; // sentinel
273      // we don't care about fgets result here
274      ::fgets (buffer + bufsz - 1, newsz - bufsz + 1, fh);
275      bufsz = newsz;
276    }
277  return buffer;
278}
279
280void
281Experiment::ExperimentFile::close ()
282{
283  if (fh)
284    {
285      offset = ftello64 (fh);
286      fclose (fh);
287      ef_status = EF_CLOSED;
288      fh = NULL;
289    }
290}
291
292
293//-------------------------------------------------- Experiment XML parser
294int
295Experiment::ExperimentHandler::toInt (Attributes *attrs, const char *atr)
296{
297  const char *str = attrs->getValue (atr);
298  return str ? atoi (str) : 0;
299}
300
301char *
302Experiment::ExperimentHandler::toStr (Attributes *attrs, const char *atr)
303{
304  const char *str = attrs->getValue (atr);
305  return dbe_strdup (str ? str : NTXT (""));
306}
307
308Experiment::ExperimentHandler::ExperimentHandler (Experiment *_exp)
309{
310  exp = _exp;
311  stack = new Vector<Element>;
312  pushElem (EL_NONE);
313  dynfuncModule = NULL;
314  dDscr = NULL;
315  pDscr = NULL;
316  propDscr = NULL;
317  text = NULL;
318  mkind = (Cmsg_warn) - 1; // CMSG_NONE
319  mnum = -1;
320  mec = -1;
321}
322
323Experiment::ExperimentHandler::~ExperimentHandler ()
324{
325  delete stack;
326  free (text);
327}
328
329void
330Experiment::ExperimentHandler::endDocument ()
331{
332  { // SP_TAG_STATE should be used to describe states, but it isn't
333    // let's do it here:
334    DataDescriptor *dd = exp->getDataDescriptor (DATA_HEAP);
335    if (dd != NULL)
336      {
337	PropDescr *prop = dd->getProp (PROP_HTYPE);
338	if (prop != NULL)
339	  {
340	    char * stateNames [HEAPTYPE_LAST] = HEAPTYPE_STATE_STRINGS;
341	    char * stateUNames[HEAPTYPE_LAST] = HEAPTYPE_STATE_USTRINGS;
342	    for (int ii = 0; ii < HEAPTYPE_LAST; ii++)
343	      prop->addState (ii, stateNames[ii], stateUNames[ii]);
344	  }
345      }
346    dd = exp->getDataDescriptor (DATA_IOTRACE);
347    if (dd != NULL)
348      {
349	PropDescr *prop = dd->getProp (PROP_IOTYPE);
350	if (prop != NULL)
351	  {
352	    char * stateNames [IOTRACETYPE_LAST] = IOTRACETYPE_STATE_STRINGS;
353	    char * stateUNames[IOTRACETYPE_LAST] = IOTRACETYPE_STATE_USTRINGS;
354	    for (int ii = 0; ii < IOTRACETYPE_LAST; ii++)
355	      prop->addState (ii, stateNames[ii], stateUNames[ii]);
356	  }
357      }
358  }
359}
360
361void
362Experiment::ExperimentHandler::pushElem (Element elem)
363{
364  curElem = elem;
365  stack->append (curElem);
366}
367
368void
369Experiment::ExperimentHandler::popElem ()
370{
371  stack->remove (stack->size () - 1);
372  curElem = stack->fetch (stack->size () - 1);
373}
374
375void
376Experiment::ExperimentHandler::startElement (char*, char*, char *qName, Attributes *attrs)
377{
378  DEBUG_CODE if (DEBUG_SAXPARSER) dump_startElement (qName, attrs);
379  if (strcmp (qName, SP_TAG_EXPERIMENT) == 0)
380    {
381      pushElem (EL_EXPERIMENT);
382      const char *str = attrs->getValue (NTXT ("version"));
383      if (str != NULL)
384	{
385	  int major = atoi (str);
386	  str = strchr (str, '.');
387	  int minor = str ? atoi (str + 1) : 0;
388	  exp->exp_maj_version = major;
389	  exp->exp_min_version = minor;
390	  if (major != SUNPERF_VERNUM || minor != SUNPERF_VERNUM_MINOR)
391	    {
392	      // not the current version, see if we support some earlier versions
393	      if (major < 12)
394		{
395		  StringBuilder sb;
396		  sb.sprintf (GTXT ("*** Error: experiment %s version %d.%d is not supported;\nuse the version of the tools that recorded the experiment to read it"),
397			      exp->get_expt_name (), major, minor);
398		  // exp->errorq->append( new Emsg(CMSG_FATAL, sb) );
399		  exp->status = FAILURE;
400		  exp->obsolete = 1;
401		  throw new SAXException (sb.toString ());
402		}
403	    }
404	}
405    }
406  else if (strcmp (qName, SP_TAG_COLLECTOR) == 0)
407    pushElem (EL_COLLECTOR);
408  else if (strcmp (qName, SP_TAG_SETTING) == 0)
409    {
410      int found = 0;
411      pushElem (EL_SETTING);
412      const char *str = attrs->getValue (SP_JCMD_LIMIT);
413      if (str != NULL)
414	{
415	  found = 1;
416	  exp->coll_params.limit = atoi (str);
417	}
418      str = attrs->getValue (SP_JCMD_BLKSZ);
419      if (str != NULL)
420	{
421	  found = 1;
422	  exp->blksz = strtol (str, NULL, 0);
423	}
424      str = attrs->getValue (SP_JCMD_STACKBASE);
425      if (str)
426	{
427	  found = 1;
428	  exp->stack_base = strtoull (str, NULL, 0);
429	}
430      str = attrs->getValue (SP_JCMD_HWC_DEFAULT);
431      if (str != NULL)
432	{
433	  found = 1;
434	  exp->hwc_default = true;
435	}
436      str = attrs->getValue (SP_JCMD_NOIDLE);
437      if (str != NULL)
438	{
439	  found = 1;
440	  exp->commentq->append (new Emsg (CMSG_COMMENT,
441					   GTXT ("*** Note: experiment does not have events from idle CPUs")));
442	}
443      str = attrs->getValue (SP_JCMD_FAKETIME);
444      if (str != NULL)
445	{
446	  found = 1;
447	  exp->timelineavail = false;
448	  exp->commentq->append (new Emsg (CMSG_COMMENT,
449					   GTXT ("*** Note: experiment does not have timestamps; timeline unavailable")));
450	}
451      str = attrs->getValue (SP_JCMD_DELAYSTART);
452      if (str != NULL)
453	{
454	  found = 1;
455	  exp->coll_params.start_delay = strdup (str);
456	}
457      str = attrs->getValue (SP_JCMD_TERMINATE);
458      if (str != NULL)
459	{
460	  found = 1;
461	  exp->coll_params.terminate = strdup (str);
462	}
463      str = attrs->getValue (SP_JCMD_PAUSE_SIG);
464      if (str != NULL)
465	{
466	  found = 1;
467	  exp->coll_params.pause_sig = strdup (str);
468	}
469      str = attrs->getValue (SP_JCMD_SAMPLE_PERIOD);
470      if (str != NULL)
471	{
472	  found = 1;
473	  exp->coll_params.sample_periodic = 1;
474	  exp->coll_params.sample_timer = atoi (str);
475	}
476      str = attrs->getValue (SP_JCMD_SAMPLE_SIG);
477      if (str != NULL)
478	{
479	  found = 1;
480	  exp->coll_params.sample_sig = str;
481	}
482      str = attrs->getValue (SP_JCMD_SRCHPATH);
483      if (str != NULL)
484	{
485	  found = 1;
486	  StringBuilder sb;
487	  sb.sprintf (GTXT ("Search path: %s"), str);
488	  exp->runlogq->append (new Emsg (CMSG_COMMENT, sb));
489	  dbeSession->add_classpath ((char*) str);
490	}
491      str = attrs->getValue (SP_JCMD_LINETRACE);
492      if (str != NULL)
493	{
494	  found = 1;
495	  exp->coll_params.linetrace = strdup (str);
496	}
497
498      str = attrs->getValue (SP_JCMD_COLLENV);
499      if (str != NULL)
500	{
501	  found = 1;
502	  StringBuilder sb;
503	  sb.sprintf (GTXT ("  Data collection environment variable: %s"), str);
504	  exp->runlogq->append (new Emsg (CMSG_COMMENT, sb));
505	}
506      if (found == 0)
507	{
508	  int nattr = attrs->getLength ();
509	  if (nattr != 0)
510	    {
511	      fprintf (stderr, "XXX Unexpected setting found; %d attributes:\n",
512		       nattr);
513	      for (int k = 0; k < nattr; k++)
514		{
515		  const char *qn = attrs->getQName (k);
516		  const char *vl = attrs->getValue (k);
517		  fprintf (stderr, "XXX      %s = %s\n", qn, vl);
518		}
519	    }
520	}
521      // END OF CODE FOR "setting"
522    }
523  else if (strcmp (qName, SP_TAG_SYSTEM) == 0)
524    {
525      pushElem (EL_SYSTEM);
526      const char *str = attrs->getValue (NTXT ("hostname"));
527      if (str != NULL)
528	exp->hostname = strdup (str);
529      str = attrs->getValue (NTXT ("os"));
530      if (str != NULL)
531	{
532	  exp->os_version = strdup (str);
533	  /* For Linux experiments expect sparse thread ID's */
534	  if (strncmp (str, NTXT ("SunOS"), 5) != 0)
535	    exp->sparse_threads = true;
536	}
537      str = attrs->getValue (NTXT ("arch"));
538      if (str != NULL)
539	{
540	  if (strcmp (str, "i86pc") == 0 || strcmp (str, "i686") == 0
541	      || strcmp (str, "x86_64") == 0)
542	    exp->platform = Intel;
543	  else if (strcmp (str, "aarch64") == 0)
544	    exp->platform = Aarch64;
545	  else
546	    exp->platform = Sparc;
547	  exp->need_swap_endian = (DbeSession::platform == Sparc) ?
548		  (exp->platform != Sparc) : (exp->platform == Sparc);
549	  exp->architecture = strdup (str);
550	}
551      str = attrs->getValue (NTXT ("pagesz"));
552      if (str != NULL)
553	exp->page_size = atoi (str);
554      str = attrs->getValue (NTXT ("npages"));
555      if (str != NULL)
556	exp->npages = atoi (str);
557    }
558  else if (strcmp (qName, SP_TAG_POWERM) == 0)
559    pushElem (EL_POWERM);
560  else if (strcmp (qName, SP_TAG_FREQUENCY) == 0)
561    {
562      pushElem (EL_FREQUENCY);
563      const char *str = attrs->getValue (NTXT ("clk"));
564      if (str != NULL)
565	exp->set_clock (atoi (str));
566      // check for frequency_scaling or turbo_mode recorded from libcollector under dbx
567      str = attrs->getValue (NTXT ("frequency_scaling"));
568      const char *str2 = attrs->getValue (NTXT ("turbo_mode"));
569      if (str != NULL || str2 != NULL)
570	exp->varclock = 1;
571    }
572  else if (strcmp (qName, SP_TAG_CPU) == 0)
573    {
574      pushElem (EL_CPU);
575      exp->ncpus++;
576      const char *str = attrs->getValue (NTXT ("clk"));
577      if (str != NULL)
578	{
579	  int clk = atoi (str);
580	  if (exp->maxclock == 0)
581	    {
582	      exp->minclock = clk;
583	      exp->maxclock = clk;
584	    }
585	  else
586	    {
587	      if (clk < exp->minclock)
588		exp->minclock = clk;
589	      if (clk > exp->maxclock)
590		exp->maxclock = clk;
591	    }
592	  exp->clock = clk;
593	}
594      // check for frequency_scaling or turbo_mode
595      str = attrs->getValue (NTXT ("frequency_scaling"));
596      const char *str2 = attrs->getValue (NTXT ("turbo_mode"));
597      if (str != NULL || str2 != NULL)
598	exp->varclock = 1;
599    }
600  else if (strcmp (qName, SP_TAG_PROCESS) == 0)
601    {
602      pushElem (EL_PROCESS);
603      const char *str = attrs->getValue (NTXT ("wsize"));
604      if (str != NULL)
605	{
606	  int wsz = atoi (str);
607	  if (wsz == 32)
608	    exp->wsize = W32;
609	  else if (wsz == 64)
610	    exp->wsize = W64;
611	}
612      str = attrs->getValue (NTXT ("pid"));
613      if (str != NULL)
614	exp->pid = atoi (str);
615      str = attrs->getValue (NTXT ("ppid"));
616      if (str != NULL)
617	exp->ppid = atoi (str);
618      str = attrs->getValue (NTXT ("pgrp"));
619      if (str != NULL)
620	exp->pgrp = atoi (str);
621      str = attrs->getValue (NTXT ("sid"));
622      if (str != NULL)
623	exp->sid = atoi (str);
624      str = attrs->getValue (NTXT ("cwd"));
625      if (str != NULL)
626	exp->ucwd = strdup (str);
627      str = attrs->getValue (NTXT ("pagesz"));
628      if (str != NULL)
629	exp->page_size = atoi (str);
630    }
631  else if (strcmp (qName, SP_TAG_EVENT) == 0)
632    { // Start code for event
633      pushElem (EL_EVENT);
634      hrtime_t ts = (hrtime_t) 0;
635      const char *str = attrs->getValue (NTXT ("tstamp"));
636      if (str != NULL)
637	ts = parseTStamp (str);
638      str = attrs->getValue (NTXT ("kind"));
639      if (str != NULL)
640	{
641	  if (strcmp (str, SP_JCMD_RUN) == 0)
642	    {
643	      exp->broken = 0;
644	      exp->exp_start_time = ts;
645	      str = attrs->getValue (NTXT ("time"));
646	      if (str != NULL)
647		exp->start_sec = atoll (str);
648	      str = attrs->getValue (NTXT ("pid"));
649	      if (str != NULL)
650		exp->pid = atoi (str);
651	      str = attrs->getValue (NTXT ("ppid"));
652	      if (str != NULL)
653		exp->ppid = atoi (str);
654	      str = attrs->getValue (NTXT ("pgrp"));
655	      if (str != NULL)
656		exp->pgrp = atoi (str);
657	      str = attrs->getValue (NTXT ("sid"));
658	      if (str != NULL)
659		exp->sid = atoi (str);
660	      exp->status = Experiment::INCOMPLETE;
661	    }
662	  else if (strcmp (str, SP_JCMD_ARCHIVE) == 0)
663	    {
664	      StringBuilder sb;
665	      sb.sprintf (GTXT ("er_archive run: XXXXXXX"));
666	      exp->pprocq->append (new Emsg (CMSG_WARN, sb));
667	    }
668	  else if (strcmp (str, SP_JCMD_SAMPLE) == 0)
669	    {
670	      exp->update_last_event (exp->exp_start_time + ts); // ts is 0-based
671	      str = attrs->getValue (NTXT ("id"));
672	      int id = str ? atoi (str) : -1;
673	      char *label = dbe_strdup (attrs->getValue (NTXT ("label")));
674	      exp->process_sample_cmd (NULL, ts, id, label);
675	    }
676	  else if (strcmp (str, SP_JCMD_EXIT) == 0)
677	    {
678	      // don't treat EXIT as an event w.r.t. last_event and non_paused_time
679	      exp->status = Experiment::SUCCESS;
680	    }
681	  else if (strcmp (str, SP_JCMD_CERROR) == 0)
682	    {
683	      mkind = CMSG_ERROR;
684	      str = attrs->getValue (NTXT ("id"));
685	      if (str != NULL)
686		{
687		  mnum = atoi (str);
688		}
689	      str = attrs->getValue (NTXT ("ec"));
690	      if (str != NULL)
691		{
692		  mec = atoi (str);
693		}
694	    }
695	  else if (strcmp (str, SP_JCMD_CWARN) == 0)
696	    {
697	      mkind = CMSG_WARN;
698	      str = attrs->getValue (NTXT ("id"));
699	      if (str != NULL)
700		mnum = atoi (str);
701	    }
702	  else if (strcmp (str, SP_JCMD_COMMENT) == 0)
703	    {
704	      mkind = CMSG_COMMENT;
705	      str = attrs->getValue (NTXT ("id"));
706	      if (str != NULL)
707		mnum = atoi (str);
708	      str = attrs->getValue (NTXT ("text"));
709	      if (str != NULL)
710		{
711		  StringBuilder sb;
712		  sb.sprintf (GTXT ("*** Note: %s"), str);
713		  exp->commentq->append (new Emsg (CMSG_COMMENT, sb));
714		}
715	    }
716	  else if (strcmp (str, SP_JCMD_DESC_START) == 0)
717	    {
718	      char *variant = toStr (attrs, NTXT ("variant"));
719	      char *lineage = toStr (attrs, NTXT ("lineage"));
720	      int follow = toInt (attrs, NTXT ("follow"));
721	      char *msg = toStr (attrs, NTXT ("msg"));
722	      exp->process_desc_start_cmd (NULL, ts, variant, lineage, follow, msg);
723	    }
724	  else if (strcmp (str, SP_JCMD_DESC_STARTED) == 0)
725	    {
726	      char *variant = toStr (attrs, NTXT ("variant"));
727	      char *lineage = toStr (attrs, NTXT ("lineage"));
728	      int follow = toInt (attrs, NTXT ("follow"));
729	      char *msg = toStr (attrs, NTXT ("msg"));
730	      exp->process_desc_started_cmd (NULL, ts, variant, lineage, follow, msg);
731	    }
732	  else if (strcmp (str, SP_JCMD_EXEC_START) == 0)
733	    {
734	      // if successful, acts like experiment termination - no "exit" entry will follow
735	      exp->update_last_event (exp->exp_start_time + ts); // ts is 0-based
736	      char *variant = toStr (attrs, NTXT ("variant"));
737	      char *lineage = toStr (attrs, NTXT ("lineage"));
738	      int follow = toInt (attrs, NTXT ("follow"));
739	      char *msg = toStr (attrs, NTXT ("msg"));
740	      exp->process_desc_start_cmd (NULL, ts, variant, lineage, follow, msg);
741	      exp->exec_started = true;
742	    }
743	  else if (strcmp (str, SP_JCMD_EXEC_ERROR) == 0)
744	    {
745	      exp->update_last_event (exp->exp_start_time + ts); // ts is 0-based
746	      char *variant = toStr (attrs, NTXT ("variant"));
747	      char *lineage = toStr (attrs, NTXT ("lineage"));
748	      int follow = toInt (attrs, NTXT ("follow"));
749	      char *msg = toStr (attrs, NTXT ("msg"));
750	      exp->process_desc_started_cmd (NULL, ts, variant, lineage, follow, msg);
751	      exp->exec_started = false;
752	    }
753	  else if (strcmp (str, SP_JCMD_JTHRSTART) == 0)
754	    {
755	      char *name = dbe_strdup (attrs->getValue (NTXT ("name")));
756	      char *grpname = dbe_strdup (attrs->getValue (NTXT ("grpname")));
757	      char *prntname = dbe_strdup (attrs->getValue (NTXT ("prntname")));
758	      str = attrs->getValue (NTXT ("tid"));
759	      uint64_t tid = str ? strtoull (str, NULL, 0) : 0;
760	      str = attrs->getValue (NTXT ("jthr"));
761	      Vaddr jthr = str ? strtoull (str, NULL, 0) : 0;
762	      str = attrs->getValue (NTXT ("jenv"));
763	      Vaddr jenv = str ? strtoull (str, NULL, 0) : 0;
764	      exp->process_jthr_start_cmd (NULL, name, grpname, prntname, tid, jthr, jenv, ts);
765	    }
766	  else if (strcmp (str, SP_JCMD_JTHREND) == 0)
767	    {
768	      str = attrs->getValue (NTXT ("tid"));
769	      uint64_t tid = str ? strtoull (str, NULL, 0) : 0;
770	      str = attrs->getValue (NTXT ("jthr"));
771	      Vaddr jthr = str ? strtoull (str, NULL, 0) : 0;
772	      str = attrs->getValue (NTXT ("jenv"));
773	      Vaddr jenv = str ? strtoull (str, NULL, 0) : 0;
774	      exp->process_jthr_end_cmd (NULL, tid, jthr, jenv, ts);
775	    }
776	  else if (strcmp (str, SP_JCMD_GCEND) == 0)
777	    {
778	      if (exp->getDataDescriptor (DATA_GCEVENT) == NULL)
779		exp->newDataDescriptor (DATA_GCEVENT);
780	      exp->process_gc_end_cmd (ts);
781	    }
782	  else if (strcmp (str, SP_JCMD_GCSTART) == 0)
783	    {
784	      if (exp->getDataDescriptor (DATA_GCEVENT) == NULL)
785		exp->newDataDescriptor (DATA_GCEVENT);
786	      exp->process_gc_start_cmd (ts);
787	    }
788	  else if (strcmp (str, SP_JCMD_PAUSE) == 0)
789	    {
790	      if (exp->resume_ts != MAX_TIME)
791		{
792		  // data collection was active
793		  hrtime_t delta = ts - exp->resume_ts;
794		  exp->non_paused_time += delta;
795		  exp->resume_ts = MAX_TIME; // collection is paused
796		}
797	      StringBuilder sb;
798	      str = attrs->getValue (NTXT ("name"));
799	      if (str == NULL)
800		sb.sprintf (GTXT ("Pause: %ld.%09ld"), (long) (ts / NANOSEC),
801			    (long) (ts % NANOSEC));
802	      else
803		sb.sprintf (GTXT ("Pause (%s): %ld.%09ld"), str,
804			    (long) (ts / NANOSEC), (long) (ts % NANOSEC));
805	      exp->runlogq->append (new Emsg (CMSG_COMMENT, sb));
806	    }
807	  else if (strcmp (str, SP_JCMD_RESUME) == 0)
808	    {
809	      if (exp->resume_ts == MAX_TIME)
810		// data collection was paused
811		exp->resume_ts = ts; // remember start time
812	      StringBuilder sb;
813	      sb.sprintf (GTXT ("Resume: %ld.%09ld"), (long) (ts / NANOSEC), (long) (ts % NANOSEC));
814	      exp->runlogq->append (new Emsg (CMSG_COMMENT, sb));
815	      if (exp->exp_start_time == ZERO_TIME)
816		exp->exp_start_time = ts;
817	    }
818	  else if (strcmp (str, SP_JCMD_THREAD_PAUSE) == 0)
819	    {
820	      str = attrs->getValue (NTXT ("tid"));
821	      uint64_t tid = str ? strtoull (str, NULL, 0) : 0;
822	      StringBuilder sb;
823	      sb.sprintf (GTXT ("Thread %llu pause: %ld.%09ld"), (unsigned long long) tid,
824			  (long) (ts / NANOSEC), (long) (ts % NANOSEC));
825	      exp->runlogq->append (new Emsg (CMSG_COMMENT, sb));
826	    }
827	  else if (strcmp (str, SP_JCMD_THREAD_RESUME) == 0)
828	    {
829	      str = attrs->getValue (NTXT ("tid"));
830	      uint64_t tid = str ? strtoull (str, NULL, 0) : 0;
831	      StringBuilder sb;
832	      sb.sprintf (GTXT ("Thread %llu resume: %ld.%09ld"), (unsigned long long) tid,
833			  (long) (ts / NANOSEC), (long) (ts % NANOSEC));
834	      exp->runlogq->append (new Emsg (CMSG_COMMENT, sb));
835	    }
836	  else if (strcmp (str, NTXT ("map")) == 0)
837	    {
838	      ts += exp->exp_start_time;
839	      str = attrs->getValue (NTXT ("vaddr"));
840	      Vaddr vaddr = str ? strtoull (str, NULL, 0) : 0;
841	      str = attrs->getValue (NTXT ("size"));
842	      int msize = str ? atoi (str) : 0;
843	      str = attrs->getValue (NTXT ("foffset"));
844	      int64_t offset = str ? strtoll (str, NULL, 0) : 0;
845	      str = attrs->getValue (NTXT ("modes"));
846	      int64_t modes = str ? strtoll (str, NULL, 0) : 0;
847	      str = attrs->getValue (NTXT ("chksum"));
848	      int64_t chksum = 0;
849	      if (str)
850		chksum = Elf::normalize_checksum (strtoll (str, NULL, 0));
851	      char *name = (char *) attrs->getValue (NTXT ("name"));
852	      str = attrs->getValue (NTXT ("object"));
853	      if (strcmp (str, NTXT ("segment")) == 0)
854		{
855		  if (strcmp (name, NTXT ("LinuxKernel")) == 0)
856		    exp->process_Linux_kernel_cmd (ts);
857		  else
858		    exp->process_seg_map_cmd (NULL, ts, vaddr, msize, 0,
859					      offset, modes, chksum, name);
860		}
861	      else if (strcmp (str, NTXT ("function")) == 0)
862		{
863		  exp->process_fn_load_cmd (dynfuncModule, name, vaddr, msize, ts);
864		  dynfuncModule = NULL;
865		}
866	      else if (strcmp (str, NTXT ("dynfunc")) == 0)
867		{
868		  if (dynfuncModule == NULL)
869		    {
870		      dynfuncModule = dbeSession->createModule (exp->get_dynfunc_lo (DYNFUNC_SEGMENT), name);
871		      dynfuncModule->flags |= MOD_FLAG_UNKNOWN;
872		      dynfuncModule->set_file_name (dbe_strdup (dynfuncModule->getMainSrc ()->get_name ()));
873		    }
874		  (void) exp->create_dynfunc (dynfuncModule,
875					      (char*) attrs->getValue (NTXT ("funcname")), vaddr, msize);
876		}
877	      else if (strcmp (str, NTXT ("jcm")) == 0)
878		{
879		  str = attrs->getValue (NTXT ("methodId"));
880		  Vaddr mid = str ? strtoull (str, NULL, 0) : 0;
881		  exp->process_jcm_load_cmd (NULL, mid, vaddr, msize, ts);
882		}
883	    }
884	  else if (strcmp (str, NTXT ("unmap")) == 0)
885	    {
886	      ts += exp->exp_start_time;
887	      str = attrs->getValue (NTXT ("vaddr"));
888	      Vaddr vaddr = str ? strtoull (str, NULL, 0) : 0;
889	      exp->process_seg_unmap_cmd (NULL, ts, vaddr);
890	    }
891	}
892      // end of code for event
893    }
894  else if (strcmp (qName, SP_TAG_PROFILE) == 0)
895    {
896      pushElem (EL_PROFILE);
897      const char *str = attrs->getValue (NTXT ("name"));
898      if (str == NULL)
899	return;
900      if (strcmp (str, NTXT ("profile")) == 0)
901	{
902	  exp->coll_params.profile_mode = 1;
903	  str = attrs->getValue (NTXT ("numstates"));
904	  if (str != NULL)
905	    exp->coll_params.lms_magic_id = atoi (str);
906	  str = attrs->getValue (NTXT ("ptimer"));
907	  if (str != NULL)
908	    exp->coll_params.ptimer_usec = atoi (str); // microseconds
909
910	  PropDescr *mstate_prop = NULL;
911	  char * stateNames [/*LMS_NUM_STATES*/] = LMS_STATE_STRINGS;
912	  char * stateUNames[/*LMS_NUM_STATES*/] = LMS_STATE_USTRINGS;
913	  {
914	    dDscr = exp->newDataDescriptor (DATA_CLOCK);
915	    PropDescr *prop = new PropDescr (PROP_MSTATE, NTXT ("MSTATE"));
916	    prop->uname = dbe_strdup (GTXT ("Thread state"));
917	    prop->vtype = TYPE_UINT32;
918	    // (states added below)
919	    dDscr->addProperty (prop);
920	    mstate_prop = prop;
921
922	    prop = new PropDescr (PROP_NTICK, NTXT ("NTICK"));
923	    prop->uname = dbe_strdup (GTXT ("Number of Profiling Ticks"));
924	    prop->vtype = TYPE_UINT32;
925	    dDscr->addProperty (prop);
926	  }
927
928	  switch (exp->coll_params.lms_magic_id)
929	    {
930	    case LMS_MAGIC_ID_SOLARIS:
931	      exp->register_metric (Metric::CP_TOTAL);
932	      exp->register_metric (Metric::CP_TOTAL_CPU);
933	      exp->register_metric (Metric::CP_LMS_USER);
934	      exp->register_metric (Metric::CP_LMS_SYSTEM);
935	      exp->register_metric (Metric::CP_LMS_TRAP);
936	      exp->register_metric (Metric::CP_LMS_DFAULT);
937	      exp->register_metric (Metric::CP_LMS_TFAULT);
938	      exp->register_metric (Metric::CP_LMS_KFAULT);
939	      exp->register_metric (Metric::CP_LMS_STOPPED);
940	      exp->register_metric (Metric::CP_LMS_WAIT_CPU);
941	      exp->register_metric (Metric::CP_LMS_SLEEP);
942	      exp->register_metric (Metric::CP_LMS_USER_LOCK);
943	      for (int ii = 0; ii < LMS_NUM_SOLARIS_MSTATES; ii++)
944		mstate_prop->addState (ii, stateNames[ii], stateUNames[ii]);
945	      break;
946	    case LMS_MAGIC_ID_ERKERNEL_KERNEL:
947	      exp->register_metric (Metric::CP_KERNEL_CPU);
948	      {
949		int ii = LMS_KERNEL_CPU;
950		mstate_prop->addState (ii, stateNames[ii], stateUNames[ii]);
951	      }
952	      break;
953	    case LMS_MAGIC_ID_ERKERNEL_USER:
954	      exp->register_metric (Metric::CP_TOTAL_CPU);
955	      exp->register_metric (Metric::CP_LMS_USER);
956	      exp->register_metric (Metric::CP_LMS_SYSTEM);
957	      {
958		int ii = LMS_KERNEL_CPU;
959		mstate_prop->addState (ii, stateNames[ii], stateUNames[ii]);
960		ii = LMS_USER;
961		mstate_prop->addState (ii, stateNames[ii], stateUNames[ii]);
962		ii = LMS_SYSTEM;
963		mstate_prop->addState (ii, stateNames[ii], stateUNames[ii]);
964	      }
965	      break;
966	    case LMS_MAGIC_ID_LINUX:
967	      exp->register_metric (Metric::CP_TOTAL_CPU);
968	      {
969		int ii = LMS_LINUX_CPU;
970		mstate_prop->addState (ii, stateNames[ii], stateUNames[ii]);
971	      }
972	      break;
973	    default:
974	      // odd
975	      break;
976	    }
977	}
978      else if (strcmp (str, NTXT ("heaptrace")) == 0)
979	{
980	  exp->coll_params.heap_mode = 1;
981	  exp->leaklistavail = true;
982	  exp->heapdataavail = true;
983	  exp->register_metric (Metric::HEAP_ALLOC_BYTES);
984	  exp->register_metric (Metric::HEAP_ALLOC_CNT);
985	  exp->register_metric (Metric::HEAP_LEAK_BYTES);
986	  exp->register_metric (Metric::HEAP_LEAK_CNT);
987	  dDscr = exp->newDataDescriptor (DATA_HEAP);
988	}
989      else if (strcmp (str, NTXT ("iotrace")) == 0)
990	{
991	  exp->coll_params.io_mode = 1;
992	  exp->iodataavail = true;
993	  exp->register_metric (Metric::IO_READ_TIME);
994	  exp->register_metric (Metric::IO_READ_BYTES);
995	  exp->register_metric (Metric::IO_READ_CNT);
996	  exp->register_metric (Metric::IO_WRITE_TIME);
997	  exp->register_metric (Metric::IO_WRITE_BYTES);
998	  exp->register_metric (Metric::IO_WRITE_CNT);
999	  exp->register_metric (Metric::IO_OTHER_TIME);
1000	  exp->register_metric (Metric::IO_OTHER_CNT);
1001	  exp->register_metric (Metric::IO_ERROR_TIME);
1002	  exp->register_metric (Metric::IO_ERROR_CNT);
1003	  dDscr = exp->newDataDescriptor (DATA_IOTRACE);
1004	}
1005      else if (strcmp (str, NTXT ("synctrace")) == 0)
1006	{
1007	  exp->coll_params.sync_mode = 1;
1008	  str = attrs->getValue (NTXT ("threshold"));
1009	  if (str != NULL)
1010	    exp->coll_params.sync_threshold = atoi (str);
1011	  str = attrs->getValue (NTXT ("scope"));
1012	  if (str != NULL)
1013	    exp->coll_params.sync_scope = atoi (str);
1014	  else  // Should only happen with old experiments; use the old default
1015	    exp->coll_params.sync_scope = SYNCSCOPE_NATIVE | SYNCSCOPE_JAVA;
1016	  exp->register_metric (Metric::SYNC_WAIT_TIME);
1017	  exp->register_metric (Metric::SYNC_WAIT_COUNT);
1018	  dDscr = exp->newDataDescriptor (DATA_SYNCH);
1019	}
1020      else if (strcmp (str, NTXT ("omptrace")) == 0)
1021	{
1022	  exp->coll_params.omp_mode = 1;
1023	  dDscr = exp->newDataDescriptor (DATA_OMP, DDFLAG_NOSHOW);
1024	}
1025      else if (strcmp (str, NTXT ("hwcounter")) == 0)
1026	{
1027	  str = attrs->getValue (NTXT ("cpuver"));
1028	  int cpuver = str ? atoi (str) : 0;
1029	  char *counter = dbe_strdup (attrs->getValue (NTXT ("hwcname")));
1030	  char *int_name = dbe_strdup (attrs->getValue (NTXT ("int_name"))); // may not be present
1031	  str = attrs->getValue (NTXT ("interval"));
1032	  int interval = str ? atoi (str) : 0;
1033	  str = attrs->getValue (NTXT ("tag"));
1034	  int tag = str ? atoi (str) : 0;
1035	  str = attrs->getValue (NTXT ("memop"));
1036	  int i_tpc = str ? atoi (str) : 0;
1037	  char *modstr = dbe_strdup (attrs->getValue (NTXT ("modstr")));
1038	  exp->process_hwcounter_cmd (NULL, cpuver, counter, int_name, interval, tag, i_tpc, modstr);
1039	  dDscr = exp->newDataDescriptor (DATA_HWC);
1040	}
1041      else if (strcmp (str, NTXT ("hwsimctr")) == 0)
1042	{
1043	  int cpuver = toInt (attrs, NTXT ("cpuver"));
1044	  char *hwcname = dbe_strdup (attrs->getValue (NTXT ("hwcname")));
1045	  char *int_name = dbe_strdup (attrs->getValue (NTXT ("int_name")));
1046	  char *metric = dbe_strdup (attrs->getValue (NTXT ("metric")));
1047	  int reg = toInt (attrs, NTXT ("reg_num"));
1048	  int interval = toInt (attrs, NTXT ("interval"));
1049	  int timecvt = toInt (attrs, NTXT ("timecvt"));
1050	  int i_tpc = toInt (attrs, NTXT ("memop"));
1051	  int tag = toInt (attrs, NTXT ("tag"));
1052	  exp->process_hwsimctr_cmd (NULL, cpuver, hwcname, int_name, metric, reg,
1053				     interval, timecvt, i_tpc, tag);
1054	  dDscr = exp->newDataDescriptor (DATA_HWC);
1055	}
1056      else if (strcmp (str, NTXT ("dversion")) == 0)
1057	exp->dversion = dbe_strdup (attrs->getValue (NTXT ("version")));
1058      else if (strcmp (str, NTXT ("jprofile")) == 0)
1059	{
1060	  exp->has_java = true;
1061	  str = attrs->getValue (NTXT ("jversion"));
1062	  if (str != NULL)
1063	    exp->jversion = strdup (str);
1064	}
1065      else if (strcmp (str, NTXT ("datarace")) == 0)
1066	{
1067	  exp->coll_params.race_mode = 1;
1068	  exp->racelistavail = true;
1069	  str = attrs->getValue (NTXT ("scheme"));
1070	  exp->coll_params.race_stack = str ? atoi (str) : 0;
1071	  exp->register_metric (Metric::RACCESS);
1072	  dDscr = exp->newDataDescriptor (DATA_RACE);
1073	}
1074      else if (strcmp (str, NTXT ("deadlock")) == 0)
1075	{
1076	  exp->coll_params.deadlock_mode = 1;
1077	  exp->deadlocklistavail = true;
1078	  exp->register_metric (Metric::DEADLOCKS);
1079	  dDscr = exp->newDataDescriptor (DATA_DLCK);
1080	}
1081    }
1082    /* XXX -- obsolete tag, but is still written to experiments */
1083  else if (strcmp (qName, SP_TAG_DATAPTR) == 0)
1084    {
1085      pushElem (EL_DATAPTR);
1086      return;
1087    }
1088  else if (strcmp (qName, SP_TAG_PROFDATA) == 0)
1089    {
1090      pushElem (EL_PROFDATA);
1091      // SS12 HWC experiments are not well structured
1092      const char *fname = attrs->getValue (NTXT ("fname"));
1093      if (fname && strcmp (fname, SP_HWCNTR_FILE) == 0)
1094	dDscr = exp->newDataDescriptor (DATA_HWC);
1095    }
1096  else if (strcmp (qName, SP_TAG_PROFPCKT) == 0)
1097    {
1098      pushElem (EL_PROFPCKT);
1099      const char *str = attrs->getValue (NTXT ("kind")); // see Pckt_type
1100      int kind = str ? atoi (str) : -1;
1101      if (kind < 0)
1102	return;
1103      if (exp->coll_params.omp_mode == 1)
1104	{
1105	  if (kind == OMP_PCKT)
1106	    dDscr = exp->newDataDescriptor (DATA_OMP, DDFLAG_NOSHOW);
1107	  else if (kind == OMP2_PCKT)
1108	    dDscr = exp->newDataDescriptor (DATA_OMP2, DDFLAG_NOSHOW);
1109	  else if (kind == OMP3_PCKT)
1110	    dDscr = exp->newDataDescriptor (DATA_OMP3, DDFLAG_NOSHOW);
1111	  else if (kind == OMP4_PCKT)
1112	    dDscr = exp->newDataDescriptor (DATA_OMP4, DDFLAG_NOSHOW);
1113	  else if (kind == OMP5_PCKT)
1114	    dDscr = exp->newDataDescriptor (DATA_OMP5, DDFLAG_NOSHOW);
1115	}
1116      pDscr = exp->newPacketDescriptor (kind, dDscr);
1117      return;
1118    }
1119  else if (strcmp (qName, SP_TAG_FIELD) == 0)
1120    {
1121      pushElem (EL_FIELD);
1122      if (pDscr != NULL)
1123	{
1124	  const char *name = attrs->getValue (NTXT ("name"));
1125	  if (name == NULL)
1126	    return;
1127	  int propID = dbeSession->registerPropertyName (name);
1128	  propDscr = new PropDescr (propID, name);
1129	  FieldDescr *fldDscr = new FieldDescr (propID, name);
1130
1131	  const char *str = attrs->getValue (NTXT ("type"));
1132	  if (str)
1133	    {
1134	      if (strcmp (str, NTXT ("INT32")) == 0)
1135		fldDscr->vtype = TYPE_INT32;
1136	      else if (strcmp (str, NTXT ("UINT32")) == 0)
1137		fldDscr->vtype = TYPE_UINT32;
1138	      else if (strcmp (str, NTXT ("INT64")) == 0)
1139		fldDscr->vtype = TYPE_INT64;
1140	      else if (strcmp (str, NTXT ("UINT64")) == 0)
1141		fldDscr->vtype = TYPE_UINT64;
1142	      else if (strcmp (str, NTXT ("STRING")) == 0)
1143		fldDscr->vtype = TYPE_STRING;
1144	      else if (strcmp (str, NTXT ("DOUBLE")) == 0)
1145		fldDscr->vtype = TYPE_DOUBLE;
1146	      else if (strcmp (str, NTXT ("DATE")) == 0)
1147		{
1148		  fldDscr->vtype = TYPE_DATE;
1149		  const char *fmt = attrs->getValue (NTXT ("format"));
1150		  fldDscr->format = strdup (fmt ? fmt : "");
1151		}
1152	    }
1153	  propDscr->vtype = fldDscr->vtype;
1154
1155	  // TYPE_DATE is converted to TYPE_UINT64 in propDscr
1156	  if (fldDscr->vtype == TYPE_DATE)
1157	    propDscr->vtype = TYPE_UINT64;
1158
1159	  // Fix some types until they are fixed in libcollector
1160	  if (propID == PROP_VIRTPC || propID == PROP_PHYSPC)
1161	    {
1162	      if (fldDscr->vtype == TYPE_INT32)
1163		propDscr->vtype = TYPE_UINT32;
1164	      else if (fldDscr->vtype == TYPE_INT64)
1165		propDscr->vtype = TYPE_UINT64;
1166	    }
1167
1168	  // The following props get mapped to 32-bit values in readPacket
1169	  if (propID == PROP_CPUID || propID == PROP_THRID
1170	      || propID == PROP_LWPID)
1171	    propDscr->vtype = TYPE_UINT32; // override experiment property
1172
1173	  str = attrs->getValue (NTXT ("uname"));
1174	  if (str)
1175	    propDscr->uname = strdup (PTXT ((char*) str));
1176	  str = attrs->getValue (NTXT ("noshow"));
1177	  if (str && atoi (str) != 0)
1178	    propDscr->flags |= PRFLAG_NOSHOW;
1179
1180	  if (dDscr == NULL)
1181	    {
1182	      StringBuilder sb;
1183	      sb.sprintf (GTXT ("*** Error: data parsing failed. Log file is corrupted."));
1184	      exp->warnq->append (new Emsg (CMSG_ERROR, sb));
1185	      throw new SAXException (sb.toString ());
1186	    }
1187
1188	  dDscr->addProperty (propDscr);
1189	  str = attrs->getValue (NTXT ("offset"));
1190	  if (str)
1191	    fldDscr->offset = atoi (str);
1192	  pDscr->addField (fldDscr);
1193	}
1194    }
1195  else if (strcmp (qName, SP_TAG_STATE) == 0)
1196    {
1197      pushElem (EL_STATE);
1198      if (propDscr != NULL)
1199	{
1200	  const char *str = attrs->getValue (NTXT ("value"));
1201	  int value = str ? atoi (str) : -1;
1202	  str = attrs->getValue (NTXT ("name"));
1203	  const char *ustr = attrs->getValue (NTXT ("uname"));
1204	  propDscr->addState (value, str, ustr);
1205	}
1206    }
1207  else if (strcmp (qName, SP_TAG_DTRACEFATAL) == 0)
1208    pushElem (EL_DTRACEFATAL);
1209  else
1210    {
1211      StringBuilder sb;
1212      sb.sprintf (GTXT ("*** Warning: unrecognized element %s"), qName);
1213      exp->warnq->append (new Emsg (CMSG_WARN, sb));
1214      pushElem (EL_NONE);
1215    }
1216}
1217
1218void
1219Experiment::ExperimentHandler::characters (char *ch, int start, int length)
1220{
1221  switch (curElem)
1222    {
1223    case EL_COLLECTOR:
1224      exp->cversion = dbe_strndup (ch + start, length);
1225      break;
1226    case EL_PROCESS:
1227      exp->process_arglist_cmd (NULL, dbe_strndup (ch + start, length));
1228      break;
1229    case EL_EVENT:
1230      free (text);
1231      text = dbe_strndup (ch + start, length);
1232      break;
1233    default:
1234      break;
1235    }
1236}
1237
1238void
1239Experiment::ExperimentHandler::endElement (char*, char*, char*)
1240{
1241  if (curElem == EL_EVENT && mkind >= 0 && mnum >= 0)
1242    {
1243      char *str;
1244      if (mec > 0)
1245	str = dbe_sprintf ("%s -- %s", text != NULL ? text : "", strerror (mec));
1246      else
1247	str = dbe_sprintf ("%s", text != NULL ? text : "");
1248      Emsg *msg = new Emsg (mkind, mnum, str);
1249      if (mkind == CMSG_WARN)
1250	{
1251	  if (mnum != COL_WARN_FSTYPE
1252	      || dbeSession->check_ignore_fs_warn () == false)
1253	    exp->warnq->append (msg);
1254	  else
1255	    exp->commentq->append (msg);
1256	}
1257      else if (mkind == CMSG_ERROR || mkind == CMSG_FATAL)
1258	exp->errorq->append (msg);
1259      else if (mkind == CMSG_COMMENT)
1260	exp->commentq->append (msg);
1261      else
1262	delete msg;
1263      mkind = (Cmsg_warn) - 1;
1264      mnum = -1;
1265      mec = -1;
1266    }
1267  else if (curElem == EL_PROFILE)
1268    dDscr = NULL;
1269  else if (curElem == EL_PROFPCKT)
1270    pDscr = NULL;
1271  else if (curElem == EL_FIELD)
1272    propDscr = NULL;
1273  free (text);
1274  text = NULL;
1275  popElem ();
1276}
1277
1278void
1279Experiment::ExperimentHandler::error (SAXParseException *e)
1280{
1281  StringBuilder sb;
1282  sb.sprintf (GTXT ("%s at line %d, column %d"),
1283	      e->getMessage (), e->getLineNumber (), e->getColumnNumber ());
1284  char *msg = sb.toString ();
1285  SAXException *e1 = new SAXException (msg);
1286  free (msg);
1287  throw ( e1);
1288}
1289
1290//-------------------------------------------------- Experiment
1291
1292Experiment::Experiment ()
1293{
1294  groupId = 0;
1295  userExpId = expIdx = -1;
1296  founder_exp = NULL;
1297  baseFounder = NULL;
1298  children_exps = new Vector<Experiment*>;
1299  loadObjs = new Vector<LoadObject*>;
1300  loadObjMap = new StringMap<LoadObject*>(128, 128);
1301  sourcesMap = NULL;
1302
1303  // Initialize configuration information.
1304  status = FAILURE;
1305  start_sec = 0;
1306  mtime = 0;
1307  hostname = NULL;
1308  username = NULL;
1309  architecture = NULL;
1310  os_version = NULL;
1311  uarglist = NULL;
1312  utargname = NULL;
1313  ucwd = NULL;
1314  cversion = NULL;
1315  dversion = NULL;
1316  jversion = NULL;
1317  exp_maj_version = 0;
1318  exp_min_version = 0;
1319  platform = Unknown;
1320  wsize = Wnone;
1321  page_size = 4096;
1322  npages = 0;
1323  stack_base = 0xf0000000;
1324  broken = 1;
1325  obsolete = 0;
1326  hwc_bogus = 0;
1327  hwc_lost_int = 0;
1328  hwc_scanned = 0;
1329  hwc_default = false;
1330  invalid_packet = 0;
1331
1332  // clear HWC event stats
1333  dsevents = 0;
1334  dsnoxhwcevents = 0;
1335
1336  memset (&coll_params, 0, sizeof (coll_params));
1337  ncpus = 0;
1338  minclock = 0;
1339  maxclock = 0;
1340  clock = 0;
1341  varclock = 0;
1342  exec_started = false;
1343  timelineavail = true;
1344  leaklistavail = false;
1345  heapdataavail = false;
1346  iodataavail = false;
1347  dataspaceavail = false;
1348  ifreqavail = false;
1349  racelistavail = false;
1350  deadlocklistavail = false;
1351  ompavail = false;
1352  tiny_threshold = -1;
1353  pid = 0;
1354  ppid = 0;
1355  pgrp = 0;
1356  sid = 0;
1357
1358  gc_duration = ZERO_TIME;
1359  exp_start_time = ZERO_TIME; // not known.  Wall-clock hrtime (not zero based)
1360  last_event = ZERO_TIME; // not known.  Wall-clock hrtime (not zero based)
1361  non_paused_time = 0; // 0 non-paused time (will sum as experiment is processed)
1362  resume_ts = 0; // by default, collection is "resumed" (not paused) from time=0
1363  need_swap_endian = false;
1364  exp_rel_start_time_set = false;
1365  exp_rel_start_time = ZERO_TIME;
1366  has_java = false;
1367  hex_field_width = 8;
1368  hw_cpuver = CPUVER_UNDEFINED;
1369  machinemodel = NULL;
1370  expt_name = NULL;
1371  arch_name = NULL;
1372  fndr_arch_name = NULL;
1373  logFile = NULL;
1374
1375  dataDscrs = new Vector<DataDescriptor*>;
1376  for (int i = 0; i < DATA_LAST; ++i)
1377    dataDscrs->append (NULL);
1378
1379  pcktDscrs = new Vector<PacketDescriptor*>;
1380  blksz = PROFILE_BUFFER_CHUNK;
1381  jthreads = new Vector<JThread*>;
1382  jthreads_idx = new Vector<JThread*>;
1383  gcevents = new Vector<GCEvent*>;
1384  gcevent_last_used = (GCEvent *) NULL;
1385  heapUnmapEvents = new Vector<UnmapChunk*>;
1386  cstack = NULL;
1387  cstackShowHide = NULL;
1388  frmpckts = new Vector<RawFramePacket*>;
1389  typedef DefaultMap2D<uint32_t, hrtime_t, uint64_t> OmpMap0;
1390  mapPRid = new OmpMap0 (OmpMap0::Interval);
1391  typedef DefaultMap2D<uint32_t, hrtime_t, void*> OmpMap;
1392  mapPReg = new OmpMap (OmpMap::Interval);
1393  mapTask = new OmpMap (OmpMap::Interval);
1394  openMPdata = NULL;
1395  archiveMap = NULL;
1396  nnodes = 0;
1397  nchunks = 0;
1398  chunks = 0;
1399  uidHTable = NULL;
1400  uidnodes = new Vector<UIDnode*>;
1401  mrecs = new Vector<MapRecord*>;
1402  samples = new Vector<Sample*>;
1403  sample_last_used = (Sample *) NULL;
1404  first_sample_label = (char*) NULL;
1405  fDataMap = NULL;
1406  vFdMap = NULL;
1407  resolveFrameInfo = true;
1408  discardTiny = false;
1409  init ();
1410}
1411
1412Experiment::~Experiment ()
1413{
1414  fini ();
1415  free (coll_params.linetrace);
1416  for (int i = 0; i < MAX_HWCOUNT; i++)
1417    {
1418      free (coll_params.hw_aux_name[i]);
1419      free (coll_params.hw_username[i]);
1420    }
1421  free (hostname);
1422  free (username);
1423  free (architecture);
1424  free (os_version);
1425  free (uarglist);
1426  free (utargname);
1427  free (ucwd);
1428  free (cversion);
1429  free (dversion);
1430  free (jversion);
1431  delete logFile;
1432  free (expt_name);
1433  free (arch_name);
1434  free (fndr_arch_name);
1435  delete jthreads_idx;
1436  delete cstack;
1437  delete cstackShowHide;
1438  delete mapPRid;
1439  delete mapPReg;
1440  delete mapTask;
1441  delete openMPdata;
1442  destroy_map (DbeFile *, archiveMap);
1443  delete[] uidHTable;
1444  delete uidnodes;
1445  delete mrecs;
1446  delete children_exps;
1447  delete loadObjs;
1448  delete loadObjMap;
1449  delete sourcesMap;
1450  free (first_sample_label);
1451  free (machinemodel);
1452
1453  dataDscrs->destroy ();
1454  delete dataDscrs;
1455  pcktDscrs->destroy ();
1456  delete pcktDscrs;
1457  jthreads->destroy ();
1458  delete jthreads;
1459  gcevents->destroy ();
1460  delete gcevents;
1461  heapUnmapEvents->destroy ();
1462  delete heapUnmapEvents;
1463  frmpckts->destroy ();
1464  delete frmpckts;
1465  samples->destroy ();
1466  delete samples;
1467  delete fDataMap;
1468  delete vFdMap;
1469
1470  for (long i = 0; i < nchunks; i++)
1471    delete[] chunks[i];
1472  delete[] chunks;
1473}
1474
1475void
1476Experiment::init_cache ()
1477{
1478  if (smemHTable)
1479    return;
1480  smemHTable = new SegMem*[HTableSize];
1481  instHTable = new DbeInstr*[HTableSize];
1482  for (int i = 0; i < HTableSize; i++)
1483    {
1484      smemHTable[i] = NULL;
1485      instHTable[i] = NULL;
1486    }
1487  uidHTable = new UIDnode*[HTableSize];
1488  for (int i = 0; i < HTableSize; i++)
1489    uidHTable[i] = NULL;
1490
1491  cstack = CallStack::getInstance (this);
1492  cstackShowHide = CallStack::getInstance (this);
1493}
1494
1495void
1496Experiment::init ()
1497{
1498  userLabels = NULL;
1499  seg_items = new Vector<SegMem*>;
1500  maps = new PRBTree ();
1501  jmaps = NULL; // used by JAVA_CLASSES only
1502  jmidHTable = NULL;
1503  smemHTable = NULL;
1504  instHTable = NULL;
1505  min_thread = (uint64_t) - 1;
1506  max_thread = 0;
1507  thread_cnt = 0;
1508  min_lwp = (uint64_t) - 1;
1509  max_lwp = 0;
1510  lwp_cnt = 0;
1511  min_cpu = (uint64_t) - 1;
1512  max_cpu = 0;
1513  cpu_cnt = 0;
1514
1515  commentq = new Emsgqueue (NTXT ("commentq"));
1516  runlogq = new Emsgqueue (NTXT ("runlogq"));
1517  errorq = new Emsgqueue (NTXT ("errorq"));
1518  warnq = new Emsgqueue (NTXT ("warnq"));
1519  notesq = new Emsgqueue (NTXT ("notesq"));
1520  pprocq = new Emsgqueue (NTXT ("pprocq"));
1521  ifreqq = NULL;
1522
1523  metrics = new Vector<BaseMetric*>;
1524  tagObjs = new Vector<Vector<Histable*>*>;
1525  tagObjs->store (PROP_THRID, new Vector<Histable*>);
1526  tagObjs->store (PROP_LWPID, new Vector<Histable*>);
1527  tagObjs->store (PROP_CPUID, new Vector<Histable*>);
1528  tagObjs->store (PROP_EXPID, new Vector<Histable*>);
1529  sparse_threads = false;
1530}
1531
1532void
1533Experiment::fini ()
1534{
1535  seg_items->destroy ();
1536  delete seg_items;
1537  delete maps;
1538  delete jmaps;
1539  delete[] smemHTable;
1540  delete[] instHTable;
1541  delete jmidHTable;
1542  delete commentq;
1543  delete runlogq;
1544  delete errorq;
1545  delete warnq;
1546  delete notesq;
1547  delete pprocq;
1548  if (ifreqq != NULL)
1549    {
1550      delete ifreqq;
1551      ifreqq = NULL;
1552    }
1553
1554  int index;
1555  BaseMetric *mtr;
1556  Vec_loop (BaseMetric*, metrics, index, mtr)
1557  {
1558    dbeSession->drop_metric (mtr);
1559  }
1560  delete metrics;
1561  tagObjs->fetch (PROP_THRID)->destroy ();
1562  tagObjs->fetch (PROP_LWPID)->destroy ();
1563  tagObjs->fetch (PROP_CPUID)->destroy ();
1564  tagObjs->fetch (PROP_EXPID)->destroy ();
1565  tagObjs->destroy ();
1566  delete tagObjs;
1567}
1568
1569// These are the data files which can be read in parallel
1570// for multiple sub-experiments.
1571// Postpone calling resolve_frame_info()
1572void
1573Experiment::read_experiment_data (bool read_ahead)
1574{
1575
1576  read_frameinfo_file ();
1577  if (read_ahead)
1578    {
1579      resolveFrameInfo = false;
1580      (void) get_profile_events ();
1581      resolveFrameInfo = true;
1582    }
1583}
1584
1585Experiment::Exp_status
1586Experiment::open_epilogue ()
1587{
1588
1589  // set up mapping for tagObj(PROP_EXPID)
1590  (void) mapTagValue (PROP_EXPID, userExpId);
1591
1592  post_process ();
1593  if (last_event != ZERO_TIME)
1594    { // if last_event is known
1595      StringBuilder sb;
1596      hrtime_t ts = last_event - exp_start_time;
1597      sb.sprintf (GTXT ("Experiment Ended: %ld.%09ld\nData Collection Duration: %ld.%09ld"),
1598		  (long) (ts / NANOSEC), (long) (ts % NANOSEC),
1599		  (long) (non_paused_time / NANOSEC),
1600		  (long) (non_paused_time % NANOSEC));
1601      runlogq->append (new Emsg (CMSG_COMMENT, sb));
1602    }
1603
1604  // Check for incomplete experiment, and inform the user
1605  if (status == INCOMPLETE)
1606    {
1607      if (exec_started == true)
1608	// experiment ended with the exec, not abnormally
1609	status = SUCCESS;
1610      else
1611	{
1612	  char * cmnt = GTXT ("*** Note: experiment was not closed");
1613	  commentq->append (new Emsg (CMSG_COMMENT, cmnt));
1614	  // runlogq->append(new Emsg(CMSG_COMMENT, cmnt));
1615	}
1616    }
1617  // write a descriptive header for the experiment
1618  write_header ();
1619  return status;
1620}
1621
1622Experiment::Exp_status
1623Experiment::open (char *path)
1624{
1625
1626  // Find experiment directory
1627  if (find_expdir (path) != SUCCESS)
1628    // message will have been queued and status set
1629    return status;
1630
1631  // Get creation time for experiment
1632  struct stat64 st;
1633  if (dbe_stat (path, &st) == 0)
1634    mtime = st.st_mtime;
1635
1636  // Read the warnings file
1637  read_warn_file ();
1638
1639  // Open the log file
1640  read_log_file ();
1641  if (status == SUCCESS && last_event // last event is initialized
1642      && (last_event - exp_start_time) / 1000000 < tiny_threshold)
1643    {
1644      // Process "tiny_threshold" (SP_ANALYZER_DISCARD_TINY_EXPERIMENTS)
1645      // At this point, we've only processed log.xml.
1646      // Note: if an experiment terminated abnormally, last_event will not yet
1647      //   represent events from clock profiling and other metrics.
1648      //   Other events will often have timestamps after the last log.xml entry.
1649      discardTiny = true;
1650      return status;
1651    }
1652  if (status == FAILURE)
1653    {
1654      if (logFile->get_status () == ExperimentFile::EF_FAILURE)
1655	{
1656	  Emsg *m = new Emsg (CMSG_FATAL, GTXT ("*** Error: log file in experiment cannot be read"));
1657	  errorq->append (m);
1658	}
1659      else if (fetch_errors () == NULL)
1660	{
1661	  if (broken == 1)
1662	    {
1663	      Emsg *m = new Emsg (CMSG_FATAL, GTXT ("*** Error: log does not show target starting"));
1664	      errorq->append (m);
1665	    }
1666	  else
1667	    {
1668	      Emsg *m = new Emsg (CMSG_FATAL, GTXT ("*** Error: log file in experiment could not be parsed"));
1669	      errorq->append (m);
1670	    }
1671	}
1672      return status;
1673    }
1674  init_cache ();
1675  if (varclock != 0)
1676    {
1677      StringBuilder sb;
1678      sb.sprintf (
1679		  GTXT ("*** Warning: system has variable clock frequency, which may cause variable execution times and inaccurate conversions of cycle counts into time."));
1680      warnq->append (new Emsg (CMSG_WARN, sb));
1681    }
1682
1683  // Read the notes file
1684  read_notes_file ();
1685  read_labels_file ();
1686  read_archives ();
1687
1688  // The log file shows experiment started
1689  read_java_classes_file ();
1690
1691  read_map_file ();
1692
1693  // Dyntext file has to be processed after loadobjects file
1694  // as we need to be able to map (vaddr,ts) to dynamic functions.
1695  read_dyntext_file ();
1696
1697  // Read the overview file and create samples.
1698  // Profiling data hasn't been read yet so we may have
1699  // events after the last recorded sample.
1700  // We'll create a fake sample to cover all those
1701  // events later.
1702  read_overview_file ();
1703
1704  // Check if instruction frequency data is available
1705  read_ifreq_file ();
1706
1707  // Check if OMP data is available
1708  read_omp_file ();
1709
1710  return status;
1711}
1712
1713/* XXX -- update() is a no-op now, but may be needed for auto-update */
1714Experiment::Exp_status
1715Experiment::update ()
1716{
1717  return status;
1718}
1719
1720void
1721Experiment::append (LoadObject *lo)
1722{
1723  loadObjs->append (lo);
1724  char *obj_name = lo->get_pathname ();
1725  char *bname = get_basename (obj_name);
1726  loadObjMap->put (obj_name, lo);
1727  loadObjMap->put (bname, lo);
1728  if (lo->flags & SEG_FLAG_EXE)
1729    loadObjMap->put (COMP_EXE_NAME, lo);
1730}
1731
1732void
1733Experiment::read_notes_file ()
1734{
1735  Emsg *m;
1736
1737  // Open log file:
1738  char *fname = dbe_sprintf (NTXT ("%s/%s"), expt_name, SP_NOTES_FILE);
1739  FILE *f = fopen (fname, NTXT ("r"));
1740  free (fname);
1741  if (f == NULL)
1742    return;
1743  if (!dbeSession->is_interactive ())
1744    {
1745      m = new Emsg (CMSG_COMMENT, NTXT ("Notes:"));
1746      notesq->append (m);
1747    }
1748
1749  while (1)
1750    {
1751      char str[MAXPATHLEN];
1752      char *e = fgets (str, ((int) sizeof (str)) - 1, f);
1753      if (e == NULL)
1754	{
1755	  if (!dbeSession->is_interactive ())
1756	    {
1757	      m = new Emsg (CMSG_COMMENT,
1758			    "============================================================");
1759	      notesq->append (m);
1760	    }
1761	  break;
1762	}
1763      size_t i = strlen (str);
1764      if (i > 0 && str[i - 1] == '\n')
1765	// remove trailing nl
1766	str[i - 1] = 0;
1767      m = new Emsg (CMSG_COMMENT, str);
1768      notesq->append (m);
1769    }
1770  (void) fclose (f);
1771}
1772
1773int
1774Experiment::save_notes (char* text, bool handle_file)
1775{
1776  if (handle_file)
1777    {
1778      FILE *fnotes;
1779      char *fname = dbe_sprintf (NTXT ("%s/%s"), expt_name, SP_NOTES_FILE);
1780      fnotes = fopen (fname, NTXT ("w"));
1781      free (fname);
1782      if (fnotes != NULL)
1783	{
1784	  (void) fprintf (fnotes, NTXT ("%s"), text);
1785	  fclose (fnotes);
1786	}
1787      else
1788	return 1; // Cannot write file
1789    }
1790  notesq->clear ();
1791  Emsg *m = new Emsg (CMSG_COMMENT, text);
1792  notesq->append (m);
1793
1794  return 0;
1795}
1796
1797int
1798Experiment::delete_notes (bool handle_file)
1799{
1800  if (handle_file)
1801    {
1802      char *fname = dbe_sprintf (NTXT ("%s/%s"), expt_name, SP_NOTES_FILE);
1803      if (unlink (fname) != 0)
1804	{
1805	  free (fname);
1806	  return 1; // Cannot delete file
1807	}
1808      free (fname);
1809    }
1810  notesq->clear ();
1811  return 0;
1812}
1813
1814int
1815Experiment::read_warn_file ()
1816{
1817  int local_status = SUCCESS;
1818
1819  ExperimentFile *warnFile = new ExperimentFile (this, SP_WARN_FILE);
1820  if (warnFile == NULL)
1821    return FAILURE;
1822  if (!warnFile->open ())
1823    {
1824      delete warnFile;
1825      return FAILURE;
1826    }
1827  SAXParserFactory *factory = SAXParserFactory::newInstance ();
1828  SAXParser *saxParser = factory->newSAXParser ();
1829  DefaultHandler *dh = new ExperimentHandler (this);
1830  try
1831    {
1832      saxParser->parse ((File*) warnFile->fh, dh);
1833    }
1834  catch (SAXException *e)
1835    {
1836      // Fatal error in the parser
1837      StringBuilder sb;
1838      sb.sprintf (NTXT ("%s: %s"), SP_WARN_FILE, e->getMessage ());
1839      char *str = sb.toString ();
1840      Emsg *m = new Emsg (CMSG_FATAL, str);
1841      errorq->append (m);
1842      local_status = FAILURE;
1843      delete e;
1844    }
1845  delete warnFile;
1846  delete dh;
1847  delete saxParser;
1848  delete factory;
1849
1850  return local_status;
1851}
1852
1853int
1854Experiment::read_log_file ()
1855{
1856  if (logFile == NULL)
1857    logFile = new ExperimentFile (this, SP_LOG_FILE);
1858  if (!logFile->open ())
1859    {
1860      status = FAILURE;
1861      return status;
1862    }
1863
1864  SAXParserFactory *factory = SAXParserFactory::newInstance ();
1865  SAXParser *saxParser = factory->newSAXParser ();
1866  DefaultHandler *dh = new ExperimentHandler (this);
1867  try
1868    {
1869      saxParser->parse ((File*) logFile->fh, dh);
1870    }
1871  catch (SAXException *e)
1872    {
1873      // Fatal error in the parser
1874      StringBuilder sb;
1875      if (obsolete == 1)
1876	sb.sprintf (NTXT ("%s"), e->getMessage ());
1877      else
1878	sb.sprintf (NTXT ("%s: %s"), SP_LOG_FILE, e->getMessage ());
1879      char *str = sb.toString ();
1880      Emsg *m = new Emsg (CMSG_FATAL, str);
1881      errorq->append (m);
1882      status = FAILURE;
1883      delete e;
1884    }
1885  logFile->close ();
1886  dbeSession->register_metric (GTXT ("IPC"), GTXT ("Instructions Per Cycle"),
1887			       NTXT ("insts/cycles"));
1888  dbeSession->register_metric (GTXT ("CPI"), GTXT ("Cycles Per Instruction"),
1889			       NTXT ("cycles/insts"));
1890  dbeSession->register_metric (GTXT ("K_IPC"),
1891			       GTXT ("Kernel Instructions Per Cycle"),
1892			       NTXT ("K_insts/K_cycles"));
1893  dbeSession->register_metric (GTXT ("K_CPI"),
1894			       GTXT ("Kernel Cycles Per Instruction"),
1895			       NTXT ("K_cycles/K_insts"));
1896
1897  delete dh;
1898  delete saxParser;
1899  delete factory;
1900
1901  return status;
1902}
1903
1904////////////////////////////////////////////////////////////////////////////////
1905//  class Experiment::ExperimentLabelsHandler
1906//
1907
1908class Experiment::ExperimentLabelsHandler : public DefaultHandler
1909{
1910public:
1911
1912  ExperimentLabelsHandler (Experiment *_exp)
1913  {
1914    exp = _exp;
1915  }
1916
1917  ~ExperimentLabelsHandler () { };
1918  void startDocument () { }
1919  void endDocument () { }
1920  void endElement (char * /*uri*/, char * /*localName*/, char * /*qName*/) { }
1921  void characters (char * /*ch*/, int /*start*/, int /*length*/) { }
1922  void ignorableWhitespace (char*, int, int) { }
1923  void error (SAXParseException * /*e*/) { }
1924
1925  void startElement (char *uri, char *localName, char *qName, Attributes *attrs);
1926
1927private:
1928
1929  inline const char *
1930  s2s (const char *s)
1931  {
1932    return s ? s : "NULL";
1933  }
1934
1935  Experiment *exp;
1936  char *hostname;
1937  hrtime_t time, tstamp;
1938};
1939
1940void
1941Experiment::ExperimentLabelsHandler::startElement (char*, char*, char *qName,
1942						   Attributes *attrs)
1943{
1944  DEBUG_CODE if (DEBUG_SAXPARSER) dump_startElement (qName, attrs);
1945  if (qName == NULL || strcmp (qName, NTXT ("id")) != 0)
1946    return;
1947  char *name = NULL, *all_times = NULL, *comment = NULL, *hostName = NULL;
1948  long startSec = 0;
1949  //    long tm_zone = 0;
1950  hrtime_t startHrtime = (hrtime_t) 0;
1951  long long lbl_ts = 0;
1952  int relative = 0;
1953  timeval start_tv;
1954  start_tv.tv_usec = start_tv.tv_sec = 0;
1955  for (int i = 0, sz = attrs ? attrs->getLength () : 0; i < sz; i++)
1956    {
1957      const char *qn = attrs->getQName (i);
1958      const char *vl = attrs->getValue (i);
1959      if (strcmp (qn, NTXT ("name")) == 0)
1960	name = dbe_xml2str (vl);
1961      else if (strcmp (qn, NTXT ("cmd")) == 0)
1962	all_times = dbe_xml2str (vl);
1963      else if (strcmp (qn, NTXT ("comment")) == 0)
1964	comment = dbe_xml2str (vl);
1965      else if (strcmp (qn, NTXT ("relative")) == 0)
1966	relative = atoi (vl);
1967      else if (strcmp (qn, NTXT ("hostname")) == 0)
1968	hostName = dbe_xml2str (vl);
1969      else if (strcmp (qn, NTXT ("time")) == 0)
1970	startSec = atol (vl);
1971      else if (strcmp (qn, NTXT ("tstamp")) == 0)
1972	startHrtime = parseTStamp (vl);
1973      else if (strcmp (qn, NTXT ("lbl_ts")) == 0)
1974	{
1975	  if (*vl == '-')
1976	    lbl_ts = -parseTStamp (vl + 1);
1977	  else
1978	    lbl_ts = parseTStamp (vl);
1979	}
1980    }
1981  if (name == NULL || hostName == NULL || (all_times == NULL && comment == NULL))
1982    {
1983      free (name);
1984      free (hostName);
1985      free (all_times);
1986      free (comment);
1987      return;
1988    }
1989  UserLabel *lbl = new UserLabel (name);
1990  lbl->comment = comment;
1991  lbl->hostname = hostName;
1992  lbl->start_sec = startSec;
1993  lbl->start_hrtime = startHrtime;
1994  exp->userLabels->append (lbl);
1995  if (all_times)
1996    {
1997      lbl->all_times = all_times;
1998      lbl->start_tv = start_tv;
1999      lbl->relative = relative;
2000      if (relative == UserLabel::REL_TIME)
2001	lbl->atime = lbl_ts;
2002      else
2003	{ // relative == UserLabel::CUR_TIME
2004	  long long delta = 0;
2005	  if (exp->hostname && strcmp (lbl->hostname, exp->hostname) == 0)
2006	    delta = lbl_ts + (lbl->start_hrtime - exp->exp_start_time);
2007	  else
2008	    for (int i = 0; i < exp->userLabels->size (); i++)
2009	      {
2010		UserLabel *firstLbl = exp->userLabels->fetch (i);
2011		if (strcmp (lbl->hostname, firstLbl->hostname) == 0)
2012		  {
2013		    delta = lbl_ts + (lbl->start_hrtime - firstLbl->start_hrtime) +
2014			    ((long long) (firstLbl->start_sec - exp->start_sec)) * NANOSEC;
2015		    break;
2016		  }
2017	      }
2018	  lbl->atime = delta > 0 ? delta : 0;
2019	}
2020    }
2021}
2022
2023static int
2024sortUserLabels (const void *a, const void *b)
2025{
2026  UserLabel *l1 = *((UserLabel **) a);
2027  UserLabel *l2 = *((UserLabel **) b);
2028  int v = dbe_strcmp (l1->name, l2->name);
2029  if (v != 0)
2030    return v;
2031  if (l1->atime < l2->atime)
2032    return -1;
2033  else if (l1->atime > l2->atime)
2034    return 1;
2035  if (l1->id < l2->id)
2036    return -1;
2037  else if (l1->id > l2->id)
2038    return 1;
2039  return 0;
2040}
2041
2042static char *
2043append_string (char *s, char *str)
2044{
2045  if (s == NULL)
2046    return dbe_strdup (str);
2047  char *new_s = dbe_sprintf (NTXT ("%s %s"), s, str);
2048  free (s);
2049  return new_s;
2050}
2051
2052void
2053Experiment::read_labels_file ()
2054{
2055  ExperimentFile *fp = new ExperimentFile (this, SP_LABELS_FILE);
2056  if (!fp->open ())
2057    {
2058      delete fp;
2059      return;
2060    }
2061  userLabels = new Vector<UserLabel*>();
2062  SAXParserFactory *factory = SAXParserFactory::newInstance ();
2063  SAXParser *saxParser = factory->newSAXParser ();
2064  DefaultHandler *dh = new ExperimentLabelsHandler (this);
2065  try
2066    {
2067      saxParser->parse ((File*) fp->fh, dh);
2068    }
2069  catch (SAXException *e)
2070    {
2071      // Fatal error in the parser
2072      StringBuilder sb;
2073      sb.sprintf (NTXT ("%s: %s"), SP_LABELS_FILE, e->getMessage ());
2074      char *str = sb.toString ();
2075      Emsg *m = new Emsg (CMSG_FATAL, str);
2076      errorq->append (m);
2077      delete e;
2078    }
2079  fp->close ();
2080  delete fp;
2081  delete dh;
2082  delete saxParser;
2083  delete factory;
2084
2085  userLabels->sort (sortUserLabels);
2086  UserLabel::dump ("After sortUserLabels:", userLabels);
2087  UserLabel *ulbl = NULL;
2088  for (int i = 0, sz = userLabels->size (); i < sz; i++)
2089    {
2090      UserLabel *lbl = userLabels->fetch (i);
2091      if (ulbl == NULL)
2092	ulbl = new UserLabel (lbl->name);
2093      else if (dbe_strcmp (lbl->name, ulbl->name) != 0)
2094	{ // new Label
2095	  ulbl->register_user_label (groupId);
2096	  if (ulbl->expr == NULL)
2097	    delete ulbl;
2098	  ulbl = new UserLabel (lbl->name);
2099	}
2100      if (lbl->all_times)
2101	{
2102	  if (strncmp (lbl->all_times, NTXT ("start"), 5) == 0)
2103	    {
2104	      if (!ulbl->start_f)
2105		{
2106		  ulbl->start_f = true;
2107		  ulbl->timeStart = lbl->atime;
2108		}
2109	    }
2110	  else
2111	    { // stop
2112	      if (!ulbl->start_f)
2113		continue;
2114	      ulbl->all_times = append_string (ulbl->all_times, lbl->all_times);
2115	      ulbl->stop_f = true;
2116	      ulbl->timeStop = lbl->atime;
2117	      ulbl->gen_expr ();
2118	    }
2119	}
2120      if (lbl->comment != NULL)
2121	ulbl->comment = append_string (ulbl->comment, lbl->comment);
2122    }
2123  if (ulbl)
2124    {
2125      ulbl->register_user_label (groupId);
2126      if (ulbl->expr == NULL)
2127	delete ulbl;
2128    }
2129  Destroy (userLabels);
2130}
2131
2132void
2133Experiment::read_archives ()
2134{
2135  if (founder_exp)
2136    return;
2137  char *allocated_str = NULL;
2138  char *nm = get_arch_name ();
2139  DIR *exp_dir = opendir (nm);
2140  if (exp_dir == NULL)
2141    {
2142      if (founder_exp == NULL)
2143	{
2144	  // Check if the user uses a subexperiment only
2145	  nm = dbe_sprintf (NTXT ("%s/../%s"), expt_name, SP_ARCHIVES_DIR);
2146	  exp_dir = opendir (nm);
2147	  if (exp_dir == NULL)
2148	    {
2149	      free (nm);
2150	      return;
2151	    }
2152	  allocated_str = nm;
2153	}
2154      else
2155	return;
2156    }
2157
2158  StringBuilder sb;
2159  sb.append (nm);
2160  sb.append ('/');
2161  int dlen = sb.length ();
2162  free (allocated_str);
2163  archiveMap = new StringMap<DbeFile *>();
2164
2165  struct dirent *entry = NULL;
2166  while ((entry = readdir (exp_dir)) != NULL)
2167    {
2168      char *dname = entry->d_name;
2169      if (dname[0] == '.'
2170	  && (dname[1] == '\0' || (dname[1] == '.' && dname[2] == '\0')))
2171	// skip links to ./ or ../
2172	continue;
2173      sb.setLength (dlen);
2174      sb.append (dname);
2175      char *fnm = sb.toString ();
2176      DbeFile *df = new DbeFile (fnm);
2177      df->set_location (fnm);
2178      df->filetype |= DbeFile::F_FILE;
2179      df->inArchive = true;
2180      df->experiment = this;
2181      archiveMap->put (dname, df);
2182      free (fnm);
2183    }
2184  closedir (exp_dir);
2185}
2186
2187static char *
2188gen_file_name (const char *packet_name, const char *src_name)
2189{
2190  char *fnm, *bname = get_basename (packet_name);
2191  if (bname == packet_name)
2192    fnm = dbe_strdup (src_name);
2193  else
2194    fnm = dbe_sprintf ("%.*s%s", (int) (bname - packet_name),
2195		       packet_name, src_name);
2196
2197  // convert "java.lang.Object/Integer.java" => "java/lang/Object/Integer.java"
2198  bname = get_basename (fnm);
2199  for (char *s = fnm; s < bname; s++)
2200    if (*s == '.')
2201      *s = '/';
2202  return fnm;
2203}
2204
2205static char *
2206get_jlass_name (const char *nm)
2207{
2208  // Convert "Ljava/lang/Object;" => "java/lang/Object.class"
2209  if (*nm == 'L')
2210    {
2211      size_t len = strlen (nm);
2212      if (nm[len - 1] == ';')
2213	return dbe_sprintf ("%.*s.class", (int) (len - 2), nm + 1);
2214    }
2215  return dbe_strdup (nm);
2216}
2217
2218static char *
2219get_jmodule_name (const char *nm)
2220{
2221  // convert "Ljava/lang/Object;" => "java.lang.Object"
2222  if (*nm == 'L')
2223    {
2224      size_t len = strlen (nm);
2225      if (nm[len - 1] == ';')
2226	{
2227	  char *mname = dbe_sprintf (NTXT ("%.*s"), (int) (len - 2), nm + 1);
2228	  for (char *s = mname; *s; s++)
2229	    if (*s == '/')
2230	      *s = '.';
2231	  return mname;
2232	}
2233    }
2234  return dbe_strdup (nm);
2235}
2236
2237LoadObject *
2238Experiment::get_j_lo (const char *className, const char *fileName)
2239{
2240  char *class_name = get_jlass_name (className);
2241  Dprintf (DUMP_JCLASS_READER,
2242	"Experiment::get_j_lo: className='%s' class_name='%s' fileName='%s'\n",
2243	   STR (className), STR (class_name), STR (fileName));
2244  LoadObject *lo = loadObjMap->get (class_name);
2245  if (lo == NULL)
2246    {
2247      lo = createLoadObject (class_name, fileName);
2248      lo->type = LoadObject::SEG_TEXT;
2249      lo->mtime = (time_t) 0;
2250      lo->size = 0;
2251      lo->set_platform (Java, wsize);
2252      lo->dbeFile->filetype |= DbeFile::F_FILE | DbeFile::F_JAVACLASS;
2253      append (lo);
2254      Dprintf (DUMP_JCLASS_READER,
2255	       "Experiment::get_j_lo: creates '%s' location='%s'\n",
2256	       STR (lo->get_name ()), STR (lo->dbeFile->get_location (false)));
2257    }
2258  free (class_name);
2259  return lo;
2260}
2261
2262Module *
2263Experiment::get_jclass (const char *className, const char *fileName)
2264{
2265  LoadObject *lo = get_j_lo (className, NULL);
2266  char *mod_name = get_jmodule_name (className);
2267  Module *mod = lo->find_module (mod_name);
2268  if (mod == NULL)
2269    {
2270      mod = dbeSession->createClassFile (mod_name);
2271      mod->loadobject = lo;
2272      if (strcmp (fileName, NTXT ("<Unknown>")) != 0)
2273	mod->set_file_name (gen_file_name (lo->get_pathname (), fileName));
2274      else
2275	mod->set_file_name (dbe_strdup (fileName));
2276      lo->append_module (mod);
2277      mod_name = NULL;
2278    }
2279  else if (mod->file_name && (strcmp (mod->file_name, "<Unknown>") == 0)
2280	   && strcmp (fileName, "<Unknown>") != 0)
2281    mod->set_file_name (gen_file_name (lo->get_pathname (), fileName));
2282  Dprintf (DUMP_JCLASS_READER,
2283	"Experiment::get_jclass: class_name='%s' mod_name='%s' fileName='%s'\n",
2284	   mod->loadobject->get_pathname (), mod->get_name (), mod->file_name);
2285  free (mod_name);
2286  return mod;
2287}
2288
2289#define ARCH_STRLEN(s) ( ( strlen(s) + 4 ) & ~0x3 )
2290
2291int
2292Experiment::read_java_classes_file ()
2293{
2294  char *data_file_name = dbe_sprintf (NTXT ("%s/%s"), expt_name, SP_JCLASSES_FILE);
2295  Data_window *dwin = new Data_window (data_file_name);
2296  free (data_file_name);
2297  if (dwin->not_opened ())
2298    {
2299      delete dwin;
2300      return INCOMPLETE;
2301    }
2302  dwin->need_swap_endian = need_swap_endian;
2303  jmaps = new PRBTree ();
2304  jmidHTable = new DbeCacheMap<unsigned long long, JMethod>;
2305
2306  hrtime_t cur_loaded = 0;
2307  Module *cur_mod = NULL;
2308  for (int64_t offset = 0;;)
2309    {
2310      CM_Packet *cpkt = (CM_Packet*) dwin->bind (offset, sizeof (CM_Packet));
2311      if (cpkt == NULL)
2312	break;
2313      uint16_t v16 = (uint16_t) cpkt->tsize;
2314      size_t cpktsize = dwin->decode (v16);
2315      cpkt = (CM_Packet*) dwin->bind (offset, cpktsize);
2316      if ((cpkt == NULL) || (cpktsize == 0))
2317	{
2318	  char *buf = dbe_sprintf (GTXT ("archive file malformed %s"),
2319				   arch_name);
2320	  errorq->append (new Emsg (CMSG_ERROR, buf));
2321	  free (buf);
2322	  break;
2323	}
2324      v16 = (uint16_t) cpkt->type;
2325      v16 = dwin->decode (v16);
2326      switch (v16)
2327	{
2328	case ARCH_JCLASS:
2329	  {
2330	    ARCH_jclass *ajcl = (ARCH_jclass*) cpkt;
2331	    uint64_t class_id = dwin->decode (ajcl->class_id);
2332	    char *className = ((char*) ajcl) + sizeof (*ajcl);
2333	    char *fileName = className + ARCH_STRLEN (className);
2334	    Dprintf (DUMP_JCLASS_READER,
2335		     "read_java_classes_file: ARCH_JCLASS(Ox%x)"
2336		     "class_id=Ox%llx className='%s' fileName='%s' \n",
2337		     (int) v16, (long long) class_id, className, fileName);
2338	    cur_mod = NULL;
2339	    if (*className == 'L')
2340	      { // Old libcollector generated '[' (one array dimension).
2341		cur_mod = get_jclass (className, fileName);
2342		cur_loaded = dwin->decode (ajcl->tstamp);
2343		jmaps->insert (class_id, cur_loaded, cur_mod);
2344	      }
2345	    break;
2346	  }
2347	case ARCH_JCLASS_LOCATION:
2348	  {
2349	    ARCH_jclass_location *ajcl = (ARCH_jclass_location *) cpkt;
2350	    uint64_t class_id = dwin->decode (ajcl->class_id);
2351	    char *className = ((char*) ajcl) + sizeof (*ajcl);
2352	    char *fileName = className + ARCH_STRLEN (className);
2353	    Dprintf (DUMP_JCLASS_READER,
2354		     "read_java_classes_file: ARCH_JCLASS_LOCATION(Ox%x)"
2355		     "class_id=Ox%llx className='%s' fileName='%s' \n",
2356		     (int) v16, (long long) class_id, className, fileName);
2357	    get_j_lo (className, fileName);
2358	    break;
2359	  }
2360	case ARCH_JMETHOD:
2361	  {
2362	    if (cur_mod == NULL)
2363	      break;
2364	    ARCH_jmethod *ajmt = (ARCH_jmethod*) cpkt;
2365	    uint64_t method_id = dwin->decode (ajmt->method_id);
2366	    char *s_name = ((char*) ajmt) + sizeof (*ajmt);
2367	    char *s_signature = s_name + ARCH_STRLEN (s_name);
2368	    char *fullname = dbe_sprintf ("%s.%s", cur_mod->get_name (), s_name);
2369	    Dprintf (DUMP_JCLASS_READER,
2370		     "read_java_classes_file: ARCH_JMETHOD(Ox%x) "
2371		     "method_id=Ox%llx name='%s' signature='%s' fullname='%s'\n",
2372		     (int) v16, (long long) method_id, s_name,
2373		     s_signature, fullname);
2374	    JMethod *jmthd = cur_mod->find_jmethod (fullname, s_signature);
2375	    if (jmthd == NULL)
2376	      {
2377		jmthd = dbeSession->createJMethod ();
2378		jmthd->size = (unsigned) - 1; // unknown until later (maybe)
2379		jmthd->module = cur_mod;
2380		jmthd->set_signature (s_signature);
2381		jmthd->set_name (fullname);
2382		cur_mod->functions->append (jmthd);
2383		cur_mod->loadobject->functions->append (jmthd);
2384		Dprintf (DUMP_JCLASS_READER,
2385		    "read_java_classes_file: ARCH_JMETHOD CREATE fullname=%s\n",
2386			 fullname);
2387	      }
2388	    jmaps->insert (method_id, cur_loaded, jmthd);
2389	    free (fullname);
2390	    break;
2391	  }
2392	default:
2393	  Dprintf (DUMP_JCLASS_READER,
2394		   "read_java_classes_file: type=Ox%x (%d) cpktsize=%d\n",
2395		   (int) v16, (int) v16, (int) cpktsize);
2396	  break; // ignore unknown packets
2397	}
2398      offset += cpktsize;
2399    }
2400  delete dwin;
2401  return SUCCESS;
2402}
2403
2404void
2405Experiment::read_map_file ()
2406{
2407  ExperimentFile *mapFile = new ExperimentFile (this, SP_MAP_FILE);
2408  if (!mapFile->open ())
2409    {
2410      delete mapFile;
2411      return;
2412    }
2413
2414  SAXParserFactory *factory = SAXParserFactory::newInstance ();
2415  SAXParser *saxParser = factory->newSAXParser ();
2416  DefaultHandler *dh = new ExperimentHandler (this);
2417  try
2418    {
2419      saxParser->parse ((File*) mapFile->fh, dh);
2420    }
2421  catch (SAXException *e)
2422    {
2423      // Fatal error in the parser
2424      StringBuilder sb;
2425      sb.sprintf (NTXT ("%s: %s"), SP_MAP_FILE, e->getMessage ());
2426      char *str = sb.toString ();
2427      Emsg *m = new Emsg (CMSG_FATAL, str);
2428      errorq->append (m);
2429      status = FAILURE;
2430      free (str);
2431      delete e;
2432    }
2433  delete mapFile;
2434  delete dh;
2435  delete saxParser;
2436  delete factory;
2437
2438  for (int i = 0, sz = mrecs ? mrecs->size () : 0; i < sz; i++)
2439    {
2440      MapRecord *mrec = mrecs->fetch (i);
2441      SegMem *smem, *sm_lo, *sm_hi;
2442      switch (mrec->kind)
2443	{
2444	case MapRecord::LOAD:
2445	  smem = new SegMem;
2446	  smem->base = mrec->base;
2447	  smem->size = mrec->size;
2448	  smem->load_time = mrec->ts;
2449	  smem->unload_time = MAX_TIME;
2450	  smem->obj = mrec->obj;
2451	  smem->set_file_offset (mrec->foff);
2452	  seg_items->append (smem); // add to the master list
2453
2454	  // Check if the new segment overlaps other active segments
2455	  sm_lo = (SegMem*) maps->locate (smem->base, smem->load_time);
2456	  if (sm_lo && sm_lo->base + sm_lo->size > smem->base)
2457	    {
2458	      // check to see if it is a duplicate record: same address and size, and
2459	      if ((smem->base == sm_lo->base) && (smem->size == sm_lo->size))
2460		{
2461		  // addresses and sizes match, check name
2462		  if (strstr (smem->obj->get_name (), sm_lo->obj->get_name ()) != NULL
2463		      || strstr (sm_lo->obj->get_name (), smem->obj->get_name ()) != NULL)
2464		    // this is a duplicate; just move on the the next map record
2465		    continue;
2466		  fprintf (stderr,
2467			   GTXT ("*** Warning: Segment `%s' loaded with same address, size as `%s' [0x%llx-0x%llx]\n"),
2468			   smem->obj->get_name (), sm_lo->obj->get_name (),
2469			   sm_lo->base, sm_lo->base + sm_lo->size);
2470		}
2471
2472	      // Not a duplicate; implicitly unload the old one
2473	      //     Note: implicit unloading causes high <Unknown>
2474	      //           when such overlapping is bogus
2475	      StringBuilder sb;
2476	      sb.sprintf (GTXT ("*** Warning: Segment %s [0x%llx-0x%llx] overlaps %s [0x%llx-0x%llx], which has been implicitly unloaded"),
2477			  smem->obj->get_name (), smem->base, smem->base + smem->size,
2478			  sm_lo->obj->get_name (), sm_lo->base, sm_lo->base + sm_lo->size);
2479	      warnq->append (new Emsg (CMSG_WARN, sb));
2480	    }
2481
2482	  // now look for other segments with which this might overlap
2483	  sm_hi = (SegMem*) maps->locate_up (smem->base, smem->load_time);
2484	  while (sm_hi && sm_hi->base < smem->base + smem->size)
2485	    {
2486
2487	      // Note: implicit unloading causes high <Unknown> when such overlapping is bogus
2488	      // maps->remove( sm_hi->base, smem->load_time );
2489	      StringBuilder sb;
2490	      sb.sprintf (GTXT ("*** Warning: Segment %s [0x%llx-0x%llx] overlaps %s [0x%llx-0x%llx], which has been implicitly unloaded"),
2491			  smem->obj->get_name (), smem->base,
2492			  smem->base + smem->size, sm_hi->obj->get_name (),
2493			  sm_hi->base, sm_hi->base + sm_hi->size);
2494	      warnq->append (new Emsg (CMSG_WARN, sb));
2495	      sm_hi = (SegMem*) maps->locate_up (sm_hi->base + sm_hi->size,
2496						 smem->load_time);
2497	    }
2498
2499	  maps->insert (smem->base, smem->load_time, smem);
2500	  break;
2501	case MapRecord::UNLOAD:
2502	  smem = (SegMem*) maps->locate (mrec->base, mrec->ts);
2503	  if (smem && smem->base == mrec->base)
2504	    {
2505	      smem->unload_time = mrec->ts;
2506	      maps->remove (mrec->base, mrec->ts);
2507	    }
2508	  break;
2509	}
2510    }
2511  mrecs->destroy ();
2512
2513  // See if there are comments or warnings for a load object;
2514  // if so, queue them to Experiment
2515  for (long i = 0, sz = loadObjs ? loadObjs->size () : 0; i < sz; i++)
2516    {
2517      LoadObject *lo = loadObjs->get (i);
2518      for (Emsg *m = lo->fetch_warnings (); m; m = m->next)
2519	warnq->append (m->get_warn (), m->get_msg ());
2520      for (Emsg *m = lo->fetch_comments (); m; m = m->next)
2521	commentq->append (m->get_warn (), m->get_msg ());
2522    }
2523}
2524
2525void
2526Experiment::read_frameinfo_file ()
2527{
2528  init_cache ();
2529  char *base_name = get_basename (expt_name);
2530  char *msg = dbe_sprintf (GTXT ("Loading CallStack Data: %s"), base_name);
2531  read_data_file ("data." SP_FRINFO_FILE, msg);
2532  free (msg);
2533  frmpckts->sort (frUidCmp);
2534  uidnodes->sort (uidNodeCmp);
2535}
2536
2537void
2538Experiment::read_omp_preg ()
2539{
2540  // Parallel region descriptions
2541  DataDescriptor *pregDdscr = getDataDescriptor (DATA_OMP4);
2542  if (pregDdscr == NULL)
2543    return;
2544  DataView *pregData = pregDdscr->createView ();
2545  pregData->sort (PROP_CPRID); // omptrace PROP_CPRID
2546
2547  // OpenMP enter parreg events
2548  DataDescriptor *dDscr = getDataDescriptor (DATA_OMP2);
2549  if (dDscr == NULL || dDscr->getSize () == 0)
2550    {
2551      delete pregData;
2552      return;
2553    }
2554
2555  char *idxname = NTXT ("OMP_preg");
2556  delete dbeSession->indxobj_define (idxname, GTXT ("OpenMP Parallel Region"),
2557				     NTXT ("CPRID"), NULL, NULL);
2558  int idxtype = dbeSession->findIndexSpaceByName (idxname);
2559  if (idxtype < 0)
2560    {
2561      delete pregData;
2562      return;
2563    }
2564  ompavail = true;
2565
2566  // Pre-create parallel region with id == 0
2567  Histable *preg0 = dbeSession->createIndexObject (idxtype, (int64_t) 0);
2568  preg0->set_name (dbe_strdup (GTXT ("Implicit OpenMP Parallel Region")));
2569
2570  // Take care of the progress bar
2571  char *msg = dbe_sprintf (GTXT ("Processing OpenMP Parallel Region Data: %s"),
2572  get_basename (expt_name));
2573  theApplication->set_progress (0, msg);
2574  free (msg);
2575  long deltaReport = 1000;
2576  long nextReport = 0;
2577  long errors_found = 0;
2578  Vector<Histable*> pregs;
2579
2580  long size = dDscr->getSize ();
2581  for (long i = 0; i < size; ++i)
2582    {
2583      if (i == nextReport)
2584	{
2585	  int percent = (int) (i * 100 / size);
2586	  if (percent > 0)
2587	    theApplication->set_progress (percent, NULL);
2588	  nextReport += deltaReport;
2589	}
2590
2591      uint32_t thrid = dDscr->getIntValue (PROP_THRID, i);
2592      hrtime_t tstamp = dDscr->getLongValue (PROP_TSTAMP, i);
2593      uint64_t cprid = dDscr->getLongValue (PROP_CPRID, i); // omptrace CPRID
2594      mapPRid->put (thrid, tstamp, cprid);
2595
2596      pregs.reset ();
2597      /*
2598       * We will use 2 pointers to make sure there is no loop.
2599       * First pointer "curpreg" goes to the next element,
2600       * second pointer "curpreg_loop_control" goes to the next->next element.
2601       * If these pointers have the same value - there is a loop.
2602       */
2603      uint64_t curpreg_loop_control = cprid;
2604      Datum tval_loop_control;
2605      if (curpreg_loop_control != 0)
2606	{
2607	  tval_loop_control.setUINT64 (curpreg_loop_control);
2608	  long idx = pregData->getIdxByVals (&tval_loop_control, DataView::REL_EQ);
2609	  if (idx < 0)
2610	    curpreg_loop_control = 0;
2611	  else
2612	    curpreg_loop_control = pregData->getLongValue (PROP_PPRID, idx);
2613	}
2614      for (uint64_t curpreg = cprid; curpreg != 0;)
2615	{
2616	  Histable *val = NULL;
2617	  Datum tval;
2618	  tval.setUINT64 (curpreg);
2619	  long idx = pregData->getIdxByVals (&tval, DataView::REL_EQ);
2620	  if (idx < 0)
2621	    break;
2622	  /*
2623	   * Check if there is a loop
2624	   */
2625	  if (0 != curpreg_loop_control)
2626	    {
2627	      if (curpreg == curpreg_loop_control)
2628		{
2629		  errors_found++;
2630		  if (1 == errors_found)
2631		    {
2632		      Emsg *m = new Emsg (CMSG_WARN, GTXT ("*** Warning: circular links in OMP regions; data may not be correct."));
2633		      warnq->append (m);
2634		    }
2635		  break;
2636		}
2637	    }
2638	  uint64_t pragmapc = pregData->getLongValue (PROP_PRPC, idx);
2639	  DbeInstr *instr = map_Vaddr_to_PC (pragmapc, tstamp);
2640	  if (instr == NULL)
2641	    {
2642	      break;
2643	    }
2644	  val = instr;
2645	  DbeLine *dbeline = (DbeLine*) instr->convertto (Histable::LINE);
2646	  if (dbeline->lineno > 0)
2647	    {
2648	      if (instr->func->usrfunc)
2649		dbeline = dbeline->sourceFile->find_dbeline
2650			(instr->func->usrfunc, dbeline->lineno);
2651	      dbeline->set_flag (DbeLine::OMPPRAGMA);
2652	      val = dbeline;
2653	    }
2654	  val = dbeSession->createIndexObject (idxtype, val);
2655	  pregs.append (val);
2656
2657	  curpreg = pregData->getLongValue (PROP_PPRID, idx);
2658	  /*
2659	   * Update curpreg_loop_control
2660	   */
2661	  if (0 != curpreg_loop_control)
2662	    {
2663	      tval_loop_control.setUINT64 (curpreg_loop_control);
2664	      idx = pregData->getIdxByVals
2665		      (&tval_loop_control, DataView::REL_EQ);
2666	      if (idx < 0)
2667		curpreg_loop_control = 0;
2668	      else
2669		{
2670		  curpreg_loop_control = pregData->getLongValue
2671			  (PROP_PPRID, idx);
2672		  tval_loop_control.setUINT64 (curpreg_loop_control);
2673		  idx = pregData->getIdxByVals
2674			  (&tval_loop_control, DataView::REL_EQ);
2675		  if (idx < 0)
2676		    curpreg_loop_control = 0;
2677		  else
2678		    curpreg_loop_control = pregData->getLongValue
2679			    (PROP_PPRID, idx);
2680		}
2681	    }
2682	}
2683      pregs.append (preg0);
2684      void *prstack = cstack->add_stack (&pregs);
2685      mapPReg->put (thrid, tstamp, prstack);
2686    }
2687  theApplication->set_progress (0, NTXT (""));
2688  delete pregData;
2689}
2690
2691void
2692Experiment::read_omp_task ()
2693{
2694  // Task description
2695  DataDescriptor *taskDataDdscr = getDataDescriptor (DATA_OMP5);
2696  if (taskDataDdscr == NULL)
2697    return;
2698
2699  //7035272: previously, DataView was global; now it's local...is this OK?
2700  DataView *taskData = taskDataDdscr->createView ();
2701  taskData->sort (PROP_TSKID); // omptrace PROP_TSKID
2702
2703  // OpenMP enter task events
2704  DataDescriptor *dDscr = getDataDescriptor (DATA_OMP3);
2705  if (dDscr == NULL || dDscr->getSize () == 0)
2706    {
2707      delete taskData;
2708      return;
2709    }
2710
2711  char *idxname = NTXT ("OMP_task");
2712  // delete a possible error message. Ugly.
2713  delete dbeSession->indxobj_define (idxname, GTXT ("OpenMP Task"), NTXT ("TSKID"), NULL, NULL);
2714  int idxtype = dbeSession->findIndexSpaceByName (idxname);
2715  if (idxtype < 0)
2716    {
2717      delete taskData;
2718      return;
2719    }
2720  ompavail = true;
2721
2722  // Pre-create task with id == 0
2723  Histable *task0 = dbeSession->createIndexObject (idxtype, (int64_t) 0);
2724  task0->set_name (dbe_strdup (GTXT ("OpenMP Task from Implicit Parallel Region")));
2725
2726  // Take care of the progress bar
2727  char *msg = dbe_sprintf (GTXT ("Processing OpenMP Task Data: %s"), get_basename (expt_name));
2728  theApplication->set_progress (0, msg);
2729  free (msg);
2730  long deltaReport = 1000;
2731  long nextReport = 0;
2732
2733  Vector<Histable*> tasks;
2734  long size = dDscr->getSize ();
2735  long errors_found = 0;
2736  for (long i = 0; i < size; ++i)
2737    {
2738      if (i == nextReport)
2739	{
2740	  int percent = (int) (i * 100 / size);
2741	  if (percent > 0)
2742	    theApplication->set_progress (percent, NULL);
2743	  nextReport += deltaReport;
2744	}
2745
2746      uint32_t thrid = dDscr->getIntValue (PROP_THRID, i);
2747      hrtime_t tstamp = dDscr->getLongValue (PROP_TSTAMP, i);
2748      uint64_t tskid = dDscr->getLongValue (PROP_TSKID, i); //omptrace TSKID
2749      tasks.reset ();
2750      /*
2751       * We will use 2 pointers to make sure there is no loop.
2752       * First pointer "curtsk" goes to the next element,
2753       * second pointer "curtsk_loop_control" goes to the next->next element.
2754       * If these pointers have the same value - there is a loop.
2755       */
2756      uint64_t curtsk_loop_control = tskid;
2757      Datum tval_loop_control;
2758      if (curtsk_loop_control != 0)
2759	{
2760	  tval_loop_control.setUINT64 (curtsk_loop_control);
2761	  long idx = taskData->getIdxByVals (&tval_loop_control, DataView::REL_EQ);
2762	  if (idx < 0)
2763	    curtsk_loop_control = 0;
2764	  else
2765	    curtsk_loop_control = taskData->getLongValue (PROP_PTSKID, idx);
2766	}
2767      for (uint64_t curtsk = tskid; curtsk != 0;)
2768	{
2769	  Histable *val = NULL;
2770
2771	  Datum tval;
2772	  tval.setUINT64 (curtsk);
2773	  long idx = taskData->getIdxByVals (&tval, DataView::REL_EQ);
2774	  if (idx < 0)
2775	    break;
2776	  /*
2777	   * Check if there is a loop
2778	   */
2779	  if (0 != curtsk_loop_control)
2780	    {
2781	      if (curtsk == curtsk_loop_control)
2782		{
2783		  errors_found++;
2784		  if (1 == errors_found)
2785		    {
2786		      Emsg *m = new Emsg (CMSG_WARN, GTXT ("*** Warning: circular links in OMP tasks; data may not be correct."));
2787		      warnq->append (m);
2788		    }
2789		  break;
2790		}
2791	    }
2792	  uint64_t pragmapc = taskData->getLongValue (PROP_PRPC, idx);
2793	  DbeInstr *instr = map_Vaddr_to_PC (pragmapc, tstamp);
2794	  if (instr == NULL)
2795	    break;
2796	  val = instr;
2797	  DbeLine *dbeline = (DbeLine*) instr->convertto (Histable::LINE);
2798	  if (dbeline->lineno > 0)
2799	    {
2800	      if (instr->func->usrfunc)
2801		dbeline = dbeline->sourceFile->find_dbeline
2802			(instr->func->usrfunc, dbeline->lineno);
2803	      dbeline->set_flag (DbeLine::OMPPRAGMA);
2804	      val = dbeline;
2805	    }
2806	  val = dbeSession->createIndexObject (idxtype, val);
2807	  tasks.append (val);
2808
2809	  curtsk = taskData->getLongValue (PROP_PTSKID, idx);
2810	  /*
2811	   * Update curtsk_loop_control
2812	   */
2813	  if (0 != curtsk_loop_control)
2814	    {
2815	      tval_loop_control.setUINT64 (curtsk_loop_control);
2816	      idx = taskData->getIdxByVals (&tval_loop_control, DataView::REL_EQ);
2817	      if (idx < 0)
2818		curtsk_loop_control = 0;
2819	      else
2820		{
2821		  curtsk_loop_control = taskData->getLongValue (PROP_PTSKID, idx);
2822		  tval_loop_control.setUINT64 (curtsk_loop_control);
2823		  idx = taskData->getIdxByVals (&tval_loop_control,
2824						DataView::REL_EQ);
2825		  if (idx < 0)
2826		    curtsk_loop_control = 0;
2827		  else
2828		    curtsk_loop_control = taskData->getLongValue (PROP_PTSKID,
2829								  idx);
2830		}
2831	    }
2832	}
2833      tasks.append (task0);
2834      void *tskstack = cstack->add_stack (&tasks);
2835      mapTask->put (thrid, tstamp, tskstack);
2836    }
2837  theApplication->set_progress (0, NTXT (""));
2838  delete taskData;
2839}
2840
2841void
2842Experiment::read_omp_file ()
2843{
2844  // DATA_OMP2 table is common between OpenMP 2.5 and 3.0 profiling
2845  DataDescriptor *dDscr = getDataDescriptor (DATA_OMP2);
2846  if (dDscr == NULL)
2847    return;
2848  if (dDscr->getSize () == 0)
2849    {
2850      char *base_name = get_basename (expt_name);
2851      char *msg = dbe_sprintf (GTXT ("Loading OpenMP Data: %s"), base_name);
2852      read_data_file (SP_OMPTRACE_FILE, msg);
2853      free (msg);
2854
2855      // OpenMP fork events
2856      dDscr = getDataDescriptor (DATA_OMP);
2857      long sz = dDscr->getSize ();
2858      if (sz > 0)
2859	{
2860	  // progress bar
2861	  msg = dbe_sprintf (GTXT ("Processing OpenMP Parallel Region Data: %s"),
2862			     base_name);
2863	  theApplication->set_progress (0, msg);
2864	  free (msg);
2865	  long deltaReport = 5000;
2866	  long nextReport = 0;
2867	  for (int i = 0; i < sz; ++i)
2868	    {
2869	      if (i == nextReport)
2870		{
2871		  int percent = (int) (i * 100 / sz);
2872		  if (percent > 0)
2873		    theApplication->set_progress (percent, NULL);
2874		  nextReport += deltaReport;
2875		}
2876	      uint32_t thrid = dDscr->getIntValue (PROP_THRID, i);
2877	      hrtime_t tstamp = dDscr->getLongValue (PROP_TSTAMP, i);
2878	      uint64_t cprid = dDscr->getLongValue (PROP_CPRID, i); //omptrace
2879	      mapPRid->put (thrid, tstamp, cprid);
2880	    }
2881	  theApplication->set_progress (0, NTXT (""));
2882
2883	  ompavail = true;
2884	  openMPdata = dDscr->createView ();
2885	  openMPdata->sort (PROP_CPRID); // omptrace PROP_CPRID
2886
2887	  // thread enters parreg events
2888	  dDscr = getDataDescriptor (DATA_OMP2);
2889	  sz = dDscr->getSize ();
2890
2891	  // progress bar
2892	  msg = dbe_sprintf (GTXT ("Processing OpenMP Parallel Region Data: %s"),
2893			     base_name);
2894	  theApplication->set_progress (0, msg);
2895	  free (msg);
2896	  deltaReport = 5000;
2897	  nextReport = 0;
2898
2899	  for (int i = 0; i < sz; ++i)
2900	    {
2901	      if (i == nextReport)
2902		{
2903		  int percent = (int) (i * 100 / sz);
2904		  if (percent > 0)
2905		    theApplication->set_progress (percent, NULL);
2906		  nextReport += deltaReport;
2907		}
2908	      uint32_t thrid = dDscr->getIntValue (PROP_THRID, i);
2909	      hrtime_t tstamp = dDscr->getLongValue (PROP_TSTAMP, i);
2910	      uint64_t cprid = dDscr->getLongValue (PROP_CPRID, i); //omptrace
2911	      mapPRid->put (thrid, tstamp, cprid);
2912	    }
2913	  theApplication->set_progress (0, NTXT (""));
2914	}
2915      else
2916	{
2917	  read_omp_preg ();
2918	  read_omp_task ();
2919	}
2920      if (ompavail && coll_params.profile_mode)
2921	{
2922	  dbeSession->status_ompavail = 1;
2923	  register_metric (Metric::OMP_WORK);
2924	  register_metric (Metric::OMP_WAIT);
2925	  register_metric (Metric::OMP_OVHD);
2926	  if (coll_params.lms_magic_id == LMS_MAGIC_ID_SOLARIS)
2927	    register_metric (Metric::OMP_MASTER_THREAD);
2928	}
2929    }
2930}
2931
2932void
2933Experiment::read_ifreq_file ()
2934{
2935  char *fname = dbe_sprintf (NTXT ("%s/%s"), expt_name, SP_IFREQ_FILE);
2936  FILE *f = fopen (fname, NTXT ("r"));
2937  free (fname);
2938  if (f == NULL)
2939    {
2940      ifreqavail = false;
2941      return;
2942    }
2943  ifreqavail = true;
2944  ifreqq = new Emsgqueue (NTXT ("ifreqq"));
2945
2946  while (1)
2947    {
2948      Emsg *m;
2949      char str[MAXPATHLEN];
2950      char *e = fgets (str, ((int) sizeof (str)) - 1, f);
2951      if (e == NULL)
2952	{
2953	  // end the list from the experiment
2954	  m = new Emsg (CMSG_COMMENT,
2955			GTXT ("============================================================"));
2956	  ifreqq->append (m);
2957	  break;
2958	}
2959      // get the string
2960      size_t i = strlen (str);
2961      if (i > 0 && str[i - 1] == '\n')
2962	// remove trailing nl
2963	str[i - 1] = 0;
2964      // and append it
2965      m = new Emsg (CMSG_COMMENT, str);
2966      ifreqq->append (m);
2967    }
2968  (void) fclose (f);
2969}
2970
2971Experiment *
2972Experiment::getBaseFounder ()
2973{
2974  if (baseFounder)
2975    return baseFounder;
2976  Experiment *founder = this;
2977  Experiment *parent = founder->founder_exp;
2978  while (parent)
2979    {
2980      founder = parent;
2981      parent = founder->founder_exp;
2982    }
2983  baseFounder = founder;
2984  return baseFounder;
2985}
2986
2987hrtime_t
2988Experiment::getRelativeStartTime ()
2989{
2990  if (exp_rel_start_time_set)
2991    return exp_rel_start_time;
2992  Experiment *founder = getBaseFounder ();
2993  hrtime_t child_start = this->getStartTime ();
2994  hrtime_t founder_start = founder->getStartTime ();
2995  exp_rel_start_time = child_start - founder_start;
2996  if (child_start == 0 && founder_start)
2997    exp_rel_start_time = 0;     // when descendents have incomplete log.xml
2998  exp_rel_start_time_set = true;
2999  return exp_rel_start_time;
3000}
3001
3002DataDescriptor *
3003Experiment::get_raw_events (int data_id)
3004{
3005  DataDescriptor *dDscr;
3006  switch (data_id)
3007    {
3008    case DATA_CLOCK:
3009      dDscr = get_profile_events ();
3010      break;
3011    case DATA_SYNCH:
3012      dDscr = get_sync_events ();
3013      break;
3014    case DATA_HWC:
3015      dDscr = get_hwc_events ();
3016      break;
3017    case DATA_HEAP:
3018      dDscr = get_heap_events ();
3019      break;
3020    case DATA_HEAPSZ:
3021      dDscr = get_heapsz_events ();
3022      break;
3023    case DATA_IOTRACE:
3024      dDscr = get_iotrace_events ();
3025      break;
3026    case DATA_RACE:
3027      dDscr = get_race_events ();
3028      break;
3029    case DATA_DLCK:
3030      dDscr = get_deadlock_events ();
3031      break;
3032    case DATA_SAMPLE:
3033      dDscr = get_sample_events ();
3034      break;
3035    case DATA_GCEVENT:
3036      dDscr = get_gc_events ();
3037      break;
3038    default:
3039      dDscr = NULL;
3040      break;
3041    }
3042  return dDscr;
3043}
3044
3045int
3046Experiment::base_data_id (int data_id)
3047{
3048  switch (data_id)
3049    {
3050    case DATA_HEAPSZ:
3051      return DATA_HEAP; // DATA_HEAPSZ DataView is based on DATA_HEAP's DataView
3052    default:
3053      break;
3054    }
3055  return data_id;
3056}
3057
3058DataView *
3059Experiment::create_derived_data_view (int data_id, DataView *dview)
3060{
3061  // dview contains filtered packets
3062  switch (data_id)
3063    {
3064    case DATA_HEAPSZ:
3065      return create_heapsz_data_view (dview);
3066    default:
3067      break;
3068    }
3069  return NULL;
3070}
3071
3072DataDescriptor *
3073Experiment::get_profile_events ()
3074{
3075  DataDescriptor *dDscr = getDataDescriptor (DATA_CLOCK);
3076  if (dDscr == NULL)
3077    return NULL;
3078  if (dDscr->getSize () == 0)
3079    {
3080      char *base_name = get_basename (expt_name);
3081      char *msg = dbe_sprintf (GTXT ("Loading Profile Data: %s"), base_name);
3082      read_data_file (SP_PROFILE_FILE, msg);
3083      free (msg);
3084      add_evt_time_to_profile_events (dDscr);
3085      resolve_frame_info (dDscr);
3086    }
3087  else if (!dDscr->isResolveFrInfoDone ())
3088    resolve_frame_info (dDscr);
3089  return dDscr;
3090}
3091
3092void
3093Experiment::add_evt_time_to_profile_events (DataDescriptor *dDscr)
3094{
3095  if (coll_params.lms_magic_id != LMS_MAGIC_ID_SOLARIS)
3096    return;
3097
3098  DataView *dview = dDscr->createView ();
3099  dview->sort (PROP_THRID, PROP_TSTAMP);
3100
3101  // add PROP_EVT_TIME
3102  PropDescr* tmp_propDscr = new PropDescr (PROP_EVT_TIME, "EVT_TIME");
3103  tmp_propDscr->uname = dbe_strdup (GTXT ("Event duration"));
3104  tmp_propDscr->vtype = TYPE_INT64;
3105  dDscr->addProperty (tmp_propDscr);
3106
3107  long sz = dview->getSize ();
3108  long long ptimer_usec = get_params ()->ptimer_usec;
3109  for (long i = 0; i < sz; i++)
3110    {
3111      int next_sample;
3112      int jj;
3113      {
3114	hrtime_t this_tstamp = dview->getLongValue (PROP_TSTAMP, i);
3115	long this_thrid = dview->getLongValue (PROP_THRID, i);
3116	for (jj = i + 1; jj < sz; jj++)
3117	  {
3118	    hrtime_t tmp_tstamp = dview->getLongValue (PROP_TSTAMP, jj);
3119	    if (tmp_tstamp != this_tstamp)
3120	      break;
3121	    long tmp_thrid = dview->getLongValue (PROP_THRID, jj);
3122	    if (tmp_thrid != this_thrid)
3123	      break;
3124	  }
3125	next_sample = jj;
3126      }
3127
3128      long nticks = 0;
3129      for (jj = i; jj < next_sample; jj++)
3130	nticks += dview->getLongValue (PROP_NTICK, jj);
3131      if (nticks <= 1)
3132	continue; // no duration
3133
3134      nticks--;
3135      hrtime_t duration = ptimer_usec * 1000LL * nticks; // nanoseconds
3136      for (jj = i; jj < next_sample; jj++)
3137	dview->setValue (PROP_EVT_TIME, jj, duration);
3138      i = jj - 1;
3139    }
3140  delete dview;
3141}
3142
3143DataDescriptor *
3144Experiment::get_sync_events ()
3145{
3146  DataDescriptor *dDscr = getDataDescriptor (DATA_SYNCH);
3147  if (dDscr == NULL)
3148    return NULL;
3149  if (dDscr->getSize () > 0)
3150    return dDscr;
3151
3152  // fetch data
3153  {
3154    char *base_name = get_basename (expt_name);
3155    char *msg = dbe_sprintf (GTXT ("Loading Synctrace Data: %s"), base_name);
3156    read_data_file (SP_SYNCTRACE_FILE, msg);
3157    free (msg);
3158    resolve_frame_info (dDscr);
3159  }
3160
3161  // check for PROP_EVT_TIME
3162  PropDescr *tmp_propDscr = dDscr->getProp (PROP_EVT_TIME);
3163  if (tmp_propDscr)
3164    return dDscr;
3165
3166  // add PROP_EVT_TIME
3167  tmp_propDscr = new PropDescr (PROP_EVT_TIME, "EVT_TIME");
3168  tmp_propDscr->uname = dbe_strdup (GTXT ("Event duration"));
3169  tmp_propDscr->vtype = TYPE_INT64;
3170  dDscr->addProperty (tmp_propDscr);
3171
3172  long sz = dDscr->getSize ();
3173  for (long i = 0; i < sz; i++)
3174    {
3175      uint64_t event_duration = dDscr->getLongValue (PROP_TSTAMP, i);
3176      event_duration -= dDscr->getLongValue (PROP_SRQST, i);
3177      dDscr->setValue (PROP_EVT_TIME, i, event_duration);
3178    }
3179  return dDscr;
3180}
3181
3182DataDescriptor *
3183Experiment::get_hwc_events ()
3184{
3185  DataDescriptor *dDscr = getDataDescriptor (DATA_HWC);
3186  if (dDscr == NULL)
3187    return NULL;
3188  if (dDscr->getSize () == 0)
3189    {
3190      char *base_name = get_basename (expt_name);
3191      char *msg = dbe_sprintf (GTXT ("Loading HW Profile Data: %s"), base_name);
3192
3193      // clear HWC event stats
3194      dsevents = 0;
3195      dsnoxhwcevents = 0;
3196      read_data_file (SP_HWCNTR_FILE, msg);
3197      free (msg);
3198      resolve_frame_info (dDscr);
3199
3200      // describe the HW counters in PropDescr
3201      PropDescr *prop = dDscr->getProp (PROP_HWCTAG);
3202      if (prop)
3203	{
3204	  Collection_params *cparam = get_params ();
3205	  if (cparam->hw_mode != 0)
3206	    for (int aux = 0; aux < MAX_HWCOUNT; aux++)
3207	      if (cparam->hw_aux_name[aux])
3208		{
3209		  const char* cmdname = cparam->hw_aux_name[aux];
3210		  const char* uname = cparam->hw_username[aux];
3211		  prop->addState (aux, cmdname, uname);
3212		}
3213	}
3214      else
3215	assert (0);
3216
3217      double dserrrate = 100.0 * ((double) dsnoxhwcevents) / ((double) dsevents);
3218      if ((dsevents > 0) && (dserrrate > 10.0))
3219	{
3220	  // warn the user that rate is high
3221	  StringBuilder sb;
3222	  if (dbeSession->check_ignore_no_xhwcprof ())
3223	    sb.sprintf (
3224			GTXT ("Warning: experiment %s has %.1f%%%% (%lld of %lld) dataspace events that were accepted\n  without verification; data may be incorrect or misleading\n  recompile with -xhwcprof and rerecord to get better data\n"),
3225			base_name, dserrrate, (long long) dsnoxhwcevents,
3226			(long long) dsevents);
3227	  else
3228	    sb.sprintf (
3229			GTXT ("Warning: experiment %s has %.1f%%%% (%lld of %lld) dataspace events that could not be verified\n  recompile with -xhwcprof and rerecord to get better data\n"),
3230			base_name, dserrrate, (long long) dsnoxhwcevents,
3231			(long long) dsevents);
3232	  errorq->append (new Emsg (CMSG_WARN, sb));
3233	}
3234
3235      // see if we've scanned the data
3236      if (hwc_scanned == 0)
3237	{
3238	  // no, scan the packets to see how many are bogus, or represent lost interrupts
3239	  long hwc_cnt = 0;
3240
3241	  // loop over the packets, counting the bad ones
3242	  if (hwc_bogus != 0 || hwc_lost_int != 0)
3243	    {
3244	      // hwc counter data had bogus packets and/or packets reflecting lost interrupts
3245	      double bogus_rate = 100. * (double) hwc_bogus / (double) hwc_cnt;
3246	      if (bogus_rate > 5.)
3247		{
3248		  StringBuilder sb;
3249		  sb.sprintf (
3250			      GTXT ("WARNING: Too many invalid HW counter profile events (%ld/%ld = %3.2f%%) in experiment %d (`%s'); data may be unreliable"),
3251			      (long) hwc_bogus, (long) hwc_cnt, bogus_rate,
3252			      (int) userExpId, base_name);
3253		  Emsg *m = new Emsg (CMSG_WARN, sb);
3254		  warnq->append (m);
3255		}
3256	      hwc_scanned = 1;
3257	    }
3258	}
3259    }
3260  return dDscr;
3261}
3262
3263DataDescriptor *
3264Experiment::get_iotrace_events ()
3265{
3266  DataDescriptor *dDscr = getDataDescriptor (DATA_IOTRACE);
3267  if (dDscr == NULL)
3268    return NULL;
3269
3270  if (dDscr->getSize () > 0)
3271    return dDscr;
3272
3273  char *base_name = get_basename (expt_name);
3274  char *msg = dbe_sprintf (GTXT ("Loading IO Trace Data: %s"), base_name);
3275  read_data_file (SP_IOTRACE_FILE, msg);
3276  free (msg);
3277
3278  if (dDscr->getSize () == 0)
3279    return dDscr;
3280  resolve_frame_info (dDscr);
3281
3282  // check for PROP_EVT_TIME
3283  PropDescr *tmp_propDscr = dDscr->getProp (PROP_EVT_TIME);
3284  if (tmp_propDscr)
3285    return dDscr;
3286
3287  // add PROP_EVT_TIME
3288  tmp_propDscr = new PropDescr (PROP_EVT_TIME, "EVT_TIME");
3289  tmp_propDscr->uname = dbe_strdup (GTXT ("Event duration"));
3290  tmp_propDscr->vtype = TYPE_INT64;
3291  dDscr->addProperty (tmp_propDscr);
3292
3293  // add PROP_IOVFD
3294  tmp_propDscr = new PropDescr (PROP_IOVFD, "IOVFD");
3295  tmp_propDscr->uname = dbe_strdup (GTXT ("Virtual File Descriptor"));
3296  tmp_propDscr->vtype = TYPE_INT64;
3297  dDscr->addProperty (tmp_propDscr);
3298
3299  delete fDataMap;
3300  fDataMap = new DefaultMap<int64_t, FileData*>;
3301
3302  delete vFdMap;
3303  vFdMap = new DefaultMap<int, int64_t>;
3304
3305  static int64_t virtualFd = 0;
3306
3307  FileData *fData;
3308  virtualFd += 10;
3309  fData = fDataMap->get (VIRTUAL_FD_STDIN);
3310  if (fData == NULL)
3311    {
3312      fData = new FileData (STDIN_FILENAME);
3313      fData->setVirtualFd (VIRTUAL_FD_STDIN);
3314      fData->id = VIRTUAL_FD_STDIN;
3315      fData->setFileDes (STDIN_FD);
3316      fDataMap->put (VIRTUAL_FD_STDIN, fData);
3317      vFdMap->put (STDIN_FD, VIRTUAL_FD_STDIN);
3318    }
3319
3320  fData = fDataMap->get (VIRTUAL_FD_STDOUT);
3321  if (fData == NULL)
3322    {
3323      fData = new FileData (STDOUT_FILENAME);
3324      fData->setVirtualFd (VIRTUAL_FD_STDOUT);
3325      fData->id = VIRTUAL_FD_STDOUT;
3326      fData->setFileDes (STDOUT_FD);
3327      fDataMap->put (VIRTUAL_FD_STDOUT, fData);
3328      vFdMap->put (STDOUT_FD, VIRTUAL_FD_STDOUT);
3329    }
3330
3331  fData = fDataMap->get (VIRTUAL_FD_STDERR);
3332  if (fData == NULL)
3333    {
3334      fData = new FileData (STDERR_FILENAME);
3335      fData->setVirtualFd (VIRTUAL_FD_STDERR);
3336      fData->id = VIRTUAL_FD_STDERR;
3337      fData->setFileDes (STDERR_FD);
3338      fDataMap->put (VIRTUAL_FD_STDERR, fData);
3339      vFdMap->put (STDERR_FD, VIRTUAL_FD_STDERR);
3340    }
3341
3342  fData = fDataMap->get (VIRTUAL_FD_OTHERIO);
3343  if (fData == NULL)
3344    {
3345      fData = new FileData (OTHERIO_FILENAME);
3346      fData->setVirtualFd (VIRTUAL_FD_OTHERIO);
3347      fData->id = VIRTUAL_FD_OTHERIO;
3348      fData->setFileDes (OTHERIO_FD);
3349      fDataMap->put (VIRTUAL_FD_OTHERIO, fData);
3350    }
3351
3352  DataView *dview = dDscr->createView ();
3353  dview->sort (PROP_TSTAMP);
3354  long sz = dview->getSize ();
3355  for (long i = 0; i < sz; i++)
3356    {
3357      hrtime_t event_duration = dview->getLongValue (PROP_TSTAMP, i);
3358      hrtime_t event_start = dview->getLongValue (PROP_IORQST, i);
3359      if (event_start > 0)
3360	event_duration -= event_start;
3361      else
3362	event_duration = 0;
3363      dview->setValue (PROP_EVT_TIME, i, event_duration);
3364
3365      int32_t fd = -1;
3366      int64_t vFd = VIRTUAL_FD_NONE;
3367      char *fName = NULL;
3368      int32_t origFd = -1;
3369      StringBuilder *sb = NULL;
3370      FileData *fDataOrig = NULL;
3371      FileSystem_type fsType;
3372
3373      IOTrace_type ioType = (IOTrace_type) dview->getIntValue (PROP_IOTYPE, i);
3374      switch (ioType)
3375	{
3376	case READ_TRACE:
3377	case WRITE_TRACE:
3378	case READ_TRACE_ERROR:
3379	case WRITE_TRACE_ERROR:
3380	  fd = dview->getIntValue (PROP_IOFD, i);
3381	  vFd = vFdMap->get (fd);
3382	  if (vFd == 0 || vFd == VIRTUAL_FD_NONE
3383	      || (fData = fDataMap->get (vFd)) == NULL)
3384	    {
3385	      fData = new FileData (UNKNOWNFD_FILENAME);
3386	      fData->setVirtualFd (virtualFd);
3387	      fData->setFsType ("N/A");
3388	      fData->setFileDes (fd);
3389	      fDataMap->put (virtualFd, fData);
3390	      vFdMap->put (fd, virtualFd);
3391	      vFd = virtualFd;
3392	      virtualFd++;
3393	    }
3394	  dview->setValue (PROP_IOVFD, i, vFd);
3395	  break;
3396	case OPEN_TRACE:
3397	  fName = NULL;
3398	  sb = (StringBuilder*) dview->getObjValue (PROP_IOFNAME, i);
3399	  if (sb != NULL && sb->length () > 0)
3400	    fName = sb->toString ();
3401	  fd = dview->getIntValue (PROP_IOFD, i);
3402	  origFd = dview->getIntValue (PROP_IOOFD, i);
3403	  fsType = (FileSystem_type) dview->getIntValue (PROP_IOFSTYPE, i);
3404
3405	  if (fName != NULL)
3406	    {
3407	      fData = new FileData (fName);
3408	      fDataMap->put (virtualFd, fData);
3409	      vFdMap->put (fd, virtualFd);
3410	      fData->setFileDes (fd);
3411	      fData->setFsType (fsType);
3412	      fData->setVirtualFd (virtualFd);
3413	      vFd = virtualFd;
3414	      virtualFd++;
3415	    }
3416	  else if (origFd > 0)
3417	    {
3418	      vFd = vFdMap->get (origFd);
3419	      if (vFd == 0 || vFd == VIRTUAL_FD_NONE)
3420		{
3421		  Dprintf (DEBUG_IO,
3422			   "*** Error I/O tracing: (open) cannot get the virtual file descriptor, fd=%d  origFd=%d\n",
3423			   fd, origFd);
3424		  continue;
3425		}
3426	      else if ((fDataOrig = fDataMap->get (vFd)) == NULL)
3427		{
3428		  Dprintf (DEBUG_IO,
3429			   "*** Error IO tracing: (open) cannot get original FileData object, fd=%d  origFd=%d\n",
3430			   fd, origFd);
3431		  continue;
3432		}
3433	      else
3434		{
3435		  fName = fDataOrig->getFileName ();
3436		  fData = new FileData (fName);
3437		  fData->setFileDes (fd);
3438		  fData->setFsType (fDataOrig->getFsType ());
3439		  fData->setVirtualFd (virtualFd);
3440		  fDataMap->put (virtualFd, fData);
3441		  vFdMap->put (fd, virtualFd);
3442		  vFd = virtualFd;
3443		  virtualFd++;
3444		}
3445	    }
3446	  else if (fd >= 0)
3447	    {
3448	      vFd = vFdMap->get (fd);
3449	      if (vFd == 0 || vFd == VIRTUAL_FD_NONE
3450		  || (fData = fDataMap->get (vFd)) == NULL)
3451		{
3452		  fData = new FileData (UNKNOWNFD_FILENAME);
3453		  fData->setVirtualFd (virtualFd);
3454		  fData->setFsType ("N/A");
3455		  fData->setFileDes (fd);
3456		  fDataMap->put (virtualFd, fData);
3457		  vFdMap->put (fd, virtualFd);
3458		  vFd = virtualFd;
3459		  virtualFd++;
3460		}
3461	    }
3462	  else
3463	    {
3464	      Dprintf (DEBUG_IO,
3465		       NTXT ("*** Error IO tracing: (open) unknown open IO type, fd=%d  origFd=%d\n"), fd, origFd);
3466	      continue;
3467	    }
3468
3469	  dview->setValue (PROP_IOVFD, i, vFd);
3470	  break;
3471
3472	case OPEN_TRACE_ERROR:
3473	  fName = NULL;
3474
3475	  sb = (StringBuilder*) dview->getObjValue (PROP_IOFNAME, i);
3476	  if (sb != NULL && sb->length () > 0)
3477	    fName = sb->toString ();
3478	  fd = dview->getIntValue (PROP_IOFD, i);
3479	  origFd = dview->getIntValue (PROP_IOOFD, i);
3480	  fsType = (FileSystem_type) dview->getIntValue (PROP_IOFSTYPE, i);
3481
3482	  if (fName != NULL)
3483	    {
3484	      fData = new FileData (fName);
3485	      fDataMap->put (virtualFd, fData);
3486	      fData->setFileDes (fd);
3487	      fData->setFsType (fsType);
3488	      fData->setVirtualFd (virtualFd);
3489	      vFd = virtualFd;
3490	      virtualFd++;
3491	    }
3492	  else if (origFd > 0)
3493	    {
3494	      vFd = vFdMap->get (origFd);
3495	      if (vFd == 0 || vFd == VIRTUAL_FD_NONE)
3496		{
3497		  Dprintf (DEBUG_IO,
3498			   "*** Error IO tracing: (open error) cannot get the virtual file descriptor, fd=%d  origFd=%d\n",
3499			   fd, origFd);
3500		  continue;
3501		}
3502	      else if ((fDataOrig = fDataMap->get (vFd)) == NULL)
3503		{
3504		  Dprintf (DEBUG_IO,
3505			   "*** Error IO tracing: (open error) cannot get original FileData object, fd=%d  origFd=%d\n",
3506			   fd, origFd);
3507		  continue;
3508		}
3509	      else
3510		{
3511		  fName = fDataOrig->getFileName ();
3512		  fData = new FileData (fName);
3513		  fData->setFileDes (fd);
3514		  fData->setFsType (fDataOrig->getFsType ());
3515		  fData->setVirtualFd (virtualFd);
3516		  fDataMap->put (virtualFd, fData);
3517		  vFd = virtualFd;
3518		  virtualFd++;
3519		}
3520	    }
3521
3522	  dview->setValue (PROP_IOVFD, i, vFd);
3523	  break;
3524
3525	case CLOSE_TRACE:
3526	case CLOSE_TRACE_ERROR:
3527	  fd = dview->getIntValue (PROP_IOFD, i);
3528	  vFd = vFdMap->get (fd);
3529	  if (vFd == 0 || vFd == VIRTUAL_FD_NONE)
3530	    {
3531	      Dprintf (DEBUG_IO,
3532		       "*** Error IO tracing: (close) cannot get the virtual file descriptor, fd=%d\n",
3533		       fd);
3534	      continue;
3535	    }
3536	  fData = fDataMap->get (vFd);
3537	  if (fData == NULL)
3538	    {
3539	      Dprintf (DEBUG_IO,
3540		       "*** Error IO tracing: (close) cannot get the FileData object, fd=%d\n",
3541		       fd);
3542	      continue;
3543	    }
3544
3545	  vFdMap->put (fd, VIRTUAL_FD_NONE);
3546	  dview->setValue (PROP_IOVFD, i, vFd);
3547	  break;
3548
3549	case OTHERIO_TRACE:
3550	case OTHERIO_TRACE_ERROR:
3551	  vFd = VIRTUAL_FD_OTHERIO;
3552	  fData = fDataMap->get (vFd);
3553	  if (fData == NULL)
3554	    {
3555	      Dprintf (DEBUG_IO,
3556		       "*** Error IO tracing: (other IO) cannot get the FileData object\n");
3557	      continue;
3558	    }
3559
3560	  dview->setValue (PROP_IOVFD, i, vFd);
3561	  break;
3562	case IOTRACETYPE_LAST:
3563	  break;
3564	}
3565    }
3566
3567  delete dview;
3568
3569  return dDscr;
3570}
3571
3572DataDescriptor *
3573Experiment::get_heap_events ()
3574{
3575  DataDescriptor *dDscr = getDataDescriptor (DATA_HEAP);
3576  if (dDscr == NULL)
3577    return NULL;
3578  if (dDscr->getSize () > 0)
3579    return dDscr;
3580
3581  char *base_name = get_basename (expt_name);
3582  char *msg = dbe_sprintf (GTXT ("Loading Heap Trace Data: %s"), base_name);
3583  read_data_file (SP_HEAPTRACE_FILE, msg);
3584  free (msg);
3585
3586  if (dDscr->getSize () == 0)
3587    return dDscr;
3588  resolve_frame_info (dDscr);
3589
3590  // Match FREE to MALLOC
3591  PropDescr *prop = new PropDescr (PROP_HLEAKED, NTXT ("HLEAKED"));
3592  prop->uname = dbe_strdup (GTXT ("Bytes Leaked"));
3593  prop->vtype = TYPE_UINT64;
3594  dDscr->addProperty (prop);
3595
3596  prop = new PropDescr (PROP_HMEM_USAGE, NTXT ("HMEM_USAGE"));
3597  prop->uname = dbe_strdup (GTXT ("Heap Memory Usage"));
3598  prop->vtype = TYPE_UINT64;
3599  dDscr->addProperty (prop);
3600
3601  prop = new PropDescr (PROP_HFREED, NTXT ("HFREED"));
3602  prop->uname = dbe_strdup (GTXT ("Bytes Freed"));
3603  prop->vtype = TYPE_UINT64;
3604  dDscr->addProperty (prop);
3605
3606  prop = new PropDescr (PROP_HCUR_ALLOCS, NTXT ("HCUR_ALLOCS"));
3607  prop->uname = dbe_strdup (GTXT ("Net Bytes Allocated"));
3608  prop->vtype = TYPE_INT64;
3609  dDscr->addProperty (prop);
3610
3611  prop = new PropDescr (PROP_HCUR_LEAKS, NTXT ("HCUR_LEAKS"));
3612  prop->uname = dbe_strdup (GTXT ("Net Bytes Leaked"));
3613  prop->vtype = TYPE_UINT64;
3614  dDscr->addProperty (prop);
3615
3616  prop = new PropDescr (PROP_HCUR_NET_ALLOC, NTXT ("HCUR_NET_ALLOC"));
3617  prop->vtype = TYPE_INT64;
3618  prop->flags = DDFLAG_NOSHOW;
3619  dDscr->addProperty (prop);
3620
3621  prop = new PropDescr (PROP_DDSCR_LNK, NTXT ("DDSCR_LNK"));
3622  prop->vtype = TYPE_UINT64;
3623  prop->flags = DDFLAG_NOSHOW;
3624  dDscr->addProperty (prop);
3625
3626  prop = new PropDescr (PROP_VOIDP_OBJ, NTXT ("VOIDP_OBJ"));
3627  prop->vtype = TYPE_OBJ;
3628  prop->flags = DDFLAG_NOSHOW;
3629  dDscr->addProperty (prop);
3630
3631  prop = new PropDescr (PROP_TSTAMP2, NTXT ("TSTAMP2"));
3632  prop->uname = dbe_strdup (GTXT ("End Timestamp (nanoseconds)"));
3633  prop->vtype = TYPE_UINT64;
3634  prop->flags = DDFLAG_NOSHOW;
3635  dDscr->addProperty (prop);
3636
3637  DataView *dview = dDscr->createView ();
3638  dview->sort (PROP_TSTAMP);
3639
3640  // Keep track of memory usage
3641  Size memoryUsage = 0;
3642
3643  HeapMap *heapmap = new HeapMap ();
3644  long sz = dview->getSize ();
3645  for (long i = 0; i < sz; i++)
3646    {
3647
3648      Heap_type mtype = (Heap_type) dview->getIntValue (PROP_HTYPE, i);
3649      Vaddr vaddr = dview->getULongValue (PROP_HVADDR, i);
3650      Vaddr ovaddr = dview->getULongValue (PROP_HOVADDR, i);
3651      Size hsize = dview->getULongValue (PROP_HSIZE, i);
3652      hrtime_t tstamp = dview->getLongValue (PROP_TSTAMP, i);
3653
3654      switch (mtype)
3655	{
3656	case MALLOC_TRACE:
3657	  dview->setValue (PROP_TSTAMP2, i, (uint64_t) MAX_TIME);
3658	  if (vaddr)
3659	    {
3660	      dview->setValue (PROP_HLEAKED, i, hsize);
3661	      heapmap->allocate (vaddr, i + 1);
3662
3663	      // Increase heap size
3664	      memoryUsage += hsize;
3665	      dview->setValue (PROP_HMEM_USAGE, i, memoryUsage);
3666	    }
3667	  break;
3668
3669	case FREE_TRACE:
3670	  if (vaddr)
3671	    {
3672	      long idx = heapmap->deallocate (vaddr) - 1;
3673	      if (idx >= 0)
3674		{
3675		  // Decrease heap size
3676		  Size leaked = dview->getLongValue (PROP_HLEAKED, idx);
3677		  memoryUsage -= leaked;
3678		  dview->setValue (PROP_HMEM_USAGE, i, memoryUsage);
3679
3680		  Size alloc = dview->getLongValue (PROP_HSIZE, idx);
3681		  // update allocation
3682		  dview->setValue (PROP_HLEAKED, idx, (uint64_t) 0);
3683		  dview->setValue (PROP_TSTAMP2, idx, tstamp);
3684		  dview->setValue (PROP_DDSCR_LNK, idx, dview->getIdByIdx (i) + 1);
3685		  // update this event
3686		  dview->setValue (PROP_HFREED, i, alloc);
3687		}
3688	    }
3689	  break;
3690
3691	case REALLOC_TRACE:
3692	  dview->setValue (PROP_TSTAMP2, i, (uint64_t) MAX_TIME);
3693	  if (ovaddr)
3694	    {
3695	      long idx = heapmap->deallocate (ovaddr) - 1;
3696	      if (idx >= 0)
3697		{
3698		  // Decrease heap size
3699		  Size leaked = dview->getLongValue (PROP_HLEAKED, idx);
3700		  memoryUsage -= leaked;
3701		  dview->setValue (PROP_HMEM_USAGE, i, memoryUsage);
3702
3703		  Size alloc = dview->getLongValue (PROP_HSIZE, idx);
3704		  // update allocation
3705		  dview->setValue (PROP_HLEAKED, idx, (uint64_t) 0);
3706		  dview->setValue (PROP_TSTAMP2, idx, tstamp);
3707		  dview->setValue (PROP_DDSCR_LNK, idx, dview->getIdByIdx (i) + 1);
3708		  // update this event
3709		  dview->setValue (PROP_HFREED, i, alloc);
3710		}
3711	    }
3712	  if (vaddr)
3713	    {
3714	      dview->setValue (PROP_HLEAKED, i, hsize);
3715	      heapmap->allocate (vaddr, i + 1);
3716
3717	      // Increase heap size
3718	      memoryUsage += hsize;
3719	      dview->setValue (PROP_HMEM_USAGE, i, memoryUsage);
3720	    }
3721	  break;
3722	case MMAP_TRACE:
3723	case MUNMAP_TRACE:
3724	  // Adjust the size to be multiple of page_size
3725	  //hsize = (( hsize - 1 ) / page_size + 1 ) * page_size;
3726	  if (vaddr)
3727	    {
3728	      UnmapChunk *list;
3729	      if (mtype == MMAP_TRACE)
3730		{
3731		  dview->setValue (PROP_TSTAMP2, i, (uint64_t) MAX_TIME);
3732		  dview->setValue (PROP_HLEAKED, i, hsize);
3733		  list = heapmap->mmap (vaddr, hsize, i);
3734
3735		  // Increase heap size
3736		  memoryUsage += hsize;
3737		  dview->setValue (PROP_HMEM_USAGE, i, memoryUsage);
3738		}
3739	      else
3740		{ // MUNMAP_TRACE
3741		  list = heapmap->munmap (vaddr, hsize);
3742
3743		  // Set allocation size to zero
3744		  // Note: We're currently reusing PROP_HSIZE to mean allocation size
3745		  // If we ever need to save the original HSIZE, we'll need to
3746		  // create a new PROP_* to represent event allocation size
3747		  //
3748		  //	For now, tuck the original size away as HOVADDR
3749		  dview->setValue (PROP_HOVADDR, i, (uint64_t) hsize);
3750		  dview->setValue (PROP_HSIZE, i, (uint64_t) 0);
3751		}
3752	      Size total_freed = 0;
3753	      while (list)
3754		{
3755		  long idx = list->val;
3756		  total_freed += list->size;
3757		  Size leaked = dview->getLongValue (PROP_HLEAKED, idx);
3758
3759		  // Decrease heap size
3760		  memoryUsage -= list->size;
3761		  dview->setValue (PROP_HMEM_USAGE, i, memoryUsage);
3762
3763		  Size leak_update = leaked - list->size;
3764		  // update allocation
3765		  dview->setValue (PROP_HLEAKED, idx, leak_update);
3766		  // update allocation's list of frees
3767		  {
3768		    UnmapChunk *copy = new UnmapChunk;
3769		    heapUnmapEvents->append (copy);
3770		    copy->val = dview->getIdByIdx (i);
3771		    copy->size = list->size;
3772		    copy->next = (UnmapChunk *) dview->getObjValue (PROP_VOIDP_OBJ, idx);
3773		    dview->setObjValue (PROP_VOIDP_OBJ, idx, copy);
3774		  }
3775		  if (leak_update <= 0)
3776		    if (leak_update == 0)
3777		      dview->setValue (PROP_TSTAMP2, idx, tstamp);
3778		  UnmapChunk *t = list;
3779		  list = list->next;
3780		  delete t;
3781		}
3782	      // update this event
3783	      if (total_freed)
3784		// only need to write value if it is non-zero
3785		dview->setValue (PROP_HFREED, i, total_freed);
3786	    }
3787	  break;
3788	  // ignoring HEAPTYPE_LAST, which will never be recorded
3789	case HEAPTYPE_LAST:
3790	  break;
3791	}
3792    }
3793  delete heapmap;
3794  delete dview;
3795
3796  return dDscr;
3797}
3798
3799DataDescriptor *
3800Experiment::get_heapsz_events ()
3801{
3802  DataDescriptor *dDscr = getDataDescriptor (DATA_HEAPSZ);
3803  if (dDscr)
3804    return dDscr;
3805  dDscr = get_heap_events (); // derived from DATA_HEAP
3806  if (dDscr == NULL)
3807    return NULL;
3808  dDscr = newDataDescriptor (DATA_HEAPSZ, 0, dDscr);
3809  return dDscr;
3810}
3811
3812static void
3813update_heapsz_packet (std::set<long> &pkt_id_set, DataView *dview,
3814		      long alloc_pkt_id, int64_t net_alloc, uint64_t leaks)
3815{
3816  // pkt_id_set: set is updated to include packet
3817  // alloc_pkt_id: data descriptor id (NOT dview idx)
3818  // net_alloc: adjustment to net allocation for this packet (note: signed value)
3819  // leaks: leak bytes to attribute to alloc_pkt_id
3820  std::pair < std::set<long>::iterator, bool> ret;
3821  ret = pkt_id_set.insert (alloc_pkt_id); // add to set
3822  bool new_to_set = ret.second; // was not in set
3823  if (!new_to_set)
3824    {
3825      // Has been seen before, update values
3826      net_alloc += dview->getDataDescriptorValue (PROP_HCUR_NET_ALLOC, alloc_pkt_id);
3827      if (leaks)
3828	{
3829	  uint64_t old = dview->getDataDescriptorValue (PROP_HCUR_LEAKS, alloc_pkt_id);
3830	  if (old != 0)
3831	    leaks = old;
3832	}
3833    }
3834  dview->setDataDescriptorValue (PROP_HCUR_NET_ALLOC, alloc_pkt_id, net_alloc);
3835  dview->setDataDescriptorValue (PROP_HCUR_LEAKS, alloc_pkt_id, leaks);
3836}
3837
3838DataView *
3839Experiment::create_heapsz_data_view (DataView *heap_dview)
3840{
3841  // heap_dview has DATA_HEAP _filtered_ packets.
3842  // This creates, populates, and returns DATA_HEAPSZ DataView
3843  DataDescriptor *dDscr = get_heapsz_events ();
3844  if (dDscr == NULL)
3845    return NULL;
3846  std::set<long> pkt_id_set;
3847  DataView *dview = heap_dview;
3848  long sz = dview->getSize ();
3849  for (long i = 0; i < sz; i++)
3850    {
3851      int64_t hsize = (int64_t) dview->getULongValue (PROP_HSIZE, i);
3852      uint64_t leaks = dview->getULongValue (PROP_HLEAKED, i);
3853      long alloc_pkt_id = dview->getIdByIdx (i);
3854      update_heapsz_packet (pkt_id_set, dview, alloc_pkt_id, hsize, leaks);
3855
3856      // linked free
3857      UnmapChunk *mmap_frees = (UnmapChunk *) dview->getObjValue (PROP_VOIDP_OBJ, i); // mmap metadata
3858      if (mmap_frees)
3859	{
3860	  // mmap: all frees associated with this packet
3861	  while (mmap_frees)
3862	    {
3863	      long free_pkt_id = mmap_frees->val;
3864	      int64_t free_sz = mmap_frees->size;
3865	      update_heapsz_packet (pkt_id_set, dview, free_pkt_id, -free_sz, 0);
3866	      mmap_frees = mmap_frees->next;
3867	    }
3868	}
3869      else
3870	{
3871	  // malloc: check for associated free
3872	  long free_pkt_id = dview->getLongValue (PROP_DDSCR_LNK, i) - 1;
3873	  if (free_pkt_id >= 0)
3874	    update_heapsz_packet (pkt_id_set, dview, free_pkt_id, -hsize, 0);
3875	}
3876    }
3877
3878  // create a new DataView based on the filtered-in and associated free events
3879  std::set<long>::iterator it;
3880  DataView *heapsz_dview = dDscr->createExtManagedView ();
3881  for (it = pkt_id_set.begin (); it != pkt_id_set.end (); ++it)
3882    {
3883      long ddscr_pkt_id = *it;
3884      heapsz_dview->appendDataDescriptorId (ddscr_pkt_id);
3885    }
3886  compute_heapsz_data_view (heapsz_dview);
3887  return heapsz_dview;
3888}
3889
3890void
3891Experiment::compute_heapsz_data_view (DataView *heapsz_dview)
3892{
3893  DataView *dview = heapsz_dview;
3894
3895  // Keep track of memory usage
3896  int64_t currentAllocs = 0;
3897  Size currentLeaks = 0;
3898  dview->sort (PROP_TSTAMP);
3899  long sz = dview->getSize ();
3900  for (long i = 0; i < sz; i++)
3901    {
3902      int64_t net_alloc = dview->getLongValue (PROP_HCUR_NET_ALLOC, i);
3903      currentAllocs += net_alloc;
3904      dview->setValue (PROP_HCUR_ALLOCS, i, currentAllocs);
3905
3906      Size leaks = dview->getULongValue (PROP_HCUR_LEAKS, i);
3907      currentLeaks += leaks;
3908      dview->setValue (PROP_HCUR_LEAKS, i, currentLeaks);
3909    }
3910}
3911
3912void
3913Experiment::DBG_memuse (Sample * s)
3914{
3915  DataDescriptor *dDscr = getDataDescriptor (DATA_HEAP);
3916  if (dDscr == NULL || dDscr->getSize () == 0)
3917    return;
3918
3919  DataView *dview = dDscr->createView ();
3920  dview->sort (PROP_TSTAMP);
3921  hrtime_t ts1 = s->get_start_time ();
3922  hrtime_t ts2 = s->get_end_time ();
3923
3924  HeapMap *heapmap = new HeapMap ();
3925  long sz = dview->getSize ();
3926  Size maxSize = 0;
3927  Size curSize = 0;
3928  hrtime_t maxTime = 0;
3929  for (long i = 0; i < sz; i++)
3930    {
3931      hrtime_t tstamp = dview->getLongValue (PROP_TSTAMP, i);
3932      if (tstamp < ts1)
3933	continue;
3934      if (tstamp >= ts2)
3935	break;
3936
3937      Heap_type mtype = (Heap_type) dview->getIntValue (PROP_HTYPE, i);
3938      Vaddr vaddr = dview->getULongValue (PROP_HVADDR, i);
3939      Vaddr ovaddr = dview->getULongValue (PROP_HOVADDR, i);
3940      switch (mtype)
3941	{
3942	case REALLOC_TRACE:
3943	  break;
3944	case MALLOC_TRACE:
3945	  ovaddr = 0;
3946	  break;
3947	case FREE_TRACE:
3948	  ovaddr = vaddr;
3949	  vaddr = 0;
3950	  break;
3951	default:
3952	  vaddr = 0;
3953	  ovaddr = 0;
3954	  break;
3955	}
3956      if (ovaddr)
3957	{
3958	  long idx = heapmap->deallocate (ovaddr) - 1;
3959	  if (idx >= 0)
3960	    curSize -= dview->getULongValue (PROP_HSIZE, idx);
3961	}
3962      if (vaddr)
3963	{
3964	  heapmap->allocate (vaddr, i + 1);
3965	  curSize += dview->getULongValue (PROP_HSIZE, i);
3966	  if (curSize > maxSize)
3967	    {
3968	      maxSize = curSize;
3969	      maxTime = tstamp;
3970	    }
3971	}
3972    }
3973  printf ("SAMPLE=%s (id=%d) MEMUSE=%lld TSTAMP=%lld\n", s->get_start_label (),
3974	  s->get_number (), maxSize, maxTime - getStartTime ());
3975  delete dview;
3976  delete heapmap;
3977}
3978
3979void
3980Experiment::DBG_memuse (const char *sname)
3981{
3982  for (int i = 0; i < samples->size (); ++i)
3983    {
3984      Sample *sample = samples->fetch (i);
3985      if (streq (sname, sample->get_start_label ()))
3986	{
3987	  DBG_memuse (sample);
3988	  break;
3989	}
3990    }
3991}
3992
3993DataDescriptor *
3994Experiment::get_race_events ()
3995{
3996  DataDescriptor *dDscr = getDataDescriptor (DATA_RACE);
3997  if (dDscr == NULL)
3998    return NULL;
3999  if (dDscr->getSize () == 0)
4000    {
4001      char *base_name = get_basename (expt_name);
4002      char *msg = dbe_sprintf (GTXT ("Loading Race Data: %s"), base_name);
4003      read_data_file (SP_RACETRACE_FILE, msg);
4004      free (msg);
4005      resolve_frame_info (dDscr);
4006    }
4007  return dDscr;
4008}
4009
4010DataDescriptor *
4011Experiment::get_deadlock_events ()
4012{
4013  DataDescriptor *dDscr = getDataDescriptor (DATA_DLCK);
4014  if (dDscr == NULL)
4015    return NULL;
4016  if (dDscr->getSize () == 0)
4017    {
4018      char *base_name = get_basename (expt_name);
4019      char *msg = dbe_sprintf (GTXT ("Loading Deadlocks Data: %s"), base_name);
4020      read_data_file (SP_DEADLOCK_FILE, msg);
4021      free (msg);
4022      resolve_frame_info (dDscr);
4023    }
4024  return dDscr;
4025}
4026
4027DataDescriptor *
4028Experiment::get_sample_events ()
4029{
4030  DataDescriptor *dDscr = getDataDescriptor (DATA_SAMPLE);
4031  if (dDscr == NULL)
4032    return NULL;
4033  if (dDscr->getSize () > 0)
4034    return dDscr;
4035
4036  // read_overview_file(); //YXXX do this here at some point instead of:
4037  PropDescr *tmp_propDscr;
4038  tmp_propDscr = new PropDescr (PROP_SMPLOBJ, NTXT ("SMPLOBJ"));
4039  tmp_propDscr->uname = NULL;
4040  tmp_propDscr->vtype = TYPE_OBJ;
4041  dDscr->addProperty (tmp_propDscr);
4042
4043  tmp_propDscr = new PropDescr (PROP_TSTAMP, NTXT ("TSTAMP"));
4044  tmp_propDscr->uname = dbe_strdup ("High resolution timestamp");
4045  tmp_propDscr->vtype = TYPE_UINT64;
4046  dDscr->addProperty (tmp_propDscr);
4047
4048  tmp_propDscr = new PropDescr (PROP_SAMPLE, NTXT ("SAMPLE"));
4049  tmp_propDscr->uname = dbe_strdup ("Sample number");
4050  tmp_propDscr->vtype = TYPE_UINT64;
4051  dDscr->addProperty (tmp_propDscr);
4052
4053  tmp_propDscr = new PropDescr (PROP_EVT_TIME, NTXT ("EVT_TIME"));
4054  tmp_propDscr->uname = dbe_strdup ("Event duration");
4055  tmp_propDscr->vtype = TYPE_UINT64;
4056  dDscr->addProperty (tmp_propDscr);
4057
4058  long ssize = samples->size ();
4059  for (long ii = 0; ii < ssize; ii++)
4060    {
4061      Sample * sample = samples->fetch (ii);
4062      long recn = dDscr->addRecord ();
4063      hrtime_t sduration = sample->get_end_time () - sample->get_start_time ();
4064      dDscr->setObjValue (PROP_SMPLOBJ, recn, sample);
4065      dDscr->setValue (PROP_SAMPLE, recn, sample->get_number ());
4066      dDscr->setValue (PROP_TSTAMP, recn, sample->get_end_time ());
4067      dDscr->setValue (PROP_EVT_TIME, recn, sduration);
4068    }
4069  return dDscr;
4070}
4071
4072DataDescriptor *
4073Experiment::get_gc_events ()
4074{
4075  DataDescriptor *dDscr = getDataDescriptor (DATA_GCEVENT);
4076  if (dDscr == NULL)
4077    return NULL;
4078  if (dDscr->getSize () > 0)
4079    return dDscr;
4080
4081  // read_overview_file(); //YXXX do this here at some point instead of:
4082  PropDescr *tmp_propDscr;
4083  tmp_propDscr = new PropDescr (PROP_GCEVENTOBJ, NTXT ("GCEVENTOBJ"));
4084  tmp_propDscr->uname = NULL;
4085  tmp_propDscr->vtype = TYPE_OBJ;
4086  dDscr->addProperty (tmp_propDscr);
4087
4088  tmp_propDscr = new PropDescr (PROP_TSTAMP, NTXT ("TSTAMP"));
4089  tmp_propDscr->uname = dbe_strdup ("High resolution timestamp");
4090  tmp_propDscr->vtype = TYPE_UINT64;
4091  dDscr->addProperty (tmp_propDscr);
4092
4093  tmp_propDscr = new PropDescr (PROP_GCEVENT, NTXT ("GCEVENT"));
4094  tmp_propDscr->uname = dbe_strdup ("GCEvent number");
4095  tmp_propDscr->vtype = TYPE_UINT64;
4096  dDscr->addProperty (tmp_propDscr);
4097
4098  tmp_propDscr = new PropDescr (PROP_EVT_TIME, NTXT ("EVT_TIME"));
4099  tmp_propDscr->uname = dbe_strdup ("Event duration");
4100  tmp_propDscr->vtype = TYPE_UINT64;
4101  dDscr->addProperty (tmp_propDscr);
4102
4103  long ssize = gcevents->size ();
4104  for (long ii = 0; ii < ssize; ii++)
4105    {
4106      GCEvent * gcevent = gcevents->fetch (ii);
4107      long recn = dDscr->addRecord ();
4108      hrtime_t sduration = gcevent->end - gcevent->start;
4109      dDscr->setObjValue (PROP_GCEVENTOBJ, recn, gcevent);
4110      dDscr->setValue (PROP_GCEVENT, recn, gcevent->id);
4111      dDscr->setValue (PROP_TSTAMP, recn, gcevent->end);
4112      dDscr->setValue (PROP_EVT_TIME, recn, sduration);
4113    }
4114  return dDscr;
4115}
4116
4117void
4118Experiment::update_last_event (hrtime_t ts/*wall_ts*/)
4119{
4120  if (last_event == ZERO_TIME)
4121    {
4122      // not yet initialized
4123      last_event = ts;
4124    }
4125  if (last_event - exp_start_time < ts - exp_start_time)
4126    // compare deltas to avoid hrtime_t wrap
4127    last_event = ts;
4128}
4129
4130void
4131Experiment::write_header ()
4132{
4133  StringBuilder sb;
4134
4135  // write commentary to the experiment, describing the parameters
4136  if (dbeSession->ipc_mode || dbeSession->rdt_mode)
4137    {
4138      // In GUI: print start time at the beginning
4139      time_t t = (time_t) start_sec;
4140      char *start_time = ctime (&t);
4141      if (start_time != NULL)
4142	{
4143	  sb.setLength (0);
4144	  sb.sprintf (GTXT ("Experiment started %s"), start_time);
4145	  commentq->append (new Emsg (CMSG_COMMENT, sb));
4146	}
4147    }
4148  // write message with target arglist
4149  if (uarglist != NULL)
4150    {
4151      sb.setLength (0);
4152      sb.sprintf (GTXT ("\nTarget command (%s): '%s'"),
4153		  (wsize == W32 ? "32-bit" : "64-bit"), uarglist);
4154      commentq->append (new Emsg (CMSG_COMMENT, sb));
4155    }
4156
4157  sb.setLength (0);
4158  sb.sprintf (GTXT ("Process pid %d, ppid %d, pgrp %d, sid %d"),
4159	      pid, ppid, pgrp, sid);
4160  commentq->append (new Emsg (CMSG_COMMENT, sb));
4161
4162  // add comment for user name, if set
4163  if (username != NULL)
4164    {
4165      sb.setLength (0);
4166      sb.sprintf (GTXT ("User: `%s'"), username);
4167      commentq->append (new Emsg (CMSG_COMMENT, sb));
4168    }
4169
4170  // add comment for current working directory
4171  if (ucwd != NULL)
4172    {
4173      sb.setLength (0);
4174      sb.sprintf (GTXT ("Current working directory: %s"), ucwd);
4175      commentq->append (new Emsg (CMSG_COMMENT, sb));
4176    }
4177
4178  // add comment for collector version string
4179  if (cversion != NULL)
4180    {
4181      char *wstring;
4182      switch (wsize)
4183	{
4184	case Wnone:
4185	  wstring = NTXT ("?");
4186	  break;
4187	case W32:
4188	  wstring = GTXT ("32-bit");
4189	  break;
4190	case W64:
4191	  wstring = GTXT ("64-bit");
4192	  break;
4193	default:
4194	  wstring = NTXT ("??");
4195	  break;
4196	}
4197      sb.setLength (0);
4198      sb.sprintf (GTXT ("Collector version: `%s'; experiment version %d.%d (%s)"),
4199		  cversion, exp_maj_version, exp_min_version, wstring);
4200      commentq->append (new Emsg (CMSG_COMMENT, sb));
4201    }
4202
4203  // add comment for driver version string (er_kernel)
4204  if (dversion != NULL)
4205    {
4206      sb.setLength (0);
4207      sb.sprintf (GTXT ("Kernel driver version: `%s'"), dversion);
4208      commentq->append (new Emsg (CMSG_COMMENT, sb));
4209    }
4210
4211  if (jversion != NULL)
4212    {
4213      sb.setLength (0);
4214      sb.sprintf (GTXT ("JVM version: `%s'"), jversion);
4215      commentq->append (new Emsg (CMSG_COMMENT, sb));
4216    }
4217
4218  // add comment for hostname, parameters
4219  if (hostname == NULL)
4220    hostname = dbe_strdup (GTXT ("unknown"));
4221  if (os_version == NULL)
4222    os_version = dbe_strdup (GTXT ("unknown"));
4223  if (architecture == NULL)
4224    architecture = dbe_strdup (GTXT ("unknown"));
4225  sb.setLength (0);
4226  sb.sprintf (GTXT ("Host `%s', OS `%s', page size %d, architecture `%s'"),
4227	      hostname, os_version, page_size, architecture);
4228  commentq->append (new Emsg (CMSG_COMMENT, sb));
4229
4230  sb.setLength (0);
4231  if (maxclock != minclock)
4232    {
4233      clock = maxclock;
4234      sb.sprintf (
4235		  GTXT ("  %d CPUs, with clocks ranging from %d to %d MHz.; max of %d MHz. assumed"),
4236		  ncpus, minclock, maxclock, clock);
4237    }
4238  else
4239    sb.sprintf (GTXT ("  %d CPU%s, clock speed %d MHz."),
4240		ncpus, (ncpus == 1 ? NTXT ("") : "s"), clock);
4241  commentq->append (new Emsg (CMSG_COMMENT, sb));
4242
4243  // add comment for machine memory size
4244  if (page_size > 0 && npages > 0)
4245    {
4246      long long memsize = ((long long) npages * page_size) / (1024 * 1024);
4247      sb.setLength (0);
4248      sb.sprintf (GTXT ("  Memory: %d pages @  %d = %lld MB."),
4249		  npages, page_size, memsize);
4250      commentq->append (new Emsg (CMSG_COMMENT, sb));
4251    }
4252
4253  // add comment for machine memory size
4254  if (machinemodel != NULL)
4255    {
4256      sb.setLength (0);
4257      sb.sprintf (GTXT ("  Machine model: %s"), machinemodel);
4258      commentq->append (new Emsg (CMSG_COMMENT, sb));
4259    }
4260
4261  // add comment for start time
4262  time_t t = (time_t) start_sec;
4263  char *p = ctime (&t);
4264  sb.setLength (0);
4265  if (p != NULL)
4266    sb.sprintf (GTXT ("Experiment started %s"), p);
4267  else
4268    sb.sprintf (GTXT ("\nExperiment start not recorded"));
4269  write_coll_params ();
4270  commentq->append (new Emsg (CMSG_COMMENT, sb));
4271  commentq->appendqueue (runlogq);
4272  runlogq->mark_clear ();
4273}
4274
4275void
4276Experiment::write_coll_params ()
4277{
4278  StringBuilder sb;
4279
4280  // now write the various collection parameters as comments
4281  sb.setLength (0);
4282  sb.append (GTXT ("Data collection parameters:"));
4283  commentq->append (new Emsg (CMSG_COMMENT, sb));
4284  if (coll_params.profile_mode == 1)
4285    {
4286      sb.setLength (0);
4287      sb.sprintf (GTXT ("  Clock-profiling, interval = %d microsecs."),
4288		  (int) (coll_params.ptimer_usec));
4289      commentq->append (new Emsg (CMSG_COMMENT, sb));
4290    }
4291  if (coll_params.sync_mode == 1)
4292    {
4293      sb.setLength (0);
4294      char *scope_str = NTXT ("");
4295      switch (coll_params.sync_scope)
4296	{
4297	case 0:
4298	  scope_str = GTXT ("Native- and Java-APIs");
4299	  break;
4300	case SYNCSCOPE_JAVA:
4301	  scope_str = GTXT ("JAVA-APIs");
4302	  break;
4303	case SYNCSCOPE_NATIVE:
4304	  scope_str = GTXT ("Native-APIs");
4305	  break;
4306	case SYNCSCOPE_JAVA | SYNCSCOPE_NATIVE:
4307	  scope_str = GTXT ("Native- and Java-APIs");
4308	  break;
4309	}
4310      if (coll_params.sync_threshold < 0)
4311	sb.sprintf (GTXT ("  Synchronization tracing, threshold = %d microsecs. (calibrated); %s"),
4312		    -coll_params.sync_threshold, scope_str);
4313      else
4314	sb.sprintf (GTXT ("  Synchronization tracing, threshold = %d microsecs.; %s"),
4315		    coll_params.sync_threshold, scope_str);
4316      commentq->append (new Emsg (CMSG_COMMENT, sb));
4317    }
4318  if (coll_params.heap_mode == 1)
4319    {
4320      sb.setLength (0);
4321      sb.append (GTXT ("  Heap tracing"));
4322      commentq->append (new Emsg (CMSG_COMMENT, sb));
4323    }
4324  if (coll_params.io_mode == 1)
4325    {
4326      sb.setLength (0);
4327      sb.append (GTXT ("  IO tracing"));
4328      commentq->append (new Emsg (CMSG_COMMENT, sb));
4329    }
4330  if (coll_params.race_mode == 1)
4331    {
4332      sb.setLength (0);
4333      char *race_stack_name;
4334      switch (coll_params.race_stack)
4335	{
4336	case 0:
4337	  race_stack_name = GTXT ("dual-stack");
4338	  break;
4339	case 1:
4340	  race_stack_name = GTXT ("single-stack");
4341	  break;
4342	case 2:
4343	  race_stack_name = GTXT ("leaf");
4344	  break;
4345	default:
4346	  abort ();
4347	}
4348      sb.sprintf (GTXT ("  Datarace detection, %s"), race_stack_name);
4349      commentq->append (new Emsg (CMSG_COMMENT, sb));
4350    }
4351  if (coll_params.deadlock_mode == 1)
4352    {
4353      sb.setLength (0);
4354      sb.append (GTXT ("  Deadlock detection"));
4355      commentq->append (new Emsg (CMSG_COMMENT, sb));
4356    }
4357  if (coll_params.hw_mode == 1)
4358    {
4359      sb.setLength (0);
4360      if (hwc_default == true)
4361	sb.append (GTXT ("  HW counter-profiling (default); counters:"));
4362      else
4363	sb.append (GTXT ("  HW counter-profiling; counters:"));
4364      commentq->append (new Emsg (CMSG_COMMENT, sb));
4365      for (int i = 0; i < MAX_HWCOUNT; i++)
4366	{
4367	  if (!coll_params.hw_aux_name[i])
4368	    continue;
4369	  sb.setLength (0);
4370	  sb.sprintf (GTXT ("    %s, tag %d, interval %d, memop %d"),
4371		      coll_params.hw_aux_name[i], i,
4372		      coll_params.hw_interval[i], coll_params.hw_tpc[i]);
4373	  commentq->append (new Emsg (CMSG_COMMENT, sb));
4374	}
4375    }
4376  if (coll_params.sample_periodic == 1)
4377    {
4378      sb.setLength (0);
4379      sb.sprintf (GTXT ("  Periodic sampling, %d secs."),
4380		  coll_params.sample_timer);
4381      commentq->append (new Emsg (CMSG_COMMENT, sb));
4382    }
4383  if (coll_params.limit != 0)
4384    {
4385      sb.setLength (0);
4386      sb.sprintf (GTXT ("  Experiment size limit, %d"),
4387		  coll_params.limit);
4388      commentq->append (new Emsg (CMSG_COMMENT, sb));
4389    }
4390  if (coll_params.linetrace != NULL)
4391    {
4392      sb.setLength (0);
4393      sb.sprintf (GTXT ("  Follow descendant processes from: %s"),
4394		  coll_params.linetrace);
4395      commentq->append (new Emsg (CMSG_COMMENT, sb));
4396    }
4397  if (coll_params.pause_sig != NULL)
4398    {
4399      sb.setLength (0);
4400      sb.sprintf (GTXT ("  Pause signal %s"), coll_params.pause_sig);
4401      commentq->append (new Emsg (CMSG_COMMENT, sb));
4402    }
4403  if (coll_params.sample_sig != NULL)
4404    {
4405      sb.setLength (0);
4406      sb.sprintf (GTXT ("  Sample signal %s"), coll_params.sample_sig);
4407      commentq->append (new Emsg (CMSG_COMMENT, sb));
4408    }
4409  if (coll_params.start_delay != NULL)
4410    {
4411      sb.setLength (0);
4412      sb.sprintf (GTXT ("  Data collection delay start %s seconds"), coll_params.start_delay);
4413      commentq->append (new Emsg (CMSG_COMMENT, sb));
4414    }
4415  if (coll_params.terminate != NULL)
4416    {
4417      sb.setLength (0);
4418      sb.sprintf (GTXT ("  Data collection termination after %s seconds"), coll_params.terminate);
4419      commentq->append (new Emsg (CMSG_COMMENT, sb));
4420    }
4421  // add a blank line after data description
4422  commentq->append (new Emsg (CMSG_COMMENT, NTXT ("")));
4423}
4424
4425
4426/*
4427 *    Raw packet processing
4428 */
4429static int
4430check_mstate (char *ptr, PacketDescriptor *pDscr, int arg)
4431{
4432  switch (arg)
4433    {
4434    case PROP_UCPU:
4435    case PROP_SCPU:
4436    case PROP_TRAP:
4437    case PROP_TFLT:
4438    case PROP_DFLT:
4439    case PROP_KFLT:
4440    case PROP_ULCK:
4441    case PROP_TSLP:
4442    case PROP_WCPU:
4443    case PROP_TSTP:
4444      break;
4445    default:
4446      return 0;
4447    }
4448  Vector<FieldDescr*> *fields = pDscr->getFields ();
4449  for (int i = 0, sz = fields->size (); i < sz; i++)
4450    {
4451      FieldDescr *fDscr = fields->fetch (i);
4452      if (fDscr->propID == arg)
4453	return *((int*) (ptr + fDscr->offset));
4454    }
4455  return 0;
4456}
4457
4458#define PACKET_ALIGNMENT 4
4459
4460uint64_t
4461Experiment::readPacket (Data_window *dwin, Data_window::Span *span)
4462{
4463  Common_packet *rcp = (Common_packet *) dwin->bind (span,
4464						    sizeof (CommonHead_packet));
4465  uint16_t v16;
4466  uint64_t size = 0;
4467  if (rcp)
4468    {
4469      if ((((long) rcp) % PACKET_ALIGNMENT) != 0)
4470	{
4471	  invalid_packet++;
4472	  size = PROFILE_BUFFER_CHUNK - span->offset % PROFILE_BUFFER_CHUNK;
4473	  return size;
4474	}
4475      v16 = (uint16_t) rcp->tsize;
4476      size = dwin->decode (v16);
4477      if (size == 0)
4478	{
4479	  size = PROFILE_BUFFER_CHUNK - span->offset % PROFILE_BUFFER_CHUNK;
4480	  return size;
4481	}
4482      rcp = (Common_packet *) dwin->bind (span, size);
4483    }
4484  if (rcp == NULL)
4485    return 0;
4486
4487  if ((((long) rcp) % PACKET_ALIGNMENT) != 0)
4488    {
4489      invalid_packet++;
4490      size = PROFILE_BUFFER_CHUNK - span->offset % PROFILE_BUFFER_CHUNK;
4491      return size;
4492    }
4493  v16 = (uint16_t) rcp->type;
4494  uint32_t rcptype = dwin->decode (v16);
4495  if (rcptype == EMPTY_PCKT)
4496    return size;
4497  if (rcptype == FRAME_PCKT)
4498    {
4499      RawFramePacket *fp = new RawFramePacket;
4500      fp->uid = dwin->decode (((Frame_packet*) rcp)->uid);
4501      fp->uidn = NULL;
4502      fp->uidj = NULL;
4503      fp->omp_uid = NULL;
4504      fp->omp_state = 0;
4505      char *ptr = (char*) rcp + dwin->decode (((Frame_packet*) rcp)->hsize);
4506      if ((((long) ptr) % PACKET_ALIGNMENT) != 0)
4507	{
4508	  invalid_packet++;
4509	  delete fp;
4510	  return size;
4511	}
4512      v16 = (uint16_t) ((Frame_packet*) rcp)->tsize;
4513      char *end = (char*) rcp + dwin->decode (v16);
4514      for (; ptr < end;)
4515	{
4516	  Common_info *cinfo = (Common_info*) ptr;
4517	  uint32_t hsize = dwin->decode (cinfo->hsize);
4518	  if (hsize == 0 || ptr + hsize > end)
4519	    break;
4520	  int kind = dwin->decode (cinfo->kind);
4521	  bool compressed = false;
4522	  if (kind & COMPRESSED_INFO)
4523	    {
4524	      compressed = true;
4525	      kind &= ~COMPRESSED_INFO;
4526	    }
4527	  switch (kind)
4528	    {
4529	    case STACK_INFO:
4530	      {
4531		char *stack = ptr + sizeof (Stack_info);
4532		size_t stack_size = hsize - sizeof (Stack_info);
4533		uint64_t uidn = dwin->decode (((Stack_info*) cinfo)->uid);
4534		if (stack_size <= 0)
4535		  {
4536		    fp->uidn = get_uid_node (uidn);
4537		    break;
4538		  }
4539		uint64_t link_uid = (uint64_t) 0;
4540		if (compressed)
4541		  {
4542		    stack_size -= sizeof (uint64_t);
4543		    unsigned char *s = (unsigned char*) (stack + stack_size);
4544		    int shift = 0;
4545		    for (size_t i = 0; i<sizeof (link_uid); i++)
4546		      {
4547			link_uid |= (uint64_t) * s++ << shift;
4548			shift += 8;
4549		      }
4550		  }
4551		if (wsize == W32)
4552		  fp->uidn = add_uid (dwin, uidn,
4553				      (int) (stack_size / sizeof (uint32_t)),
4554				      (uint32_t*) stack, link_uid);
4555		else
4556		  fp->uidn = add_uid (dwin, uidn,
4557				      (int) (stack_size / sizeof (uint64_t)),
4558				      (uint64_t*) stack, link_uid);
4559		break;
4560	      }
4561	    case JAVA_INFO:
4562	      {
4563		char *stack = ptr + sizeof (Java_info);
4564		size_t stack_size = hsize - sizeof (Java_info);
4565		uint64_t uidj = dwin->decode (((Java_info*) cinfo)->uid);
4566		if (stack_size <= 0)
4567		  {
4568		    fp->uidj = get_uid_node (uidj);
4569		    break;
4570		  }
4571
4572		uint64_t link_uid = (uint64_t) 0;
4573		if (compressed)
4574		  {
4575		    stack_size -= sizeof (uint64_t);
4576		    unsigned char *s = (unsigned char*) (stack + stack_size);
4577		    int shift = 0;
4578		    for (size_t i = 0; i<sizeof (link_uid); i++)
4579		      {
4580			link_uid |= (uint64_t) * s++ << shift;
4581			shift += 8;
4582		      }
4583		  }
4584		if (wsize == W32)
4585		  fp->uidj = add_uid (dwin, uidj,
4586				      (int) (stack_size / sizeof (uint32_t)),
4587				      (uint32_t*) stack, link_uid);
4588		else
4589		  {
4590		    // bug 6909545: garbage in 64-bit JAVA_INFO
4591		    char *nstack = (char*) malloc (stack_size);
4592		    char *dst = nstack;
4593		    char *srcmax = stack + stack_size - sizeof (uint64_t);
4594		    for (char *src = stack; src <= srcmax;)
4595		      {
4596			int64_t val = dwin->decode (*(int32_t*) src);
4597			*(uint64_t*) dst = dwin->decode (val);
4598			src += sizeof (uint64_t);
4599			dst += sizeof (uint64_t);
4600			if (src > srcmax)
4601			  {
4602			    fprintf (stderr, "er_print: Experiment::readPacket: Error in data: src=%llx greater than %llx\n",
4603				     (long long) src, (long long) srcmax);
4604			    break;
4605			  }
4606			*(uint64_t*) dst = *(uint64_t*) src;
4607			src += sizeof (uint64_t);
4608			dst += sizeof (uint64_t);
4609		      }
4610		    fp->uidj = add_uid (dwin, uidj,
4611					(int) (stack_size / sizeof (uint64_t)),
4612					(uint64_t*) nstack, link_uid);
4613		    free (nstack);
4614		  }
4615		break;
4616	      }
4617	    case OMP_INFO:
4618	      fp->omp_state = dwin->decode (((OMP_info*) ptr)->omp_state);
4619	      break;
4620	    case OMP2_INFO:
4621	      {
4622		uint64_t omp_uid = dwin->decode (((OMP2_info*) ptr)->uid);
4623		fp->omp_uid = get_uid_node (omp_uid);
4624		fp->omp_state = dwin->decode (((OMP2_info*) ptr)->omp_state);
4625		break;
4626	      }
4627	    default:
4628	      break;
4629	    }
4630	  ptr += hsize;
4631	}
4632      frmpckts->append (fp);
4633      return size;
4634    }
4635  else if (rcptype == UID_PCKT)
4636    {
4637      Uid_packet *uidp = (Uid_packet*) rcp;
4638      uint64_t uid = dwin->decode (uidp->uid);
4639      char *arr_bytes = (char*) (uidp + 1);
4640      v16 = (uint16_t) rcp->tsize;
4641      size_t arr_length = dwin->decode (v16) - sizeof (Uid_packet);
4642      if (arr_length <= 0)
4643	return size;
4644      uint64_t link_uid = (uint64_t) 0;
4645      if (dwin->decode (uidp->flags) & COMPRESSED_INFO)
4646	{
4647	  arr_length -= sizeof (uint64_t);
4648	  unsigned char *s = (unsigned char*) (arr_bytes + arr_length);
4649	  int shift = 0;
4650	  for (size_t i = 0; i<sizeof (link_uid); i++)
4651	    {
4652	      link_uid |= (uint64_t) * s++ << shift;
4653	      shift += 8;
4654	    }
4655	}
4656      if (wsize == W32)
4657	add_uid (dwin, uid, (int) (arr_length / sizeof (uint32_t)),
4658		 (uint32_t*) arr_bytes, link_uid);
4659      else
4660	add_uid (dwin, uid, (int) (arr_length / sizeof (uint64_t)),
4661		 (uint64_t*) arr_bytes, link_uid);
4662      return size;
4663    }
4664
4665  PacketDescriptor *pcktDescr = getPacketDescriptor (rcptype);
4666  if (pcktDescr == NULL)
4667    return size;
4668  DataDescriptor *dataDescr = pcktDescr->getDataDescriptor ();
4669  if (dataDescr == NULL)
4670    return size;
4671
4672  /* omazur: TBR START -- old experiment */
4673  if (rcptype == PROF_PCKT)
4674    {
4675      // For backward compatibility with older SS12 experiments
4676      int numstates = get_params ()->lms_magic_id; // ugly, for old experiments
4677      if (numstates > LMS_NUM_SOLARIS_MSTATES)
4678	numstates = LMS_NUM_SOLARIS_MSTATES;
4679      for (int i = 0; i < numstates; i++)
4680	if (check_mstate ((char*) rcp, pcktDescr, PROP_UCPU + i))
4681	  readPacket (dwin, (char*) rcp, pcktDescr, dataDescr, PROP_UCPU + i,
4682		      size);
4683    }
4684  else
4685    readPacket (dwin, (char*) rcp, pcktDescr, dataDescr, 0, size);
4686  return size;
4687}
4688
4689void
4690Experiment::readPacket (Data_window *dwin, char *ptr, PacketDescriptor *pDscr,
4691			DataDescriptor *dDscr, int arg, uint64_t pktsz)
4692{
4693  union Value
4694  {
4695    uint32_t val32;
4696    uint64_t val64;
4697  } *v;
4698
4699  long recn = dDscr->addRecord ();
4700  Vector<FieldDescr*> *fields = pDscr->getFields ();
4701  int sz = fields->size ();
4702  for (int i = 0; i < sz; i++)
4703    {
4704      FieldDescr *field = fields->fetch (i);
4705      v = (Value*) (ptr + field->offset);
4706      if (field->propID == arg)
4707	{
4708	  dDscr->setValue (PROP_NTICK, recn, dwin->decode (v->val32));
4709	  dDscr->setValue (PROP_MSTATE, recn, (uint32_t) (field->propID - PROP_UCPU));
4710	}
4711      if (field->propID == PROP_THRID || field->propID == PROP_LWPID
4712	  || field->propID == PROP_CPUID)
4713	{
4714	  uint64_t tmp64 = 0;
4715	  switch (field->vtype)
4716	    {
4717	    case TYPE_INT32:
4718	    case TYPE_UINT32:
4719	      tmp64 = dwin->decode (v->val32);
4720	      break;
4721	    case TYPE_INT64:
4722	    case TYPE_UINT64:
4723	      tmp64 = dwin->decode (v->val64);
4724	      break;
4725	    case TYPE_STRING:
4726	    case TYPE_DOUBLE:
4727	    case TYPE_OBJ:
4728	    case TYPE_DATE:
4729	    case TYPE_BOOL:
4730	    case TYPE_ENUM:
4731	    case TYPE_LAST:
4732	    case TYPE_NONE:
4733	      break;
4734	    }
4735	  uint32_t tag = mapTagValue ((Prop_type) field->propID, tmp64);
4736	  dDscr->setValue (field->propID, recn, tag);
4737	}
4738      else
4739	{
4740	  switch (field->vtype)
4741	    {
4742	    case TYPE_INT32:
4743	    case TYPE_UINT32:
4744	      dDscr->setValue (field->propID, recn, dwin->decode (v->val32));
4745	      break;
4746	    case TYPE_INT64:
4747	    case TYPE_UINT64:
4748	      dDscr->setValue (field->propID, recn, dwin->decode (v->val64));
4749	      break;
4750	    case TYPE_STRING:
4751	      {
4752		int len = (int) (pktsz - field->offset);
4753		if ((len > 0) && (ptr[field->offset] != 0))
4754		  {
4755		    StringBuilder *sb = new StringBuilder ();
4756		    sb->append (ptr + field->offset, 0, len);
4757		    dDscr->setObjValue (field->propID, recn, sb);
4758		  }
4759		break;
4760	      }
4761	      // ignoring the following cases (why?)
4762	    case TYPE_DOUBLE:
4763	    case TYPE_OBJ:
4764	    case TYPE_DATE:
4765	    case TYPE_BOOL:
4766	    case TYPE_ENUM:
4767	    case TYPE_LAST:
4768	    case TYPE_NONE:
4769	      break;
4770	    }
4771	}
4772    }
4773}
4774
4775#define PROG_BYTE 102400 // update progress bar every PROG_BYTE bytes
4776
4777void
4778Experiment::read_data_file (const char *fname, const char *msg)
4779{
4780  Data_window::Span span;
4781  off64_t total_len, remain_len;
4782  char *progress_bar_msg;
4783  int progress_bar_percent = -1;
4784
4785  char *data_file_name = dbe_sprintf (NTXT ("%s/%s"), expt_name, fname);
4786  Data_window *dwin = new Data_window (data_file_name);
4787  // Here we can call stat(data_file_name) to get file size,
4788  // and call a function to reallocate vectors for clock profiling data
4789  free (data_file_name);
4790  if (dwin->not_opened ())
4791    {
4792      delete dwin;
4793      return;
4794    }
4795  dwin->need_swap_endian = need_swap_endian;
4796
4797  span.offset = 0;
4798  span.length = dwin->get_fsize ();
4799  total_len = remain_len = span.length;
4800  progress_bar_msg = dbe_sprintf (NTXT ("%s %s"), NTXT ("  "), msg);
4801  invalid_packet = 0;
4802  for (;;)
4803    {
4804      uint64_t pcktsz = readPacket (dwin, &span);
4805      if (pcktsz == 0)
4806	break;
4807      // Update progress bar
4808      if ((span.length <= remain_len) && (remain_len > 0))
4809	{
4810	  int percent = (int) (100 * (total_len - remain_len) / total_len);
4811	  if (percent > progress_bar_percent)
4812	    {
4813	      progress_bar_percent += 10;
4814	      theApplication->set_progress (percent, progress_bar_msg);
4815	    }
4816	  remain_len -= PROG_BYTE;
4817	}
4818      span.length -= pcktsz;
4819      span.offset += pcktsz;
4820    }
4821  delete dwin;
4822
4823  if (invalid_packet)
4824    {
4825      StringBuilder sb;
4826      sb.sprintf (GTXT ("WARNING: There are %d invalid packet(s) in the %s file"),
4827		  invalid_packet, fname);
4828      Emsg *m = new Emsg (CMSG_WARN, sb);
4829      warnq->append (m);
4830    }
4831
4832  theApplication->set_progress (0, NTXT (""));
4833  free (progress_bar_msg);
4834}
4835
4836int
4837Experiment::read_overview_file ()
4838{
4839  char *data_file_name = dbe_sprintf ("%s/%s", expt_name, SP_OVERVIEW_FILE);
4840  Data_window *dwin = new Data_window (data_file_name);
4841  free (data_file_name);
4842  if (dwin->not_opened ())
4843    {
4844      delete dwin;
4845      return 0;
4846    }
4847  dwin->need_swap_endian = need_swap_endian;
4848  newDataDescriptor (DATA_SAMPLE);
4849
4850  Data_window::Span span;
4851  span.offset = 0;
4852  span.length = dwin->get_fsize ();
4853
4854  PrUsage *data = NULL, *data_prev = NULL;
4855  Sample *sample;
4856  int sample_number = 1;
4857
4858  int64_t prDataSize;
4859  if (wsize == W32)
4860    prDataSize = PrUsage::bind32Size ();
4861  else
4862    prDataSize = PrUsage::bind64Size ();
4863
4864  while (span.length > 0)
4865    {
4866      data_prev = data;
4867      data = new PrUsage ();
4868
4869      void *dw = dwin->bind (&span, prDataSize);
4870      if ((dw == NULL) || (prDataSize > span.length))
4871	{
4872	  Emsg *m = new Emsg (CMSG_ERROR, GTXT ("Warning: overview data file can't be read"));
4873	  warnq->append (m);
4874	  status = FAILURE;
4875	  delete dwin;
4876	  return status;
4877	}
4878
4879      if (wsize == W32)
4880	data->bind32 (dw, need_swap_endian);
4881      else
4882	data->bind64 (dw, need_swap_endian);
4883      span.length -= prDataSize;
4884      span.offset += prDataSize;
4885
4886      // Skip the first packet
4887      if (data_prev == NULL)
4888	continue;
4889      if (sample_number > samples->size ())
4890	{ // inconsistent log/overview
4891	  sample = new Sample (sample_number);
4892	  char * label = GTXT ("<unknown>");
4893	  sample->start_label = dbe_strdup (label);
4894	  sample->end_label = dbe_strdup (label);
4895	  samples->append (sample);
4896	}
4897      else
4898	sample = samples->fetch (sample_number - 1);
4899      sample_number++;
4900      sample->start_time = data_prev->pr_tstamp + 1;
4901      sample->end_time = data->pr_tstamp;
4902      sample->prusage = data_prev;
4903
4904      data_prev->pr_rtime = data->pr_rtime - data_prev->pr_rtime;
4905      data_prev->pr_utime = data->pr_utime - data_prev->pr_utime;
4906      data_prev->pr_stime = data->pr_stime - data_prev->pr_stime;
4907      data_prev->pr_ttime = data->pr_ttime - data_prev->pr_ttime;
4908      data_prev->pr_tftime = data->pr_tftime - data_prev->pr_tftime;
4909      data_prev->pr_dftime = data->pr_dftime - data_prev->pr_dftime;
4910      data_prev->pr_kftime = data->pr_kftime - data_prev->pr_kftime;
4911      data_prev->pr_ltime = data->pr_ltime - data_prev->pr_ltime;
4912      data_prev->pr_slptime = data->pr_slptime - data_prev->pr_slptime;
4913      data_prev->pr_wtime = data->pr_wtime - data_prev->pr_wtime;
4914      data_prev->pr_stoptime = data->pr_stoptime - data_prev->pr_stoptime;
4915      data_prev->pr_minf = data->pr_minf - data_prev->pr_minf;
4916      data_prev->pr_majf = data->pr_majf - data_prev->pr_majf;
4917      data_prev->pr_nswap = data->pr_nswap - data_prev->pr_nswap;
4918      data_prev->pr_inblk = data->pr_inblk - data_prev->pr_inblk;
4919      data_prev->pr_oublk = data->pr_oublk - data_prev->pr_oublk;
4920      data_prev->pr_msnd = data->pr_msnd - data_prev->pr_msnd;
4921      data_prev->pr_mrcv = data->pr_mrcv - data_prev->pr_mrcv;
4922      data_prev->pr_sigs = data->pr_sigs - data_prev->pr_sigs;
4923      data_prev->pr_vctx = data->pr_vctx - data_prev->pr_vctx;
4924      data_prev->pr_ictx = data->pr_ictx - data_prev->pr_ictx;
4925      data_prev->pr_sysc = data->pr_sysc - data_prev->pr_sysc;
4926      data_prev->pr_ioch = data->pr_ioch - data_prev->pr_ioch;
4927      sample->get_usage (); // force validation
4928    }
4929
4930  for (long smpNum = samples->size (); smpNum >= sample_number; smpNum--)
4931    {
4932      // overview file was truncated
4933      sample = samples->remove (smpNum - 1);
4934      delete sample;
4935    }
4936
4937  if (data)
4938    {
4939      // Update last_event so that getEndTime() covers
4940      // all loadobjects, too.
4941      update_last_event (data->pr_tstamp);
4942      delete data;
4943    }
4944  delete dwin;
4945  return SUCCESS;
4946}
4947
4948int
4949Experiment::uidNodeCmp (const void *a, const void *b)
4950{
4951  UIDnode *nd1 = *(UIDnode**) a;
4952  UIDnode *nd2 = *(UIDnode**) b;
4953  if (nd1->uid == nd2->uid)
4954    return 0;
4955  return nd1->uid < nd2->uid ? -1 : 1;
4956}
4957
4958static uint64_t
4959funcAddr (uint32_t val)
4960{
4961  if (val == (uint32_t) SP_LEAF_CHECK_MARKER)
4962    return (uint64_t) SP_LEAF_CHECK_MARKER;
4963  if (val == (uint32_t) SP_TRUNC_STACK_MARKER)
4964    return (uint64_t) SP_TRUNC_STACK_MARKER;
4965  if (val == (uint32_t) SP_FAILED_UNWIND_MARKER)
4966    return (uint64_t) SP_FAILED_UNWIND_MARKER;
4967  return val;
4968}
4969
4970Experiment::UIDnode *
4971Experiment::add_uid (Data_window *dwin, uint64_t uid, int size,
4972		     uint32_t *array, uint64_t link_uid)
4973{
4974  if (uid == (uint64_t) 0)
4975    return NULL;
4976  uint64_t val = funcAddr (dwin->decode (array[0]));
4977  UIDnode *node = NULL;
4978  UIDnode *res = get_uid_node (uid, val);
4979  UIDnode *next = res;
4980  for (int i = 0; i < size; i++)
4981    {
4982      val = funcAddr (dwin->decode (array[i]));
4983      if (next == NULL)
4984	{
4985	  next = get_uid_node ((uint64_t) 0, val);
4986	  if (node != NULL)
4987	    node->next = next;
4988	}
4989      node = next;
4990      next = node->next;
4991      if (node->val == 0)
4992	node->val = val;
4993      else if (node->val != val)   // Algorithmic error (should never happen)
4994	node->val = (uint64_t) SP_LEAF_CHECK_MARKER;
4995    }
4996  if (next == NULL && link_uid != (uint64_t) 0 && node != NULL)
4997    node->next = get_uid_node (link_uid);
4998  return res;
4999}
5000
5001Experiment::UIDnode *
5002Experiment::add_uid (Data_window *dwin, uint64_t uid, int size, uint64_t *array, uint64_t link_uid)
5003{
5004  if (uid == (uint64_t) 0)
5005    return NULL;
5006  UIDnode *node = NULL;
5007  uint64_t val = dwin->decode (array[0]);
5008  UIDnode *res = get_uid_node (uid, val);
5009  UIDnode *next = res;
5010  for (int i = 0; i < size; i++)
5011    {
5012      val = dwin->decode (array[i]);
5013      if (next == NULL)
5014	{
5015	  next = get_uid_node ((uint64_t) 0, val);
5016	  if (node != NULL)
5017	    node->next = next;
5018	}
5019      node = next;
5020      next = node->next;
5021      if (node->val == (uint64_t) 0)
5022	node->val = val;
5023      else if (node->val != val)   // Algorithmic error (should never happen)
5024	node->val = (uint64_t) - 1;
5025    }
5026  if (next == NULL && link_uid != (uint64_t) 0 && node != NULL)
5027    node->next = get_uid_node (link_uid);
5028  return res;
5029}
5030
5031Experiment::UIDnode *
5032Experiment::new_uid_node (uint64_t uid, uint64_t val)
5033{
5034#define NCHUNKSTEP 1024
5035  if (nnodes >= nchunks * CHUNKSZ)
5036    {
5037      // Reallocate Node chunk array
5038      UIDnode** old_chunks = chunks;
5039      chunks = new UIDnode*[nchunks + NCHUNKSTEP];
5040      memcpy (chunks, old_chunks, nchunks * sizeof (UIDnode*));
5041      nchunks += NCHUNKSTEP;
5042      delete[] old_chunks;
5043      // Clean future pointers
5044      memset (&chunks[nchunks - NCHUNKSTEP], 0, NCHUNKSTEP * sizeof (UIDnode*));
5045    }
5046
5047  if (NULL == chunks[nnodes / CHUNKSZ])   // Allocate new chunk for nodes.
5048    chunks[nnodes / CHUNKSZ] = new UIDnode[CHUNKSZ];
5049  UIDnode *node = &chunks[nnodes / CHUNKSZ][nnodes % CHUNKSZ];
5050  node->uid = uid;
5051  node->val = val;
5052  node->next = NULL;
5053  nnodes++;
5054  return node;
5055}
5056
5057Experiment::UIDnode *
5058Experiment::get_uid_node (uint64_t uid, uint64_t val)
5059{
5060  int hash = (((int) uid) >> 4) & (HTableSize - 1);
5061  if (uid != (uint64_t) 0)
5062    {
5063      UIDnode *node = uidHTable[hash];
5064      if (node && node->uid == uid)
5065	return node;
5066    }
5067  UIDnode *node = new_uid_node (uid, val);
5068  if (uid != (uint64_t) 0)
5069    {
5070      uidHTable[hash] = node;
5071      uidnodes->append (node);
5072    }
5073  return node;
5074}
5075
5076Experiment::UIDnode *
5077Experiment::get_uid_node (uint64_t uid)
5078{
5079  if (uid == (uint64_t) 0)
5080    return NULL;
5081  int hash = (((int) uid) >> 4) & (HTableSize - 1);
5082  UIDnode *node = uidHTable[hash];
5083  if (node && node->uid == uid)
5084    return node;
5085  node = new_uid_node (uid, (uint64_t) 0);
5086  node->next = node;
5087  return node;
5088}
5089
5090Experiment::UIDnode *
5091Experiment::find_uid_node (uint64_t uid)
5092{
5093  int hash = (((int) uid) >> 4) & (HTableSize - 1);
5094  UIDnode *node = uidHTable[hash];
5095  if (node && node->uid == uid)
5096    return node;
5097  int lt = 0;
5098  int rt = uidnodes->size () - 1;
5099  while (lt <= rt)
5100    {
5101      int md = (lt + rt) / 2;
5102      node = uidnodes->fetch (md);
5103      if (node->uid < uid)
5104	lt = md + 1;
5105      else if (node->uid > uid)
5106	rt = md - 1;
5107      else
5108	{
5109	  uidHTable[hash] = node;
5110	  return node;
5111	}
5112    }
5113  return NULL;
5114}
5115
5116int
5117Experiment::frUidCmp (const void *a, const void *b)
5118{
5119  RawFramePacket *fp1 = *(RawFramePacket**) a;
5120  RawFramePacket *fp2 = *(RawFramePacket**) b;
5121  if (fp1->uid == fp2->uid)
5122    return 0;
5123  return fp1->uid < fp2->uid ? -1 : 1;
5124}
5125
5126Experiment::RawFramePacket *
5127Experiment::find_frame_packet (uint64_t uid)
5128{
5129  int lt = 0;
5130  int rt = frmpckts->size () - 1;
5131  while (lt <= rt)
5132    {
5133      int md = (lt + rt) / 2;
5134      RawFramePacket *fp = frmpckts->fetch (md);
5135      if (fp->uid < uid)
5136	lt = md + 1;
5137      else if (fp->uid > uid)
5138	rt = md - 1;
5139      else
5140	return fp;
5141    }
5142
5143  return NULL;
5144}
5145
5146#define FRINFO_CACHEOPT_SIZE_LIMIT  4000000
5147#define FRINFO_PIPELINE_SIZE_LIMIT  500000
5148#define FRINFO_PIPELINE_NUM_STAGES  3
5149
5150// Pipelined execution of resolve_frame_info() and add_stack().
5151// Since this is the largest time consuming part of loading an experiment (especially
5152// so for large java experiments) - executing this part as a 3 stage pipeline can
5153// give significant performance gain - and this concept can be aggressively applied
5154// to enhance the gain further in future. The three stages are:
5155// Phase 1:  resolve_frame_info()
5156// Phase 2:  first part of add_stack() where the native stack is built
5157// Phase 3:  second part og add_stack() where the java stack is built
5158// Phase 4:   insert the native and java stacks into the stack map
5159// The main thread operates in the first Phase and the other stages are
5160// operated by a ssplib sequential queue - The threads working on the queues run concurrently
5161// with each other and with the main thread. But within a particular queue, jobs are
5162// executed sequentially
5163
5164
5165// This is the second phase of the pipeline of resolve_frame_info and add_stack
5166//  It works on a chunk of iterations (size CSTCTX_CHUNK_SZ) and invokes add_stack()
5167// for each one of them
5168
5169void
5170Experiment::resolve_frame_info (DataDescriptor *dDscr)
5171{
5172  if (!resolveFrameInfo)
5173    return;
5174  if (NULL == cstack)
5175    return;
5176  dDscr->setResolveFrInfoDone ();
5177
5178  // Check for TSTAMP
5179  int propID = dbeSession->getPropIdByName (NTXT ("TSTAMP"));
5180  Data *dataTStamp = dDscr->getData (propID);
5181  if (dataTStamp == NULL)
5182    return;
5183
5184  propID = dbeSession->getPropIdByName (NTXT ("FRINFO"));
5185  Data *dataFrinfo = dDscr->getData (propID);
5186
5187  propID = dbeSession->getPropIdByName (NTXT ("THRID"));
5188  Data *dataThrId = dDscr->getData (propID);
5189
5190  // We can get frame info either by FRINFO or by [THRID,STKIDX]
5191  if (dataFrinfo == NULL)
5192    return;
5193
5194  char *propName = NTXT ("MSTACK");
5195  propID = dbeSession->getPropIdByName (propName);
5196  PropDescr *prMStack = new PropDescr (propID, propName);
5197  prMStack->uname = dbe_strdup (GTXT ("Machine Call Stack"));
5198  prMStack->vtype = TYPE_OBJ;
5199  dDscr->addProperty (prMStack);
5200
5201  propName = NTXT ("USTACK");
5202  propID = dbeSession->getPropIdByName (propName);
5203  PropDescr *prUStack = new PropDescr (propID, propName);
5204  prUStack->uname = dbe_strdup (GTXT ("User Call Stack"));
5205  prUStack->vtype = TYPE_OBJ;
5206  dDscr->addProperty (prUStack);
5207
5208  propName = NTXT ("XSTACK");
5209  propID = dbeSession->getPropIdByName (propName);
5210  PropDescr *prXStack = new PropDescr (propID, propName);
5211  prXStack->uname = dbe_strdup (GTXT ("Expert Call Stack"));
5212  prXStack->vtype = TYPE_OBJ;
5213  dDscr->addProperty (prXStack);
5214
5215  propName = NTXT ("HSTACK");
5216  propID = dbeSession->getPropIdByName (propName);
5217  PropDescr *prHStack = new PropDescr (propID, propName);
5218  prHStack->uname = dbe_strdup (GTXT ("ShowHide Call Stack"));
5219  prHStack->vtype = TYPE_OBJ;
5220  dDscr->addProperty (prHStack);
5221
5222  if (has_java)
5223    {
5224      propName = NTXT ("JTHREAD");
5225      propID = dbeSession->getPropIdByName (propName);
5226      PropDescr *prJThread = new PropDescr (propID, propName);
5227      prJThread->uname = dbe_strdup (GTXT ("Java Thread"));
5228      prJThread->vtype = TYPE_OBJ;
5229      dDscr->addProperty (prJThread);
5230    }
5231
5232  if (ompavail)
5233    {
5234      PropDescr *prop = new PropDescr (PROP_OMPSTATE, NTXT ("OMPSTATE"));
5235      prop->uname = dbe_strdup (GTXT ("OpenMP state"));
5236      prop->vtype = TYPE_UINT32;
5237      char * stateNames [OMP_LAST_STATE] = OMP_THR_STATE_STRINGS;
5238      char * stateUNames[OMP_LAST_STATE] = OMP_THR_STATE_USTRINGS;
5239      for (int ii = 0; ii < OMP_LAST_STATE; ii++)
5240	prop->addState (ii, stateNames[ii], stateUNames[ii]);
5241      dDscr->addProperty (prop);
5242
5243      // add PROP_CPRID to profiling data (not same as omptrace's PROP_CPRID)
5244      prop = dDscr->getProp (PROP_CPRID);
5245      if (prop)
5246	{
5247	  VType_type type = prop->vtype;
5248	  assert (type == TYPE_OBJ); //see 7040526
5249	}
5250      prop = new PropDescr (PROP_CPRID, NTXT ("CPRID")); //profiling PROP_CPRID
5251      prop->uname = dbe_strdup (GTXT ("OpenMP parallel region"));
5252      prop->vtype = TYPE_OBJ;
5253      dDscr->addProperty (prop);
5254
5255      // add PROP_TSKID to profiling data (not same as omptrace's PROP_TSKID)
5256      prop = dDscr->getProp (PROP_TSKID);
5257      if (prop)
5258	{
5259	  VType_type type = prop->vtype;
5260	  assert (type == TYPE_OBJ); //see 7040526
5261	}
5262      prop = new PropDescr (PROP_TSKID, NTXT ("TSKID")); //profiling PROP_TSKID
5263      prop->uname = dbe_strdup (GTXT ("OpenMP task"));
5264      prop->vtype = TYPE_OBJ;
5265      dDscr->addProperty (prop);
5266    }
5267  char *progress_bar_msg = dbe_sprintf (NTXT ("%s %s: %s"), NTXT ("  "),
5268					GTXT ("Processing CallStack Data"),
5269					get_basename (expt_name));
5270  int progress_bar_percent = -1;
5271  long deltaReport = 5000;
5272  long nextReport = 0;
5273
5274  long size = dDscr->getSize ();
5275  //    bool resolve_frinfo_pipelined = size > FRINFO_PIPELINE_SIZE_LIMIT && !ompavail;
5276  bool resolve_frinfo_pipelined = false;
5277
5278  Map<uint64_t, uint64_t> *nodeCache = NULL;
5279  Map<uint64_t, uint64_t> *frameInfoCache = NULL;
5280  if (size > FRINFO_CACHEOPT_SIZE_LIMIT && dversion == NULL)
5281    {
5282      frameInfoCache = new CacheMap<uint64_t, uint64_t>;
5283      nodeCache = new CacheMap<uint64_t, uint64_t>;
5284    }
5285
5286  pushCnt = popCnt = pushCnt3 = popCnt3 = 0;
5287  nPush = nPop = 0;
5288
5289  FramePacket *fp = NULL;
5290  //    DbeThreadPool * threadPool = new DbeThreadPool(5);
5291  fp = new FramePacket;
5292  fp->stack = new Vector<Vaddr>;
5293  fp->jstack = new Vector<Vaddr>;
5294  fp->ompstack = new Vector<Vaddr>;
5295  fp->omp_state = 0;
5296  fp->mpi_state = 0;
5297
5298  // piggyback on post-processing to calculate exp->last_event
5299  const hrtime_t _exp_start_time = getStartTime (); // wall clock time
5300  hrtime_t exp_duration = getLastEvent () == ZERO_TIME ? 0
5301	  : getLastEvent () - _exp_start_time; // zero-based
5302
5303  int missed_fi = 0;
5304  int total_fi = 0;
5305
5306  for (long i = 0; i < size; i++)
5307    {
5308      if (i == nextReport)
5309	{
5310	  int percent = (int) (i * 100 / size);
5311	  if (percent > progress_bar_percent)
5312	    {
5313	      progress_bar_percent += 10;
5314	      theApplication->set_progress (percent, progress_bar_msg);
5315	    }
5316	  nextReport += deltaReport;
5317	}
5318
5319      uint32_t thrid = (uint32_t) dataThrId->fetchInt (i);
5320      hrtime_t tstamp = (hrtime_t) dataTStamp->fetchLong (i);
5321
5322      // piggyback on post-processing to calculate exp->last_event
5323      {
5324	hrtime_t relative_timestamp = tstamp - _exp_start_time;
5325	if (exp_duration < relative_timestamp)
5326	  exp_duration = relative_timestamp;
5327      }
5328      uint64_t frinfo = (uint64_t) dataFrinfo->fetchLong (i);
5329
5330      RawFramePacket *rfp = NULL;
5331      if (frinfo)
5332	{
5333	  // CacheMap does not work with NULL key
5334	  if (frameInfoCache != NULL)
5335	    rfp = (RawFramePacket *) frameInfoCache->get (frinfo);
5336	}
5337      if (rfp == 0)
5338	{
5339	  rfp = find_frame_packet (frinfo);
5340	  if (rfp != 0)
5341	    {
5342	      if (frameInfoCache != NULL)
5343		frameInfoCache->put (frinfo, (uint64_t) rfp);
5344	    }
5345	  else
5346	    missed_fi++;
5347	  total_fi++;
5348	}
5349
5350      // Process OpenMP properties
5351      if (ompavail)
5352	{
5353	  fp->omp_state = rfp ? rfp->omp_state : 0;
5354	  dDscr->setValue (PROP_OMPSTATE, i, fp->omp_state);
5355
5356	  fp->omp_cprid = mapPRid->get (thrid, tstamp, mapPRid->REL_EQLE);
5357	  void *omp_preg = mapPReg->get (thrid, tstamp, mapPReg->REL_EQLE);
5358	  if (!omp_preg)
5359	    {
5360	      char *idxname = NTXT ("OMP_preg");
5361	      int idxtype = dbeSession->findIndexSpaceByName (idxname);
5362	      if (idxtype != -1)
5363		{
5364		  Histable *preg0 = dbeSession->findObjectById (Histable::INDEXOBJ, idxtype, (int64_t) 0);
5365		  if (preg0)
5366		    {
5367		      Vector<Histable*> pregs;
5368		      pregs.append (preg0);
5369		      omp_preg = cstack->add_stack (&pregs);
5370		      mapPReg->put (thrid, tstamp, omp_preg);
5371		    }
5372		}
5373	    }
5374	  dDscr->setObjValue (PROP_CPRID, i, omp_preg); //profiling PROP_CPRID
5375	  void *omp_task = mapTask->get (thrid, tstamp, mapTask->REL_EQLE);
5376	  if (!omp_task)
5377	    {
5378	      char *idxname = NTXT ("OMP_task");
5379	      int idxtype = dbeSession->findIndexSpaceByName (idxname);
5380	      if (idxtype != -1)
5381		{
5382		  Histable *task0 = dbeSession->findObjectById (Histable::INDEXOBJ, idxtype, (int64_t) 0);
5383		  if (task0)
5384		    {
5385		      Vector<Histable*> tasks;
5386		      tasks.append (task0);
5387		      omp_task = cstack->add_stack (&tasks);
5388		      mapTask->put (thrid, tstamp, omp_task);
5389		    }
5390		}
5391	    }
5392	  dDscr->setObjValue (PROP_TSKID, i, omp_task); //profiling PROP_TSKID
5393	}
5394      else
5395	{
5396	  fp->omp_state = 0;
5397	  fp->omp_cprid = 0;
5398	}
5399
5400      // Construct the native stack
5401      fp->stack->reset ();
5402      Vaddr leafpc = dDscr->getULongValue (PROP_LEAFPC, i);
5403      if (leafpc)
5404	fp->stack->append (leafpc);
5405      UIDnode *node = rfp ? rfp->uidn : NULL;
5406      while (node)
5407	{
5408	  if (node->next == node)
5409	    // this node contains link_uid
5410	    node = find_uid_node (node->uid);
5411	  else
5412	    {
5413	      fp->stack->append (node->val);
5414	      node = node->next;
5415	    }
5416	}
5417      fp->truncated = 0;
5418      int last = fp->stack->size () - 1;
5419      if (last >= 0)
5420	{
5421	  switch (fp->stack->fetch (last))
5422	    {
5423	    case SP_TRUNC_STACK_MARKER:
5424	      fp->truncated = (Vaddr) SP_TRUNC_STACK_MARKER;
5425	      fp->stack->remove (last);
5426	      break;
5427	    case SP_FAILED_UNWIND_MARKER:
5428	      fp->truncated = (Vaddr) SP_FAILED_UNWIND_MARKER;
5429	      fp->stack->remove (last);
5430	      break;
5431	    }
5432	}
5433
5434      // Construct the Java stack
5435      fp->jstack->reset ();
5436      node = rfp ? rfp->uidj : NULL;
5437      while (node)
5438	{
5439	  if (node->next == node)
5440	    {
5441	      // this node contains link_uid
5442	      UIDnode *n = NULL;
5443	      if (node->uid)
5444		{
5445		  // CacheMap does not work with NULL key
5446		  if (nodeCache != NULL)
5447		    n = (UIDnode *) nodeCache->get (node->uid);
5448		}
5449	      if (n == NULL)
5450		{
5451		  n = find_uid_node (node->uid);
5452		  if (n != NULL)
5453		    {
5454		      if (nodeCache != NULL)
5455			nodeCache->put (node->uid, (uint64_t) n);
5456		    }
5457		}
5458	      node = n;
5459	    }
5460	  else
5461	    {
5462	      fp->jstack->append (node->val);
5463	      node = node->next;
5464	    }
5465	}
5466      fp->jtruncated = false;
5467      last = fp->jstack->size () - 1;
5468      if (last >= 1 && fp->jstack->fetch (last) == SP_TRUNC_STACK_MARKER)
5469	{
5470	  fp->jtruncated = true;
5471	  fp->jstack->remove (last);
5472	  fp->jstack->remove (last - 1);
5473	}
5474
5475      // Construct the OpenMP stack
5476      if (ompavail)
5477	{
5478	  fp->ompstack->reset ();
5479	  if (rfp && rfp->omp_uid)
5480	    {
5481	      if (leafpc)
5482		fp->ompstack->append (leafpc);
5483	      node = rfp->omp_uid;
5484	      while (node)
5485		{
5486		  if (node->next == node)
5487		    // this node contains link_uid
5488		    node = find_uid_node (node->uid);
5489		  else
5490		    {
5491		      fp->ompstack->append (node->val);
5492		      node = node->next;
5493		    }
5494		}
5495	      fp->omptruncated = false;
5496	      last = fp->ompstack->size () - 1;
5497	      if (last >= 0)
5498		{
5499		  switch (fp->ompstack->fetch (last))
5500		    {
5501		    case SP_TRUNC_STACK_MARKER:
5502		      fp->omptruncated = (Vaddr) SP_TRUNC_STACK_MARKER;
5503		      fp->ompstack->remove (last);
5504		      break;
5505		    case SP_FAILED_UNWIND_MARKER:
5506		      fp->omptruncated = (Vaddr) SP_FAILED_UNWIND_MARKER;
5507		      fp->ompstack->remove (last);
5508		      break;
5509		    }
5510		}
5511	    }
5512	}
5513      cstack->add_stack (dDscr, i, fp, NULL);
5514    }
5515
5516  // piggyback on post-processing to calculate exp->last_event
5517  {
5518    hrtime_t exp_end_time = _exp_start_time + exp_duration;
5519    update_last_event (exp_end_time);
5520  }
5521
5522  if (missed_fi > 0)
5523    {
5524      StringBuilder sb;
5525      sb.sprintf (
5526		  GTXT ("*** Warning: %d frameinfo packets are missing from total of %d when resolving %s."),
5527		  missed_fi, total_fi, dDscr->getName ());
5528      warnq->append (new Emsg (CMSG_WARN, sb));
5529    }
5530
5531  //    threadPool->wait_group();
5532  //    delete threadPool;
5533  theApplication->set_progress (0, NTXT (""));
5534  free (progress_bar_msg);
5535  if (!resolve_frinfo_pipelined && fp != NULL)
5536    {
5537      delete fp->ompstack;
5538      delete fp->jstack;
5539      delete fp->stack;
5540      delete fp;
5541    }
5542  delete frameInfoCache;
5543  frameInfoCache = NULL;
5544  delete nodeCache;
5545  nodeCache = NULL;
5546}
5547
5548void
5549Experiment::post_process ()
5550{
5551  // update non_paused_time after final update to "last_event"
5552  if (resume_ts != MAX_TIME && last_event)
5553    {
5554      hrtime_t ts = last_event - exp_start_time;
5555      hrtime_t delta = ts - resume_ts;
5556      non_paused_time += delta;
5557      resume_ts = MAX_TIME; // collection is paused
5558    }
5559
5560  // GC: prune events outside of experiment duration, calculate GC duration, update indices
5561  int index;
5562  GCEvent * gcevent;
5563  gc_duration = ZERO_TIME;
5564  if (gcevents != NULL)
5565    {
5566      // delete events that finish before exp_start_time or start after last_event
5567      for (int ii = 0; ii < gcevents->size ();)
5568	{
5569	  gcevent = gcevents->fetch (ii);
5570	  if (gcevent->end - exp_start_time < 0
5571	      || last_event - gcevent->start < 0)
5572	    delete gcevents->remove (ii);
5573	  else
5574	    ii++;
5575	}
5576    }
5577  Vec_loop (GCEvent*, gcevents, index, gcevent)
5578  {
5579    gcevent->id = index + 1; // renumber to account for any deleted events
5580    if (gcevent->start - exp_start_time < 0 || gcevent->start == ZERO_TIME)
5581      // truncate events that start before experiment start
5582      gcevent->start = exp_start_time;
5583    if (last_event - gcevent->end < 0)
5584      // truncate events that end after experiment end
5585      gcevent->end = last_event;
5586    gc_duration += gcevent->end - gcevent->start;
5587  }
5588}
5589
5590Experiment::Exp_status
5591Experiment::find_expdir (char *path)
5592{
5593  // This function checks that the experiment directory
5594  // is of the proper form, and accessible
5595  struct stat64 sbuf;
5596
5597  // Save the name
5598  expt_name = dbe_strdup (path);
5599
5600  // Check that the name ends in .er
5601  size_t i = strlen (path);
5602  if (i > 0 && path[i - 1] == '/')
5603    path[--i] = '\0';
5604
5605  if (i < 4 || strcmp (&path[i - 3], NTXT (".er")) != 0)
5606    {
5607      Emsg *m = new Emsg (CMSG_FATAL,
5608			  GTXT ("*** Error: not a valid experiment name"));
5609      errorq->append (m);
5610      status = FAILURE;
5611      return FAILURE;
5612    }
5613
5614  // Check if new directory structure (i.e., no pointer file)
5615  if (dbe_stat (path, &sbuf))
5616    {
5617      Emsg *m = new Emsg (CMSG_FATAL, GTXT ("*** Error: experiment not found"));
5618      errorq->append (m);
5619      status = FAILURE;
5620      return FAILURE;
5621    }
5622  if (S_ISDIR (sbuf.st_mode) == 0)
5623    {
5624      // ignore pointer-file experiments
5625      Emsg *m = new Emsg (CMSG_FATAL,
5626			  GTXT ("*** Error: experiment was recorded with an earlier version, and can not be read"));
5627      errorq->append (m);
5628      obsolete = 1;
5629      status = FAILURE;
5630      return FAILURE;
5631    }
5632  return SUCCESS;
5633}
5634
5635void
5636Experiment::purge ()
5637{
5638  // This routine will purge all of the caches of releasable storage.
5639  for (int i = 0; i < dataDscrs->size (); ++i)
5640    {
5641      DataDescriptor *dataDscr = dataDscrs->fetch (i);
5642      if (dataDscr == NULL)
5643	continue;
5644      dataDscr->reset ();
5645    }
5646  delete cstack;
5647  delete cstackShowHide;
5648  cstack = CallStack::getInstance (this);
5649  cstackShowHide = CallStack::getInstance (this);
5650}
5651
5652void
5653Experiment::resetShowHideStack ()
5654{
5655  delete cstackShowHide;
5656  cstackShowHide = CallStack::getInstance (this);
5657}
5658
5659#define GET_INT_VAL(v, s, len) \
5660    for (v = len = 0; isdigit(*s); s++, len++) { v = v * 10 + (*s -'0'); }
5661
5662static int
5663dir_name_cmp (const void *a, const void *b)
5664{
5665  char *s1 = *((char **) a);
5666  char *s2 = *((char **) b);
5667  while (*s1)
5668    {
5669      if (isdigit (*s1) && isdigit (*s2))
5670	{
5671	  int v1, v2, len1, len2;
5672	  GET_INT_VAL (v1, s1, len1);
5673	  GET_INT_VAL (v2, s2, len2);
5674	  if (v1 != v2)
5675	    return v1 - v2;
5676	  if (len1 != len2)
5677	    return len2 - len1;
5678	  continue;
5679	}
5680      if (*s1 != *s2)
5681	break;
5682      s1++;
5683      s2++;
5684    }
5685  return *s1 - *s2;
5686}
5687
5688Vector<char*> *
5689Experiment::get_descendants_names ()
5690{
5691  char *dir_name = get_expt_name ();
5692  if (dir_name == NULL)
5693    return NULL;
5694  DIR *exp_dir = opendir (dir_name);
5695  if (exp_dir == NULL)
5696    return NULL;
5697  Vector<char*> *exp_names = new Vector<char*>();
5698  for (struct dirent *entry = readdir (exp_dir); entry;
5699	  entry = readdir (exp_dir))
5700    {
5701      if (entry->d_name[0] == '_' || strncmp (entry->d_name, "M_r", 3) == 0)
5702	{
5703	  char *dpath = dbe_sprintf (NTXT ("%s/%s"), dir_name, entry->d_name);
5704	  struct stat64 sbuf;
5705	  if (dbe_stat (dpath, &sbuf) == 0 && S_ISDIR (sbuf.st_mode))
5706	    exp_names->append (dpath);
5707	  else
5708	    free (dpath);
5709	}
5710    }
5711  closedir (exp_dir);
5712  if (exp_names->size () == 0)
5713    {
5714      delete exp_names;
5715      return NULL;
5716    }
5717  exp_names->sort (dir_name_cmp);
5718  return exp_names;
5719}
5720
5721bool
5722Experiment::create_dir (char *dname)
5723{
5724  if (mkdir (dname, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) == 0)
5725    {
5726      return true;
5727    }
5728  struct stat64 sbuf;
5729  if (dbe_stat (dname, &sbuf) != 0 || S_ISDIR (sbuf.st_mode) == 0)
5730    {
5731      char *buf = dbe_sprintf (GTXT ("Unable to create directory `%s'\n"),
5732			       dname);
5733      errorq->append (new Emsg (CMSG_ERROR, buf));
5734      free (buf);
5735      return false;
5736    }
5737  return true;
5738}
5739
5740char *
5741Experiment::get_arch_name ()
5742{
5743  if (arch_name == NULL)
5744    {
5745      // Determine the master experiment directory.
5746      // omazur: should do it in a less hacky way. XXXX
5747      char *ptr = strstr_r (expt_name, DESCENDANT_EXPT_KEY);
5748      ptr = ptr ? ptr + 3 : expt_name + strlen (expt_name);
5749      arch_name = dbe_sprintf (NTXT ("%.*s/%s"), (int) (ptr - expt_name),
5750			       expt_name, SP_ARCHIVES_DIR);
5751    }
5752  return arch_name;
5753}
5754
5755char *
5756Experiment::get_fndr_arch_name ()
5757{
5758  if (fndr_arch_name == NULL)
5759    // Determine the founder experiment directory.
5760    fndr_arch_name = dbe_strdup (get_arch_name ());
5761  return fndr_arch_name;
5762}
5763
5764enum
5765{
5766  HASH_NAME_LEN     = 11    // (64 / 6 + 1) = 11
5767};
5768
5769static char *
5770get_hash_string (char buf[HASH_NAME_LEN + 1], uint64_t hash)
5771{
5772  static const char *har =
5773	  "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-_";
5774  for (int i = 0; i < HASH_NAME_LEN; i++)
5775    {
5776      buf[i] = har[hash & 0x3f];
5777      hash = hash >> 6;
5778    }
5779  buf[HASH_NAME_LEN] = 0;
5780  return buf;
5781}
5782
5783char *
5784Experiment::getNameInArchive (const char *fname, bool archiveFile)
5785{
5786  char *aname = get_archived_name (fname, archiveFile);
5787  char *ret = dbe_sprintf (NTXT ("%s/%s"), get_arch_name (), aname);
5788  free (aname);
5789  return ret;
5790}
5791
5792#define MAX_ARCHIVE_FILENAME_LEN    (256 - HASH_NAME_LEN - 2)
5793
5794char *
5795Experiment::get_archived_name (const char *fname, bool archiveFile)
5796{
5797  char *bname = get_basename (fname);
5798
5799  // dirname_hash:
5800  char dirnameHash[HASH_NAME_LEN + 1];
5801  // Treat "a.out" and "./a.out" equally
5802  uint64_t hash = bname != fname ? crc64 (fname, bname - fname)
5803				 : crc64 (NTXT ("./"), 2);
5804  get_hash_string (dirnameHash, hash);
5805
5806  char *ret;
5807  long bname_len = dbe_sstrlen (bname);
5808  if (bname_len > MAX_ARCHIVE_FILENAME_LEN)
5809    {
5810      char basenameHash[HASH_NAME_LEN + 1];
5811      hash = crc64 (bname, bname_len);
5812      get_hash_string (basenameHash, hash);
5813      ret = dbe_sprintf ("%.*s%c%s_%s",
5814			 MAX_ARCHIVE_FILENAME_LEN - HASH_NAME_LEN - 1,
5815			 bname, archiveFile ? '.' : '_',
5816			 dirnameHash, basenameHash);
5817    }
5818  else
5819    ret = dbe_sprintf ("%s%c%s", bname, archiveFile ? '.' : '_', dirnameHash);
5820  return ret;
5821}
5822
5823char *
5824Experiment::checkFileInArchive (const char *fname, bool archiveFile)
5825{
5826  if (archiveMap)
5827    {
5828      char *aname = get_archived_name (fname, archiveFile);
5829      DbeFile *df = archiveMap->get (aname);
5830      free (aname);
5831      if (df)
5832	return strdup (df->get_location ());
5833      return NULL;
5834    }
5835  if (founder_exp)
5836    return founder_exp->checkFileInArchive (fname, archiveFile);
5837  return NULL;
5838}
5839
5840
5841// Comparing SegMem
5842
5843static int
5844SegMemCmp (const void *a, const void *b)
5845{
5846  SegMem *item1 = *((SegMem **) a);
5847  SegMem *item2 = *((SegMem **) b);
5848  return item1->unload_time > item2->unload_time ? 1 :
5849	 item1->unload_time == item2->unload_time ? 0 : -1;
5850}
5851
5852SegMem*
5853Experiment::update_ts_in_maps (Vaddr addr, hrtime_t ts)
5854{
5855  Vector<SegMem *> *segMems = (Vector<SegMem *> *) maps->values ();
5856  if (!segMems->is_sorted ())
5857    {
5858      Dprintf (DEBUG_MAPS, NTXT ("update_ts_in_maps: segMems.size=%lld\n"), (long long) segMems->size ());
5859      segMems->sort (SegMemCmp);
5860    }
5861  for (int i = 0, sz = segMems ? segMems->size () : 0; i < sz; i++)
5862    {
5863      SegMem *sm = segMems->fetch (i);
5864      if (ts < sm->unload_time)
5865	{
5866	  for (; i < sz; i++)
5867	    {
5868	      sm = segMems->fetch (i);
5869	      if ((addr >= sm->base) && (addr < sm->base + sm->size))
5870		{
5871		  Dprintf (DEBUG_MAPS,
5872			   "update_ts_in_maps: old:%u.%09u -> %u.%09u addr=0x%08llx size=%lld\n",
5873			   (unsigned) (sm->load_time / NANOSEC),
5874			   (unsigned) (sm->load_time % NANOSEC),
5875			   (unsigned) (ts / NANOSEC), (unsigned) (ts % NANOSEC),
5876			   (unsigned long long) sm->base, (long long) sm->size);
5877		  maps->remove (sm->base, sm->load_time);
5878		  sm->load_time = ts;
5879		  maps->insert (sm->base, ts, sm);
5880		  return sm;
5881		}
5882	    }
5883	}
5884    }
5885  Dprintf (DEBUG_MAPS, "update_ts_in_maps: NOT FOUND %u.%09u addr=0x%08llx\n",
5886	   (unsigned) (ts / NANOSEC), (unsigned) (ts % NANOSEC),
5887	   (unsigned long long) addr);
5888  return NULL;
5889}
5890
5891DbeInstr*
5892Experiment::map_Vaddr_to_PC (Vaddr addr, hrtime_t ts)
5893{
5894  // Look up in the hash table first
5895  int hash = (((int) addr) >> 8) & (HTableSize - 1);
5896  SegMem *si = smemHTable[hash];
5897  if (si == NULL || addr < si->base || addr >= si->base + si->size
5898      || ts < si->load_time || ts >= si->unload_time)
5899    {
5900      // Not in the hash table
5901      si = (SegMem*) maps->locate (addr, ts);
5902      if (si == NULL || addr < si->base || addr >= si->base + si->size
5903	  || ts < si->load_time || ts >= si->unload_time)
5904	{
5905	  si = update_ts_in_maps (addr, ts);
5906	  if (si == NULL)
5907	    return dbeSession->get_Unknown_Function ()->find_dbeinstr (PCInvlFlag, addr);
5908	}
5909      smemHTable[hash] = si;
5910    }
5911
5912  // Calculate the file offset of 'addr'
5913  uint64_t f_offset = si->get_file_offset () + (addr - si->base);
5914
5915  DbeInstr *instr;
5916  if (si->obj->get_type () == Histable::LOADOBJECT)
5917    {
5918      LoadObject *lo = (LoadObject*) si->obj;
5919      lo->sync_read_stabs ();
5920      instr = lo->find_dbeinstr (f_offset);
5921    }
5922  else
5923    {
5924      int hash2 = ((((int) addr) & 0xFFFC00) | (((int) f_offset) >> 2))
5925	      & (HTableSize - 1);
5926      instr = instHTable[hash2];
5927      if (instr == NULL || instr->func != si->obj || instr->addr != f_offset)
5928	{
5929	  // Not in the hash table
5930	  Function *fp = (Function *) si->obj;
5931	  instr = fp->find_dbeinstr (0, f_offset);
5932	  instHTable[hash2] = instr;
5933	}
5934    }
5935  if (!instr->func->isUsed)
5936    {
5937      instr->func->isUsed = true;
5938      instr->func->module->isUsed = true;
5939      instr->func->module->loadobject->isUsed = true;
5940    }
5941  return instr;
5942}
5943
5944Sample *
5945Experiment::map_event_to_Sample (hrtime_t ts)
5946{
5947  Sample *sample;
5948  int index;
5949
5950  // Check if the last used sample is the right one,
5951  // if not then find it.
5952  if (sample_last_used && ts >= sample_last_used->start_time
5953      && ts <= sample_last_used->end_time)
5954    return sample_last_used;
5955
5956  Vec_loop (Sample*, samples, index, sample)
5957  {
5958    if ((ts >= sample->start_time) &&
5959	(ts <= sample->end_time))
5960      {
5961	sample_last_used = sample;
5962	return sample;
5963      }
5964  }
5965  return (Sample*) NULL;
5966}
5967
5968GCEvent *
5969Experiment::map_event_to_GCEvent (hrtime_t ts)
5970{
5971  GCEvent *gcevent;
5972  int index;
5973
5974  // Check if the last used sample is the right one,
5975  // if not then find it.
5976  if (gcevent_last_used && ts >= gcevent_last_used->start
5977      && ts <= gcevent_last_used->end)
5978    return gcevent_last_used;
5979  Vec_loop (GCEvent*, gcevents, index, gcevent)
5980  {
5981    if ((ts >= gcevent->start) &&
5982	(ts <= gcevent->end))
5983      {
5984	gcevent_last_used = gcevent;
5985	return gcevent;
5986      }
5987  }
5988  return (GCEvent*) NULL;
5989}
5990
5991DbeInstr*
5992Experiment::map_jmid_to_PC (Vaddr mid, int bci, hrtime_t ts)
5993{
5994  if (mid == 0 || jmaps == NULL)
5995    // special case: no Java stack was recorded, bci - error code
5996    return dbeSession->get_JUnknown_Function ()->find_dbeinstr (0, bci);
5997
5998  JMethod *jmthd = jmidHTable->get (mid);
5999  if (jmthd == NULL)
6000    {
6001      jmthd = (JMethod *) jmaps->locate_exact_match (mid, ts);
6002      if (jmthd)
6003	jmidHTable->put (mid, jmthd);
6004    }
6005  if (jmthd == NULL || jmthd->get_type () != Histable::FUNCTION)
6006    return dbeSession->get_JUnknown_Function ()->find_dbeinstr (0, (uint64_t) mid);
6007  return jmthd->find_dbeinstr (0, bci);
6008}
6009
6010Emsg *
6011Experiment::fetch_comments ()
6012{
6013  return commentq->fetch ();
6014}
6015
6016Emsg *
6017Experiment::fetch_runlogq ()
6018{
6019  return runlogq->fetch ();
6020}
6021
6022Emsg *
6023Experiment::fetch_errors ()
6024{
6025  return errorq->fetch ();
6026}
6027
6028Emsg *
6029Experiment::fetch_warnings ()
6030{
6031  return warnq->fetch ();
6032}
6033
6034Emsg *
6035Experiment::fetch_notes ()
6036{
6037  return notesq->fetch ();
6038}
6039
6040Emsg *
6041Experiment::fetch_ifreq ()
6042{
6043  return ifreqq->fetch ();
6044}
6045
6046Emsg *
6047Experiment::fetch_pprocq ()
6048{
6049  return pprocq->fetch ();
6050}
6051
6052int
6053Experiment::read_dyntext_file ()
6054{
6055  char *data_file_name = dbe_sprintf ("%s/%s", expt_name, SP_DYNTEXT_FILE);
6056  Data_window *dwin = new Data_window (data_file_name);
6057  if (dwin->not_opened ())
6058    {
6059      free (data_file_name);
6060      delete dwin;
6061      return 1;
6062    }
6063  dwin->need_swap_endian = need_swap_endian;
6064
6065  Function *fp = NULL;
6066  char *progress_msg = NULL; // Message for the progress bar
6067  for (int64_t offset = 0;;)
6068    {
6069      DT_common *cpckt = (DT_common *) dwin->bind (offset, sizeof (DT_common));
6070      if (cpckt == NULL)
6071	break;
6072      size_t cpcktsize = dwin->decode (cpckt->size);
6073      cpckt = (DT_common *) dwin->bind (offset, cpcktsize);
6074      if (cpckt == NULL)
6075	break;
6076      switch (dwin->decode (cpckt->type))
6077	{
6078	case DT_HEADER:
6079	  {
6080	    DT_header *hdr = (DT_header*) cpckt;
6081	    hrtime_t ts = dwin->decode (hdr->time) + exp_start_time;
6082	    SegMem *si = (SegMem*) maps->locate (dwin->decode (hdr->vaddr), ts);
6083	    fp = si ? (Function *) si->obj : NULL;
6084	    if (fp && (fp->get_type () != Histable::FUNCTION
6085		       || !(fp->flags & FUNC_FLAG_DYNAMIC)))
6086	      fp = NULL;
6087	    break;
6088	  }
6089	case DT_CODE:
6090	  if (fp)
6091	    {
6092	      fp->img_fname = data_file_name;
6093	      fp->img_offset = offset + sizeof (DT_common);
6094	      if ((platform != Intel) && (platform != Amd64))
6095		{ //ARCH(SPARC)
6096		  // Find out 'save' instruction address for SPARC
6097		  char *ptr = ((char*) cpckt) + sizeof (DT_common);
6098		  size_t img_size = cpcktsize - sizeof (DT_common);
6099		  for (size_t i = 0; i < img_size; i += 4)
6100		    if (ptr[i] == (char) 0x9d && ptr[i + 1] == (char) 0xe3)
6101		      {
6102			fp->save_addr = i;
6103			break;
6104		      }
6105		}
6106	    }
6107	  break;
6108	case DT_SRCFILE:
6109	  if (fp)
6110	    {
6111	      char *srcname = dbe_strndup (((char*) cpckt) + sizeof (DT_common),
6112					   cpcktsize - sizeof (DT_common));
6113	      LoadObject *ds = fp->module ? fp->module->loadobject : NULL;
6114	      assert (ds != NULL);
6115	      Module *mod = dbeSession->createModule (ds, NULL);
6116	      mod->set_file_name (srcname);
6117	      //}
6118	      if (fp->module)
6119		{
6120		  // It's most likely (unknown). Remove fp from it.
6121		  long idx = fp->module->functions->find (fp);
6122		  if (idx >= 0)
6123		    fp->module->functions->remove (idx);
6124		}
6125	      fp->module = mod;
6126	      mod->functions->append (fp);
6127	    }
6128	  break;
6129	case DT_LTABLE:
6130	  if (fp)
6131	    {
6132	      DT_lineno *ltab = (DT_lineno*) ((char*) cpckt + sizeof (DT_common));
6133	      size_t sz = (cpcktsize - sizeof (DT_common)) / sizeof (DT_lineno);
6134	      if (sz <= 0)
6135		break;
6136	      // Take care of the progress bar
6137	      static int percent = 0;
6138	      static long deltaReport = sz / 100; // 1000;
6139	      static long nextReport = 0;
6140	      static long progress_count = 0;
6141	      fp->pushSrcFile (fp->getDefSrc (), 0);
6142	      for (size_t i = 0; i < sz; i++)
6143		{
6144		  int lineno = dwin->decode (ltab[i].lineno);
6145		  if (fp->usrfunc != NULL)
6146		    {
6147		      // Update progress bar
6148		      if (dbeSession->is_interactive ())
6149			{
6150			  if (progress_count == nextReport)
6151			    {
6152			      if (percent < 99)
6153				{
6154				  percent++;
6155				  if (NULL == progress_msg)
6156				    {
6157				      progress_msg = dbe_sprintf (GTXT ("Processing Dynamic Text: %s"),
6158								  get_basename (expt_name));
6159				    }
6160				  theApplication->set_progress (percent, progress_msg);
6161				  nextReport += deltaReport;
6162				}
6163			    }
6164			  progress_count++;
6165			}
6166		      DbeLine *dbeline = fp->usrfunc->mapPCtoLine (lineno, NULL);
6167		      lineno = dbeline != NULL ? dbeline->lineno : -1;
6168		    }
6169		  fp->add_PC_info (dwin->decode (ltab[i].offset), lineno);
6170		}
6171	      fp->popSrcFile ();
6172	    }
6173	  break;
6174	default:
6175	  // skip unknown records
6176	  break;
6177	}
6178      offset += cpcktsize;
6179    }
6180  free (progress_msg);
6181  free (data_file_name);
6182  delete dwin;
6183  return 0;
6184}
6185
6186uint32_t
6187Experiment::mapTagValue (Prop_type prop, uint64_t value)
6188{
6189  Vector<Histable*> *objs = tagObjs->fetch (prop);
6190  int lt = 0;
6191  int rt = objs->size () - 1;
6192  while (lt <= rt)
6193    {
6194      int md = (lt + rt) / 2;
6195      Other *obj = (Other*) objs->fetch (md);
6196      if (obj->value64 < value)
6197	lt = md + 1;
6198      else if (obj->value64 > value)
6199	rt = md - 1;
6200      else
6201	return obj->tag;
6202    }
6203
6204  uint32_t tag;
6205  if (sparse_threads && (prop == PROP_THRID || prop == PROP_LWPID))
6206    tag = objs->size () + 1; // "+ 1" related to 7038295
6207  else
6208    tag = (int) value; // truncation; See 6788767
6209
6210  Other *obj = new Other ();
6211  obj->value64 = value;
6212  obj->tag = tag;
6213  if (lt == objs->size ())
6214    objs->append (obj);
6215  else
6216    objs->insert (lt, obj);
6217
6218  // Update min and max tags
6219  if (prop == PROP_LWPID)
6220    {
6221      if ((uint64_t) tag < min_lwp)
6222	min_lwp = (uint64_t) tag;
6223      if ((uint64_t) tag > max_lwp)
6224	max_lwp = (uint64_t) tag;
6225      lwp_cnt++;
6226    }
6227  else if (prop == PROP_THRID)
6228    {
6229      if ((uint64_t) tag < min_thread)
6230	min_thread = (uint64_t) tag;
6231      if ((uint64_t) tag > max_thread)
6232	max_thread = (uint64_t) tag;
6233      thread_cnt++;
6234    }
6235  else if (prop == PROP_CPUID)
6236    {
6237      // On Solaris 8, we don't get CPU id -- don't change
6238      if (value != (uint64_t) - 1)
6239	{//YXXX is this related only to solaris 8?
6240	  if ((uint64_t) tag < min_cpu)
6241	    min_cpu = (uint64_t) tag;
6242	  if ((uint64_t) tag > max_cpu)
6243	    max_cpu = (uint64_t) tag;
6244	}
6245      cpu_cnt++;
6246    }
6247  return obj->tag;
6248}
6249
6250Vector<Histable*> *
6251Experiment::getTagObjs (Prop_type prop)
6252{
6253  return tagObjs->fetch (prop);
6254}
6255
6256Histable *
6257Experiment::getTagObj (Prop_type prop, uint32_t tag)
6258{
6259  Vector<Histable*> *objs = tagObjs->fetch (prop);
6260  if (objs == NULL)
6261    return NULL;
6262  for (int i = 0; i < objs->size (); i++)
6263    {
6264      Other *obj = (Other*) objs->fetch (i);
6265      if (obj->tag == tag)
6266	return obj;
6267    }
6268  return NULL;
6269}
6270
6271JThread *
6272Experiment::map_pckt_to_Jthread (uint32_t tid, hrtime_t tstamp)
6273{
6274  if (!has_java)
6275    return JTHREAD_DEFAULT;
6276  int lt = 0;
6277  int rt = jthreads_idx->size () - 1;
6278  while (lt <= rt)
6279    {
6280      int md = (lt + rt) / 2;
6281      JThread *jthread = jthreads_idx->fetch (md);
6282      if (jthread->tid < tid)
6283	lt = md + 1;
6284      else if (jthread->tid > tid)
6285	rt = md - 1;
6286      else
6287	{
6288	  for (; jthread; jthread = jthread->next)
6289	    if (tstamp >= jthread->start && tstamp < jthread->end)
6290	      return jthread;
6291	  break;
6292	}
6293    }
6294
6295  return JTHREAD_NONE;
6296}
6297
6298JThread*
6299Experiment::get_jthread (uint32_t tid)
6300{
6301  if (!has_java)
6302    return JTHREAD_DEFAULT;
6303  int lt = 0;
6304  int rt = jthreads_idx->size () - 1;
6305  while (lt <= rt)
6306    {
6307      int md = (lt + rt) / 2;
6308      JThread *jthread = jthreads_idx->fetch (md);
6309      if (jthread->tid < tid)
6310	lt = md + 1;
6311      else if (jthread->tid > tid)
6312	rt = md - 1;
6313      else
6314	{
6315	  JThread *jthread_first = jthread;
6316	  while ((jthread = jthread->next) != NULL)
6317	    if (!jthread->is_system () &&
6318		jthread->jthr_id < jthread_first->jthr_id)
6319	      jthread_first = jthread;
6320	  return jthread_first;
6321	}
6322    }
6323
6324  return JTHREAD_NONE;
6325}
6326
6327// SS12 experiment
6328DataDescriptor *
6329Experiment::newDataDescriptor (int data_id, int flags,
6330			       DataDescriptor *master_dDscr)
6331{
6332  DataDescriptor *dataDscr = NULL;
6333  if (data_id >= 0 && data_id < dataDscrs->size ())
6334    {
6335      dataDscr = dataDscrs->fetch (data_id);
6336      if (dataDscr != NULL)
6337	return dataDscr;
6338    }
6339
6340  assert (data_id >= 0 && data_id < DATA_LAST);
6341  const char *nm = get_prof_data_type_name (data_id);
6342  const char *uname = get_prof_data_type_uname (data_id);
6343
6344  if (master_dDscr)
6345    dataDscr = new DataDescriptor (data_id, nm, uname, master_dDscr);
6346  else
6347    dataDscr = new DataDescriptor (data_id, nm, uname, flags);
6348  dataDscrs->store (data_id, dataDscr);
6349  return dataDscr;
6350}
6351
6352Vector<DataDescriptor*> *
6353Experiment::getDataDescriptors ()
6354{
6355  Vector<DataDescriptor*> *result = new Vector<DataDescriptor*>;
6356  for (int i = 0; i < dataDscrs->size (); ++i)
6357    {
6358      DataDescriptor *dd;
6359      dd = get_raw_events (i); // force data fetch
6360      if (dd != NULL)
6361	result->append (dd);
6362    }
6363  return result;
6364}
6365
6366DataDescriptor *
6367Experiment::getDataDescriptor (int data_id)
6368{
6369  if (data_id < 0 || data_id >= dataDscrs->size ())
6370    return NULL;
6371  return dataDscrs->fetch (data_id);
6372}
6373
6374PacketDescriptor *
6375Experiment::newPacketDescriptor (int kind, DataDescriptor *dDscr)
6376{
6377  PacketDescriptor *pDscr = new PacketDescriptor (dDscr);
6378  pcktDscrs->store (kind, pDscr);
6379  return pDscr;
6380}
6381
6382PacketDescriptor *
6383Experiment::getPacketDescriptor (int kind)
6384{
6385  if (kind < 0 || kind >= pcktDscrs->size ())
6386    return NULL;
6387  return pcktDscrs->fetch (kind);
6388}
6389
6390void
6391Experiment::set_clock (int clk)
6392{
6393  if (clk > 0)
6394    {
6395      if (maxclock < clk)
6396	{
6397	  maxclock = clk;
6398	  clock = maxclock;
6399	}
6400      if (minclock == 0 || minclock > clk)
6401	minclock = clk;
6402    }
6403}
6404
6405bool
6406JThread::is_system ()
6407{
6408  if (group_name == NULL)
6409    return false;
6410  return strcmp (group_name, NTXT ("system")) == 0;
6411}
6412
6413void
6414Experiment::dump_stacks (FILE *outfile)
6415{
6416  cstack->print (outfile);
6417}
6418
6419void
6420Experiment::dump_map (FILE *outfile)
6421{
6422  int index;
6423  SegMem *s;
6424  fprintf (outfile, GTXT ("Experiment %s\n"), get_expt_name ());
6425  fprintf (outfile, GTXT ("Address         Size (hex)              Load time     Unload time    Checksum  Name\n"));
6426  Vec_loop (SegMem*, seg_items, index, s)
6427  {
6428    timestruc_t load;
6429    timestruc_t unload;
6430    hr2timestruc (&load, (s->load_time - exp_start_time));
6431    if (load.tv_nsec < 0)
6432      {
6433	load.tv_sec--;
6434	load.tv_nsec += NANOSEC;
6435      }
6436    if (s->unload_time == MAX_TIME)
6437      {
6438	unload.tv_sec = 0;
6439	unload.tv_nsec = 0;
6440      }
6441    else
6442      hr2timestruc (&unload, (s->unload_time - exp_start_time));
6443    if (load.tv_nsec < 0)
6444      {
6445	load.tv_sec--;
6446	load.tv_nsec += NANOSEC;
6447      }
6448    fprintf (outfile,
6449	     "0x%08llx  %8lld (0x%08llx) %5lld.%09lld %5lld.%09lld  \"%s\"\n",
6450	     (long long) s->base, (long long) s->size, (long long) s->size,
6451	     (long long) load.tv_sec, (long long) load.tv_nsec,
6452	     (long long) unload.tv_sec, (long long) unload.tv_nsec,
6453	     s->obj->get_name ());
6454  }
6455  fprintf (outfile, NTXT ("\n"));
6456}
6457
6458/**
6459 * Copy file to archive
6460 * @param name
6461 * @param aname
6462 * @param hide_msg
6463 * @return 0 - success, 1 - error
6464 */
6465int
6466Experiment::copy_file_to_archive (const char *name, const char *aname, int hide_msg)
6467{
6468  errno = 0;
6469  int fd_w = open64 (aname, O_WRONLY | O_CREAT | O_EXCL, 0644);
6470  if (fd_w == -1)
6471    {
6472      if (errno == EEXIST)
6473	return 0;
6474      fprintf (stderr, GTXT ("er_archive: unable to copy `%s': %s\n"),
6475	       name, STR (strerror (errno)));
6476      return 1;
6477    }
6478
6479  if (dbe_stat_file (name, NULL) != 0)
6480    {
6481      fprintf (stderr, GTXT ("er_archive: cannot access file `%s': %s\n"),
6482	       name, STR (strerror (errno)));
6483      close (fd_w);
6484      return 1;
6485    }
6486
6487  int fd_r = open64 (name, O_RDONLY);
6488  if (fd_r == -1)
6489    {
6490      fprintf (stderr, GTXT ("er_archive: unable to open `%s': %s\n"),
6491	       name, strerror (errno));
6492      close (fd_w);
6493      unlink (aname);
6494      return 1;
6495    }
6496
6497  if (!hide_msg)
6498    fprintf (stderr, GTXT ("Copying `%s'  to `%s'\n"), name, aname);
6499  bool do_unlink = false;
6500  for (;;)
6501    {
6502      unsigned char buf[65536];
6503      int n, n1;
6504      n = (int) read (fd_r, (void *) buf, sizeof (buf));
6505      if (n <= 0)
6506	break;
6507      n1 = (int) write (fd_w, buf, n);
6508      if (n != n1)
6509	{
6510	  fprintf (stderr, GTXT ("er_archive: unable to write %d bytes to `%s': %s\n"),
6511		   n, aname, STR (strerror (errno)));
6512	  do_unlink = true;
6513	  break;
6514	}
6515    }
6516  close (fd_w);
6517
6518  struct stat64 s_buf;
6519  if (fstat64 (fd_r, &s_buf) == 0)
6520    {
6521      struct utimbuf u_buf;
6522      u_buf.actime = s_buf.st_atime;
6523      u_buf.modtime = s_buf.st_mtime;
6524      utime (aname, &u_buf);
6525    }
6526  close (fd_r);
6527  if (do_unlink)
6528    {
6529      if (!hide_msg)
6530	fprintf (stderr, GTXT ("er_archive: remove %s\n"), aname);
6531      unlink (aname);
6532      return 1;
6533    }
6534  return 0;
6535}
6536
6537/**
6538 * Copy file to common archive
6539 * Algorithm:
6540 * Calculate checksum
6541 * Generate file name to be created in common archive
6542 * Check if it is not in common archive yet
6543 * Copy file to the common archive directory if it is not there yet
6544 * Create symbolic link: "aname" -> "caname", where "caname" is the name in common archive
6545 * @param name - original file name
6546 * @param aname - file name in experiment archive
6547 * @param common_archive - common archive directory
6548 * @return 0 - success, 1 - error
6549 */
6550int
6551Experiment::copy_file_to_common_archive (const char *name, const char *aname,
6552					 int hide_msg,
6553					 const char *common_archive,
6554					 int relative_path)
6555{
6556  if (!name || !aname || !common_archive)
6557    {
6558      if (!name)
6559	fprintf (stderr, GTXT ("er_archive: Internal error: file name is NULL\n"));
6560      if (!aname)
6561	fprintf (stderr, GTXT ("er_archive: Internal error: file name in archive is NULL\n"));
6562      if (!common_archive)
6563	fprintf (stderr, GTXT ("er_archive: Internal error: path to common archive is NULL\n"));
6564      return 1;
6565    }
6566  // Check if file is already archived
6567  if (dbe_stat (aname, NULL) == 0)
6568    return 0; // File is already archived
6569  // Generate full path to common archive directory
6570  char *cad = NULL;
6571  char *abs_aname = NULL;
6572  if ((common_archive[0] != '/') || (aname[0] != '/'))
6573    {
6574      long size = pathconf (NTXT ("."), _PC_PATH_MAX);
6575      if (size < 0)
6576	{
6577	  fprintf (stderr, GTXT ("er_archive: Fatal error: pathconf(\".\", _PC_PATH_MAX) failed\n"));
6578	  return 1;
6579	}
6580      char *buf = (char *) malloc ((size_t) size);
6581      if (buf == NULL)
6582	{
6583	  fprintf (stderr, GTXT ("er_archive: Fatal error: unable to allocate memory\n"));
6584	  return 1;
6585	}
6586      char *ptr = getcwd (buf, (size_t) size);
6587      if (ptr == NULL)
6588	{
6589	  fprintf (stderr, GTXT ("er_archive: Fatal error: cannot determine current directory\n"));
6590	  free (buf);
6591	  return 1;
6592	}
6593      if (common_archive[0] != '/')
6594	cad = dbe_sprintf (NTXT ("%s/%s"), ptr, common_archive);
6595      else
6596	cad = dbe_strdup (common_archive);
6597      if (aname[0] != '/')
6598	abs_aname = dbe_sprintf (NTXT ("%s/%s"), ptr, aname);
6599      else
6600	abs_aname = dbe_strdup (aname);
6601      free (buf);
6602    }
6603  else
6604    {
6605      cad = dbe_strdup (common_archive);
6606      abs_aname = dbe_strdup (aname);
6607    }
6608  // Calculate checksum
6609  char * errmsg = NULL;
6610  uint32_t crcval = get_cksum (name, &errmsg);
6611  if (0 == crcval)
6612    { // error
6613      free (cad);
6614      free (abs_aname);
6615      if (NULL != errmsg)
6616	{
6617	  fprintf (stderr, GTXT ("er_archive: Fatal error: %s\n"), errmsg);
6618	  free (errmsg);
6619	  return 1;
6620	}
6621      fprintf (stderr,
6622	       GTXT ("er_archive: Fatal error: get_cksum(%s) returned %d\n"),
6623	       name, crcval);
6624      return 1;
6625    }
6626  // Generate file name to be created in common archive
6627  char *fname = get_basename (name);
6628  char *abs_caname = dbe_sprintf (NTXT ("%s/%u_%s"), cad, crcval, fname);
6629  if (abs_caname == NULL)
6630    {
6631      free (cad);
6632      free (abs_aname);
6633      fprintf (stderr,
6634	       GTXT ("er_archive: Fatal error: unable to allocate memory\n"));
6635      return 1;
6636    }
6637  // Check if full name is not too long
6638  long len = dbe_sstrlen (abs_caname);
6639  long max = pathconf (cad, _PC_PATH_MAX);
6640  if ((max < 0) || (len <= 0))
6641    { // unknown error
6642      fprintf (stderr, GTXT ("er_archive: Fatal error: pathconf(%s, _PC_PATH_MAX) failed\n"),
6643	       cad);
6644      free (abs_caname);
6645      free (cad);
6646      free (abs_aname);
6647      return 1;
6648    }
6649  if (len >= max)
6650    {
6651      // Try to truncate the name
6652      if ((len - max) <= dbe_sstrlen (fname))
6653	{
6654	  // Yes, we can do it
6655	  abs_caname[max - 1] = 0;
6656	  if (!hide_msg)
6657	    fprintf (stderr, GTXT ("er_archive: file path is too long - truncated:%s\n"),
6658		     abs_caname);
6659	}
6660    }
6661  // Check if file name is not too long
6662  char *cafname = get_basename (abs_caname);
6663  len = dbe_sstrlen (cafname);
6664  max = pathconf (cad, _PC_NAME_MAX);
6665  if ((max < 0) || (len <= 0))
6666    { // unknown error
6667      fprintf (stderr, GTXT ("er_archive: Fatal error: pathconf(%s, _PC_NAME_MAX) failed\n"),
6668	       cad);
6669      free (abs_caname);
6670      free (cad);
6671      free (abs_aname);
6672      return 1;
6673    }
6674  if (len >= max)
6675    {
6676      // Try to truncate the name
6677      if ((len - max) <= dbe_sstrlen (fname))
6678	{
6679	  // Yes, we can do it
6680	  cafname[max - 1] = 0;
6681	  if (!hide_msg)
6682	    fprintf (stderr, GTXT ("er_archive: file name is too long - truncated:%s\n"),
6683		     abs_caname);
6684	}
6685    }
6686  // Copy file to the common archive directory if it is not there yet
6687  int res = 0;
6688  if (dbe_stat_file (abs_caname, NULL) != 0)
6689    {
6690      // Use temporary file to avoid synchronization problems
6691      char *t = dbe_sprintf ("%s/archive_%llx", cad, (unsigned long long) gethrtime());
6692      free (cad);
6693      // Copy file to temporary file
6694      res = copy_file_to_archive (name, t, hide_msg); // hide messages
6695      if (res != 0)
6696	{
6697	  fprintf (stderr, GTXT ("er_archive: Fatal error: cannot copy file %s to temporary file: %s\n"),
6698		   name, t);
6699	  unlink (t);
6700	  free (t);
6701	  free (abs_caname);
6702	  free (abs_aname);
6703	  return 1;
6704	}
6705      // Set read-only permissions
6706      struct stat64 statbuf;
6707      if (0 == dbe_stat_file (name, &statbuf))
6708	{
6709	  mode_t mask = S_IRUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH;
6710	  mode_t mode = statbuf.st_mode & mask;
6711	  chmod (t, mode);
6712	}
6713      // Try to rename temporary file "t" to "abs_caname"
6714      // res = link(t, abs_caname); // link() fails on some f/s - use rename()
6715      res = rename (t, abs_caname);
6716      if (res != 0)
6717	{
6718	  if (errno != EEXIST)
6719	    {
6720	      fprintf (stderr, GTXT ("er_archive: Fatal error: rename(%s, %s) returned error: %d\n"),
6721		       t, abs_caname, res);
6722	      unlink (t);
6723	      free (t);
6724	      free (abs_caname);
6725	      free (abs_aname);
6726	      return 1;
6727	    }
6728	  // File "abs_caname" is already there - continue
6729	}
6730      unlink (t);
6731      free (t);
6732    }
6733  else
6734    free (cad);
6735  char *lname = NULL;
6736  if (relative_path)
6737    {
6738      if (common_archive[0] != '/' && aname[0] != '/')
6739	{
6740	  // compare one relative path to another and find common beginning
6741	  char *rel_caname = dbe_sprintf ("%s/%s", common_archive, cafname);
6742	  if (rel_caname == NULL)
6743	    {
6744	      fprintf (stderr, GTXT ("er_archive: Fatal error: unable to allocate memory\n"));
6745	      return 1;
6746	    }
6747	  lname = get_relative_link (rel_caname, aname);
6748	  free (rel_caname);
6749	}
6750      else
6751	{
6752	  if (abs_aname == NULL)
6753	    {
6754	      fprintf (stderr, GTXT ("er_archive: Fatal error: unable to allocate memory\n"));
6755	      return 1;
6756	    }
6757	  lname = get_relative_link (abs_caname, abs_aname);
6758	}
6759    }
6760  else  // absolute path
6761    lname = dbe_strdup (abs_caname);
6762  free (abs_aname);
6763  if (lname == NULL)
6764    {
6765      fprintf (stderr, GTXT ("er_archive: Fatal error: unable to allocate memory\n"));
6766      return 1;
6767    }
6768  // Create symbolic link: aname -> lname
6769  if (dbe_stat_file (abs_caname, NULL) == 0)
6770    {
6771      res = symlink (lname, aname);
6772      if (res != 0)
6773	{
6774	  fprintf (stderr, GTXT ("er_archive: Fatal error: symlink(%s, %s) returned error: %d (errno=%s)\n"),
6775		   lname, aname, res, strerror (errno));
6776	  free (abs_caname);
6777	  free (lname);
6778	  return 1;
6779	}
6780      if (!hide_msg)
6781	fprintf (stderr, GTXT ("Created symbolic link %s to file in common archive: %s\n"),
6782		 aname, lname);
6783    }
6784  else
6785    {
6786      fprintf (stderr, GTXT ("er_archive: Internal error: file does not exist in common archive: %s\n"),
6787	       abs_caname);
6788      res = 1;
6789    }
6790  free (abs_caname);
6791  free (lname);
6792  return res;
6793}
6794
6795/**
6796 * Copy file to archive
6797 * @param name
6798 * @param aname
6799 * @param hide_msg
6800 * @param common_archive
6801 * @return 0 - success
6802 */
6803int
6804Experiment::copy_file (char *name, char *aname, int hide_msg, char *common_archive, int relative_path)
6805{
6806  if (common_archive)
6807    {
6808      if (0 == copy_file_to_common_archive (name, aname, hide_msg,
6809					    common_archive, relative_path))
6810	return 0;
6811      // Error. For now - fatal error. Message is already printed.
6812      fprintf (stderr, GTXT ("er_archive: Fatal error: cannot copy file %s to common archive %s\n"),
6813	       name, common_archive);
6814      return 1;
6815    }
6816  return (copy_file_to_archive (name, aname, hide_msg));
6817}
6818
6819LoadObject *
6820Experiment::createLoadObject (const char *path, uint64_t chksum)
6821{
6822  LoadObject *lo = dbeSession->createLoadObject (path, chksum);
6823  if (lo->firstExp == NULL)
6824    lo->firstExp = this;
6825  return lo;
6826}
6827
6828LoadObject *
6829Experiment::createLoadObject (const char *path, const char *runTimePath)
6830{
6831  DbeFile *df = findFileInArchive (path, runTimePath);
6832  if (df && (df->get_stat () == NULL))
6833    df = NULL; // No access to file
6834  LoadObject *lo = dbeSession->createLoadObject (path, runTimePath, df);
6835  if (df && (lo->dbeFile->get_location (false) == NULL))
6836    {
6837      lo->dbeFile->set_location (df->get_location ());
6838      lo->dbeFile->inArchive = df->inArchive;
6839      lo->dbeFile->sbuf = df->sbuf;
6840      lo->dbeFile->experiment = df->experiment;
6841      lo->firstExp = df->experiment;
6842    }
6843  if (lo->firstExp == NULL)
6844    {
6845      lo->firstExp = this;
6846      lo->dbeFile->experiment = this;
6847    }
6848  return lo;
6849}
6850
6851SourceFile *
6852Experiment::get_source (const char *path)
6853{
6854  if (founder_exp && (founder_exp != this))
6855    return founder_exp->get_source (path);
6856  if (sourcesMap == NULL)
6857    sourcesMap = new StringMap<SourceFile*>(1024, 1024);
6858  if (strncmp (path, NTXT ("./"), 2) == 0)
6859    path += 2;
6860  SourceFile *sf = sourcesMap->get (path);
6861  if (sf)
6862    return sf;
6863  char *fnm = checkFileInArchive (path, false);
6864  if (fnm)
6865    {
6866      sf = new SourceFile (path);
6867      dbeSession->append (sf);
6868      DbeFile *df = sf->dbeFile;
6869      df->set_location (fnm);
6870      df->inArchive = true;
6871      df->check_access (fnm); // init 'sbuf'
6872      df->sbuf.st_mtime = 0; // Don't check timestamps
6873      free (fnm);
6874    }
6875  else
6876    sf = dbeSession->createSourceFile (path);
6877  sourcesMap->put (path, sf);
6878  return sf;
6879}
6880
6881Vector<Histable*> *
6882Experiment::get_comparable_objs ()
6883{
6884  update_comparable_objs ();
6885  if (comparable_objs || dbeSession->expGroups->size () <= 1)
6886    return comparable_objs;
6887  comparable_objs = new Vector<Histable*>(dbeSession->expGroups->size ());
6888  for (long i = 0, sz = dbeSession->expGroups->size (); i < sz; i++)
6889    {
6890      ExpGroup *gr = dbeSession->expGroups->get (i);
6891      if (groupId == gr->groupId)
6892	{
6893	  comparable_objs->append (this);
6894	  continue;
6895	}
6896      Histable *h = NULL;
6897      for (long i1 = 0, sz1 = gr->exps ? gr->exps->size () : 0; i1 < sz1; i1++)
6898	{
6899	  Experiment *exp = gr->exps->get (i1);
6900	  if ((exp->comparable_objs == NULL) && (dbe_strcmp (utargname, exp->utargname) == 0))
6901	    {
6902	      exp->phaseCompareIdx = phaseCompareIdx;
6903	      h = exp;
6904	      h->comparable_objs = comparable_objs;
6905	      break;
6906	    }
6907	}
6908      comparable_objs->append (h);
6909    }
6910  dump_comparable_objs ();
6911  return comparable_objs;
6912}
6913
6914DbeFile *
6915Experiment::findFileInArchive (const char *fname)
6916{
6917  if (archiveMap)
6918    {
6919      char *aname = get_archived_name (fname);
6920      DbeFile *df = archiveMap->get (aname);
6921      free (aname);
6922      return df;
6923    }
6924  if (founder_exp)
6925    return founder_exp->findFileInArchive (fname);
6926  return NULL;
6927}
6928
6929DbeFile *
6930Experiment::findFileInArchive (const char *className, const char *runTimePath)
6931{
6932  DbeFile *df = NULL;
6933  if (runTimePath)
6934    {
6935      const char *fnm = NULL;
6936      if (strncmp (runTimePath, NTXT ("zip:"), 4) == 0)
6937	fnm = runTimePath + 4;
6938      else if (strncmp (runTimePath, NTXT ("jar:file:"), 9) == 0)
6939	fnm = runTimePath + 9;
6940      if (fnm)
6941	{
6942	  const char *s = strchr (fnm, '!');
6943	  if (s)
6944	    {
6945	      char *s1 = dbe_strndup (fnm, s - fnm);
6946	      df = findFileInArchive (s1);
6947	      free (s1);
6948	    }
6949	  else
6950	    df = findFileInArchive (fnm);
6951	  if (df)
6952	    df->filetype |= DbeFile::F_JAR_FILE;
6953	}
6954      else if (strncmp (runTimePath, NTXT ("file:"), 5) == 0)
6955	{
6956	  fnm = runTimePath + 5;
6957	  df = findFileInArchive (fnm);
6958	}
6959      else
6960	df = findFileInArchive (runTimePath);
6961    }
6962  if (df == NULL)
6963    df = findFileInArchive (className);
6964  return df;
6965}
6966