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 
68 int nPush;
69 int nPop;
70 int pushCnt;
71 int popCnt;
72 int pushCnt3;
73 int popCnt3;
74 
75 struct Experiment::UIDnode
76 {
77   uint64_t uid;
78   uint64_t val;
79   UIDnode *next;
80 };
81 
82 struct Experiment::RawFramePacket
83 {
84   uint64_t uid;
85   UIDnode *uidn;
86   UIDnode *uidj;
87   UIDnode *omp_uid;
88   uint32_t omp_state;
89 };
90 
91 static hrtime_t
parseTStamp(const char * s)92 parseTStamp (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 
102 class Experiment::ExperimentFile
103 {
104 public:
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 *
get_name()120   get_name ()
121   {
122     return fname;
123   }
124 
125   inline int
get_status()126   get_status ()
127   {
128     return ef_status;
129   }
130 
131   char *fgets ();
132   void close ();
133 
134   FILE *fh;
135 
136 private:
137   Experiment *exp;
138   char *fname;
139   off64_t offset;
140   int bufsz, ef_status;
141   char *buffer;
142 };
143 
144 class Experiment::ExperimentHandler : public DefaultHandler
145 {
146 public:
147 
148   ExperimentHandler (Experiment *_exp);
149   ~ExperimentHandler ();
150 
151   void
startDocument()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
ignorableWhitespace(char *,int,int)159   ignorableWhitespace (char*, int, int) { }
160   void
161   error (SAXParseException *e);
162 
163 private:
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;
207 static const int HTableSize = 8192;
208 
209 //-------------------------------------------------- Experiment file handler
210 
ExperimentFile(Experiment * _exp,const char * _fname)211 Experiment::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 
~ExperimentFile()222 Experiment::ExperimentFile::~ExperimentFile ()
223 {
224   close ();
225   free (buffer);
226   free (fname);
227 }
228 
229 bool
open(bool new_open)230 Experiment::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 
249 char *
fgets()250 Experiment::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 
280 void
close()281 Experiment::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
294 int
toInt(Attributes * attrs,const char * atr)295 Experiment::ExperimentHandler::toInt (Attributes *attrs, const char *atr)
296 {
297   const char *str = attrs->getValue (atr);
298   return str ? atoi (str) : 0;
299 }
300 
301 char *
toStr(Attributes * attrs,const char * atr)302 Experiment::ExperimentHandler::toStr (Attributes *attrs, const char *atr)
303 {
304   const char *str = attrs->getValue (atr);
305   return dbe_strdup (str ? str : NTXT (""));
306 }
307 
ExperimentHandler(Experiment * _exp)308 Experiment::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 
~ExperimentHandler()323 Experiment::ExperimentHandler::~ExperimentHandler ()
324 {
325   delete stack;
326   free (text);
327 }
328 
329 void
endDocument()330 Experiment::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 
361 void
pushElem(Element elem)362 Experiment::ExperimentHandler::pushElem (Element elem)
363 {
364   curElem = elem;
365   stack->append (curElem);
366 }
367 
368 void
popElem()369 Experiment::ExperimentHandler::popElem ()
370 {
371   stack->remove (stack->size () - 1);
372   curElem = stack->fetch (stack->size () - 1);
373 }
374 
375 void
startElement(char *,char *,char * qName,Attributes * attrs)376 Experiment::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 
1218 void
characters(char * ch,int start,int length)1219 Experiment::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 
1238 void
endElement(char *,char *,char *)1239 Experiment::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 
1278 void
error(SAXParseException * e)1279 Experiment::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 
Experiment()1292 Experiment::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 
~Experiment()1412 Experiment::~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 
1475 void
init_cache()1476 Experiment::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 
1495 void
init()1496 Experiment::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 
1532 void
fini()1533 Experiment::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()
1572 void
read_experiment_data(bool read_ahead)1573 Experiment::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 
1585 Experiment::Exp_status
open_epilogue()1586 Experiment::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 
1622 Experiment::Exp_status
open(char * path)1623 Experiment::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 */
1714 Experiment::Exp_status
update()1715 Experiment::update ()
1716 {
1717   return status;
1718 }
1719 
1720 void
append(LoadObject * lo)1721 Experiment::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 
1732 void
read_notes_file()1733 Experiment::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 
1773 int
save_notes(char * text,bool handle_file)1774 Experiment::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 
1797 int
delete_notes(bool handle_file)1798 Experiment::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 
1814 int
read_warn_file()1815 Experiment::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 
1853 int
read_log_file()1854 Experiment::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 
1908 class Experiment::ExperimentLabelsHandler : public DefaultHandler
1909 {
1910 public:
1911 
ExperimentLabelsHandler(Experiment * _exp)1912   ExperimentLabelsHandler (Experiment *_exp)
1913   {
1914     exp = _exp;
1915   }
1916 
~ExperimentLabelsHandler()1917   ~ExperimentLabelsHandler () { };
startDocument()1918   void startDocument () { }
endDocument()1919   void endDocument () { }
endElement(char *,char *,char *)1920   void endElement (char * /*uri*/, char * /*localName*/, char * /*qName*/) { }
characters(char *,int,int)1921   void characters (char * /*ch*/, int /*start*/, int /*length*/) { }
ignorableWhitespace(char *,int,int)1922   void ignorableWhitespace (char*, int, int) { }
error(SAXParseException *)1923   void error (SAXParseException * /*e*/) { }
1924 
1925   void startElement (char *uri, char *localName, char *qName, Attributes *attrs);
1926 
1927 private:
1928 
1929   inline const char *
s2s(const char * s)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 
1940 void
startElement(char *,char *,char * qName,Attributes * attrs)1941 Experiment::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 
2023 static int
sortUserLabels(const void * a,const void * b)2024 sortUserLabels (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 
2042 static char *
append_string(char * s,char * str)2043 append_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 
2052 void
read_labels_file()2053 Experiment::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 
2132 void
read_archives()2133 Experiment::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 
2187 static char *
gen_file_name(const char * packet_name,const char * src_name)2188 gen_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 
2205 static char *
get_jlass_name(const char * nm)2206 get_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 
2218 static char *
get_jmodule_name(const char * nm)2219 get_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 
2237 LoadObject *
get_j_lo(const char * className,const char * fileName)2238 Experiment::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 
2262 Module *
get_jclass(const char * className,const char * fileName)2263 Experiment::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 
2291 int
read_java_classes_file()2292 Experiment::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 
2404 void
read_map_file()2405 Experiment::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 
2525 void
read_frameinfo_file()2526 Experiment::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 
2537 void
read_omp_preg()2538 Experiment::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 
2691 void
read_omp_task()2692 Experiment::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 
2841 void
read_omp_file()2842 Experiment::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 
2932 void
read_ifreq_file()2933 Experiment::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 
2971 Experiment *
getBaseFounder()2972 Experiment::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 
2987 hrtime_t
getRelativeStartTime()2988 Experiment::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 
3002 DataDescriptor *
get_raw_events(int data_id)3003 Experiment::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 
3045 int
base_data_id(int data_id)3046 Experiment::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 
3058 DataView *
create_derived_data_view(int data_id,DataView * dview)3059 Experiment::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 
3072 DataDescriptor *
get_profile_events()3073 Experiment::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 
3092 void
add_evt_time_to_profile_events(DataDescriptor * dDscr)3093 Experiment::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 
3143 DataDescriptor *
get_sync_events()3144 Experiment::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 
3182 DataDescriptor *
get_hwc_events()3183 Experiment::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 
3263 DataDescriptor *
get_iotrace_events()3264 Experiment::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 
3572 DataDescriptor *
get_heap_events()3573 Experiment::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 
3799 DataDescriptor *
get_heapsz_events()3800 Experiment::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 
3812 static void
update_heapsz_packet(std::set<long> & pkt_id_set,DataView * dview,long alloc_pkt_id,int64_t net_alloc,uint64_t leaks)3813 update_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 
3838 DataView *
create_heapsz_data_view(DataView * heap_dview)3839 Experiment::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 
3890 void
compute_heapsz_data_view(DataView * heapsz_dview)3891 Experiment::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 
3912 void
DBG_memuse(Sample * s)3913 Experiment::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 
3979 void
DBG_memuse(const char * sname)3980 Experiment::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 
3993 DataDescriptor *
get_race_events()3994 Experiment::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 
4010 DataDescriptor *
get_deadlock_events()4011 Experiment::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 
4027 DataDescriptor *
get_sample_events()4028 Experiment::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 
4072 DataDescriptor *
get_gc_events()4073 Experiment::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 
4117 void
update_last_event(hrtime_t ts)4118 Experiment::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 
4130 void
write_header()4131 Experiment::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 
4275 void
write_coll_params()4276 Experiment::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  */
4429 static int
check_mstate(char * ptr,PacketDescriptor * pDscr,int arg)4430 check_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 
4460 uint64_t
readPacket(Data_window * dwin,Data_window::Span * span)4461 Experiment::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 
4689 void
readPacket(Data_window * dwin,char * ptr,PacketDescriptor * pDscr,DataDescriptor * dDscr,int arg,uint64_t pktsz)4690 Experiment::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 
4777 void
read_data_file(const char * fname,const char * msg)4778 Experiment::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 
4836 int
read_overview_file()4837 Experiment::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 
4948 int
uidNodeCmp(const void * a,const void * b)4949 Experiment::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 
4958 static uint64_t
funcAddr(uint32_t val)4959 funcAddr (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 
4970 Experiment::UIDnode *
add_uid(Data_window * dwin,uint64_t uid,int size,uint32_t * array,uint64_t link_uid)4971 Experiment::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 
5001 Experiment::UIDnode *
add_uid(Data_window * dwin,uint64_t uid,int size,uint64_t * array,uint64_t link_uid)5002 Experiment::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 
5031 Experiment::UIDnode *
new_uid_node(uint64_t uid,uint64_t val)5032 Experiment::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 
5057 Experiment::UIDnode *
get_uid_node(uint64_t uid,uint64_t val)5058 Experiment::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 
5076 Experiment::UIDnode *
get_uid_node(uint64_t uid)5077 Experiment::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 
5090 Experiment::UIDnode *
find_uid_node(uint64_t uid)5091 Experiment::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 
5116 int
frUidCmp(const void * a,const void * b)5117 Experiment::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 
5126 Experiment::RawFramePacket *
find_frame_packet(uint64_t uid)5127 Experiment::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 
5169 void
resolve_frame_info(DataDescriptor * dDscr)5170 Experiment::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 
5548 void
post_process()5549 Experiment::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 
5590 Experiment::Exp_status
find_expdir(char * path)5591 Experiment::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 
5635 void
purge()5636 Experiment::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 
5652 void
resetShowHideStack()5653 Experiment::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 
5662 static int
dir_name_cmp(const void * a,const void * b)5663 dir_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 
5688 Vector<char*> *
get_descendants_names()5689 Experiment::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 
5721 bool
create_dir(char * dname)5722 Experiment::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 
5740 char *
get_arch_name()5741 Experiment::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 
5755 char *
get_fndr_arch_name()5756 Experiment::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 
5764 enum
5765 {
5766   HASH_NAME_LEN     = 11    // (64 / 6 + 1) = 11
5767 };
5768 
5769 static char *
get_hash_string(char buf[HASH_NAME_LEN+1],uint64_t hash)5770 get_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 
5783 char *
getNameInArchive(const char * fname,bool archiveFile)5784 Experiment::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 
5794 char *
get_archived_name(const char * fname,bool archiveFile)5795 Experiment::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 
5823 char *
checkFileInArchive(const char * fname,bool archiveFile)5824 Experiment::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 
5843 static int
SegMemCmp(const void * a,const void * b)5844 SegMemCmp (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 
5852 SegMem*
update_ts_in_maps(Vaddr addr,hrtime_t ts)5853 Experiment::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 
5891 DbeInstr*
map_Vaddr_to_PC(Vaddr addr,hrtime_t ts)5892 Experiment::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 
5944 Sample *
map_event_to_Sample(hrtime_t ts)5945 Experiment::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 
5968 GCEvent *
map_event_to_GCEvent(hrtime_t ts)5969 Experiment::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 
5991 DbeInstr*
map_jmid_to_PC(Vaddr mid,int bci,hrtime_t ts)5992 Experiment::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 
6010 Emsg *
fetch_comments()6011 Experiment::fetch_comments ()
6012 {
6013   return commentq->fetch ();
6014 }
6015 
6016 Emsg *
fetch_runlogq()6017 Experiment::fetch_runlogq ()
6018 {
6019   return runlogq->fetch ();
6020 }
6021 
6022 Emsg *
fetch_errors()6023 Experiment::fetch_errors ()
6024 {
6025   return errorq->fetch ();
6026 }
6027 
6028 Emsg *
fetch_warnings()6029 Experiment::fetch_warnings ()
6030 {
6031   return warnq->fetch ();
6032 }
6033 
6034 Emsg *
fetch_notes()6035 Experiment::fetch_notes ()
6036 {
6037   return notesq->fetch ();
6038 }
6039 
6040 Emsg *
fetch_ifreq()6041 Experiment::fetch_ifreq ()
6042 {
6043   return ifreqq->fetch ();
6044 }
6045 
6046 Emsg *
fetch_pprocq()6047 Experiment::fetch_pprocq ()
6048 {
6049   return pprocq->fetch ();
6050 }
6051 
6052 int
read_dyntext_file()6053 Experiment::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 
6186 uint32_t
mapTagValue(Prop_type prop,uint64_t value)6187 Experiment::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 
6250 Vector<Histable*> *
getTagObjs(Prop_type prop)6251 Experiment::getTagObjs (Prop_type prop)
6252 {
6253   return tagObjs->fetch (prop);
6254 }
6255 
6256 Histable *
getTagObj(Prop_type prop,uint32_t tag)6257 Experiment::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 
6271 JThread *
map_pckt_to_Jthread(uint32_t tid,hrtime_t tstamp)6272 Experiment::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 
6298 JThread*
get_jthread(uint32_t tid)6299 Experiment::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
6328 DataDescriptor *
newDataDescriptor(int data_id,int flags,DataDescriptor * master_dDscr)6329 Experiment::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 
6352 Vector<DataDescriptor*> *
getDataDescriptors()6353 Experiment::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 
6366 DataDescriptor *
getDataDescriptor(int data_id)6367 Experiment::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 
6374 PacketDescriptor *
newPacketDescriptor(int kind,DataDescriptor * dDscr)6375 Experiment::newPacketDescriptor (int kind, DataDescriptor *dDscr)
6376 {
6377   PacketDescriptor *pDscr = new PacketDescriptor (dDscr);
6378   pcktDscrs->store (kind, pDscr);
6379   return pDscr;
6380 }
6381 
6382 PacketDescriptor *
getPacketDescriptor(int kind)6383 Experiment::getPacketDescriptor (int kind)
6384 {
6385   if (kind < 0 || kind >= pcktDscrs->size ())
6386     return NULL;
6387   return pcktDscrs->fetch (kind);
6388 }
6389 
6390 void
set_clock(int clk)6391 Experiment::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 
6405 bool
is_system()6406 JThread::is_system ()
6407 {
6408   if (group_name == NULL)
6409     return false;
6410   return strcmp (group_name, NTXT ("system")) == 0;
6411 }
6412 
6413 void
dump_stacks(FILE * outfile)6414 Experiment::dump_stacks (FILE *outfile)
6415 {
6416   cstack->print (outfile);
6417 }
6418 
6419 void
dump_map(FILE * outfile)6420 Experiment::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  */
6465 int
copy_file_to_archive(const char * name,const char * aname,int hide_msg)6466 Experiment::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  */
6550 int
copy_file_to_common_archive(const char * name,const char * aname,int hide_msg,const char * common_archive,int relative_path)6551 Experiment::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  */
6803 int
copy_file(char * name,char * aname,int hide_msg,char * common_archive,int relative_path)6804 Experiment::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 
6819 LoadObject *
createLoadObject(const char * path,uint64_t chksum)6820 Experiment::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 
6828 LoadObject *
createLoadObject(const char * path,const char * runTimePath)6829 Experiment::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 
6851 SourceFile *
get_source(const char * path)6852 Experiment::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 
6881 Vector<Histable*> *
get_comparable_objs()6882 Experiment::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 
6914 DbeFile *
findFileInArchive(const char * fname)6915 Experiment::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 
6929 DbeFile *
findFileInArchive(const char * className,const char * runTimePath)6930 Experiment::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