]> Git Repo - binutils.git/blob - gprofng/src/Experiment.cc
Automatic date update in version.in
[binutils.git] / gprofng / src / Experiment.cc
1 /* Copyright (C) 2021 Free Software Foundation, Inc.
2    Contributed by Oracle.
3
4    This file is part of GNU Binutils.
5
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 3, or (at your option)
9    any later version.
10
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, write to the Free Software
18    Foundation, 51 Franklin Street - Fifth Floor, Boston,
19    MA 02110-1301, USA.  */
20
21 #include "config.h"
22 #include <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
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 *
120   get_name ()
121   {
122     return fname;
123   }
124
125   inline int
126   get_status ()
127   {
128     return ef_status;
129   }
130
131   char *fgets ();
132   void close ();
133
134   FILE *fh;
135
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
152   startDocument () { }
153   void endDocument ();
154   void startElement (char *uri, char *localName, char *qName, Attributes *attrs);
155   void endElement (char *uri, char *localName, char *qName);
156   void characters (char *ch, int start, int length);
157
158   void
159   ignorableWhitespace (char*, int, int) { }
160   void
161   error (SAXParseException *e);
162
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
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
222 Experiment::ExperimentFile::~ExperimentFile ()
223 {
224   close ();
225   free (buffer);
226   free (fname);
227 }
228
229 bool
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 *
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
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
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 *
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
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
323 Experiment::ExperimentHandler::~ExperimentHandler ()
324 {
325   delete stack;
326   free (text);
327 }
328
329 void
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
362 Experiment::ExperimentHandler::pushElem (Element elem)
363 {
364   curElem = elem;
365   stack->append (curElem);
366 }
367
368 void
369 Experiment::ExperimentHandler::popElem ()
370 {
371   stack->remove (stack->size () - 1);
372   curElem = stack->fetch (stack->size () - 1);
373 }
374
375 void
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
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
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
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
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   dyntext_name = NULL;
1374   logFile = NULL;
1375
1376   dataDscrs = new Vector<DataDescriptor*>;
1377   for (int i = 0; i < DATA_LAST; ++i)
1378     dataDscrs->append (NULL);
1379
1380   pcktDscrs = new Vector<PacketDescriptor*>;
1381   blksz = PROFILE_BUFFER_CHUNK;
1382   jthreads = new Vector<JThread*>;
1383   jthreads_idx = new Vector<JThread*>;
1384   gcevents = new Vector<GCEvent*>;
1385   gcevent_last_used = (GCEvent *) NULL;
1386   heapUnmapEvents = new Vector<UnmapChunk*>;
1387   cstack = NULL;
1388   cstackShowHide = NULL;
1389   frmpckts = new Vector<RawFramePacket*>;
1390   typedef DefaultMap2D<uint32_t, hrtime_t, uint64_t> OmpMap0;
1391   mapPRid = new OmpMap0 (OmpMap0::Interval);
1392   typedef DefaultMap2D<uint32_t, hrtime_t, void*> OmpMap;
1393   mapPReg = new OmpMap (OmpMap::Interval);
1394   mapTask = new OmpMap (OmpMap::Interval);
1395   openMPdata = NULL;
1396   archiveMap = NULL;
1397   nnodes = 0;
1398   nchunks = 0;
1399   chunks = 0;
1400   uidHTable = NULL;
1401   uidnodes = new Vector<UIDnode*>;
1402   mrecs = new Vector<MapRecord*>;
1403   samples = new Vector<Sample*>;
1404   sample_last_used = (Sample *) NULL;
1405   first_sample_label = (char*) NULL;
1406   fDataMap = NULL;
1407   vFdMap = NULL;
1408   resolveFrameInfo = true;
1409   discardTiny = false;
1410   init ();
1411 }
1412
1413 Experiment::~Experiment ()
1414 {
1415   fini ();
1416   free (coll_params.linetrace);
1417   for (int i = 0; i < MAX_HWCOUNT; i++)
1418     {
1419       free (coll_params.hw_aux_name[i]);
1420       free (coll_params.hw_username[i]);
1421     }
1422   free (hostname);
1423   free (username);
1424   free (architecture);
1425   free (os_version);
1426   free (uarglist);
1427   free (utargname);
1428   free (ucwd);
1429   free (cversion);
1430   free (dversion);
1431   free (jversion);
1432   delete logFile;
1433   free (expt_name);
1434   free (arch_name);
1435   free (fndr_arch_name);
1436   free (dyntext_name);
1437   delete jthreads_idx;
1438   delete cstack;
1439   delete cstackShowHide;
1440   delete mapPRid;
1441   delete mapPReg;
1442   delete mapTask;
1443   delete openMPdata;
1444   destroy_map (DbeFile *, archiveMap);
1445   delete[] uidHTable;
1446   delete uidnodes;
1447   delete mrecs;
1448   delete children_exps;
1449   delete loadObjs;
1450   delete loadObjMap;
1451   delete sourcesMap;
1452   free (first_sample_label);
1453   free (machinemodel);
1454
1455   dataDscrs->destroy ();
1456   delete dataDscrs;
1457   pcktDscrs->destroy ();
1458   delete pcktDscrs;
1459   jthreads->destroy ();
1460   delete jthreads;
1461   gcevents->destroy ();
1462   delete gcevents;
1463   heapUnmapEvents->destroy ();
1464   delete heapUnmapEvents;
1465   frmpckts->destroy ();
1466   delete frmpckts;
1467   samples->destroy ();
1468   delete samples;
1469   delete fDataMap;
1470   delete vFdMap;
1471
1472   for (long i = 0; i < nchunks; i++)
1473     delete[] chunks[i];
1474   delete[] chunks;
1475 }
1476
1477 void
1478 Experiment::init_cache ()
1479 {
1480   if (smemHTable)
1481     return;
1482   smemHTable = new SegMem*[HTableSize];
1483   instHTable = new DbeInstr*[HTableSize];
1484   for (int i = 0; i < HTableSize; i++)
1485     {
1486       smemHTable[i] = NULL;
1487       instHTable[i] = NULL;
1488     }
1489   uidHTable = new UIDnode*[HTableSize];
1490   for (int i = 0; i < HTableSize; i++)
1491     uidHTable[i] = NULL;
1492
1493   cstack = CallStack::getInstance (this);
1494   cstackShowHide = CallStack::getInstance (this);
1495 }
1496
1497 void
1498 Experiment::init ()
1499 {
1500   userLabels = NULL;
1501   seg_items = new Vector<SegMem*>;
1502   maps = new PRBTree ();
1503   jmaps = NULL; // used by JAVA_CLASSES only
1504   jmidHTable = NULL;
1505   smemHTable = NULL;
1506   instHTable = NULL;
1507   min_thread = (uint64_t) - 1;
1508   max_thread = 0;
1509   thread_cnt = 0;
1510   min_lwp = (uint64_t) - 1;
1511   max_lwp = 0;
1512   lwp_cnt = 0;
1513   min_cpu = (uint64_t) - 1;
1514   max_cpu = 0;
1515   cpu_cnt = 0;
1516
1517   commentq = new Emsgqueue (NTXT ("commentq"));
1518   runlogq = new Emsgqueue (NTXT ("runlogq"));
1519   errorq = new Emsgqueue (NTXT ("errorq"));
1520   warnq = new Emsgqueue (NTXT ("warnq"));
1521   notesq = new Emsgqueue (NTXT ("notesq"));
1522   pprocq = new Emsgqueue (NTXT ("pprocq"));
1523   ifreqq = NULL;
1524
1525   metrics = new Vector<BaseMetric*>;
1526   tagObjs = new Vector<Vector<Histable*>*>;
1527   tagObjs->store (PROP_THRID, new Vector<Histable*>);
1528   tagObjs->store (PROP_LWPID, new Vector<Histable*>);
1529   tagObjs->store (PROP_CPUID, new Vector<Histable*>);
1530   tagObjs->store (PROP_EXPID, new Vector<Histable*>);
1531   sparse_threads = false;
1532 }
1533
1534 void
1535 Experiment::fini ()
1536 {
1537   seg_items->destroy ();
1538   delete seg_items;
1539   delete maps;
1540   delete jmaps;
1541   delete[] smemHTable;
1542   delete[] instHTable;
1543   delete jmidHTable;
1544   delete commentq;
1545   delete runlogq;
1546   delete errorq;
1547   delete warnq;
1548   delete notesq;
1549   delete pprocq;
1550   if (ifreqq != NULL)
1551     {
1552       delete ifreqq;
1553       ifreqq = NULL;
1554     }
1555
1556   int index;
1557   BaseMetric *mtr;
1558   Vec_loop (BaseMetric*, metrics, index, mtr)
1559   {
1560     dbeSession->drop_metric (mtr);
1561   }
1562   delete metrics;
1563   tagObjs->fetch (PROP_THRID)->destroy ();
1564   tagObjs->fetch (PROP_LWPID)->destroy ();
1565   tagObjs->fetch (PROP_CPUID)->destroy ();
1566   tagObjs->fetch (PROP_EXPID)->destroy ();
1567   tagObjs->destroy ();
1568   delete tagObjs;
1569 }
1570
1571 // These are the data files which can be read in parallel
1572 // for multiple sub-experiments.
1573 // Postpone calling resolve_frame_info()
1574 void
1575 Experiment::read_experiment_data (bool read_ahead)
1576 {
1577
1578   read_frameinfo_file ();
1579   if (read_ahead)
1580     {
1581       resolveFrameInfo = false;
1582       (void) get_profile_events ();
1583       resolveFrameInfo = true;
1584     }
1585 }
1586
1587 Experiment::Exp_status
1588 Experiment::open_epilogue ()
1589 {
1590
1591   // set up mapping for tagObj(PROP_EXPID)
1592   (void) mapTagValue (PROP_EXPID, userExpId);
1593
1594   post_process ();
1595   if (last_event != ZERO_TIME)
1596     { // if last_event is known
1597       StringBuilder sb;
1598       hrtime_t ts = last_event - exp_start_time;
1599       sb.sprintf (GTXT ("Experiment Ended: %ld.%09ld\nData Collection Duration: %ld.%09ld"),
1600                   (long) (ts / NANOSEC), (long) (ts % NANOSEC),
1601                   (long) (non_paused_time / NANOSEC),
1602                   (long) (non_paused_time % NANOSEC));
1603       runlogq->append (new Emsg (CMSG_COMMENT, sb));
1604     }
1605
1606   // Check for incomplete experiment, and inform the user
1607   if (status == INCOMPLETE)
1608     {
1609       if (exec_started == true)
1610         // experiment ended with the exec, not abnormally
1611         status = SUCCESS;
1612       else
1613         {
1614           char * cmnt = GTXT ("*** Note: experiment was not closed");
1615           commentq->append (new Emsg (CMSG_COMMENT, cmnt));
1616           // runlogq->append(new Emsg(CMSG_COMMENT, cmnt));
1617         }
1618     }
1619   // write a descriptive header for the experiment
1620   write_header ();
1621   return status;
1622 }
1623
1624 Experiment::Exp_status
1625 Experiment::open (char *path)
1626 {
1627
1628   // Find experiment directory
1629   if (find_expdir (path) != SUCCESS)
1630     // message will have been queued and status set
1631     return status;
1632
1633   // Get creation time for experiment
1634   struct stat64 st;
1635   if (dbe_stat (path, &st) == 0)
1636     mtime = st.st_mtime;
1637
1638   // Read the warnings file
1639   read_warn_file ();
1640
1641   // Open the log file
1642   read_log_file ();
1643   if (status == SUCCESS && last_event // last event is initialized
1644       && (last_event - exp_start_time) / 1000000 < tiny_threshold)
1645     {
1646       // Process "tiny_threshold" (SP_ANALYZER_DISCARD_TINY_EXPERIMENTS)
1647       // At this point, we've only processed log.xml.
1648       // Note: if an experiment terminated abnormally, last_event will not yet
1649       //   represent events from clock profiling and other metrics.
1650       //   Other events will often have timestamps after the last log.xml entry.
1651       discardTiny = true;
1652       return status;
1653     }
1654   if (status == FAILURE)
1655     {
1656       if (logFile->get_status () == ExperimentFile::EF_FAILURE)
1657         {
1658           Emsg *m = new Emsg (CMSG_FATAL, GTXT ("*** Error: log file in experiment cannot be read"));
1659           errorq->append (m);
1660         }
1661       else if (fetch_errors () == NULL)
1662         {
1663           if (broken == 1)
1664             {
1665               Emsg *m = new Emsg (CMSG_FATAL, GTXT ("*** Error: log does not show target starting"));
1666               errorq->append (m);
1667             }
1668           else
1669             {
1670               Emsg *m = new Emsg (CMSG_FATAL, GTXT ("*** Error: log file in experiment could not be parsed"));
1671               errorq->append (m);
1672             }
1673         }
1674       return status;
1675     }
1676   init_cache ();
1677   if (varclock != 0)
1678     {
1679       StringBuilder sb;
1680       sb.sprintf (
1681                   GTXT ("*** Warning: system has variable clock frequency, which may cause variable execution times and inaccurate conversions of cycle counts into time."));
1682       warnq->append (new Emsg (CMSG_WARN, sb));
1683     }
1684
1685   // Read the notes file
1686   read_notes_file ();
1687   read_labels_file ();
1688   read_archives ();
1689
1690   // The log file shows experiment started
1691   read_java_classes_file ();
1692
1693   read_map_file ();
1694
1695   // Dyntext file has to be processed after loadobjects file
1696   // as we need to be able to map (vaddr,ts) to dynamic functions.
1697   read_dyntext_file ();
1698
1699   // Read the overview file and create samples.
1700   // Profiling data hasn't been read yet so we may have
1701   // events after the last recorded sample.
1702   // We'll create a fake sample to cover all those
1703   // events later.
1704   read_overview_file ();
1705
1706   // Check if instruction frequency data is available
1707   read_ifreq_file ();
1708
1709   // Check if OMP data is available
1710   read_omp_file ();
1711
1712   return status;
1713 }
1714
1715 /* XXX -- update() is a no-op now, but may be needed for auto-update */
1716 Experiment::Exp_status
1717 Experiment::update ()
1718 {
1719   return status;
1720 }
1721
1722 void
1723 Experiment::append (LoadObject *lo)
1724 {
1725   loadObjs->append (lo);
1726   char *obj_name = lo->get_pathname ();
1727   char *bname = get_basename (obj_name);
1728   loadObjMap->put (obj_name, lo);
1729   loadObjMap->put (bname, lo);
1730   if (lo->flags & SEG_FLAG_EXE)
1731     loadObjMap->put (COMP_EXE_NAME, lo);
1732 }
1733
1734 void
1735 Experiment::read_notes_file ()
1736 {
1737   Emsg *m;
1738
1739   // Open log file:
1740   char *fname = dbe_sprintf (NTXT ("%s/%s"), expt_name, SP_NOTES_FILE);
1741   FILE *f = fopen (fname, NTXT ("r"));
1742   free (fname);
1743   if (f == NULL)
1744     return;
1745   if (!dbeSession->is_interactive ())
1746     {
1747       m = new Emsg (CMSG_COMMENT, NTXT ("Notes:"));
1748       notesq->append (m);
1749     }
1750
1751   while (1)
1752     {
1753       char str[MAXPATHLEN];
1754       char *e = fgets (str, ((int) sizeof (str)) - 1, f);
1755       if (e == NULL)
1756         {
1757           if (!dbeSession->is_interactive ())
1758             {
1759               m = new Emsg (CMSG_COMMENT,
1760                             "============================================================");
1761               notesq->append (m);
1762             }
1763           break;
1764         }
1765       size_t i = strlen (str);
1766       if (i > 0 && str[i - 1] == '\n')
1767         // remove trailing nl
1768         str[i - 1] = 0;
1769       m = new Emsg (CMSG_COMMENT, str);
1770       notesq->append (m);
1771     }
1772   (void) fclose (f);
1773 }
1774
1775 int
1776 Experiment::save_notes (char* text, bool handle_file)
1777 {
1778   if (handle_file)
1779     {
1780       FILE *fnotes;
1781       char *fname = dbe_sprintf (NTXT ("%s/%s"), expt_name, SP_NOTES_FILE);
1782       fnotes = fopen (fname, NTXT ("w"));
1783       free (fname);
1784       if (fnotes != NULL)
1785         {
1786           (void) fprintf (fnotes, NTXT ("%s"), text);
1787           fclose (fnotes);
1788         }
1789       else
1790         return 1; // Cannot write file
1791     }
1792   notesq->clear ();
1793   Emsg *m = new Emsg (CMSG_COMMENT, text);
1794   notesq->append (m);
1795
1796   return 0;
1797 }
1798
1799 int
1800 Experiment::delete_notes (bool handle_file)
1801 {
1802   if (handle_file)
1803     {
1804       char *fname = dbe_sprintf (NTXT ("%s/%s"), expt_name, SP_NOTES_FILE);
1805       if (unlink (fname) != 0)
1806         {
1807           free (fname);
1808           return 1; // Cannot delete file
1809         }
1810       free (fname);
1811     }
1812   notesq->clear ();
1813   return 0;
1814 }
1815
1816 int
1817 Experiment::read_warn_file ()
1818 {
1819   int local_status = SUCCESS;
1820
1821   ExperimentFile *warnFile = new ExperimentFile (this, SP_WARN_FILE);
1822   if (warnFile == NULL)
1823     return FAILURE;
1824   if (!warnFile->open ())
1825     {
1826       delete warnFile;
1827       return FAILURE;
1828     }
1829   SAXParserFactory *factory = SAXParserFactory::newInstance ();
1830   SAXParser *saxParser = factory->newSAXParser ();
1831   DefaultHandler *dh = new ExperimentHandler (this);
1832   try
1833     {
1834       saxParser->parse ((File*) warnFile->fh, dh);
1835     }
1836   catch (SAXException *e)
1837     {
1838       // Fatal error in the parser
1839       StringBuilder sb;
1840       sb.sprintf (NTXT ("%s: %s"), SP_WARN_FILE, e->getMessage ());
1841       char *str = sb.toString ();
1842       Emsg *m = new Emsg (CMSG_FATAL, str);
1843       errorq->append (m);
1844       local_status = FAILURE;
1845       delete e;
1846     }
1847   delete warnFile;
1848   delete dh;
1849   delete saxParser;
1850   delete factory;
1851
1852   return local_status;
1853 }
1854
1855 int
1856 Experiment::read_log_file ()
1857 {
1858   if (logFile == NULL)
1859     logFile = new ExperimentFile (this, SP_LOG_FILE);
1860   if (!logFile->open ())
1861     {
1862       status = FAILURE;
1863       return status;
1864     }
1865
1866   SAXParserFactory *factory = SAXParserFactory::newInstance ();
1867   SAXParser *saxParser = factory->newSAXParser ();
1868   DefaultHandler *dh = new ExperimentHandler (this);
1869   try
1870     {
1871       saxParser->parse ((File*) logFile->fh, dh);
1872     }
1873   catch (SAXException *e)
1874     {
1875       // Fatal error in the parser
1876       StringBuilder sb;
1877       if (obsolete == 1)
1878         sb.sprintf (NTXT ("%s"), e->getMessage ());
1879       else
1880         sb.sprintf (NTXT ("%s: %s"), SP_LOG_FILE, e->getMessage ());
1881       char *str = sb.toString ();
1882       Emsg *m = new Emsg (CMSG_FATAL, str);
1883       errorq->append (m);
1884       status = FAILURE;
1885       delete e;
1886     }
1887   logFile->close ();
1888   dbeSession->register_metric (GTXT ("IPC"), GTXT ("Instructions Per Cycle"),
1889                                NTXT ("insts/cycles"));
1890   dbeSession->register_metric (GTXT ("CPI"), GTXT ("Cycles Per Instruction"),
1891                                NTXT ("cycles/insts"));
1892   dbeSession->register_metric (GTXT ("K_IPC"),
1893                                GTXT ("Kernel Instructions Per Cycle"),
1894                                NTXT ("K_insts/K_cycles"));
1895   dbeSession->register_metric (GTXT ("K_CPI"),
1896                                GTXT ("Kernel Cycles Per Instruction"),
1897                                NTXT ("K_cycles/K_insts"));
1898
1899   delete dh;
1900   delete saxParser;
1901   delete factory;
1902
1903   return status;
1904 }
1905
1906 ////////////////////////////////////////////////////////////////////////////////
1907 //  class Experiment::ExperimentLabelsHandler
1908 //
1909
1910 class Experiment::ExperimentLabelsHandler : public DefaultHandler
1911 {
1912 public:
1913
1914   ExperimentLabelsHandler (Experiment *_exp)
1915   {
1916     exp = _exp;
1917   }
1918
1919   ~ExperimentLabelsHandler () { };
1920   void startDocument () { }
1921   void endDocument () { }
1922   void endElement (char * /*uri*/, char * /*localName*/, char * /*qName*/) { }
1923   void characters (char * /*ch*/, int /*start*/, int /*length*/) { }
1924   void ignorableWhitespace (char*, int, int) { }
1925   void error (SAXParseException * /*e*/) { }
1926
1927   void startElement (char *uri, char *localName, char *qName, Attributes *attrs);
1928
1929 private:
1930
1931   inline const char *
1932   s2s (const char *s)
1933   {
1934     return s ? s : "NULL";
1935   }
1936
1937   Experiment *exp;
1938   char *hostname;
1939   hrtime_t time, tstamp;
1940 };
1941
1942 void
1943 Experiment::ExperimentLabelsHandler::startElement (char*, char*, char *qName,
1944                                                    Attributes *attrs)
1945 {
1946   DEBUG_CODE if (DEBUG_SAXPARSER) dump_startElement (qName, attrs);
1947   if (qName == NULL || strcmp (qName, NTXT ("id")) != 0)
1948     return;
1949   char *name = NULL, *all_times = NULL, *comment = NULL, *hostName = NULL;
1950   long startSec = 0;
1951   //    long tm_zone = 0;
1952   hrtime_t startHrtime = (hrtime_t) 0;
1953   long long lbl_ts = 0;
1954   int relative = 0;
1955   timeval start_tv;
1956   start_tv.tv_usec = start_tv.tv_sec = 0;
1957   for (int i = 0, sz = attrs ? attrs->getLength () : 0; i < sz; i++)
1958     {
1959       const char *qn = attrs->getQName (i);
1960       const char *vl = attrs->getValue (i);
1961       if (strcmp (qn, NTXT ("name")) == 0)
1962         name = dbe_xml2str (vl);
1963       else if (strcmp (qn, NTXT ("cmd")) == 0)
1964         all_times = dbe_xml2str (vl);
1965       else if (strcmp (qn, NTXT ("comment")) == 0)
1966         comment = dbe_xml2str (vl);
1967       else if (strcmp (qn, NTXT ("relative")) == 0)
1968         relative = atoi (vl);
1969       else if (strcmp (qn, NTXT ("hostname")) == 0)
1970         hostName = dbe_xml2str (vl);
1971       else if (strcmp (qn, NTXT ("time")) == 0)
1972         startSec = atol (vl);
1973       else if (strcmp (qn, NTXT ("tstamp")) == 0)
1974         startHrtime = parseTStamp (vl);
1975       else if (strcmp (qn, NTXT ("lbl_ts")) == 0)
1976         {
1977           if (*vl == '-')
1978             lbl_ts = -parseTStamp (vl + 1);
1979           else
1980             lbl_ts = parseTStamp (vl);
1981         }
1982     }
1983   if (name == NULL || hostName == NULL || (all_times == NULL && comment == NULL))
1984     {
1985       free (name);
1986       free (hostName);
1987       free (all_times);
1988       free (comment);
1989       return;
1990     }
1991   UserLabel *lbl = new UserLabel (name);
1992   lbl->comment = comment;
1993   lbl->hostname = hostName;
1994   lbl->start_sec = startSec;
1995   lbl->start_hrtime = startHrtime;
1996   exp->userLabels->append (lbl);
1997   if (all_times)
1998     {
1999       lbl->all_times = all_times;
2000       lbl->start_tv = start_tv;
2001       lbl->relative = relative;
2002       if (relative == UserLabel::REL_TIME)
2003         lbl->atime = lbl_ts;
2004       else
2005         { // relative == UserLabel::CUR_TIME
2006           long long delta = 0;
2007           if (exp->hostname && strcmp (lbl->hostname, exp->hostname) == 0)
2008             delta = lbl_ts + (lbl->start_hrtime - exp->exp_start_time);
2009           else
2010             for (int i = 0; i < exp->userLabels->size (); i++)
2011               {
2012                 UserLabel *firstLbl = exp->userLabels->fetch (i);
2013                 if (strcmp (lbl->hostname, firstLbl->hostname) == 0)
2014                   {
2015                     delta = lbl_ts + (lbl->start_hrtime - firstLbl->start_hrtime) +
2016                             ((long long) (firstLbl->start_sec - exp->start_sec)) * NANOSEC;
2017                     break;
2018                   }
2019               }
2020           lbl->atime = delta > 0 ? delta : 0;
2021         }
2022     }
2023 }
2024
2025 static int
2026 sortUserLabels (const void *a, const void *b)
2027 {
2028   UserLabel *l1 = *((UserLabel **) a);
2029   UserLabel *l2 = *((UserLabel **) b);
2030   int v = dbe_strcmp (l1->name, l2->name);
2031   if (v != 0)
2032     return v;
2033   if (l1->atime < l2->atime)
2034     return -1;
2035   else if (l1->atime > l2->atime)
2036     return 1;
2037   if (l1->id < l2->id)
2038     return -1;
2039   else if (l1->id > l2->id)
2040     return 1;
2041   return 0;
2042 }
2043
2044 static char *
2045 append_string (char *s, char *str)
2046 {
2047   if (s == NULL)
2048     return dbe_strdup (str);
2049   char *new_s = dbe_sprintf (NTXT ("%s %s"), s, str);
2050   free (s);
2051   return new_s;
2052 }
2053
2054 void
2055 Experiment::read_labels_file ()
2056 {
2057   ExperimentFile *fp = new ExperimentFile (this, SP_LABELS_FILE);
2058   if (!fp->open ())
2059     {
2060       delete fp;
2061       return;
2062     }
2063   userLabels = new Vector<UserLabel*>();
2064   SAXParserFactory *factory = SAXParserFactory::newInstance ();
2065   SAXParser *saxParser = factory->newSAXParser ();
2066   DefaultHandler *dh = new ExperimentLabelsHandler (this);
2067   try
2068     {
2069       saxParser->parse ((File*) fp->fh, dh);
2070     }
2071   catch (SAXException *e)
2072     {
2073       // Fatal error in the parser
2074       StringBuilder sb;
2075       sb.sprintf (NTXT ("%s: %s"), SP_LABELS_FILE, e->getMessage ());
2076       char *str = sb.toString ();
2077       Emsg *m = new Emsg (CMSG_FATAL, str);
2078       errorq->append (m);
2079       delete e;
2080     }
2081   fp->close ();
2082   delete fp;
2083   delete dh;
2084   delete saxParser;
2085   delete factory;
2086
2087   userLabels->sort (sortUserLabels);
2088   UserLabel::dump ("After sortUserLabels:", userLabels);
2089   UserLabel *ulbl = NULL;
2090   for (int i = 0, sz = userLabels->size (); i < sz; i++)
2091     {
2092       UserLabel *lbl = userLabels->fetch (i);
2093       if (ulbl == NULL)
2094         ulbl = new UserLabel (lbl->name);
2095       else if (dbe_strcmp (lbl->name, ulbl->name) != 0)
2096         { // new Label
2097           ulbl->register_user_label (groupId);
2098           if (ulbl->expr == NULL)
2099             delete ulbl;
2100           ulbl = new UserLabel (lbl->name);
2101         }
2102       if (lbl->all_times)
2103         {
2104           if (strncmp (lbl->all_times, NTXT ("start"), 5) == 0)
2105             {
2106               if (!ulbl->start_f)
2107                 {
2108                   ulbl->start_f = true;
2109                   ulbl->timeStart = lbl->atime;
2110                 }
2111             }
2112           else
2113             { // stop
2114               if (!ulbl->start_f)
2115                 continue;
2116               ulbl->all_times = append_string (ulbl->all_times, lbl->all_times);
2117               ulbl->stop_f = true;
2118               ulbl->timeStop = lbl->atime;
2119               ulbl->gen_expr ();
2120             }
2121         }
2122       if (lbl->comment != NULL)
2123         ulbl->comment = append_string (ulbl->comment, lbl->comment);
2124     }
2125   if (ulbl)
2126     {
2127       ulbl->register_user_label (groupId);
2128       if (ulbl->expr == NULL)
2129         delete ulbl;
2130     }
2131   Destroy (userLabels);
2132 }
2133
2134 void
2135 Experiment::read_archives ()
2136 {
2137   if (founder_exp)
2138     return;
2139   char *allocated_str = NULL;
2140   char *nm = get_arch_name ();
2141   DIR *exp_dir = opendir (nm);
2142   if (exp_dir == NULL)
2143     {
2144       if (founder_exp == NULL)
2145         {
2146           // Check if the user uses a subexperiment only
2147           nm = dbe_sprintf (NTXT ("%s/../%s"), expt_name, SP_ARCHIVES_DIR);
2148           exp_dir = opendir (nm);
2149           if (exp_dir == NULL)
2150             {
2151               free (nm);
2152               return;
2153             }
2154           allocated_str = nm;
2155         }
2156       else
2157         return;
2158     }
2159
2160   StringBuilder sb;
2161   sb.append (nm);
2162   sb.append ('/');
2163   int dlen = sb.length ();
2164   free (allocated_str);
2165   archiveMap = new StringMap<DbeFile *>();
2166
2167   struct dirent *entry = NULL;
2168   while ((entry = readdir (exp_dir)) != NULL)
2169     {
2170       char *dname = entry->d_name;
2171       if (dname[0] == '.'
2172           && (dname[1] == '\0' || (dname[1] == '.' && dname[2] == '\0')))
2173         // skip links to ./ or ../
2174         continue;
2175       sb.setLength (dlen);
2176       sb.append (dname);
2177       char *fnm = sb.toString ();
2178       DbeFile *df = new DbeFile (fnm);
2179       df->set_location (fnm);
2180       df->filetype |= DbeFile::F_FILE;
2181       df->inArchive = true;
2182       df->experiment = this;
2183       archiveMap->put (dname, df);
2184       free (fnm);
2185     }
2186   closedir (exp_dir);
2187 }
2188
2189 static char *
2190 gen_file_name (const char *packet_name, const char *src_name)
2191 {
2192   char *fnm, *bname = get_basename (packet_name);
2193   if (bname == packet_name)
2194     fnm = dbe_strdup (src_name);
2195   else
2196     fnm = dbe_sprintf ("%.*s%s", (int) (bname - packet_name),
2197                        packet_name, src_name);
2198
2199   // convert "java.lang.Object/Integer.java" => "java/lang/Object/Integer.java"
2200   bname = get_basename (fnm);
2201   for (char *s = fnm; s < bname; s++)
2202     if (*s == '.')
2203       *s = '/';
2204   return fnm;
2205 }
2206
2207 static char *
2208 get_jlass_name (const char *nm)
2209 {
2210   // Convert "Ljava/lang/Object;" => "java/lang/Object.class"
2211   if (*nm == 'L')
2212     {
2213       size_t len = strlen (nm);
2214       if (nm[len - 1] == ';')
2215         return dbe_sprintf ("%.*s.class", (int) (len - 2), nm + 1);
2216     }
2217   return dbe_strdup (nm);
2218 }
2219
2220 static char *
2221 get_jmodule_name (const char *nm)
2222 {
2223   // convert "Ljava/lang/Object;" => "java.lang.Object"
2224   if (*nm == 'L')
2225     {
2226       size_t len = strlen (nm);
2227       if (nm[len - 1] == ';')
2228         {
2229           char *mname = dbe_sprintf (NTXT ("%.*s"), (int) (len - 2), nm + 1);
2230           for (char *s = mname; *s; s++)
2231             if (*s == '/')
2232               *s = '.';
2233           return mname;
2234         }
2235     }
2236   return dbe_strdup (nm);
2237 }
2238
2239 LoadObject *
2240 Experiment::get_j_lo (const char *className, const char *fileName)
2241 {
2242   char *class_name = get_jlass_name (className);
2243   Dprintf (DUMP_JCLASS_READER,
2244         "Experiment::get_j_lo: className='%s' class_name='%s' fileName='%s'\n",
2245            STR (className), STR (class_name), STR (fileName));
2246   LoadObject *lo = loadObjMap->get (class_name);
2247   if (lo == NULL)
2248     {
2249       lo = createLoadObject (class_name, fileName);
2250       lo->type = LoadObject::SEG_TEXT;
2251       lo->mtime = (time_t) 0;
2252       lo->size = 0;
2253       lo->set_platform (Java, wsize);
2254       lo->dbeFile->filetype |= DbeFile::F_FILE | DbeFile::F_JAVACLASS;
2255       append (lo);
2256       Dprintf (DUMP_JCLASS_READER,
2257                "Experiment::get_j_lo: creates '%s' location='%s'\n",
2258                STR (lo->get_name ()), STR (lo->dbeFile->get_location (false)));
2259     }
2260   free (class_name);
2261   return lo;
2262 }
2263
2264 Module *
2265 Experiment::get_jclass (const char *className, const char *fileName)
2266 {
2267   LoadObject *lo = get_j_lo (className, NULL);
2268   char *mod_name = get_jmodule_name (className);
2269   Module *mod = lo->find_module (mod_name);
2270   if (mod == NULL)
2271     {
2272       mod = dbeSession->createClassFile (mod_name);
2273       mod->loadobject = lo;
2274       if (strcmp (fileName, NTXT ("<Unknown>")) != 0)
2275         mod->set_file_name (gen_file_name (lo->get_pathname (), fileName));
2276       else
2277         mod->set_file_name (dbe_strdup (fileName));
2278       lo->append_module (mod);
2279       mod_name = NULL;
2280     }
2281   else if (mod->file_name && (strcmp (mod->file_name, "<Unknown>") == 0)
2282            && strcmp (fileName, "<Unknown>") != 0)
2283     mod->set_file_name (gen_file_name (lo->get_pathname (), fileName));
2284   Dprintf (DUMP_JCLASS_READER,
2285         "Experiment::get_jclass: class_name='%s' mod_name='%s' fileName='%s'\n",
2286            mod->loadobject->get_pathname (), mod->get_name (), mod->file_name);
2287   free (mod_name);
2288   return mod;
2289 }
2290
2291 #define ARCH_STRLEN(s) ( ( strlen(s) + 4 ) & ~0x3 )
2292
2293 int
2294 Experiment::read_java_classes_file ()
2295 {
2296   char *data_file_name = dbe_sprintf (NTXT ("%s/%s"), expt_name, SP_JCLASSES_FILE);
2297   Data_window *dwin = new Data_window (data_file_name);
2298   free (data_file_name);
2299   if (dwin->not_opened ())
2300     {
2301       delete dwin;
2302       return INCOMPLETE;
2303     }
2304   dwin->need_swap_endian = need_swap_endian;
2305   jmaps = new PRBTree ();
2306   jmidHTable = new DbeCacheMap<unsigned long long, JMethod>;
2307
2308   hrtime_t cur_loaded = 0;
2309   Module *cur_mod = NULL;
2310   for (int64_t offset = 0;;)
2311     {
2312       CM_Packet *cpkt = (CM_Packet*) dwin->bind (offset, sizeof (CM_Packet));
2313       if (cpkt == NULL)
2314         break;
2315       uint16_t v16 = (uint16_t) cpkt->tsize;
2316       size_t cpktsize = dwin->decode (v16);
2317       cpkt = (CM_Packet*) dwin->bind (offset, cpktsize);
2318       if ((cpkt == NULL) || (cpktsize == 0))
2319         {
2320           char *buf = dbe_sprintf (GTXT ("archive file malformed %s"),
2321                                    arch_name);
2322           errorq->append (new Emsg (CMSG_ERROR, buf));
2323           free (buf);
2324           break;
2325         }
2326       v16 = (uint16_t) cpkt->type;
2327       v16 = dwin->decode (v16);
2328       switch (v16)
2329         {
2330         case ARCH_JCLASS:
2331           {
2332             ARCH_jclass *ajcl = (ARCH_jclass*) cpkt;
2333             uint64_t class_id = dwin->decode (ajcl->class_id);
2334             char *className = ((char*) ajcl) + sizeof (*ajcl);
2335             char *fileName = className + ARCH_STRLEN (className);
2336             Dprintf (DUMP_JCLASS_READER,
2337                      "read_java_classes_file: ARCH_JCLASS(Ox%x)"
2338                      "class_id=Ox%llx className='%s' fileName='%s' \n",
2339                      (int) v16, (long long) class_id, className, fileName);
2340             cur_mod = NULL;
2341             if (*className == 'L')
2342               { // Old libcollector generated '[' (one array dimension).
2343                 cur_mod = get_jclass (className, fileName);
2344                 cur_loaded = dwin->decode (ajcl->tstamp);
2345                 jmaps->insert (class_id, cur_loaded, cur_mod);
2346               }
2347             break;
2348           }
2349         case ARCH_JCLASS_LOCATION:
2350           {
2351             ARCH_jclass_location *ajcl = (ARCH_jclass_location *) cpkt;
2352             uint64_t class_id = dwin->decode (ajcl->class_id);
2353             char *className = ((char*) ajcl) + sizeof (*ajcl);
2354             char *fileName = className + ARCH_STRLEN (className);
2355             Dprintf (DUMP_JCLASS_READER,
2356                      "read_java_classes_file: ARCH_JCLASS_LOCATION(Ox%x)"
2357                      "class_id=Ox%llx className='%s' fileName='%s' \n",
2358                      (int) v16, (long long) class_id, className, fileName);
2359             get_j_lo (className, fileName);
2360             break;
2361           }
2362         case ARCH_JMETHOD:
2363           {
2364             if (cur_mod == NULL)
2365               break;
2366             ARCH_jmethod *ajmt = (ARCH_jmethod*) cpkt;
2367             uint64_t method_id = dwin->decode (ajmt->method_id);
2368             char *s_name = ((char*) ajmt) + sizeof (*ajmt);
2369             char *s_signature = s_name + ARCH_STRLEN (s_name);
2370             char *fullname = dbe_sprintf ("%s.%s", cur_mod->get_name (), s_name);
2371             Dprintf (DUMP_JCLASS_READER,
2372                      "read_java_classes_file: ARCH_JMETHOD(Ox%x) "
2373                      "method_id=Ox%llx name='%s' signature='%s' fullname='%s'\n",
2374                      (int) v16, (long long) method_id, s_name,
2375                      s_signature, fullname);
2376             JMethod *jmthd = cur_mod->find_jmethod (fullname, s_signature);
2377             if (jmthd == NULL)
2378               {
2379                 jmthd = dbeSession->createJMethod ();
2380                 jmthd->size = (unsigned) - 1; // unknown until later (maybe)
2381                 jmthd->module = cur_mod;
2382                 jmthd->set_signature (s_signature);
2383                 jmthd->set_name (fullname);
2384                 cur_mod->functions->append (jmthd);
2385                 cur_mod->loadobject->functions->append (jmthd);
2386                 Dprintf (DUMP_JCLASS_READER,
2387                     "read_java_classes_file: ARCH_JMETHOD CREATE fullname=%s\n",
2388                          fullname);
2389               }
2390             jmaps->insert (method_id, cur_loaded, jmthd);
2391             free (fullname);
2392             break;
2393           }
2394         default:
2395           Dprintf (DUMP_JCLASS_READER,
2396                    "read_java_classes_file: type=Ox%x (%d) cpktsize=%d\n",
2397                    (int) v16, (int) v16, (int) cpktsize);
2398           break; // ignore unknown packets
2399         }
2400       offset += cpktsize;
2401     }
2402   delete dwin;
2403   return SUCCESS;
2404 }
2405
2406 void
2407 Experiment::read_map_file ()
2408 {
2409   ExperimentFile *mapFile = new ExperimentFile (this, SP_MAP_FILE);
2410   if (!mapFile->open ())
2411     {
2412       delete mapFile;
2413       return;
2414     }
2415
2416   SAXParserFactory *factory = SAXParserFactory::newInstance ();
2417   SAXParser *saxParser = factory->newSAXParser ();
2418   DefaultHandler *dh = new ExperimentHandler (this);
2419   try
2420     {
2421       saxParser->parse ((File*) mapFile->fh, dh);
2422     }
2423   catch (SAXException *e)
2424     {
2425       // Fatal error in the parser
2426       StringBuilder sb;
2427       sb.sprintf (NTXT ("%s: %s"), SP_MAP_FILE, e->getMessage ());
2428       char *str = sb.toString ();
2429       Emsg *m = new Emsg (CMSG_FATAL, str);
2430       errorq->append (m);
2431       status = FAILURE;
2432       free (str);
2433       delete e;
2434     }
2435   delete mapFile;
2436   delete dh;
2437   delete saxParser;
2438   delete factory;
2439
2440   for (int i = 0, sz = mrecs ? mrecs->size () : 0; i < sz; i++)
2441     {
2442       MapRecord *mrec = mrecs->fetch (i);
2443       SegMem *smem, *sm_lo, *sm_hi;
2444       switch (mrec->kind)
2445         {
2446         case MapRecord::LOAD:
2447           smem = new SegMem;
2448           smem->base = mrec->base;
2449           smem->size = mrec->size;
2450           smem->load_time = mrec->ts;
2451           smem->unload_time = MAX_TIME;
2452           smem->obj = mrec->obj;
2453           smem->set_file_offset (mrec->foff);
2454           seg_items->append (smem); // add to the master list
2455
2456           // Check if the new segment overlaps other active segments
2457           sm_lo = (SegMem*) maps->locate (smem->base, smem->load_time);
2458           if (sm_lo && sm_lo->base + sm_lo->size > smem->base)
2459             {
2460               // check to see if it is a duplicate record: same address and size, and
2461               if ((smem->base == sm_lo->base) && (smem->size == sm_lo->size))
2462                 {
2463                   // addresses and sizes match, check name
2464                   if (strstr (smem->obj->get_name (), sm_lo->obj->get_name ()) != NULL
2465                       || strstr (sm_lo->obj->get_name (), smem->obj->get_name ()) != NULL)
2466                     // this is a duplicate; just move on the the next map record
2467                     continue;
2468                   fprintf (stderr,
2469                            GTXT ("*** Warning: Segment `%s' loaded with same address, size as `%s' [0x%llx-0x%llx]\n"),
2470                            smem->obj->get_name (), sm_lo->obj->get_name (),
2471                            sm_lo->base, sm_lo->base + sm_lo->size);
2472                 }
2473
2474               // Not a duplicate; implicitly unload the old one
2475               //     Note: implicit unloading causes high <Unknown>
2476               //           when such overlapping is bogus
2477               StringBuilder sb;
2478               sb.sprintf (GTXT ("*** Warning: Segment %s [0x%llx-0x%llx] overlaps %s [0x%llx-0x%llx], which has been implicitly unloaded"),
2479                           smem->obj->get_name (), smem->base, smem->base + smem->size,
2480                           sm_lo->obj->get_name (), sm_lo->base, sm_lo->base + sm_lo->size);
2481               warnq->append (new Emsg (CMSG_WARN, sb));
2482             }
2483
2484           // now look for other segments with which this might overlap
2485           sm_hi = (SegMem*) maps->locate_up (smem->base, smem->load_time);
2486           while (sm_hi && sm_hi->base < smem->base + smem->size)
2487             {
2488
2489               // Note: implicit unloading causes high <Unknown> when such overlapping is bogus
2490               // maps->remove( sm_hi->base, smem->load_time );
2491               StringBuilder sb;
2492               sb.sprintf (GTXT ("*** Warning: Segment %s [0x%llx-0x%llx] overlaps %s [0x%llx-0x%llx], which has been implicitly unloaded"),
2493                           smem->obj->get_name (), smem->base,
2494                           smem->base + smem->size, sm_hi->obj->get_name (),
2495                           sm_hi->base, sm_hi->base + sm_hi->size);
2496               warnq->append (new Emsg (CMSG_WARN, sb));
2497               sm_hi = (SegMem*) maps->locate_up (sm_hi->base + sm_hi->size,
2498                                                  smem->load_time);
2499             }
2500
2501           maps->insert (smem->base, smem->load_time, smem);
2502           break;
2503         case MapRecord::UNLOAD:
2504           smem = (SegMem*) maps->locate (mrec->base, mrec->ts);
2505           if (smem && smem->base == mrec->base)
2506             {
2507               smem->unload_time = mrec->ts;
2508               maps->remove (mrec->base, mrec->ts);
2509             }
2510           break;
2511         }
2512     }
2513   mrecs->destroy ();
2514
2515   // See if there are comments or warnings for a load object;
2516   // if so, queue them to Experiment
2517   for (long i = 0, sz = loadObjs ? loadObjs->size () : 0; i < sz; i++)
2518     {
2519       LoadObject *lo = loadObjs->get (i);
2520       for (Emsg *m = lo->fetch_warnings (); m; m = m->next)
2521         warnq->append (m->get_warn (), m->get_msg ());
2522       for (Emsg *m = lo->fetch_comments (); m; m = m->next)
2523         commentq->append (m->get_warn (), m->get_msg ());
2524     }
2525 }
2526
2527 void
2528 Experiment::read_frameinfo_file ()
2529 {
2530   init_cache ();
2531   char *base_name = get_basename (expt_name);
2532   char *msg = dbe_sprintf (GTXT ("Loading CallStack Data: %s"), base_name);
2533   read_data_file ("data." SP_FRINFO_FILE, msg);
2534   free (msg);
2535   frmpckts->sort (frUidCmp);
2536   uidnodes->sort (uidNodeCmp);
2537 }
2538
2539 void
2540 Experiment::read_omp_preg ()
2541 {
2542   // Parallel region descriptions
2543   DataDescriptor *pregDdscr = getDataDescriptor (DATA_OMP4);
2544   if (pregDdscr == NULL)
2545     return;
2546   DataView *pregData = pregDdscr->createView ();
2547   pregData->sort (PROP_CPRID); // omptrace PROP_CPRID
2548
2549   // OpenMP enter parreg events
2550   DataDescriptor *dDscr = getDataDescriptor (DATA_OMP2);
2551   if (dDscr == NULL || dDscr->getSize () == 0)
2552     {
2553       delete pregData;
2554       return;
2555     }
2556
2557   char *idxname = NTXT ("OMP_preg");
2558   delete dbeSession->indxobj_define (idxname, GTXT ("OpenMP Parallel Region"),
2559                                      NTXT ("CPRID"), NULL, NULL);
2560   int idxtype = dbeSession->findIndexSpaceByName (idxname);
2561   if (idxtype < 0)
2562     {
2563       delete pregData;
2564       return;
2565     }
2566   ompavail = true;
2567
2568   // Pre-create parallel region with id == 0
2569   Histable *preg0 = dbeSession->createIndexObject (idxtype, (int64_t) 0);
2570   preg0->set_name (dbe_strdup (GTXT ("Implicit OpenMP Parallel Region")));
2571
2572   // Take care of the progress bar
2573   char *msg = dbe_sprintf (GTXT ("Processing OpenMP Parallel Region Data: %s"),
2574   get_basename (expt_name));
2575   theApplication->set_progress (0, msg);
2576   free (msg);
2577   long deltaReport = 1000;
2578   long nextReport = 0;
2579   long errors_found = 0;
2580   Vector<Histable*> pregs;
2581
2582   long size = dDscr->getSize ();
2583   for (long i = 0; i < size; ++i)
2584     {
2585       if (i == nextReport)
2586         {
2587           int percent = (int) (i * 100 / size);
2588           if (percent > 0)
2589             theApplication->set_progress (percent, NULL);
2590           nextReport += deltaReport;
2591         }
2592
2593       uint32_t thrid = dDscr->getIntValue (PROP_THRID, i);
2594       hrtime_t tstamp = dDscr->getLongValue (PROP_TSTAMP, i);
2595       uint64_t cprid = dDscr->getLongValue (PROP_CPRID, i); // omptrace CPRID
2596       mapPRid->put (thrid, tstamp, cprid);
2597
2598       pregs.reset ();
2599       /*
2600        * We will use 2 pointers to make sure there is no loop.
2601        * First pointer "curpreg" goes to the next element,
2602        * second pointer "curpreg_loop_control" goes to the next->next element.
2603        * If these pointers have the same value - there is a loop.
2604        */
2605       uint64_t curpreg_loop_control = cprid;
2606       Datum tval_loop_control;
2607       if (curpreg_loop_control != 0)
2608         {
2609           tval_loop_control.setUINT64 (curpreg_loop_control);
2610           long idx = pregData->getIdxByVals (&tval_loop_control, DataView::REL_EQ);
2611           if (idx < 0)
2612             curpreg_loop_control = 0;
2613           else
2614             curpreg_loop_control = pregData->getLongValue (PROP_PPRID, idx);
2615         }
2616       for (uint64_t curpreg = cprid; curpreg != 0;)
2617         {
2618           Histable *val = NULL;
2619           Datum tval;
2620           tval.setUINT64 (curpreg);
2621           long idx = pregData->getIdxByVals (&tval, DataView::REL_EQ);
2622           if (idx < 0)
2623             break;
2624           /*
2625            * Check if there is a loop
2626            */
2627           if (0 != curpreg_loop_control)
2628             {
2629               if (curpreg == curpreg_loop_control)
2630                 {
2631                   errors_found++;
2632                   if (1 == errors_found)
2633                     {
2634                       Emsg *m = new Emsg (CMSG_WARN, GTXT ("*** Warning: circular links in OMP regions; data may not be correct."));
2635                       warnq->append (m);
2636                     }
2637                   break;
2638                 }
2639             }
2640           uint64_t pragmapc = pregData->getLongValue (PROP_PRPC, idx);
2641           DbeInstr *instr = map_Vaddr_to_PC (pragmapc, tstamp);
2642           if (instr == NULL)
2643             {
2644               break;
2645             }
2646           val = instr;
2647           DbeLine *dbeline = (DbeLine*) instr->convertto (Histable::LINE);
2648           if (dbeline->lineno > 0)
2649             {
2650               if (instr->func->usrfunc)
2651                 dbeline = dbeline->sourceFile->find_dbeline
2652                         (instr->func->usrfunc, dbeline->lineno);
2653               dbeline->set_flag (DbeLine::OMPPRAGMA);
2654               val = dbeline;
2655             }
2656           val = dbeSession->createIndexObject (idxtype, val);
2657           pregs.append (val);
2658
2659           curpreg = pregData->getLongValue (PROP_PPRID, idx);
2660           /*
2661            * Update curpreg_loop_control
2662            */
2663           if (0 != curpreg_loop_control)
2664             {
2665               tval_loop_control.setUINT64 (curpreg_loop_control);
2666               idx = pregData->getIdxByVals
2667                       (&tval_loop_control, DataView::REL_EQ);
2668               if (idx < 0)
2669                 curpreg_loop_control = 0;
2670               else
2671                 {
2672                   curpreg_loop_control = pregData->getLongValue
2673                           (PROP_PPRID, idx);
2674                   tval_loop_control.setUINT64 (curpreg_loop_control);
2675                   idx = pregData->getIdxByVals
2676                           (&tval_loop_control, DataView::REL_EQ);
2677                   if (idx < 0)
2678                     curpreg_loop_control = 0;
2679                   else
2680                     curpreg_loop_control = pregData->getLongValue
2681                             (PROP_PPRID, idx);
2682                 }
2683             }
2684         }
2685       pregs.append (preg0);
2686       void *prstack = cstack->add_stack (&pregs);
2687       mapPReg->put (thrid, tstamp, prstack);
2688     }
2689   theApplication->set_progress (0, NTXT (""));
2690   delete pregData;
2691 }
2692
2693 void
2694 Experiment::read_omp_task ()
2695 {
2696   // Task description
2697   DataDescriptor *taskDataDdscr = getDataDescriptor (DATA_OMP5);
2698   if (taskDataDdscr == NULL)
2699     return;
2700
2701   //7035272: previously, DataView was global; now it's local...is this OK?
2702   DataView *taskData = taskDataDdscr->createView ();
2703   taskData->sort (PROP_TSKID); // omptrace PROP_TSKID
2704
2705   // OpenMP enter task events
2706   DataDescriptor *dDscr = getDataDescriptor (DATA_OMP3);
2707   if (dDscr == NULL || dDscr->getSize () == 0)
2708     {
2709       delete taskData;
2710       return;
2711     }
2712
2713   char *idxname = NTXT ("OMP_task");
2714   // delete a possible error message. Ugly.
2715   delete dbeSession->indxobj_define (idxname, GTXT ("OpenMP Task"), NTXT ("TSKID"), NULL, NULL);
2716   int idxtype = dbeSession->findIndexSpaceByName (idxname);
2717   if (idxtype < 0)
2718     {
2719       delete taskData;
2720       return;
2721     }
2722   ompavail = true;
2723
2724   // Pre-create task with id == 0
2725   Histable *task0 = dbeSession->createIndexObject (idxtype, (int64_t) 0);
2726   task0->set_name (dbe_strdup (GTXT ("OpenMP Task from Implicit Parallel Region")));
2727
2728   // Take care of the progress bar
2729   char *msg = dbe_sprintf (GTXT ("Processing OpenMP Task Data: %s"), get_basename (expt_name));
2730   theApplication->set_progress (0, msg);
2731   free (msg);
2732   long deltaReport = 1000;
2733   long nextReport = 0;
2734
2735   Vector<Histable*> tasks;
2736   long size = dDscr->getSize ();
2737   long errors_found = 0;
2738   for (long i = 0; i < size; ++i)
2739     {
2740       if (i == nextReport)
2741         {
2742           int percent = (int) (i * 100 / size);
2743           if (percent > 0)
2744             theApplication->set_progress (percent, NULL);
2745           nextReport += deltaReport;
2746         }
2747
2748       uint32_t thrid = dDscr->getIntValue (PROP_THRID, i);
2749       hrtime_t tstamp = dDscr->getLongValue (PROP_TSTAMP, i);
2750       uint64_t tskid = dDscr->getLongValue (PROP_TSKID, i); //omptrace TSKID
2751       tasks.reset ();
2752       /*
2753        * We will use 2 pointers to make sure there is no loop.
2754        * First pointer "curtsk" goes to the next element,
2755        * second pointer "curtsk_loop_control" goes to the next->next element.
2756        * If these pointers have the same value - there is a loop.
2757        */
2758       uint64_t curtsk_loop_control = tskid;
2759       Datum tval_loop_control;
2760       if (curtsk_loop_control != 0)
2761         {
2762           tval_loop_control.setUINT64 (curtsk_loop_control);
2763           long idx = taskData->getIdxByVals (&tval_loop_control, DataView::REL_EQ);
2764           if (idx < 0)
2765             curtsk_loop_control = 0;
2766           else
2767             curtsk_loop_control = taskData->getLongValue (PROP_PTSKID, idx);
2768         }
2769       for (uint64_t curtsk = tskid; curtsk != 0;)
2770         {
2771           Histable *val = NULL;
2772
2773           Datum tval;
2774           tval.setUINT64 (curtsk);
2775           long idx = taskData->getIdxByVals (&tval, DataView::REL_EQ);
2776           if (idx < 0)
2777             break;
2778           /*
2779            * Check if there is a loop
2780            */
2781           if (0 != curtsk_loop_control)
2782             {
2783               if (curtsk == curtsk_loop_control)
2784                 {
2785                   errors_found++;
2786                   if (1 == errors_found)
2787                     {
2788                       Emsg *m = new Emsg (CMSG_WARN, GTXT ("*** Warning: circular links in OMP tasks; data may not be correct."));
2789                       warnq->append (m);
2790                     }
2791                   break;
2792                 }
2793             }
2794           uint64_t pragmapc = taskData->getLongValue (PROP_PRPC, idx);
2795           DbeInstr *instr = map_Vaddr_to_PC (pragmapc, tstamp);
2796           if (instr == NULL)
2797             break;
2798           val = instr;
2799           DbeLine *dbeline = (DbeLine*) instr->convertto (Histable::LINE);
2800           if (dbeline->lineno > 0)
2801             {
2802               if (instr->func->usrfunc)
2803                 dbeline = dbeline->sourceFile->find_dbeline
2804                         (instr->func->usrfunc, dbeline->lineno);
2805               dbeline->set_flag (DbeLine::OMPPRAGMA);
2806               val = dbeline;
2807             }
2808           val = dbeSession->createIndexObject (idxtype, val);
2809           tasks.append (val);
2810
2811           curtsk = taskData->getLongValue (PROP_PTSKID, idx);
2812           /*
2813            * Update curtsk_loop_control
2814            */
2815           if (0 != curtsk_loop_control)
2816             {
2817               tval_loop_control.setUINT64 (curtsk_loop_control);
2818               idx = taskData->getIdxByVals (&tval_loop_control, DataView::REL_EQ);
2819               if (idx < 0)
2820                 curtsk_loop_control = 0;
2821               else
2822                 {
2823                   curtsk_loop_control = taskData->getLongValue (PROP_PTSKID, idx);
2824                   tval_loop_control.setUINT64 (curtsk_loop_control);
2825                   idx = taskData->getIdxByVals (&tval_loop_control,
2826                                                 DataView::REL_EQ);
2827                   if (idx < 0)
2828                     curtsk_loop_control = 0;
2829                   else
2830                     curtsk_loop_control = taskData->getLongValue (PROP_PTSKID,
2831                                                                   idx);
2832                 }
2833             }
2834         }
2835       tasks.append (task0);
2836       void *tskstack = cstack->add_stack (&tasks);
2837       mapTask->put (thrid, tstamp, tskstack);
2838     }
2839   theApplication->set_progress (0, NTXT (""));
2840   delete taskData;
2841 }
2842
2843 void
2844 Experiment::read_omp_file ()
2845 {
2846   // DATA_OMP2 table is common between OpenMP 2.5 and 3.0 profiling
2847   DataDescriptor *dDscr = getDataDescriptor (DATA_OMP2);
2848   if (dDscr == NULL)
2849     return;
2850   if (dDscr->getSize () == 0)
2851     {
2852       char *base_name = get_basename (expt_name);
2853       char *msg = dbe_sprintf (GTXT ("Loading OpenMP Data: %s"), base_name);
2854       read_data_file (SP_OMPTRACE_FILE, msg);
2855       free (msg);
2856
2857       // OpenMP fork events
2858       dDscr = getDataDescriptor (DATA_OMP);
2859       long sz = dDscr->getSize ();
2860       if (sz > 0)
2861         {
2862           // progress bar
2863           msg = dbe_sprintf (GTXT ("Processing OpenMP Parallel Region Data: %s"),
2864                              base_name);
2865           theApplication->set_progress (0, msg);
2866           free (msg);
2867           long deltaReport = 5000;
2868           long nextReport = 0;
2869           for (int i = 0; i < sz; ++i)
2870             {
2871               if (i == nextReport)
2872                 {
2873                   int percent = (int) (i * 100 / sz);
2874                   if (percent > 0)
2875                     theApplication->set_progress (percent, NULL);
2876                   nextReport += deltaReport;
2877                 }
2878               uint32_t thrid = dDscr->getIntValue (PROP_THRID, i);
2879               hrtime_t tstamp = dDscr->getLongValue (PROP_TSTAMP, i);
2880               uint64_t cprid = dDscr->getLongValue (PROP_CPRID, i); //omptrace
2881               mapPRid->put (thrid, tstamp, cprid);
2882             }
2883           theApplication->set_progress (0, NTXT (""));
2884
2885           ompavail = true;
2886           openMPdata = dDscr->createView ();
2887           openMPdata->sort (PROP_CPRID); // omptrace PROP_CPRID
2888
2889           // thread enters parreg events
2890           dDscr = getDataDescriptor (DATA_OMP2);
2891           sz = dDscr->getSize ();
2892
2893           // progress bar
2894           msg = dbe_sprintf (GTXT ("Processing OpenMP Parallel Region Data: %s"),
2895                              base_name);
2896           theApplication->set_progress (0, msg);
2897           free (msg);
2898           deltaReport = 5000;
2899           nextReport = 0;
2900
2901           for (int i = 0; i < sz; ++i)
2902             {
2903               if (i == nextReport)
2904                 {
2905                   int percent = (int) (i * 100 / sz);
2906                   if (percent > 0)
2907                     theApplication->set_progress (percent, NULL);
2908                   nextReport += deltaReport;
2909                 }
2910               uint32_t thrid = dDscr->getIntValue (PROP_THRID, i);
2911               hrtime_t tstamp = dDscr->getLongValue (PROP_TSTAMP, i);
2912               uint64_t cprid = dDscr->getLongValue (PROP_CPRID, i); //omptrace
2913               mapPRid->put (thrid, tstamp, cprid);
2914             }
2915           theApplication->set_progress (0, NTXT (""));
2916         }
2917       else
2918         {
2919           read_omp_preg ();
2920           read_omp_task ();
2921         }
2922       if (ompavail && coll_params.profile_mode)
2923         {
2924           dbeSession->status_ompavail = 1;
2925           register_metric (Metric::OMP_WORK);
2926           register_metric (Metric::OMP_WAIT);
2927           register_metric (Metric::OMP_OVHD);
2928           if (coll_params.lms_magic_id == LMS_MAGIC_ID_SOLARIS)
2929             register_metric (Metric::OMP_MASTER_THREAD);
2930         }
2931     }
2932 }
2933
2934 void
2935 Experiment::read_ifreq_file ()
2936 {
2937   char *fname = dbe_sprintf (NTXT ("%s/%s"), expt_name, SP_IFREQ_FILE);
2938   FILE *f = fopen (fname, NTXT ("r"));
2939   free (fname);
2940   if (f == NULL)
2941     {
2942       ifreqavail = false;
2943       return;
2944     }
2945   ifreqavail = true;
2946   ifreqq = new Emsgqueue (NTXT ("ifreqq"));
2947
2948   while (1)
2949     {
2950       Emsg *m;
2951       char str[MAXPATHLEN];
2952       char *e = fgets (str, ((int) sizeof (str)) - 1, f);
2953       if (e == NULL)
2954         {
2955           // end the list from the experiment
2956           m = new Emsg (CMSG_COMMENT,
2957                         GTXT ("============================================================"));
2958           ifreqq->append (m);
2959           break;
2960         }
2961       // get the string
2962       size_t i = strlen (str);
2963       if (i > 0 && str[i - 1] == '\n')
2964         // remove trailing nl
2965         str[i - 1] = 0;
2966       // and append it
2967       m = new Emsg (CMSG_COMMENT, str);
2968       ifreqq->append (m);
2969     }
2970   (void) fclose (f);
2971 }
2972
2973 Experiment *
2974 Experiment::getBaseFounder ()
2975 {
2976   if (baseFounder)
2977     return baseFounder;
2978   Experiment *founder = this;
2979   Experiment *parent = founder->founder_exp;
2980   while (parent)
2981     {
2982       founder = parent;
2983       parent = founder->founder_exp;
2984     }
2985   baseFounder = founder;
2986   return baseFounder;
2987 }
2988
2989 hrtime_t
2990 Experiment::getRelativeStartTime ()
2991 {
2992   if (exp_rel_start_time_set)
2993     return exp_rel_start_time;
2994   Experiment *founder = getBaseFounder ();
2995   hrtime_t child_start = this->getStartTime ();
2996   hrtime_t founder_start = founder->getStartTime ();
2997   exp_rel_start_time = child_start - founder_start;
2998   if (child_start == 0 && founder_start)
2999     exp_rel_start_time = 0;     // when descendents have incomplete log.xml
3000   exp_rel_start_time_set = true;
3001   return exp_rel_start_time;
3002 }
3003
3004 DataDescriptor *
3005 Experiment::get_raw_events (int data_id)
3006 {
3007   DataDescriptor *dDscr;
3008   switch (data_id)
3009     {
3010     case DATA_CLOCK:
3011       dDscr = get_profile_events ();
3012       break;
3013     case DATA_SYNCH:
3014       dDscr = get_sync_events ();
3015       break;
3016     case DATA_HWC:
3017       dDscr = get_hwc_events ();
3018       break;
3019     case DATA_HEAP:
3020       dDscr = get_heap_events ();
3021       break;
3022     case DATA_HEAPSZ:
3023       dDscr = get_heapsz_events ();
3024       break;
3025     case DATA_IOTRACE:
3026       dDscr = get_iotrace_events ();
3027       break;
3028     case DATA_RACE:
3029       dDscr = get_race_events ();
3030       break;
3031     case DATA_DLCK:
3032       dDscr = get_deadlock_events ();
3033       break;
3034     case DATA_SAMPLE:
3035       dDscr = get_sample_events ();
3036       break;
3037     case DATA_GCEVENT:
3038       dDscr = get_gc_events ();
3039       break;
3040     default:
3041       dDscr = NULL;
3042       break;
3043     }
3044   return dDscr;
3045 }
3046
3047 int
3048 Experiment::base_data_id (int data_id)
3049 {
3050   switch (data_id)
3051     {
3052     case DATA_HEAPSZ:
3053       return DATA_HEAP; // DATA_HEAPSZ DataView is based on DATA_HEAP's DataView
3054     default:
3055       break;
3056     }
3057   return data_id;
3058 }
3059
3060 DataView *
3061 Experiment::create_derived_data_view (int data_id, DataView *dview)
3062 {
3063   // dview contains filtered packets
3064   switch (data_id)
3065     {
3066     case DATA_HEAPSZ:
3067       return create_heapsz_data_view (dview);
3068     default:
3069       break;
3070     }
3071   return NULL;
3072 }
3073
3074 DataDescriptor *
3075 Experiment::get_profile_events ()
3076 {
3077   DataDescriptor *dDscr = getDataDescriptor (DATA_CLOCK);
3078   if (dDscr == NULL)
3079     return NULL;
3080   if (dDscr->getSize () == 0)
3081     {
3082       char *base_name = get_basename (expt_name);
3083       char *msg = dbe_sprintf (GTXT ("Loading Profile Data: %s"), base_name);
3084       read_data_file (SP_PROFILE_FILE, msg);
3085       free (msg);
3086       add_evt_time_to_profile_events (dDscr);
3087       resolve_frame_info (dDscr);
3088     }
3089   else if (!dDscr->isResolveFrInfoDone ())
3090     resolve_frame_info (dDscr);
3091   return dDscr;
3092 }
3093
3094 void
3095 Experiment::add_evt_time_to_profile_events (DataDescriptor *dDscr)
3096 {
3097   if (coll_params.lms_magic_id != LMS_MAGIC_ID_SOLARIS)
3098     return;
3099
3100   DataView *dview = dDscr->createView ();
3101   dview->sort (PROP_THRID, PROP_TSTAMP);
3102
3103   // add PROP_EVT_TIME
3104   PropDescr* tmp_propDscr = new PropDescr (PROP_EVT_TIME, "EVT_TIME");
3105   tmp_propDscr->uname = dbe_strdup (GTXT ("Event duration"));
3106   tmp_propDscr->vtype = TYPE_INT64;
3107   dDscr->addProperty (tmp_propDscr);
3108
3109   long sz = dview->getSize ();
3110   long long ptimer_usec = get_params ()->ptimer_usec;
3111   for (long i = 0; i < sz; i++)
3112     {
3113       int next_sample;
3114       int jj;
3115       {
3116         hrtime_t this_tstamp = dview->getLongValue (PROP_TSTAMP, i);
3117         long this_thrid = dview->getLongValue (PROP_THRID, i);
3118         for (jj = i + 1; jj < sz; jj++)
3119           {
3120             hrtime_t tmp_tstamp = dview->getLongValue (PROP_TSTAMP, jj);
3121             if (tmp_tstamp != this_tstamp)
3122               break;
3123             long tmp_thrid = dview->getLongValue (PROP_THRID, jj);
3124             if (tmp_thrid != this_thrid)
3125               break;
3126           }
3127         next_sample = jj;
3128       }
3129
3130       long nticks = 0;
3131       for (jj = i; jj < next_sample; jj++)
3132         nticks += dview->getLongValue (PROP_NTICK, jj);
3133       if (nticks <= 1)
3134         continue; // no duration
3135
3136       nticks--;
3137       hrtime_t duration = ptimer_usec * 1000LL * nticks; // nanoseconds
3138       for (jj = i; jj < next_sample; jj++)
3139         dview->setValue (PROP_EVT_TIME, jj, duration);
3140       i = jj - 1;
3141     }
3142   delete dview;
3143 }
3144
3145 DataDescriptor *
3146 Experiment::get_sync_events ()
3147 {
3148   DataDescriptor *dDscr = getDataDescriptor (DATA_SYNCH);
3149   if (dDscr == NULL)
3150     return NULL;
3151   if (dDscr->getSize () > 0)
3152     return dDscr;
3153
3154   // fetch data
3155   {
3156     char *base_name = get_basename (expt_name);
3157     char *msg = dbe_sprintf (GTXT ("Loading Synctrace Data: %s"), base_name);
3158     read_data_file (SP_SYNCTRACE_FILE, msg);
3159     free (msg);
3160     resolve_frame_info (dDscr);
3161   }
3162
3163   // check for PROP_EVT_TIME
3164   PropDescr *tmp_propDscr = dDscr->getProp (PROP_EVT_TIME);
3165   if (tmp_propDscr)
3166     return dDscr;
3167
3168   // add PROP_EVT_TIME
3169   tmp_propDscr = new PropDescr (PROP_EVT_TIME, "EVT_TIME");
3170   tmp_propDscr->uname = dbe_strdup (GTXT ("Event duration"));
3171   tmp_propDscr->vtype = TYPE_INT64;
3172   dDscr->addProperty (tmp_propDscr);
3173
3174   long sz = dDscr->getSize ();
3175   for (long i = 0; i < sz; i++)
3176     {
3177       uint64_t event_duration = dDscr->getLongValue (PROP_TSTAMP, i);
3178       event_duration -= dDscr->getLongValue (PROP_SRQST, i);
3179       dDscr->setValue (PROP_EVT_TIME, i, event_duration);
3180     }
3181   return dDscr;
3182 }
3183
3184 DataDescriptor *
3185 Experiment::get_hwc_events ()
3186 {
3187   DataDescriptor *dDscr = getDataDescriptor (DATA_HWC);
3188   if (dDscr == NULL)
3189     return NULL;
3190   if (dDscr->getSize () == 0)
3191     {
3192       char *base_name = get_basename (expt_name);
3193       char *msg = dbe_sprintf (GTXT ("Loading HW Profile Data: %s"), base_name);
3194
3195       // clear HWC event stats
3196       dsevents = 0;
3197       dsnoxhwcevents = 0;
3198       read_data_file (SP_HWCNTR_FILE, msg);
3199       free (msg);
3200       resolve_frame_info (dDscr);
3201
3202       // describe the HW counters in PropDescr
3203       PropDescr *prop = dDscr->getProp (PROP_HWCTAG);
3204       if (prop)
3205         {
3206           Collection_params *cparam = get_params ();
3207           if (cparam->hw_mode != 0)
3208             for (int aux = 0; aux < MAX_HWCOUNT; aux++)
3209               if (cparam->hw_aux_name[aux])
3210                 {
3211                   const char* cmdname = cparam->hw_aux_name[aux];
3212                   const char* uname = cparam->hw_username[aux];
3213                   prop->addState (aux, cmdname, uname);
3214                 }
3215         }
3216       else
3217         assert (0);
3218
3219       double dserrrate = 100.0 * ((double) dsnoxhwcevents) / ((double) dsevents);
3220       if ((dsevents > 0) && (dserrrate > 10.0))
3221         {
3222           // warn the user that rate is high
3223           StringBuilder sb;
3224           if (dbeSession->check_ignore_no_xhwcprof ())
3225             sb.sprintf (
3226                         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"),
3227                         base_name, dserrrate, (long long) dsnoxhwcevents,
3228                         (long long) dsevents);
3229           else
3230             sb.sprintf (
3231                         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"),
3232                         base_name, dserrrate, (long long) dsnoxhwcevents,
3233                         (long long) dsevents);
3234           errorq->append (new Emsg (CMSG_WARN, sb));
3235         }
3236
3237       // see if we've scanned the data
3238       if (hwc_scanned == 0)
3239         {
3240           // no, scan the packets to see how many are bogus, or represent lost interrupts
3241           long hwc_cnt = 0;
3242
3243           // loop over the packets, counting the bad ones
3244           if (hwc_bogus != 0 || hwc_lost_int != 0)
3245             {
3246               // hwc counter data had bogus packets and/or packets reflecting lost interrupts
3247               double bogus_rate = 100. * (double) hwc_bogus / (double) hwc_cnt;
3248               if (bogus_rate > 5.)
3249                 {
3250                   StringBuilder sb;
3251                   sb.sprintf (
3252                               GTXT ("WARNING: Too many invalid HW counter profile events (%ld/%ld = %3.2f%%) in experiment %d (`%s'); data may be unreliable"),
3253                               (long) hwc_bogus, (long) hwc_cnt, bogus_rate,
3254                               (int) userExpId, base_name);
3255                   Emsg *m = new Emsg (CMSG_WARN, sb);
3256                   warnq->append (m);
3257                 }
3258               hwc_scanned = 1;
3259             }
3260         }
3261     }
3262   return dDscr;
3263 }
3264
3265 DataDescriptor *
3266 Experiment::get_iotrace_events ()
3267 {
3268   DataDescriptor *dDscr = getDataDescriptor (DATA_IOTRACE);
3269   if (dDscr == NULL)
3270     return NULL;
3271
3272   if (dDscr->getSize () > 0)
3273     return dDscr;
3274
3275   char *base_name = get_basename (expt_name);
3276   char *msg = dbe_sprintf (GTXT ("Loading IO Trace Data: %s"), base_name);
3277   read_data_file (SP_IOTRACE_FILE, msg);
3278   free (msg);
3279
3280   if (dDscr->getSize () == 0)
3281     return dDscr;
3282   resolve_frame_info (dDscr);
3283
3284   // check for PROP_EVT_TIME
3285   PropDescr *tmp_propDscr = dDscr->getProp (PROP_EVT_TIME);
3286   if (tmp_propDscr)
3287     return dDscr;
3288
3289   // add PROP_EVT_TIME
3290   tmp_propDscr = new PropDescr (PROP_EVT_TIME, "EVT_TIME");
3291   tmp_propDscr->uname = dbe_strdup (GTXT ("Event duration"));
3292   tmp_propDscr->vtype = TYPE_INT64;
3293   dDscr->addProperty (tmp_propDscr);
3294
3295   // add PROP_IOVFD
3296   tmp_propDscr = new PropDescr (PROP_IOVFD, "IOVFD");
3297   tmp_propDscr->uname = dbe_strdup (GTXT ("Virtual File Descriptor"));
3298   tmp_propDscr->vtype = TYPE_INT64;
3299   dDscr->addProperty (tmp_propDscr);
3300
3301   delete fDataMap;
3302   fDataMap = new DefaultMap<int64_t, FileData*>;
3303
3304   delete vFdMap;
3305   vFdMap = new DefaultMap<int, int64_t>;
3306
3307   static int64_t virtualFd = 0;
3308
3309   FileData *fData;
3310   virtualFd += 10;
3311   fData = fDataMap->get (VIRTUAL_FD_STDIN);
3312   if (fData == NULL)
3313     {
3314       fData = new FileData (STDIN_FILENAME);
3315       fData->setVirtualFd (VIRTUAL_FD_STDIN);
3316       fData->id = VIRTUAL_FD_STDIN;
3317       fData->setFileDes (STDIN_FD);
3318       fDataMap->put (VIRTUAL_FD_STDIN, fData);
3319       vFdMap->put (STDIN_FD, VIRTUAL_FD_STDIN);
3320     }
3321
3322   fData = fDataMap->get (VIRTUAL_FD_STDOUT);
3323   if (fData == NULL)
3324     {
3325       fData = new FileData (STDOUT_FILENAME);
3326       fData->setVirtualFd (VIRTUAL_FD_STDOUT);
3327       fData->id = VIRTUAL_FD_STDOUT;
3328       fData->setFileDes (STDOUT_FD);
3329       fDataMap->put (VIRTUAL_FD_STDOUT, fData);
3330       vFdMap->put (STDOUT_FD, VIRTUAL_FD_STDOUT);
3331     }
3332
3333   fData = fDataMap->get (VIRTUAL_FD_STDERR);
3334   if (fData == NULL)
3335     {
3336       fData = new FileData (STDERR_FILENAME);
3337       fData->setVirtualFd (VIRTUAL_FD_STDERR);
3338       fData->id = VIRTUAL_FD_STDERR;
3339       fData->setFileDes (STDERR_FD);
3340       fDataMap->put (VIRTUAL_FD_STDERR, fData);
3341       vFdMap->put (STDERR_FD, VIRTUAL_FD_STDERR);
3342     }
3343
3344   fData = fDataMap->get (VIRTUAL_FD_OTHERIO);
3345   if (fData == NULL)
3346     {
3347       fData = new FileData (OTHERIO_FILENAME);
3348       fData->setVirtualFd (VIRTUAL_FD_OTHERIO);
3349       fData->id = VIRTUAL_FD_OTHERIO;
3350       fData->setFileDes (OTHERIO_FD);
3351       fDataMap->put (VIRTUAL_FD_OTHERIO, fData);
3352     }
3353
3354   DataView *dview = dDscr->createView ();
3355   dview->sort (PROP_TSTAMP);
3356   long sz = dview->getSize ();
3357   for (long i = 0; i < sz; i++)
3358     {
3359       hrtime_t event_duration = dview->getLongValue (PROP_TSTAMP, i);
3360       hrtime_t event_start = dview->getLongValue (PROP_IORQST, i);
3361       if (event_start > 0)
3362         event_duration -= event_start;
3363       else
3364         event_duration = 0;
3365       dview->setValue (PROP_EVT_TIME, i, event_duration);
3366
3367       int32_t fd = -1;
3368       int64_t vFd = VIRTUAL_FD_NONE;
3369       char *fName = NULL;
3370       int32_t origFd = -1;
3371       StringBuilder *sb = NULL;
3372       FileData *fDataOrig = NULL;
3373       FileSystem_type fsType;
3374
3375       IOTrace_type ioType = (IOTrace_type) dview->getIntValue (PROP_IOTYPE, i);
3376       switch (ioType)
3377         {
3378         case READ_TRACE:
3379         case WRITE_TRACE:
3380         case READ_TRACE_ERROR:
3381         case WRITE_TRACE_ERROR:
3382           fd = dview->getIntValue (PROP_IOFD, i);
3383           vFd = vFdMap->get (fd);
3384           if (vFd == 0 || vFd == VIRTUAL_FD_NONE
3385               || (fData = fDataMap->get (vFd)) == NULL)
3386             {
3387               fData = new FileData (UNKNOWNFD_FILENAME);
3388               fData->setVirtualFd (virtualFd);
3389               fData->setFsType ("N/A");
3390               fData->setFileDes (fd);
3391               fDataMap->put (virtualFd, fData);
3392               vFdMap->put (fd, virtualFd);
3393               vFd = virtualFd;
3394               virtualFd++;
3395             }
3396           dview->setValue (PROP_IOVFD, i, vFd);
3397           break;
3398         case OPEN_TRACE:
3399           fName = NULL;
3400           sb = (StringBuilder*) dview->getObjValue (PROP_IOFNAME, i);
3401           if (sb != NULL && sb->length () > 0)
3402             fName = sb->toString ();
3403           fd = dview->getIntValue (PROP_IOFD, i);
3404           origFd = dview->getIntValue (PROP_IOOFD, i);
3405           fsType = (FileSystem_type) dview->getIntValue (PROP_IOFSTYPE, i);
3406
3407           if (fName != NULL)
3408             {
3409               fData = new FileData (fName);
3410               fDataMap->put (virtualFd, fData);
3411               vFdMap->put (fd, virtualFd);
3412               fData->setFileDes (fd);
3413               fData->setFsType (fsType);
3414               fData->setVirtualFd (virtualFd);
3415               vFd = virtualFd;
3416               virtualFd++;
3417             }
3418           else if (origFd > 0)
3419             {
3420               vFd = vFdMap->get (origFd);
3421               if (vFd == 0 || vFd == VIRTUAL_FD_NONE)
3422                 {
3423                   Dprintf (DEBUG_IO,
3424                            "*** Error I/O tracing: (open) cannot get the virtual file descriptor, fd=%d  origFd=%d\n",
3425                            fd, origFd);
3426                   continue;
3427                 }
3428               else if ((fDataOrig = fDataMap->get (vFd)) == NULL)
3429                 {
3430                   Dprintf (DEBUG_IO,
3431                            "*** Error IO tracing: (open) cannot get original FileData object, fd=%d  origFd=%d\n",
3432                            fd, origFd);
3433                   continue;
3434                 }
3435               else
3436                 {
3437                   fName = fDataOrig->getFileName ();
3438                   fData = new FileData (fName);
3439                   fData->setFileDes (fd);
3440                   fData->setFsType (fDataOrig->getFsType ());
3441                   fData->setVirtualFd (virtualFd);
3442                   fDataMap->put (virtualFd, fData);
3443                   vFdMap->put (fd, virtualFd);
3444                   vFd = virtualFd;
3445                   virtualFd++;
3446                 }
3447             }
3448           else if (fd >= 0)
3449             {
3450               vFd = vFdMap->get (fd);
3451               if (vFd == 0 || vFd == VIRTUAL_FD_NONE
3452                   || (fData = fDataMap->get (vFd)) == NULL)
3453                 {
3454                   fData = new FileData (UNKNOWNFD_FILENAME);
3455                   fData->setVirtualFd (virtualFd);
3456                   fData->setFsType ("N/A");
3457                   fData->setFileDes (fd);
3458                   fDataMap->put (virtualFd, fData);
3459                   vFdMap->put (fd, virtualFd);
3460                   vFd = virtualFd;
3461                   virtualFd++;
3462                 }
3463             }
3464           else
3465             {
3466               Dprintf (DEBUG_IO,
3467                        NTXT ("*** Error IO tracing: (open) unknown open IO type, fd=%d  origFd=%d\n"), fd, origFd);
3468               continue;
3469             }
3470
3471           dview->setValue (PROP_IOVFD, i, vFd);
3472           break;
3473
3474         case OPEN_TRACE_ERROR:
3475           fName = NULL;
3476
3477           sb = (StringBuilder*) dview->getObjValue (PROP_IOFNAME, i);
3478           if (sb != NULL && sb->length () > 0)
3479             fName = sb->toString ();
3480           fd = dview->getIntValue (PROP_IOFD, i);
3481           origFd = dview->getIntValue (PROP_IOOFD, i);
3482           fsType = (FileSystem_type) dview->getIntValue (PROP_IOFSTYPE, i);
3483
3484           if (fName != NULL)
3485             {
3486               fData = new FileData (fName);
3487               fDataMap->put (virtualFd, fData);
3488               fData->setFileDes (fd);
3489               fData->setFsType (fsType);
3490               fData->setVirtualFd (virtualFd);
3491               vFd = virtualFd;
3492               virtualFd++;
3493             }
3494           else if (origFd > 0)
3495             {
3496               vFd = vFdMap->get (origFd);
3497               if (vFd == 0 || vFd == VIRTUAL_FD_NONE)
3498                 {
3499                   Dprintf (DEBUG_IO,
3500                            "*** Error IO tracing: (open error) cannot get the virtual file descriptor, fd=%d  origFd=%d\n",
3501                            fd, origFd);
3502                   continue;
3503                 }
3504               else if ((fDataOrig = fDataMap->get (vFd)) == NULL)
3505                 {
3506                   Dprintf (DEBUG_IO,
3507                            "*** Error IO tracing: (open error) cannot get original FileData object, fd=%d  origFd=%d\n",
3508                            fd, origFd);
3509                   continue;
3510                 }
3511               else
3512                 {
3513                   fName = fDataOrig->getFileName ();
3514                   fData = new FileData (fName);
3515                   fData->setFileDes (fd);
3516                   fData->setFsType (fDataOrig->getFsType ());
3517                   fData->setVirtualFd (virtualFd);
3518                   fDataMap->put (virtualFd, fData);
3519                   vFd = virtualFd;
3520                   virtualFd++;
3521                 }
3522             }
3523
3524           dview->setValue (PROP_IOVFD, i, vFd);
3525           break;
3526
3527         case CLOSE_TRACE:
3528         case CLOSE_TRACE_ERROR:
3529           fd = dview->getIntValue (PROP_IOFD, i);
3530           vFd = vFdMap->get (fd);
3531           if (vFd == 0 || vFd == VIRTUAL_FD_NONE)
3532             {
3533               Dprintf (DEBUG_IO,
3534                        "*** Error IO tracing: (close) cannot get the virtual file descriptor, fd=%d\n",
3535                        fd);
3536               continue;
3537             }
3538           fData = fDataMap->get (vFd);
3539           if (fData == NULL)
3540             {
3541               Dprintf (DEBUG_IO,
3542                        "*** Error IO tracing: (close) cannot get the FileData object, fd=%d\n",
3543                        fd);
3544               continue;
3545             }
3546
3547           vFdMap->put (fd, VIRTUAL_FD_NONE);
3548           dview->setValue (PROP_IOVFD, i, vFd);
3549           break;
3550
3551         case OTHERIO_TRACE:
3552         case OTHERIO_TRACE_ERROR:
3553           vFd = VIRTUAL_FD_OTHERIO;
3554           fData = fDataMap->get (vFd);
3555           if (fData == NULL)
3556             {
3557               Dprintf (DEBUG_IO,
3558                        "*** Error IO tracing: (other IO) cannot get the FileData object\n");
3559               continue;
3560             }
3561
3562           dview->setValue (PROP_IOVFD, i, vFd);
3563           break;
3564         case IOTRACETYPE_LAST:
3565           break;
3566         }
3567     }
3568
3569   delete dview;
3570
3571   return dDscr;
3572 }
3573
3574 DataDescriptor *
3575 Experiment::get_heap_events ()
3576 {
3577   DataDescriptor *dDscr = getDataDescriptor (DATA_HEAP);
3578   if (dDscr == NULL)
3579     return NULL;
3580   if (dDscr->getSize () > 0)
3581     return dDscr;
3582
3583   char *base_name = get_basename (expt_name);
3584   char *msg = dbe_sprintf (GTXT ("Loading Heap Trace Data: %s"), base_name);
3585   read_data_file (SP_HEAPTRACE_FILE, msg);
3586   free (msg);
3587
3588   if (dDscr->getSize () == 0)
3589     return dDscr;
3590   resolve_frame_info (dDscr);
3591
3592   // Match FREE to MALLOC
3593   PropDescr *prop = new PropDescr (PROP_HLEAKED, NTXT ("HLEAKED"));
3594   prop->uname = dbe_strdup (GTXT ("Bytes Leaked"));
3595   prop->vtype = TYPE_UINT64;
3596   dDscr->addProperty (prop);
3597
3598   prop = new PropDescr (PROP_HMEM_USAGE, NTXT ("HMEM_USAGE"));
3599   prop->uname = dbe_strdup (GTXT ("Heap Memory Usage"));
3600   prop->vtype = TYPE_UINT64;
3601   dDscr->addProperty (prop);
3602
3603   prop = new PropDescr (PROP_HFREED, NTXT ("HFREED"));
3604   prop->uname = dbe_strdup (GTXT ("Bytes Freed"));
3605   prop->vtype = TYPE_UINT64;
3606   dDscr->addProperty (prop);
3607
3608   prop = new PropDescr (PROP_HCUR_ALLOCS, NTXT ("HCUR_ALLOCS"));
3609   prop->uname = dbe_strdup (GTXT ("Net Bytes Allocated"));
3610   prop->vtype = TYPE_INT64;
3611   dDscr->addProperty (prop);
3612
3613   prop = new PropDescr (PROP_HCUR_LEAKS, NTXT ("HCUR_LEAKS"));
3614   prop->uname = dbe_strdup (GTXT ("Net Bytes Leaked"));
3615   prop->vtype = TYPE_UINT64;
3616   dDscr->addProperty (prop);
3617
3618   prop = new PropDescr (PROP_HCUR_NET_ALLOC, NTXT ("HCUR_NET_ALLOC"));
3619   prop->vtype = TYPE_INT64;
3620   prop->flags = DDFLAG_NOSHOW;
3621   dDscr->addProperty (prop);
3622
3623   prop = new PropDescr (PROP_DDSCR_LNK, NTXT ("DDSCR_LNK"));
3624   prop->vtype = TYPE_UINT64;
3625   prop->flags = DDFLAG_NOSHOW;
3626   dDscr->addProperty (prop);
3627
3628   prop = new PropDescr (PROP_VOIDP_OBJ, NTXT ("VOIDP_OBJ"));
3629   prop->vtype = TYPE_OBJ;
3630   prop->flags = DDFLAG_NOSHOW;
3631   dDscr->addProperty (prop);
3632
3633   prop = new PropDescr (PROP_TSTAMP2, NTXT ("TSTAMP2"));
3634   prop->uname = dbe_strdup (GTXT ("End Timestamp (nanoseconds)"));
3635   prop->vtype = TYPE_UINT64;
3636   prop->flags = DDFLAG_NOSHOW;
3637   dDscr->addProperty (prop);
3638
3639   DataView *dview = dDscr->createView ();
3640   dview->sort (PROP_TSTAMP);
3641
3642   // Keep track of memory usage
3643   Size memoryUsage = 0;
3644
3645   HeapMap *heapmap = new HeapMap ();
3646   long sz = dview->getSize ();
3647   for (long i = 0; i < sz; i++)
3648     {
3649
3650       Heap_type mtype = (Heap_type) dview->getIntValue (PROP_HTYPE, i);
3651       Vaddr vaddr = dview->getULongValue (PROP_HVADDR, i);
3652       Vaddr ovaddr = dview->getULongValue (PROP_HOVADDR, i);
3653       Size hsize = dview->getULongValue (PROP_HSIZE, i);
3654       hrtime_t tstamp = dview->getLongValue (PROP_TSTAMP, i);
3655
3656       switch (mtype)
3657         {
3658         case MALLOC_TRACE:
3659           dview->setValue (PROP_TSTAMP2, i, (uint64_t) MAX_TIME);
3660           if (vaddr)
3661             {
3662               dview->setValue (PROP_HLEAKED, i, hsize);
3663               heapmap->allocate (vaddr, i + 1);
3664
3665               // Increase heap size
3666               memoryUsage += hsize;
3667               dview->setValue (PROP_HMEM_USAGE, i, memoryUsage);
3668             }
3669           break;
3670
3671         case FREE_TRACE:
3672           if (vaddr)
3673             {
3674               long idx = heapmap->deallocate (vaddr) - 1;
3675               if (idx >= 0)
3676                 {
3677                   // Decrease heap size
3678                   Size leaked = dview->getLongValue (PROP_HLEAKED, idx);
3679                   memoryUsage -= leaked;
3680                   dview->setValue (PROP_HMEM_USAGE, i, memoryUsage);
3681
3682                   Size alloc = dview->getLongValue (PROP_HSIZE, idx);
3683                   // update allocation
3684                   dview->setValue (PROP_HLEAKED, idx, (uint64_t) 0);
3685                   dview->setValue (PROP_TSTAMP2, idx, tstamp);
3686                   dview->setValue (PROP_DDSCR_LNK, idx, dview->getIdByIdx (i) + 1);
3687                   // update this event
3688                   dview->setValue (PROP_HFREED, i, alloc);
3689                 }
3690             }
3691           break;
3692
3693         case REALLOC_TRACE:
3694           dview->setValue (PROP_TSTAMP2, i, (uint64_t) MAX_TIME);
3695           if (ovaddr)
3696             {
3697               long idx = heapmap->deallocate (ovaddr) - 1;
3698               if (idx >= 0)
3699                 {
3700                   // Decrease heap size
3701                   Size leaked = dview->getLongValue (PROP_HLEAKED, idx);
3702                   memoryUsage -= leaked;
3703                   dview->setValue (PROP_HMEM_USAGE, i, memoryUsage);
3704
3705                   Size alloc = dview->getLongValue (PROP_HSIZE, idx);
3706                   // update allocation
3707                   dview->setValue (PROP_HLEAKED, idx, (uint64_t) 0);
3708                   dview->setValue (PROP_TSTAMP2, idx, tstamp);
3709                   dview->setValue (PROP_DDSCR_LNK, idx, dview->getIdByIdx (i) + 1);
3710                   // update this event
3711                   dview->setValue (PROP_HFREED, i, alloc);
3712                 }
3713             }
3714           if (vaddr)
3715             {
3716               dview->setValue (PROP_HLEAKED, i, hsize);
3717               heapmap->allocate (vaddr, i + 1);
3718
3719               // Increase heap size
3720               memoryUsage += hsize;
3721               dview->setValue (PROP_HMEM_USAGE, i, memoryUsage);
3722             }
3723           break;
3724         case MMAP_TRACE:
3725         case MUNMAP_TRACE:
3726           // Adjust the size to be multiple of page_size
3727           //hsize = (( hsize - 1 ) / page_size + 1 ) * page_size;
3728           if (vaddr)
3729             {
3730               UnmapChunk *list;
3731               if (mtype == MMAP_TRACE)
3732                 {
3733                   dview->setValue (PROP_TSTAMP2, i, (uint64_t) MAX_TIME);
3734                   dview->setValue (PROP_HLEAKED, i, hsize);
3735                   list = heapmap->mmap (vaddr, hsize, i);
3736
3737                   // Increase heap size
3738                   memoryUsage += hsize;
3739                   dview->setValue (PROP_HMEM_USAGE, i, memoryUsage);
3740                 }
3741               else
3742                 { // MUNMAP_TRACE
3743                   list = heapmap->munmap (vaddr, hsize);
3744
3745                   // Set allocation size to zero
3746                   // Note: We're currently reusing PROP_HSIZE to mean allocation size
3747                   // If we ever need to save the original HSIZE, we'll need to
3748                   // create a new PROP_* to represent event allocation size
3749                   //
3750                   //    For now, tuck the original size away as HOVADDR
3751                   dview->setValue (PROP_HOVADDR, i, (uint64_t) hsize);
3752                   dview->setValue (PROP_HSIZE, i, (uint64_t) 0);
3753                 }
3754               Size total_freed = 0;
3755               while (list)
3756                 {
3757                   long idx = list->val;
3758                   total_freed += list->size;
3759                   Size leaked = dview->getLongValue (PROP_HLEAKED, idx);
3760
3761                   // Decrease heap size
3762                   memoryUsage -= list->size;
3763                   dview->setValue (PROP_HMEM_USAGE, i, memoryUsage);
3764
3765                   Size leak_update = leaked - list->size;
3766                   // update allocation
3767                   dview->setValue (PROP_HLEAKED, idx, leak_update);
3768                   // update allocation's list of frees
3769                   {
3770                     UnmapChunk *copy = new UnmapChunk;
3771                     heapUnmapEvents->append (copy);
3772                     copy->val = dview->getIdByIdx (i);
3773                     copy->size = list->size;
3774                     copy->next = (UnmapChunk *) dview->getObjValue (PROP_VOIDP_OBJ, idx);
3775                     dview->setObjValue (PROP_VOIDP_OBJ, idx, copy);
3776                   }
3777                   if (leak_update <= 0)
3778                     if (leak_update == 0)
3779                       dview->setValue (PROP_TSTAMP2, idx, tstamp);
3780                   UnmapChunk *t = list;
3781                   list = list->next;
3782                   delete t;
3783                 }
3784               // update this event
3785               if (total_freed)
3786                 // only need to write value if it is non-zero
3787                 dview->setValue (PROP_HFREED, i, total_freed);
3788             }
3789           break;
3790           // ignoring HEAPTYPE_LAST, which will never be recorded
3791         case HEAPTYPE_LAST:
3792           break;
3793         }
3794     }
3795   delete heapmap;
3796   delete dview;
3797
3798   return dDscr;
3799 }
3800
3801 DataDescriptor *
3802 Experiment::get_heapsz_events ()
3803 {
3804   DataDescriptor *dDscr = getDataDescriptor (DATA_HEAPSZ);
3805   if (dDscr)
3806     return dDscr;
3807   dDscr = get_heap_events (); // derived from DATA_HEAP
3808   if (dDscr == NULL)
3809     return NULL;
3810   dDscr = newDataDescriptor (DATA_HEAPSZ, 0, dDscr);
3811   return dDscr;
3812 }
3813
3814 static void
3815 update_heapsz_packet (std::set<long> &pkt_id_set, DataView *dview,
3816                       long alloc_pkt_id, int64_t net_alloc, uint64_t leaks)
3817 {
3818   // pkt_id_set: set is updated to include packet
3819   // alloc_pkt_id: data descriptor id (NOT dview idx)
3820   // net_alloc: adjustment to net allocation for this packet (note: signed value)
3821   // leaks: leak bytes to attribute to alloc_pkt_id
3822   std::pair < std::set<long>::iterator, bool> ret;
3823   ret = pkt_id_set.insert (alloc_pkt_id); // add to set
3824   bool new_to_set = ret.second; // was not in set
3825   if (!new_to_set)
3826     {
3827       // Has been seen before, update values
3828       net_alloc += dview->getDataDescriptorValue (PROP_HCUR_NET_ALLOC, alloc_pkt_id);
3829       if (leaks)
3830         {
3831           uint64_t old = dview->getDataDescriptorValue (PROP_HCUR_LEAKS, alloc_pkt_id);
3832           if (old != 0)
3833             leaks = old;
3834         }
3835     }
3836   dview->setDataDescriptorValue (PROP_HCUR_NET_ALLOC, alloc_pkt_id, net_alloc);
3837   dview->setDataDescriptorValue (PROP_HCUR_LEAKS, alloc_pkt_id, leaks);
3838 }
3839
3840 DataView *
3841 Experiment::create_heapsz_data_view (DataView *heap_dview)
3842 {
3843   // heap_dview has DATA_HEAP _filtered_ packets.
3844   // This creates, populates, and returns DATA_HEAPSZ DataView
3845   DataDescriptor *dDscr = get_heapsz_events ();
3846   if (dDscr == NULL)
3847     return NULL;
3848   std::set<long> pkt_id_set;
3849   DataView *dview = heap_dview;
3850   long sz = dview->getSize ();
3851   for (long i = 0; i < sz; i++)
3852     {
3853       int64_t hsize = (int64_t) dview->getULongValue (PROP_HSIZE, i);
3854       uint64_t leaks = dview->getULongValue (PROP_HLEAKED, i);
3855       long alloc_pkt_id = dview->getIdByIdx (i);
3856       update_heapsz_packet (pkt_id_set, dview, alloc_pkt_id, hsize, leaks);
3857
3858       // linked free
3859       UnmapChunk *mmap_frees = (UnmapChunk *) dview->getObjValue (PROP_VOIDP_OBJ, i); // mmap metadata
3860       if (mmap_frees)
3861         {
3862           // mmap: all frees associated with this packet
3863           while (mmap_frees)
3864             {
3865               long free_pkt_id = mmap_frees->val;
3866               int64_t free_sz = mmap_frees->size;
3867               update_heapsz_packet (pkt_id_set, dview, free_pkt_id, -free_sz, 0);
3868               mmap_frees = mmap_frees->next;
3869             }
3870         }
3871       else
3872         {
3873           // malloc: check for associated free
3874           long free_pkt_id = dview->getLongValue (PROP_DDSCR_LNK, i) - 1;
3875           if (free_pkt_id >= 0)
3876             update_heapsz_packet (pkt_id_set, dview, free_pkt_id, -hsize, 0);
3877         }
3878     }
3879
3880   // create a new DataView based on the filtered-in and associated free events
3881   std::set<long>::iterator it;
3882   DataView *heapsz_dview = dDscr->createExtManagedView ();
3883   for (it = pkt_id_set.begin (); it != pkt_id_set.end (); ++it)
3884     {
3885       long ddscr_pkt_id = *it;
3886       heapsz_dview->appendDataDescriptorId (ddscr_pkt_id);
3887     }
3888   compute_heapsz_data_view (heapsz_dview);
3889   return heapsz_dview;
3890 }
3891
3892 void
3893 Experiment::compute_heapsz_data_view (DataView *heapsz_dview)
3894 {
3895   DataView *dview = heapsz_dview;
3896
3897   // Keep track of memory usage
3898   int64_t currentAllocs = 0;
3899   Size currentLeaks = 0;
3900   dview->sort (PROP_TSTAMP);
3901   long sz = dview->getSize ();
3902   for (long i = 0; i < sz; i++)
3903     {
3904       int64_t net_alloc = dview->getLongValue (PROP_HCUR_NET_ALLOC, i);
3905       currentAllocs += net_alloc;
3906       dview->setValue (PROP_HCUR_ALLOCS, i, currentAllocs);
3907
3908       Size leaks = dview->getULongValue (PROP_HCUR_LEAKS, i);
3909       currentLeaks += leaks;
3910       dview->setValue (PROP_HCUR_LEAKS, i, currentLeaks);
3911     }
3912 }
3913
3914 void
3915 Experiment::DBG_memuse (Sample * s)
3916 {
3917   DataDescriptor *dDscr = getDataDescriptor (DATA_HEAP);
3918   if (dDscr == NULL || dDscr->getSize () == 0)
3919     return;
3920
3921   DataView *dview = dDscr->createView ();
3922   dview->sort (PROP_TSTAMP);
3923   hrtime_t ts1 = s->get_start_time ();
3924   hrtime_t ts2 = s->get_end_time ();
3925
3926   HeapMap *heapmap = new HeapMap ();
3927   long sz = dview->getSize ();
3928   Size maxSize = 0;
3929   Size curSize = 0;
3930   hrtime_t maxTime = 0;
3931   for (long i = 0; i < sz; i++)
3932     {
3933       hrtime_t tstamp = dview->getLongValue (PROP_TSTAMP, i);
3934       if (tstamp < ts1)
3935         continue;
3936       if (tstamp >= ts2)
3937         break;
3938
3939       Heap_type mtype = (Heap_type) dview->getIntValue (PROP_HTYPE, i);
3940       Vaddr vaddr = dview->getULongValue (PROP_HVADDR, i);
3941       Vaddr ovaddr = dview->getULongValue (PROP_HOVADDR, i);
3942       switch (mtype)
3943         {
3944         case REALLOC_TRACE:
3945           break;
3946         case MALLOC_TRACE:
3947           ovaddr = 0;
3948           break;
3949         case FREE_TRACE:
3950           ovaddr = vaddr;
3951           vaddr = 0;
3952           break;
3953         default:
3954           vaddr = 0;
3955           ovaddr = 0;
3956           break;
3957         }
3958       if (ovaddr)
3959         {
3960           long idx = heapmap->deallocate (ovaddr) - 1;
3961           if (idx >= 0)
3962             curSize -= dview->getULongValue (PROP_HSIZE, idx);
3963         }
3964       if (vaddr)
3965         {
3966           heapmap->allocate (vaddr, i + 1);
3967           curSize += dview->getULongValue (PROP_HSIZE, i);
3968           if (curSize > maxSize)
3969             {
3970               maxSize = curSize;
3971               maxTime = tstamp;
3972             }
3973         }
3974     }
3975   printf ("SAMPLE=%s (id=%d) MEMUSE=%lld TSTAMP=%lld\n", s->get_start_label (),
3976           s->get_number (), maxSize, maxTime - getStartTime ());
3977   delete dview;
3978   delete heapmap;
3979 }
3980
3981 void
3982 Experiment::DBG_memuse (const char *sname)
3983 {
3984   for (int i = 0; i < samples->size (); ++i)
3985     {
3986       Sample *sample = samples->fetch (i);
3987       if (streq (sname, sample->get_start_label ()))
3988         {
3989           DBG_memuse (sample);
3990           break;
3991         }
3992     }
3993 }
3994
3995 DataDescriptor *
3996 Experiment::get_race_events ()
3997 {
3998   DataDescriptor *dDscr = getDataDescriptor (DATA_RACE);
3999   if (dDscr == NULL)
4000     return NULL;
4001   if (dDscr->getSize () == 0)
4002     {
4003       char *base_name = get_basename (expt_name);
4004       char *msg = dbe_sprintf (GTXT ("Loading Race Data: %s"), base_name);
4005       read_data_file (SP_RACETRACE_FILE, msg);
4006       free (msg);
4007       resolve_frame_info (dDscr);
4008     }
4009   return dDscr;
4010 }
4011
4012 DataDescriptor *
4013 Experiment::get_deadlock_events ()
4014 {
4015   DataDescriptor *dDscr = getDataDescriptor (DATA_DLCK);
4016   if (dDscr == NULL)
4017     return NULL;
4018   if (dDscr->getSize () == 0)
4019     {
4020       char *base_name = get_basename (expt_name);
4021       char *msg = dbe_sprintf (GTXT ("Loading Deadlocks Data: %s"), base_name);
4022       read_data_file (SP_DEADLOCK_FILE, msg);
4023       free (msg);
4024       resolve_frame_info (dDscr);
4025     }
4026   return dDscr;
4027 }
4028
4029 DataDescriptor *
4030 Experiment::get_sample_events ()
4031 {
4032   DataDescriptor *dDscr = getDataDescriptor (DATA_SAMPLE);
4033   if (dDscr == NULL)
4034     return NULL;
4035   if (dDscr->getSize () > 0)
4036     return dDscr;
4037
4038   // read_overview_file(); //YXXX do this here at some point instead of:
4039   PropDescr *tmp_propDscr;
4040   tmp_propDscr = new PropDescr (PROP_SMPLOBJ, NTXT ("SMPLOBJ"));
4041   tmp_propDscr->uname = NULL;
4042   tmp_propDscr->vtype = TYPE_OBJ;
4043   dDscr->addProperty (tmp_propDscr);
4044
4045   tmp_propDscr = new PropDescr (PROP_TSTAMP, NTXT ("TSTAMP"));
4046   tmp_propDscr->uname = dbe_strdup ("High resolution timestamp");
4047   tmp_propDscr->vtype = TYPE_UINT64;
4048   dDscr->addProperty (tmp_propDscr);
4049
4050   tmp_propDscr = new PropDescr (PROP_SAMPLE, NTXT ("SAMPLE"));
4051   tmp_propDscr->uname = dbe_strdup ("Sample number");
4052   tmp_propDscr->vtype = TYPE_UINT64;
4053   dDscr->addProperty (tmp_propDscr);
4054
4055   tmp_propDscr = new PropDescr (PROP_EVT_TIME, NTXT ("EVT_TIME"));
4056   tmp_propDscr->uname = dbe_strdup ("Event duration");
4057   tmp_propDscr->vtype = TYPE_UINT64;
4058   dDscr->addProperty (tmp_propDscr);
4059
4060   long ssize = samples->size ();
4061   for (long ii = 0; ii < ssize; ii++)
4062     {
4063       Sample * sample = samples->fetch (ii);
4064       long recn = dDscr->addRecord ();
4065       hrtime_t sduration = sample->get_end_time () - sample->get_start_time ();
4066       dDscr->setObjValue (PROP_SMPLOBJ, recn, sample);
4067       dDscr->setValue (PROP_SAMPLE, recn, sample->get_number ());
4068       dDscr->setValue (PROP_TSTAMP, recn, sample->get_end_time ());
4069       dDscr->setValue (PROP_EVT_TIME, recn, sduration);
4070     }
4071   return dDscr;
4072 }
4073
4074 DataDescriptor *
4075 Experiment::get_gc_events ()
4076 {
4077   DataDescriptor *dDscr = getDataDescriptor (DATA_GCEVENT);
4078   if (dDscr == NULL)
4079     return NULL;
4080   if (dDscr->getSize () > 0)
4081     return dDscr;
4082
4083   // read_overview_file(); //YXXX do this here at some point instead of:
4084   PropDescr *tmp_propDscr;
4085   tmp_propDscr = new PropDescr (PROP_GCEVENTOBJ, NTXT ("GCEVENTOBJ"));
4086   tmp_propDscr->uname = NULL;
4087   tmp_propDscr->vtype = TYPE_OBJ;
4088   dDscr->addProperty (tmp_propDscr);
4089
4090   tmp_propDscr = new PropDescr (PROP_TSTAMP, NTXT ("TSTAMP"));
4091   tmp_propDscr->uname = dbe_strdup ("High resolution timestamp");
4092   tmp_propDscr->vtype = TYPE_UINT64;
4093   dDscr->addProperty (tmp_propDscr);
4094
4095   tmp_propDscr = new PropDescr (PROP_GCEVENT, NTXT ("GCEVENT"));
4096   tmp_propDscr->uname = dbe_strdup ("GCEvent number");
4097   tmp_propDscr->vtype = TYPE_UINT64;
4098   dDscr->addProperty (tmp_propDscr);
4099
4100   tmp_propDscr = new PropDescr (PROP_EVT_TIME, NTXT ("EVT_TIME"));
4101   tmp_propDscr->uname = dbe_strdup ("Event duration");
4102   tmp_propDscr->vtype = TYPE_UINT64;
4103   dDscr->addProperty (tmp_propDscr);
4104
4105   long ssize = gcevents->size ();
4106   for (long ii = 0; ii < ssize; ii++)
4107     {
4108       GCEvent * gcevent = gcevents->fetch (ii);
4109       long recn = dDscr->addRecord ();
4110       hrtime_t sduration = gcevent->end - gcevent->start;
4111       dDscr->setObjValue (PROP_GCEVENTOBJ, recn, gcevent);
4112       dDscr->setValue (PROP_GCEVENT, recn, gcevent->id);
4113       dDscr->setValue (PROP_TSTAMP, recn, gcevent->end);
4114       dDscr->setValue (PROP_EVT_TIME, recn, sduration);
4115     }
4116   return dDscr;
4117 }
4118
4119 void
4120 Experiment::update_last_event (hrtime_t ts/*wall_ts*/)
4121 {
4122   if (last_event == ZERO_TIME)
4123     {
4124       // not yet initialized
4125       last_event = ts;
4126     }
4127   if (last_event - exp_start_time < ts - exp_start_time)
4128     // compare deltas to avoid hrtime_t wrap
4129     last_event = ts;
4130 }
4131
4132 void
4133 Experiment::write_header ()
4134 {
4135   StringBuilder sb;
4136
4137   // write commentary to the experiment, describing the parameters
4138   if (dbeSession->ipc_mode || dbeSession->rdt_mode)
4139     {
4140       // In GUI: print start time at the beginning
4141       time_t t = (time_t) start_sec;
4142       char *start_time = ctime (&t);
4143       if (start_time != NULL)
4144         {
4145           sb.setLength (0);
4146           sb.sprintf (GTXT ("Experiment started %s"), start_time);
4147           commentq->append (new Emsg (CMSG_COMMENT, sb));
4148         }
4149     }
4150   // write message with target arglist
4151   if (uarglist != NULL)
4152     {
4153       sb.setLength (0);
4154       sb.sprintf (GTXT ("\nTarget command (%s): '%s'"),
4155                   (wsize == W32 ? "32-bit" : "64-bit"), uarglist);
4156       commentq->append (new Emsg (CMSG_COMMENT, sb));
4157     }
4158
4159   sb.setLength (0);
4160   sb.sprintf (GTXT ("Process pid %d, ppid %d, pgrp %d, sid %d"),
4161               pid, ppid, pgrp, sid);
4162   commentq->append (new Emsg (CMSG_COMMENT, sb));
4163
4164   // add comment for user name, if set
4165   if (username != NULL)
4166     {
4167       sb.setLength (0);
4168       sb.sprintf (GTXT ("User: `%s'"), username);
4169       commentq->append (new Emsg (CMSG_COMMENT, sb));
4170     }
4171
4172   // add comment for current working directory
4173   if (ucwd != NULL)
4174     {
4175       sb.setLength (0);
4176       sb.sprintf (GTXT ("Current working directory: %s"), ucwd);
4177       commentq->append (new Emsg (CMSG_COMMENT, sb));
4178     }
4179
4180   // add comment for collector version string
4181   if (cversion != NULL)
4182     {
4183       char *wstring;
4184       switch (wsize)
4185         {
4186         case Wnone:
4187           wstring = NTXT ("?");
4188           break;
4189         case W32:
4190           wstring = GTXT ("32-bit");
4191           break;
4192         case W64:
4193           wstring = GTXT ("64-bit");
4194           break;
4195         default:
4196           wstring = NTXT ("??");
4197           break;
4198         }
4199       sb.setLength (0);
4200       sb.sprintf (GTXT ("Collector version: `%s'; experiment version %d.%d (%s)"),
4201                   cversion, exp_maj_version, exp_min_version, wstring);
4202       commentq->append (new Emsg (CMSG_COMMENT, sb));
4203     }
4204
4205   // add comment for driver version string (er_kernel)
4206   if (dversion != NULL)
4207     {
4208       sb.setLength (0);
4209       sb.sprintf (GTXT ("Kernel driver version: `%s'"), dversion);
4210       commentq->append (new Emsg (CMSG_COMMENT, sb));
4211     }
4212
4213   if (jversion != NULL)
4214     {
4215       sb.setLength (0);
4216       sb.sprintf (GTXT ("JVM version: `%s'"), jversion);
4217       commentq->append (new Emsg (CMSG_COMMENT, sb));
4218     }
4219
4220   // add comment for hostname, parameters
4221   if (hostname == NULL)
4222     hostname = dbe_strdup (GTXT ("unknown"));
4223   if (os_version == NULL)
4224     os_version = dbe_strdup (GTXT ("unknown"));
4225   if (architecture == NULL)
4226     architecture = dbe_strdup (GTXT ("unknown"));
4227   sb.setLength (0);
4228   sb.sprintf (GTXT ("Host `%s', OS `%s', page size %d, architecture `%s'"),
4229               hostname, os_version, page_size, architecture);
4230   commentq->append (new Emsg (CMSG_COMMENT, sb));
4231
4232   sb.setLength (0);
4233   if (maxclock != minclock)
4234     {
4235       clock = maxclock;
4236       sb.sprintf (
4237                   GTXT ("  %d CPUs, with clocks ranging from %d to %d MHz.; max of %d MHz. assumed"),
4238                   ncpus, minclock, maxclock, clock);
4239     }
4240   else
4241     sb.sprintf (GTXT ("  %d CPU%s, clock speed %d MHz."),
4242                 ncpus, (ncpus == 1 ? NTXT ("") : "s"), clock);
4243   commentq->append (new Emsg (CMSG_COMMENT, sb));
4244
4245   // add comment for machine memory size
4246   if (page_size > 0 && npages > 0)
4247     {
4248       long long memsize = ((long long) npages * page_size) / (1024 * 1024);
4249       sb.setLength (0);
4250       sb.sprintf (GTXT ("  Memory: %d pages @  %d = %lld MB."),
4251                   npages, page_size, memsize);
4252       commentq->append (new Emsg (CMSG_COMMENT, sb));
4253     }
4254
4255   // add comment for machine memory size
4256   if (machinemodel != NULL)
4257     {
4258       sb.setLength (0);
4259       sb.sprintf (GTXT ("  Machine model: %s"), machinemodel);
4260       commentq->append (new Emsg (CMSG_COMMENT, sb));
4261     }
4262
4263   // add comment for start time
4264   time_t t = (time_t) start_sec;
4265   char *p = ctime (&t);
4266   sb.setLength (0);
4267   if (p != NULL)
4268     sb.sprintf (GTXT ("Experiment started %s"), p);
4269   else
4270     sb.sprintf (GTXT ("\nExperiment start not recorded"));
4271   write_coll_params ();
4272   commentq->append (new Emsg (CMSG_COMMENT, sb));
4273   commentq->appendqueue (runlogq);
4274   runlogq->mark_clear ();
4275 }
4276
4277 void
4278 Experiment::write_coll_params ()
4279 {
4280   StringBuilder sb;
4281
4282   // now write the various collection parameters as comments
4283   sb.setLength (0);
4284   sb.append (GTXT ("Data collection parameters:"));
4285   commentq->append (new Emsg (CMSG_COMMENT, sb));
4286   if (coll_params.profile_mode == 1)
4287     {
4288       sb.setLength (0);
4289       sb.sprintf (GTXT ("  Clock-profiling, interval = %d microsecs."),
4290                   (int) (coll_params.ptimer_usec));
4291       commentq->append (new Emsg (CMSG_COMMENT, sb));
4292     }
4293   if (coll_params.sync_mode == 1)
4294     {
4295       sb.setLength (0);
4296       char *scope_str = NTXT ("");
4297       switch (coll_params.sync_scope)
4298         {
4299         case 0:
4300           scope_str = GTXT ("Native- and Java-APIs");
4301           break;
4302         case SYNCSCOPE_JAVA:
4303           scope_str = GTXT ("JAVA-APIs");
4304           break;
4305         case SYNCSCOPE_NATIVE:
4306           scope_str = GTXT ("Native-APIs");
4307           break;
4308         case SYNCSCOPE_JAVA | SYNCSCOPE_NATIVE:
4309           scope_str = GTXT ("Native- and Java-APIs");
4310           break;
4311         }
4312       if (coll_params.sync_threshold < 0)
4313         sb.sprintf (GTXT ("  Synchronization tracing, threshold = %d microsecs. (calibrated); %s"),
4314                     -coll_params.sync_threshold, scope_str);
4315       else
4316         sb.sprintf (GTXT ("  Synchronization tracing, threshold = %d microsecs.; %s"),
4317                     coll_params.sync_threshold, scope_str);
4318       commentq->append (new Emsg (CMSG_COMMENT, sb));
4319     }
4320   if (coll_params.heap_mode == 1)
4321     {
4322       sb.setLength (0);
4323       sb.append (GTXT ("  Heap tracing"));
4324       commentq->append (new Emsg (CMSG_COMMENT, sb));
4325     }
4326   if (coll_params.io_mode == 1)
4327     {
4328       sb.setLength (0);
4329       sb.append (GTXT ("  IO tracing"));
4330       commentq->append (new Emsg (CMSG_COMMENT, sb));
4331     }
4332   if (coll_params.race_mode == 1)
4333     {
4334       sb.setLength (0);
4335       char *race_stack_name;
4336       switch (coll_params.race_stack)
4337         {
4338         case 0:
4339           race_stack_name = GTXT ("dual-stack");
4340           break;
4341         case 1:
4342           race_stack_name = GTXT ("single-stack");
4343           break;
4344         case 2:
4345           race_stack_name = GTXT ("leaf");
4346           break;
4347         default:
4348           abort ();
4349         }
4350       sb.sprintf (GTXT ("  Datarace detection, %s"), race_stack_name);
4351       commentq->append (new Emsg (CMSG_COMMENT, sb));
4352     }
4353   if (coll_params.deadlock_mode == 1)
4354     {
4355       sb.setLength (0);
4356       sb.append (GTXT ("  Deadlock detection"));
4357       commentq->append (new Emsg (CMSG_COMMENT, sb));
4358     }
4359   if (coll_params.hw_mode == 1)
4360     {
4361       sb.setLength (0);
4362       if (hwc_default == true)
4363         sb.append (GTXT ("  HW counter-profiling (default); counters:"));
4364       else
4365         sb.append (GTXT ("  HW counter-profiling; counters:"));
4366       commentq->append (new Emsg (CMSG_COMMENT, sb));
4367       for (int i = 0; i < MAX_HWCOUNT; i++)
4368         {
4369           if (!coll_params.hw_aux_name[i])
4370             continue;
4371           sb.setLength (0);
4372           sb.sprintf (GTXT ("    %s, tag %d, interval %d, memop %d"),
4373                       coll_params.hw_aux_name[i], i,
4374                       coll_params.hw_interval[i], coll_params.hw_tpc[i]);
4375           commentq->append (new Emsg (CMSG_COMMENT, sb));
4376         }
4377     }
4378   if (coll_params.sample_periodic == 1)
4379     {
4380       sb.setLength (0);
4381       sb.sprintf (GTXT ("  Periodic sampling, %d secs."),
4382                   coll_params.sample_timer);
4383       commentq->append (new Emsg (CMSG_COMMENT, sb));
4384     }
4385   if (coll_params.limit != 0)
4386     {
4387       sb.setLength (0);
4388       sb.sprintf (GTXT ("  Experiment size limit, %d"),
4389                   coll_params.limit);
4390       commentq->append (new Emsg (CMSG_COMMENT, sb));
4391     }
4392   if (coll_params.linetrace != NULL)
4393     {
4394       sb.setLength (0);
4395       sb.sprintf (GTXT ("  Follow descendant processes from: %s"),
4396                   coll_params.linetrace);
4397       commentq->append (new Emsg (CMSG_COMMENT, sb));
4398     }
4399   if (coll_params.pause_sig != NULL)
4400     {
4401       sb.setLength (0);
4402       sb.sprintf (GTXT ("  Pause signal %s"), coll_params.pause_sig);
4403       commentq->append (new Emsg (CMSG_COMMENT, sb));
4404     }
4405   if (coll_params.sample_sig != NULL)
4406     {
4407       sb.setLength (0);
4408       sb.sprintf (GTXT ("  Sample signal %s"), coll_params.sample_sig);
4409       commentq->append (new Emsg (CMSG_COMMENT, sb));
4410     }
4411   if (coll_params.start_delay != NULL)
4412     {
4413       sb.setLength (0);
4414       sb.sprintf (GTXT ("  Data collection delay start %s seconds"), coll_params.start_delay);
4415       commentq->append (new Emsg (CMSG_COMMENT, sb));
4416     }
4417   if (coll_params.terminate != NULL)
4418     {
4419       sb.setLength (0);
4420       sb.sprintf (GTXT ("  Data collection termination after %s seconds"), coll_params.terminate);
4421       commentq->append (new Emsg (CMSG_COMMENT, sb));
4422     }
4423   // add a blank line after data description
4424   commentq->append (new Emsg (CMSG_COMMENT, NTXT ("")));
4425 }
4426
4427
4428 /*
4429  *    Raw packet processing
4430  */
4431 static int
4432 check_mstate (char *ptr, PacketDescriptor *pDscr, int arg)
4433 {
4434   switch (arg)
4435     {
4436     case PROP_UCPU:
4437     case PROP_SCPU:
4438     case PROP_TRAP:
4439     case PROP_TFLT:
4440     case PROP_DFLT:
4441     case PROP_KFLT:
4442     case PROP_ULCK:
4443     case PROP_TSLP:
4444     case PROP_WCPU:
4445     case PROP_TSTP:
4446       break;
4447     default:
4448       return 0;
4449     }
4450   Vector<FieldDescr*> *fields = pDscr->getFields ();
4451   for (int i = 0, sz = fields->size (); i < sz; i++)
4452     {
4453       FieldDescr *fDscr = fields->fetch (i);
4454       if (fDscr->propID == arg)
4455         return *((int*) (ptr + fDscr->offset));
4456     }
4457   return 0;
4458 }
4459
4460 #define PACKET_ALIGNMENT 4
4461
4462 uint64_t
4463 Experiment::readPacket (Data_window *dwin, Data_window::Span *span)
4464 {
4465   Common_packet *rcp = (Common_packet *) dwin->bind (span,
4466                                                     sizeof (CommonHead_packet));
4467   uint16_t v16;
4468   uint64_t size = 0;
4469   if (rcp)
4470     {
4471       if ((((long) rcp) % PACKET_ALIGNMENT) != 0)
4472         {
4473           invalid_packet++;
4474           size = PROFILE_BUFFER_CHUNK - span->offset % PROFILE_BUFFER_CHUNK;
4475           return size;
4476         }
4477       v16 = (uint16_t) rcp->tsize;
4478       size = dwin->decode (v16);
4479       if (size == 0)
4480         {
4481           size = PROFILE_BUFFER_CHUNK - span->offset % PROFILE_BUFFER_CHUNK;
4482           return size;
4483         }
4484       rcp = (Common_packet *) dwin->bind (span, size);
4485     }
4486   if (rcp == NULL)
4487     return 0;
4488
4489   if ((((long) rcp) % PACKET_ALIGNMENT) != 0)
4490     {
4491       invalid_packet++;
4492       size = PROFILE_BUFFER_CHUNK - span->offset % PROFILE_BUFFER_CHUNK;
4493       return size;
4494     }
4495   v16 = (uint16_t) rcp->type;
4496   uint32_t rcptype = dwin->decode (v16);
4497   if (rcptype == EMPTY_PCKT)
4498     return size;
4499   if (rcptype == FRAME_PCKT)
4500     {
4501       RawFramePacket *fp = new RawFramePacket;
4502       fp->uid = dwin->decode (((Frame_packet*) rcp)->uid);
4503       fp->uidn = NULL;
4504       fp->uidj = NULL;
4505       fp->omp_uid = NULL;
4506       fp->omp_state = 0;
4507       char *ptr = (char*) rcp + dwin->decode (((Frame_packet*) rcp)->hsize);
4508       if ((((long) ptr) % PACKET_ALIGNMENT) != 0)
4509         {
4510           invalid_packet++;
4511           delete fp;
4512           return size;
4513         }
4514       v16 = (uint16_t) ((Frame_packet*) rcp)->tsize;
4515       char *end = (char*) rcp + dwin->decode (v16);
4516       for (; ptr < end;)
4517         {
4518           Common_info *cinfo = (Common_info*) ptr;
4519           uint32_t hsize = dwin->decode (cinfo->hsize);
4520           if (hsize == 0 || ptr + hsize > end)
4521             break;
4522           int kind = dwin->decode (cinfo->kind);
4523           bool compressed = false;
4524           if (kind & COMPRESSED_INFO)
4525             {
4526               compressed = true;
4527               kind &= ~COMPRESSED_INFO;
4528             }
4529           switch (kind)
4530             {
4531             case STACK_INFO:
4532               {
4533                 char *stack = ptr + sizeof (Stack_info);
4534                 size_t stack_size = hsize - sizeof (Stack_info);
4535                 uint64_t uidn = dwin->decode (((Stack_info*) cinfo)->uid);
4536                 if (stack_size <= 0)
4537                   {
4538                     fp->uidn = get_uid_node (uidn);
4539                     break;
4540                   }
4541                 uint64_t link_uid = (uint64_t) 0;
4542                 if (compressed)
4543                   {
4544                     stack_size -= sizeof (uint64_t);
4545                     unsigned char *s = (unsigned char*) (stack + stack_size);
4546                     int shift = 0;
4547                     for (size_t i = 0; i<sizeof (link_uid); i++)
4548                       {
4549                         link_uid |= (uint64_t) * s++ << shift;
4550                         shift += 8;
4551                       }
4552                   }
4553                 if (wsize == W32)
4554                   fp->uidn = add_uid (dwin, uidn,
4555                                       (int) (stack_size / sizeof (uint32_t)),
4556                                       (uint32_t*) stack, link_uid);
4557                 else
4558                   fp->uidn = add_uid (dwin, uidn,
4559                                       (int) (stack_size / sizeof (uint64_t)),
4560                                       (uint64_t*) stack, link_uid);
4561                 break;
4562               }
4563             case JAVA_INFO:
4564               {
4565                 char *stack = ptr + sizeof (Java_info);
4566                 size_t stack_size = hsize - sizeof (Java_info);
4567                 uint64_t uidj = dwin->decode (((Java_info*) cinfo)->uid);
4568                 if (stack_size <= 0)
4569                   {
4570                     fp->uidj = get_uid_node (uidj);
4571                     break;
4572                   }
4573
4574                 uint64_t link_uid = (uint64_t) 0;
4575                 if (compressed)
4576                   {
4577                     stack_size -= sizeof (uint64_t);
4578                     unsigned char *s = (unsigned char*) (stack + stack_size);
4579                     int shift = 0;
4580                     for (size_t i = 0; i<sizeof (link_uid); i++)
4581                       {
4582                         link_uid |= (uint64_t) * s++ << shift;
4583                         shift += 8;
4584                       }
4585                   }
4586                 if (wsize == W32)
4587                   fp->uidj = add_uid (dwin, uidj,
4588                                       (int) (stack_size / sizeof (uint32_t)),
4589                                       (uint32_t*) stack, link_uid);
4590                 else
4591                   {
4592                     // bug 6909545: garbage in 64-bit JAVA_INFO
4593                     char *nstack = (char*) malloc (stack_size);
4594                     char *dst = nstack;
4595                     char *srcmax = stack + stack_size - sizeof (uint64_t);
4596                     for (char *src = stack; src <= srcmax;)
4597                       {
4598                         int64_t val = dwin->decode (*(int32_t*) src);
4599                         *(uint64_t*) dst = dwin->decode (val);
4600                         src += sizeof (uint64_t);
4601                         dst += sizeof (uint64_t);
4602                         if (src > srcmax)
4603                           {
4604                             fprintf (stderr, "er_print: Experiment::readPacket: Error in data: src=%llx greater than %llx\n",
4605                                      (long long) src, (long long) srcmax);
4606                             break;
4607                           }
4608                         *(uint64_t*) dst = *(uint64_t*) src;
4609                         src += sizeof (uint64_t);
4610                         dst += sizeof (uint64_t);
4611                       }
4612                     fp->uidj = add_uid (dwin, uidj,
4613                                         (int) (stack_size / sizeof (uint64_t)),
4614                                         (uint64_t*) nstack, link_uid);
4615                     free (nstack);
4616                   }
4617                 break;
4618               }
4619             case OMP_INFO:
4620               fp->omp_state = dwin->decode (((OMP_info*) ptr)->omp_state);
4621               break;
4622             case OMP2_INFO:
4623               {
4624                 uint64_t omp_uid = dwin->decode (((OMP2_info*) ptr)->uid);
4625                 fp->omp_uid = get_uid_node (omp_uid);
4626                 fp->omp_state = dwin->decode (((OMP2_info*) ptr)->omp_state);
4627                 break;
4628               }
4629             default:
4630               break;
4631             }
4632           ptr += hsize;
4633         }
4634       frmpckts->append (fp);
4635       return size;
4636     }
4637   else if (rcptype == UID_PCKT)
4638     {
4639       Uid_packet *uidp = (Uid_packet*) rcp;
4640       uint64_t uid = dwin->decode (uidp->uid);
4641       char *arr_bytes = (char*) (uidp + 1);
4642       v16 = (uint16_t) rcp->tsize;
4643       size_t arr_length = dwin->decode (v16) - sizeof (Uid_packet);
4644       if (arr_length <= 0)
4645         return size;
4646       uint64_t link_uid = (uint64_t) 0;
4647       if (dwin->decode (uidp->flags) & COMPRESSED_INFO)
4648         {
4649           arr_length -= sizeof (uint64_t);
4650           unsigned char *s = (unsigned char*) (arr_bytes + arr_length);
4651           int shift = 0;
4652           for (size_t i = 0; i<sizeof (link_uid); i++)
4653             {
4654               link_uid |= (uint64_t) * s++ << shift;
4655               shift += 8;
4656             }
4657         }
4658       if (wsize == W32)
4659         add_uid (dwin, uid, (int) (arr_length / sizeof (uint32_t)),
4660                  (uint32_t*) arr_bytes, link_uid);
4661       else
4662         add_uid (dwin, uid, (int) (arr_length / sizeof (uint64_t)),
4663                  (uint64_t*) arr_bytes, link_uid);
4664       return size;
4665     }
4666
4667   PacketDescriptor *pcktDescr = getPacketDescriptor (rcptype);
4668   if (pcktDescr == NULL)
4669     return size;
4670   DataDescriptor *dataDescr = pcktDescr->getDataDescriptor ();
4671   if (dataDescr == NULL)
4672     return size;
4673
4674   /* omazur: TBR START -- old experiment */
4675   if (rcptype == PROF_PCKT)
4676     {
4677       // For backward compatibility with older SS12 experiments
4678       int numstates = get_params ()->lms_magic_id; // ugly, for old experiments
4679       if (numstates > LMS_NUM_SOLARIS_MSTATES)
4680         numstates = LMS_NUM_SOLARIS_MSTATES;
4681       for (int i = 0; i < numstates; i++)
4682         if (check_mstate ((char*) rcp, pcktDescr, PROP_UCPU + i))
4683           readPacket (dwin, (char*) rcp, pcktDescr, dataDescr, PROP_UCPU + i,
4684                       size);
4685     }
4686   else
4687     readPacket (dwin, (char*) rcp, pcktDescr, dataDescr, 0, size);
4688   return size;
4689 }
4690
4691 void
4692 Experiment::readPacket (Data_window *dwin, char *ptr, PacketDescriptor *pDscr,
4693                         DataDescriptor *dDscr, int arg, uint64_t pktsz)
4694 {
4695   union Value
4696   {
4697     uint32_t val32;
4698     uint64_t val64;
4699   } *v;
4700
4701   long recn = dDscr->addRecord ();
4702   Vector<FieldDescr*> *fields = pDscr->getFields ();
4703   int sz = fields->size ();
4704   for (int i = 0; i < sz; i++)
4705     {
4706       FieldDescr *field = fields->fetch (i);
4707       v = (Value*) (ptr + field->offset);
4708       if (field->propID == arg)
4709         {
4710           dDscr->setValue (PROP_NTICK, recn, dwin->decode (v->val32));
4711           dDscr->setValue (PROP_MSTATE, recn, (uint32_t) (field->propID - PROP_UCPU));
4712         }
4713       if (field->propID == PROP_THRID || field->propID == PROP_LWPID
4714           || field->propID == PROP_CPUID)
4715         {
4716           uint64_t tmp64 = 0;
4717           switch (field->vtype)
4718             {
4719             case TYPE_INT32:
4720             case TYPE_UINT32:
4721               tmp64 = dwin->decode (v->val32);
4722               break;
4723             case TYPE_INT64:
4724             case TYPE_UINT64:
4725               tmp64 = dwin->decode (v->val64);
4726               break;
4727             case TYPE_STRING:
4728             case TYPE_DOUBLE:
4729             case TYPE_OBJ:
4730             case TYPE_DATE:
4731             case TYPE_BOOL:
4732             case TYPE_ENUM:
4733             case TYPE_LAST:
4734             case TYPE_NONE:
4735               break;
4736             }
4737           uint32_t tag = mapTagValue ((Prop_type) field->propID, tmp64);
4738           dDscr->setValue (field->propID, recn, tag);
4739         }
4740       else
4741         {
4742           switch (field->vtype)
4743             {
4744             case TYPE_INT32:
4745             case TYPE_UINT32:
4746               dDscr->setValue (field->propID, recn, dwin->decode (v->val32));
4747               break;
4748             case TYPE_INT64:
4749             case TYPE_UINT64:
4750               dDscr->setValue (field->propID, recn, dwin->decode (v->val64));
4751               break;
4752             case TYPE_STRING:
4753               {
4754                 int len = (int) (pktsz - field->offset);
4755                 if ((len > 0) && (ptr[field->offset] != 0))
4756                   {
4757                     StringBuilder *sb = new StringBuilder ();
4758                     sb->append (ptr + field->offset, 0, len);
4759                     dDscr->setObjValue (field->propID, recn, sb);
4760                   }
4761                 break;
4762               }
4763               // ignoring the following cases (why?)
4764             case TYPE_DOUBLE:
4765             case TYPE_OBJ:
4766             case TYPE_DATE:
4767             case TYPE_BOOL:
4768             case TYPE_ENUM:
4769             case TYPE_LAST:
4770             case TYPE_NONE:
4771               break;
4772             }
4773         }
4774     }
4775 }
4776
4777 #define PROG_BYTE 102400 // update progress bar every PROG_BYTE bytes
4778
4779 void
4780 Experiment::read_data_file (const char *fname, const char *msg)
4781 {
4782   Data_window::Span span;
4783   off64_t total_len, remain_len;
4784   char *progress_bar_msg;
4785   int progress_bar_percent = -1;
4786
4787   char *data_file_name = dbe_sprintf (NTXT ("%s/%s"), expt_name, fname);
4788   Data_window *dwin = new Data_window (data_file_name);
4789   // Here we can call stat(data_file_name) to get file size,
4790   // and call a function to reallocate vectors for clock profiling data
4791   free (data_file_name);
4792   if (dwin->not_opened ())
4793     {
4794       delete dwin;
4795       return;
4796     }
4797   dwin->need_swap_endian = need_swap_endian;
4798
4799   span.offset = 0;
4800   span.length = dwin->get_fsize ();
4801   total_len = remain_len = span.length;
4802   progress_bar_msg = dbe_sprintf (NTXT ("%s %s"), NTXT ("  "), msg);
4803   invalid_packet = 0;
4804   for (;;)
4805     {
4806       uint64_t pcktsz = readPacket (dwin, &span);
4807       if (pcktsz == 0)
4808         break;
4809       // Update progress bar
4810       if ((span.length <= remain_len) && (remain_len > 0))
4811         {
4812           int percent = (int) (100 * (total_len - remain_len) / total_len);
4813           if (percent > progress_bar_percent)
4814             {
4815               progress_bar_percent += 10;
4816               theApplication->set_progress (percent, progress_bar_msg);
4817             }
4818           remain_len -= PROG_BYTE;
4819         }
4820       span.length -= pcktsz;
4821       span.offset += pcktsz;
4822     }
4823   delete dwin;
4824
4825   if (invalid_packet)
4826     {
4827       StringBuilder sb;
4828       sb.sprintf (GTXT ("WARNING: There are %d invalid packet(s) in the %s file"),
4829                   invalid_packet, fname);
4830       Emsg *m = new Emsg (CMSG_WARN, sb);
4831       warnq->append (m);
4832     }
4833
4834   theApplication->set_progress (0, NTXT (""));
4835   free (progress_bar_msg);
4836 }
4837
4838 int
4839 Experiment::read_overview_file ()
4840 {
4841   char *data_file_name = dbe_sprintf ("%s/%s", expt_name, SP_OVERVIEW_FILE);
4842   Data_window *dwin = new Data_window (data_file_name);
4843   free (data_file_name);
4844   if (dwin->not_opened ())
4845     {
4846       delete dwin;
4847       return 0;
4848     }
4849   dwin->need_swap_endian = need_swap_endian;
4850   newDataDescriptor (DATA_SAMPLE);
4851
4852   Data_window::Span span;
4853   span.offset = 0;
4854   span.length = dwin->get_fsize ();
4855
4856   PrUsage *data = NULL, *data_prev = NULL;
4857   Sample *sample;
4858   int sample_number = 1;
4859
4860   int64_t prDataSize;
4861   if (wsize == W32)
4862     prDataSize = PrUsage::bind32Size ();
4863   else
4864     prDataSize = PrUsage::bind64Size ();
4865
4866   while (span.length > 0)
4867     {
4868       data_prev = data;
4869       data = new PrUsage ();
4870
4871       void *dw = dwin->bind (&span, prDataSize);
4872       if ((dw == NULL) || (prDataSize > span.length))
4873         {
4874           Emsg *m = new Emsg (CMSG_ERROR, GTXT ("Warning: overview data file can't be read"));
4875           warnq->append (m);
4876           status = FAILURE;
4877           delete dwin;
4878           return status;
4879         }
4880
4881       if (wsize == W32)
4882         data->bind32 (dw, need_swap_endian);
4883       else
4884         data->bind64 (dw, need_swap_endian);
4885       span.length -= prDataSize;
4886       span.offset += prDataSize;
4887
4888       // Skip the first packet
4889       if (data_prev == NULL)
4890         continue;
4891       if (sample_number > samples->size ())
4892         { // inconsistent log/overview
4893           sample = new Sample (sample_number);
4894           char * label = GTXT ("<unknown>");
4895           sample->start_label = dbe_strdup (label);
4896           sample->end_label = dbe_strdup (label);
4897           samples->append (sample);
4898         }
4899       else
4900         sample = samples->fetch (sample_number - 1);
4901       sample_number++;
4902       sample->start_time = data_prev->pr_tstamp + 1;
4903       sample->end_time = data->pr_tstamp;
4904       sample->prusage = data_prev;
4905
4906       data_prev->pr_rtime = data->pr_rtime - data_prev->pr_rtime;
4907       data_prev->pr_utime = data->pr_utime - data_prev->pr_utime;
4908       data_prev->pr_stime = data->pr_stime - data_prev->pr_stime;
4909       data_prev->pr_ttime = data->pr_ttime - data_prev->pr_ttime;
4910       data_prev->pr_tftime = data->pr_tftime - data_prev->pr_tftime;
4911       data_prev->pr_dftime = data->pr_dftime - data_prev->pr_dftime;
4912       data_prev->pr_kftime = data->pr_kftime - data_prev->pr_kftime;
4913       data_prev->pr_ltime = data->pr_ltime - data_prev->pr_ltime;
4914       data_prev->pr_slptime = data->pr_slptime - data_prev->pr_slptime;
4915       data_prev->pr_wtime = data->pr_wtime - data_prev->pr_wtime;
4916       data_prev->pr_stoptime = data->pr_stoptime - data_prev->pr_stoptime;
4917       data_prev->pr_minf = data->pr_minf - data_prev->pr_minf;
4918       data_prev->pr_majf = data->pr_majf - data_prev->pr_majf;
4919       data_prev->pr_nswap = data->pr_nswap - data_prev->pr_nswap;
4920       data_prev->pr_inblk = data->pr_inblk - data_prev->pr_inblk;
4921       data_prev->pr_oublk = data->pr_oublk - data_prev->pr_oublk;
4922       data_prev->pr_msnd = data->pr_msnd - data_prev->pr_msnd;
4923       data_prev->pr_mrcv = data->pr_mrcv - data_prev->pr_mrcv;
4924       data_prev->pr_sigs = data->pr_sigs - data_prev->pr_sigs;
4925       data_prev->pr_vctx = data->pr_vctx - data_prev->pr_vctx;
4926       data_prev->pr_ictx = data->pr_ictx - data_prev->pr_ictx;
4927       data_prev->pr_sysc = data->pr_sysc - data_prev->pr_sysc;
4928       data_prev->pr_ioch = data->pr_ioch - data_prev->pr_ioch;
4929       sample->get_usage (); // force validation
4930     }
4931
4932   for (long smpNum = samples->size (); smpNum >= sample_number; smpNum--)
4933     {
4934       // overview file was truncated
4935       sample = samples->remove (smpNum - 1);
4936       delete sample;
4937     }
4938
4939   if (data)
4940     {
4941       // Update last_event so that getEndTime() covers
4942       // all loadobjects, too.
4943       update_last_event (data->pr_tstamp);
4944       delete data;
4945     }
4946   delete dwin;
4947   return SUCCESS;
4948 }
4949
4950 int
4951 Experiment::uidNodeCmp (const void *a, const void *b)
4952 {
4953   UIDnode *nd1 = *(UIDnode**) a;
4954   UIDnode *nd2 = *(UIDnode**) b;
4955   if (nd1->uid == nd2->uid)
4956     return 0;
4957   return nd1->uid < nd2->uid ? -1 : 1;
4958 }
4959
4960 static uint64_t
4961 funcAddr (uint32_t val)
4962 {
4963   if (val == (uint32_t) SP_LEAF_CHECK_MARKER)
4964     return (uint64_t) SP_LEAF_CHECK_MARKER;
4965   if (val == (uint32_t) SP_TRUNC_STACK_MARKER)
4966     return (uint64_t) SP_TRUNC_STACK_MARKER;
4967   if (val == (uint32_t) SP_FAILED_UNWIND_MARKER)
4968     return (uint64_t) SP_FAILED_UNWIND_MARKER;
4969   return val;
4970 }
4971
4972 Experiment::UIDnode *
4973 Experiment::add_uid (Data_window *dwin, uint64_t uid, int size,
4974                      uint32_t *array, uint64_t link_uid)
4975 {
4976   if (uid == (uint64_t) 0)
4977     return NULL;
4978   uint64_t val = funcAddr (dwin->decode (array[0]));
4979   UIDnode *node = NULL;
4980   UIDnode *res = get_uid_node (uid, val);
4981   UIDnode *next = res;
4982   for (int i = 0; i < size; i++)
4983     {
4984       val = funcAddr (dwin->decode (array[i]));
4985       if (next == NULL)
4986         {
4987           next = get_uid_node ((uint64_t) 0, val);
4988           if (node != NULL)
4989             node->next = next;
4990         }
4991       node = next;
4992       next = node->next;
4993       if (node->val == 0)
4994         node->val = val;
4995       else if (node->val != val)   // Algorithmic error (should never happen)
4996         node->val = (uint64_t) SP_LEAF_CHECK_MARKER;
4997     }
4998   if (next == NULL && link_uid != (uint64_t) 0 && node != NULL)
4999     node->next = get_uid_node (link_uid);
5000   return res;
5001 }
5002
5003 Experiment::UIDnode *
5004 Experiment::add_uid (Data_window *dwin, uint64_t uid, int size, uint64_t *array, uint64_t link_uid)
5005 {
5006   if (uid == (uint64_t) 0)
5007     return NULL;
5008   UIDnode *node = NULL;
5009   uint64_t val = dwin->decode (array[0]);
5010   UIDnode *res = get_uid_node (uid, val);
5011   UIDnode *next = res;
5012   for (int i = 0; i < size; i++)
5013     {
5014       val = dwin->decode (array[i]);
5015       if (next == NULL)
5016         {
5017           next = get_uid_node ((uint64_t) 0, val);
5018           if (node != NULL)
5019             node->next = next;
5020         }
5021       node = next;
5022       next = node->next;
5023       if (node->val == (uint64_t) 0)
5024         node->val = val;
5025       else if (node->val != val)   // Algorithmic error (should never happen)
5026         node->val = (uint64_t) - 1;
5027     }
5028   if (next == NULL && link_uid != (uint64_t) 0 && node != NULL)
5029     node->next = get_uid_node (link_uid);
5030   return res;
5031 }
5032
5033 Experiment::UIDnode *
5034 Experiment::new_uid_node (uint64_t uid, uint64_t val)
5035 {
5036 #define NCHUNKSTEP 1024
5037   if (nnodes >= nchunks * CHUNKSZ)
5038     {
5039       // Reallocate Node chunk array
5040       UIDnode** old_chunks = chunks;
5041       chunks = new UIDnode*[nchunks + NCHUNKSTEP];
5042       memcpy (chunks, old_chunks, nchunks * sizeof (UIDnode*));
5043       nchunks += NCHUNKSTEP;
5044       delete[] old_chunks;
5045       // Clean future pointers
5046       memset (&chunks[nchunks - NCHUNKSTEP], 0, NCHUNKSTEP * sizeof (UIDnode*));
5047     }
5048
5049   if (NULL == chunks[nnodes / CHUNKSZ])   // Allocate new chunk for nodes.
5050     chunks[nnodes / CHUNKSZ] = new UIDnode[CHUNKSZ];
5051   UIDnode *node = &chunks[nnodes / CHUNKSZ][nnodes % CHUNKSZ];
5052   node->uid = uid;
5053   node->val = val;
5054   node->next = NULL;
5055   nnodes++;
5056   return node;
5057 }
5058
5059 Experiment::UIDnode *
5060 Experiment::get_uid_node (uint64_t uid, uint64_t val)
5061 {
5062   int hash = (((int) uid) >> 4) & (HTableSize - 1);
5063   if (uid != (uint64_t) 0)
5064     {
5065       UIDnode *node = uidHTable[hash];
5066       if (node && node->uid == uid)
5067         return node;
5068     }
5069   UIDnode *node = new_uid_node (uid, val);
5070   if (uid != (uint64_t) 0)
5071     {
5072       uidHTable[hash] = node;
5073       uidnodes->append (node);
5074     }
5075   return node;
5076 }
5077
5078 Experiment::UIDnode *
5079 Experiment::get_uid_node (uint64_t uid)
5080 {
5081   if (uid == (uint64_t) 0)
5082     return NULL;
5083   int hash = (((int) uid) >> 4) & (HTableSize - 1);
5084   UIDnode *node = uidHTable[hash];
5085   if (node && node->uid == uid)
5086     return node;
5087   node = new_uid_node (uid, (uint64_t) 0);
5088   node->next = node;
5089   return node;
5090 }
5091
5092 Experiment::UIDnode *
5093 Experiment::find_uid_node (uint64_t uid)
5094 {
5095   int hash = (((int) uid) >> 4) & (HTableSize - 1);
5096   UIDnode *node = uidHTable[hash];
5097   if (node && node->uid == uid)
5098     return node;
5099   int lt = 0;
5100   int rt = uidnodes->size () - 1;
5101   while (lt <= rt)
5102     {
5103       int md = (lt + rt) / 2;
5104       node = uidnodes->fetch (md);
5105       if (node->uid < uid)
5106         lt = md + 1;
5107       else if (node->uid > uid)
5108         rt = md - 1;
5109       else
5110         {
5111           uidHTable[hash] = node;
5112           return node;
5113         }
5114     }
5115   return NULL;
5116 }
5117
5118 int
5119 Experiment::frUidCmp (const void *a, const void *b)
5120 {
5121   RawFramePacket *fp1 = *(RawFramePacket**) a;
5122   RawFramePacket *fp2 = *(RawFramePacket**) b;
5123   if (fp1->uid == fp2->uid)
5124     return 0;
5125   return fp1->uid < fp2->uid ? -1 : 1;
5126 }
5127
5128 Experiment::RawFramePacket *
5129 Experiment::find_frame_packet (uint64_t uid)
5130 {
5131   int lt = 0;
5132   int rt = frmpckts->size () - 1;
5133   while (lt <= rt)
5134     {
5135       int md = (lt + rt) / 2;
5136       RawFramePacket *fp = frmpckts->fetch (md);
5137       if (fp->uid < uid)
5138         lt = md + 1;
5139       else if (fp->uid > uid)
5140         rt = md - 1;
5141       else
5142         return fp;
5143     }
5144
5145   return NULL;
5146 }
5147
5148 #define FRINFO_CACHEOPT_SIZE_LIMIT  4000000
5149 #define FRINFO_PIPELINE_SIZE_LIMIT  500000
5150 #define FRINFO_PIPELINE_NUM_STAGES  3
5151
5152 // Pipelined execution of resolve_frame_info() and add_stack().
5153 // Since this is the largest time consuming part of loading an experiment (especially
5154 // so for large java experiments) - executing this part as a 3 stage pipeline can
5155 // give significant performance gain - and this concept can be aggressively applied
5156 // to enhance the gain further in future. The three stages are:
5157 // Phase 1:  resolve_frame_info()
5158 // Phase 2:  first part of add_stack() where the native stack is built
5159 // Phase 3:  second part og add_stack() where the java stack is built
5160 // Phase 4:   insert the native and java stacks into the stack map
5161 // The main thread operates in the first Phase and the other stages are
5162 // operated by a ssplib sequential queue - The threads working on the queues run concurrently
5163 // with each other and with the main thread. But within a particular queue, jobs are
5164 // executed sequentially
5165
5166
5167 // This is the second phase of the pipeline of resolve_frame_info and add_stack
5168 //  It works on a chunk of iterations (size CSTCTX_CHUNK_SZ) and invokes add_stack()
5169 // for each one of them
5170
5171 void
5172 Experiment::resolve_frame_info (DataDescriptor *dDscr)
5173 {
5174   if (!resolveFrameInfo)
5175     return;
5176   if (NULL == cstack)
5177     return;
5178   dDscr->setResolveFrInfoDone ();
5179
5180   // Check for TSTAMP
5181   int propID = dbeSession->getPropIdByName (NTXT ("TSTAMP"));
5182   Data *dataTStamp = dDscr->getData (propID);
5183   if (dataTStamp == NULL)
5184     return;
5185
5186   propID = dbeSession->getPropIdByName (NTXT ("FRINFO"));
5187   Data *dataFrinfo = dDscr->getData (propID);
5188
5189   propID = dbeSession->getPropIdByName (NTXT ("THRID"));
5190   Data *dataThrId = dDscr->getData (propID);
5191
5192   // We can get frame info either by FRINFO or by [THRID,STKIDX]
5193   if (dataFrinfo == NULL)
5194     return;
5195
5196   char *propName = NTXT ("MSTACK");
5197   propID = dbeSession->getPropIdByName (propName);
5198   PropDescr *prMStack = new PropDescr (propID, propName);
5199   prMStack->uname = dbe_strdup (GTXT ("Machine Call Stack"));
5200   prMStack->vtype = TYPE_OBJ;
5201   dDscr->addProperty (prMStack);
5202
5203   propName = NTXT ("USTACK");
5204   propID = dbeSession->getPropIdByName (propName);
5205   PropDescr *prUStack = new PropDescr (propID, propName);
5206   prUStack->uname = dbe_strdup (GTXT ("User Call Stack"));
5207   prUStack->vtype = TYPE_OBJ;
5208   dDscr->addProperty (prUStack);
5209
5210   propName = NTXT ("XSTACK");
5211   propID = dbeSession->getPropIdByName (propName);
5212   PropDescr *prXStack = new PropDescr (propID, propName);
5213   prXStack->uname = dbe_strdup (GTXT ("Expert Call Stack"));
5214   prXStack->vtype = TYPE_OBJ;
5215   dDscr->addProperty (prXStack);
5216
5217   propName = NTXT ("HSTACK");
5218   propID = dbeSession->getPropIdByName (propName);
5219   PropDescr *prHStack = new PropDescr (propID, propName);
5220   prHStack->uname = dbe_strdup (GTXT ("ShowHide Call Stack"));
5221   prHStack->vtype = TYPE_OBJ;
5222   dDscr->addProperty (prHStack);
5223
5224   if (has_java)
5225     {
5226       propName = NTXT ("JTHREAD");
5227       propID = dbeSession->getPropIdByName (propName);
5228       PropDescr *prJThread = new PropDescr (propID, propName);
5229       prJThread->uname = dbe_strdup (GTXT ("Java Thread"));
5230       prJThread->vtype = TYPE_OBJ;
5231       dDscr->addProperty (prJThread);
5232     }
5233
5234   if (ompavail)
5235     {
5236       PropDescr *prop = new PropDescr (PROP_OMPSTATE, NTXT ("OMPSTATE"));
5237       prop->uname = dbe_strdup (GTXT ("OpenMP state"));
5238       prop->vtype = TYPE_UINT32;
5239       char * stateNames [OMP_LAST_STATE] = OMP_THR_STATE_STRINGS;
5240       char * stateUNames[OMP_LAST_STATE] = OMP_THR_STATE_USTRINGS;
5241       for (int ii = 0; ii < OMP_LAST_STATE; ii++)
5242         prop->addState (ii, stateNames[ii], stateUNames[ii]);
5243       dDscr->addProperty (prop);
5244
5245       // add PROP_CPRID to profiling data (not same as omptrace's PROP_CPRID)
5246       prop = dDscr->getProp (PROP_CPRID);
5247       if (prop)
5248         {
5249           VType_type type = prop->vtype;
5250           assert (type == TYPE_OBJ); //see 7040526
5251         }
5252       prop = new PropDescr (PROP_CPRID, NTXT ("CPRID")); //profiling PROP_CPRID
5253       prop->uname = dbe_strdup (GTXT ("OpenMP parallel region"));
5254       prop->vtype = TYPE_OBJ;
5255       dDscr->addProperty (prop);
5256
5257       // add PROP_TSKID to profiling data (not same as omptrace's PROP_TSKID)
5258       prop = dDscr->getProp (PROP_TSKID);
5259       if (prop)
5260         {
5261           VType_type type = prop->vtype;
5262           assert (type == TYPE_OBJ); //see 7040526
5263         }
5264       prop = new PropDescr (PROP_TSKID, NTXT ("TSKID")); //profiling PROP_TSKID
5265       prop->uname = dbe_strdup (GTXT ("OpenMP task"));
5266       prop->vtype = TYPE_OBJ;
5267       dDscr->addProperty (prop);
5268     }
5269   char *progress_bar_msg = dbe_sprintf (NTXT ("%s %s: %s"), NTXT ("  "),
5270                                         GTXT ("Processing CallStack Data"),
5271                                         get_basename (expt_name));
5272   int progress_bar_percent = -1;
5273   long deltaReport = 5000;
5274   long nextReport = 0;
5275
5276   long size = dDscr->getSize ();
5277   //    bool resolve_frinfo_pipelined = size > FRINFO_PIPELINE_SIZE_LIMIT && !ompavail;
5278   bool resolve_frinfo_pipelined = false;
5279
5280   Map<uint64_t, uint64_t> *nodeCache = NULL;
5281   Map<uint64_t, uint64_t> *frameInfoCache = NULL;
5282   if (size > FRINFO_CACHEOPT_SIZE_LIMIT && dversion == NULL)
5283     {
5284       frameInfoCache = new CacheMap<uint64_t, uint64_t>;
5285       nodeCache = new CacheMap<uint64_t, uint64_t>;
5286     }
5287
5288   pushCnt = popCnt = pushCnt3 = popCnt3 = 0;
5289   nPush = nPop = 0;
5290
5291   FramePacket *fp = NULL;
5292   //    DbeThreadPool * threadPool = new DbeThreadPool(5);
5293   fp = new FramePacket;
5294   fp->stack = new Vector<Vaddr>;
5295   fp->jstack = new Vector<Vaddr>;
5296   fp->ompstack = new Vector<Vaddr>;
5297   fp->omp_state = 0;
5298   fp->mpi_state = 0;
5299
5300   // piggyback on post-processing to calculate exp->last_event
5301   const hrtime_t _exp_start_time = getStartTime (); // wall clock time
5302   hrtime_t exp_duration = getLastEvent () == ZERO_TIME ? 0
5303           : getLastEvent () - _exp_start_time; // zero-based
5304
5305   int missed_fi = 0;
5306   int total_fi = 0;
5307
5308   for (long i = 0; i < size; i++)
5309     {
5310       if (i == nextReport)
5311         {
5312           int percent = (int) (i * 100 / size);
5313           if (percent > progress_bar_percent)
5314             {
5315               progress_bar_percent += 10;
5316               theApplication->set_progress (percent, progress_bar_msg);
5317             }
5318           nextReport += deltaReport;
5319         }
5320
5321       uint32_t thrid = (uint32_t) dataThrId->fetchInt (i);
5322       hrtime_t tstamp = (hrtime_t) dataTStamp->fetchLong (i);
5323
5324       // piggyback on post-processing to calculate exp->last_event
5325       {
5326         hrtime_t relative_timestamp = tstamp - _exp_start_time;
5327         if (exp_duration < relative_timestamp)
5328           exp_duration = relative_timestamp;
5329       }
5330       uint64_t frinfo = (uint64_t) dataFrinfo->fetchLong (i);
5331
5332       RawFramePacket *rfp = NULL;
5333       if (frinfo)
5334         {
5335           // CacheMap does not work with NULL key
5336           if (frameInfoCache != NULL)
5337             rfp = (RawFramePacket *) frameInfoCache->get (frinfo);
5338         }
5339       if (rfp == 0)
5340         {
5341           rfp = find_frame_packet (frinfo);
5342           if (rfp != 0)
5343             {
5344               if (frameInfoCache != NULL)
5345                 frameInfoCache->put (frinfo, (uint64_t) rfp);
5346             }
5347           else
5348             missed_fi++;
5349           total_fi++;
5350         }
5351
5352       // Process OpenMP properties
5353       if (ompavail)
5354         {
5355           fp->omp_state = rfp ? rfp->omp_state : 0;
5356           dDscr->setValue (PROP_OMPSTATE, i, fp->omp_state);
5357
5358           fp->omp_cprid = mapPRid->get (thrid, tstamp, mapPRid->REL_EQLE);
5359           void *omp_preg = mapPReg->get (thrid, tstamp, mapPReg->REL_EQLE);
5360           if (!omp_preg)
5361             {
5362               char *idxname = NTXT ("OMP_preg");
5363               int idxtype = dbeSession->findIndexSpaceByName (idxname);
5364               if (idxtype != -1)
5365                 {
5366                   Histable *preg0 = dbeSession->findObjectById (Histable::INDEXOBJ, idxtype, (int64_t) 0);
5367                   if (preg0)
5368                     {
5369                       Vector<Histable*> pregs;
5370                       pregs.append (preg0);
5371                       omp_preg = cstack->add_stack (&pregs);
5372                       mapPReg->put (thrid, tstamp, omp_preg);
5373                     }
5374                 }
5375             }
5376           dDscr->setObjValue (PROP_CPRID, i, omp_preg); //profiling PROP_CPRID
5377           void *omp_task = mapTask->get (thrid, tstamp, mapTask->REL_EQLE);
5378           if (!omp_task)
5379             {
5380               char *idxname = NTXT ("OMP_task");
5381               int idxtype = dbeSession->findIndexSpaceByName (idxname);
5382               if (idxtype != -1)
5383                 {
5384                   Histable *task0 = dbeSession->findObjectById (Histable::INDEXOBJ, idxtype, (int64_t) 0);
5385                   if (task0)
5386                     {
5387                       Vector<Histable*> tasks;
5388                       tasks.append (task0);
5389                       omp_task = cstack->add_stack (&tasks);
5390                       mapTask->put (thrid, tstamp, omp_task);
5391                     }
5392                 }
5393             }
5394           dDscr->setObjValue (PROP_TSKID, i, omp_task); //profiling PROP_TSKID
5395         }
5396       else
5397         {
5398           fp->omp_state = 0;
5399           fp->omp_cprid = 0;
5400         }
5401
5402       // Construct the native stack
5403       fp->stack->reset ();
5404       Vaddr leafpc = dDscr->getULongValue (PROP_LEAFPC, i);
5405       if (leafpc)
5406         fp->stack->append (leafpc);
5407       UIDnode *node = rfp ? rfp->uidn : NULL;
5408       while (node)
5409         {
5410           if (node->next == node)
5411             // this node contains link_uid
5412             node = find_uid_node (node->uid);
5413           else
5414             {
5415               fp->stack->append (node->val);
5416               node = node->next;
5417             }
5418         }
5419       fp->truncated = 0;
5420       int last = fp->stack->size () - 1;
5421       if (last >= 0)
5422         {
5423           switch (fp->stack->fetch (last))
5424             {
5425             case SP_TRUNC_STACK_MARKER:
5426               fp->truncated = (Vaddr) SP_TRUNC_STACK_MARKER;
5427               fp->stack->remove (last);
5428               break;
5429             case SP_FAILED_UNWIND_MARKER:
5430               fp->truncated = (Vaddr) SP_FAILED_UNWIND_MARKER;
5431               fp->stack->remove (last);
5432               break;
5433             }
5434         }
5435
5436       // Construct the Java stack
5437       fp->jstack->reset ();
5438       node = rfp ? rfp->uidj : NULL;
5439       while (node)
5440         {
5441           if (node->next == node)
5442             {
5443               // this node contains link_uid
5444               UIDnode *n = NULL;
5445               if (node->uid)
5446                 {
5447                   // CacheMap does not work with NULL key
5448                   if (nodeCache != NULL)
5449                     n = (UIDnode *) nodeCache->get (node->uid);
5450                 }
5451               if (n == NULL)
5452                 {
5453                   n = find_uid_node (node->uid);
5454                   if (n != NULL)
5455                     {
5456                       if (nodeCache != NULL)
5457                         nodeCache->put (node->uid, (uint64_t) n);
5458                     }
5459                 }
5460               node = n;
5461             }
5462           else
5463             {
5464               fp->jstack->append (node->val);
5465               node = node->next;
5466             }
5467         }
5468       fp->jtruncated = false;
5469       last = fp->jstack->size () - 1;
5470       if (last >= 1 && fp->jstack->fetch (last) == SP_TRUNC_STACK_MARKER)
5471         {
5472           fp->jtruncated = true;
5473           fp->jstack->remove (last);
5474           fp->jstack->remove (last - 1);
5475         }
5476
5477       // Construct the OpenMP stack
5478       if (ompavail)
5479         {
5480           fp->ompstack->reset ();
5481           if (rfp && rfp->omp_uid)
5482             {
5483               if (leafpc)
5484                 fp->ompstack->append (leafpc);
5485               node = rfp->omp_uid;
5486               while (node)
5487                 {
5488                   if (node->next == node)
5489                     // this node contains link_uid
5490                     node = find_uid_node (node->uid);
5491                   else
5492                     {
5493                       fp->ompstack->append (node->val);
5494                       node = node->next;
5495                     }
5496                 }
5497               fp->omptruncated = false;
5498               last = fp->ompstack->size () - 1;
5499               if (last >= 0)
5500                 {
5501                   switch (fp->ompstack->fetch (last))
5502                     {
5503                     case SP_TRUNC_STACK_MARKER:
5504                       fp->omptruncated = (Vaddr) SP_TRUNC_STACK_MARKER;
5505                       fp->ompstack->remove (last);
5506                       break;
5507                     case SP_FAILED_UNWIND_MARKER:
5508                       fp->omptruncated = (Vaddr) SP_FAILED_UNWIND_MARKER;
5509                       fp->ompstack->remove (last);
5510                       break;
5511                     }
5512                 }
5513             }
5514         }
5515       cstack->add_stack (dDscr, i, fp, NULL);
5516     }
5517
5518   // piggyback on post-processing to calculate exp->last_event
5519   {
5520     hrtime_t exp_end_time = _exp_start_time + exp_duration;
5521     update_last_event (exp_end_time);
5522   }
5523
5524   if (missed_fi > 0)
5525     {
5526       StringBuilder sb;
5527       sb.sprintf (
5528                   GTXT ("*** Warning: %d frameinfo packets are missing from total of %d when resolving %s."),
5529                   missed_fi, total_fi, dDscr->getName ());
5530       warnq->append (new Emsg (CMSG_WARN, sb));
5531     }
5532
5533   //    threadPool->wait_group();
5534   //    delete threadPool;
5535   theApplication->set_progress (0, NTXT (""));
5536   free (progress_bar_msg);
5537   if (!resolve_frinfo_pipelined && fp != NULL)
5538     {
5539       delete fp->ompstack;
5540       delete fp->jstack;
5541       delete fp->stack;
5542       delete fp;
5543     }
5544   delete frameInfoCache;
5545   frameInfoCache = NULL;
5546   delete nodeCache;
5547   nodeCache = NULL;
5548 }
5549
5550 void
5551 Experiment::post_process ()
5552 {
5553   // update non_paused_time after final update to "last_event"
5554   if (resume_ts != MAX_TIME && last_event)
5555     {
5556       hrtime_t ts = last_event - exp_start_time;
5557       hrtime_t delta = ts - resume_ts;
5558       non_paused_time += delta;
5559       resume_ts = MAX_TIME; // collection is paused
5560     }
5561
5562   // GC: prune events outside of experiment duration, calculate GC duration, update indices
5563   int index;
5564   GCEvent * gcevent;
5565   gc_duration = ZERO_TIME;
5566   if (gcevents != NULL)
5567     {
5568       // delete events that finish before exp_start_time or start after last_event
5569       for (int ii = 0; ii < gcevents->size ();)
5570         {
5571           gcevent = gcevents->fetch (ii);
5572           if (gcevent->end - exp_start_time < 0
5573               || last_event - gcevent->start < 0)
5574             delete gcevents->remove (ii);
5575           else
5576             ii++;
5577         }
5578     }
5579   Vec_loop (GCEvent*, gcevents, index, gcevent)
5580   {
5581     gcevent->id = index + 1; // renumber to account for any deleted events
5582     if (gcevent->start - exp_start_time < 0 || gcevent->start == ZERO_TIME)
5583       // truncate events that start before experiment start
5584       gcevent->start = exp_start_time;
5585     if (last_event - gcevent->end < 0)
5586       // truncate events that end after experiment end
5587       gcevent->end = last_event;
5588     gc_duration += gcevent->end - gcevent->start;
5589   }
5590 }
5591
5592 Experiment::Exp_status
5593 Experiment::find_expdir (char *path)
5594 {
5595   // This function checks that the experiment directory
5596   // is of the proper form, and accessible
5597   struct stat64 sbuf;
5598
5599   // Save the name
5600   expt_name = dbe_strdup (path);
5601
5602   // Check that the name ends in .er
5603   size_t i = strlen (path);
5604   if (i > 0 && path[i - 1] == '/')
5605     path[--i] = '\0';
5606
5607   if (i < 4 || strcmp (&path[i - 3], NTXT (".er")) != 0)
5608     {
5609       Emsg *m = new Emsg (CMSG_FATAL,
5610                           GTXT ("*** Error: not a valid experiment name"));
5611       errorq->append (m);
5612       status = FAILURE;
5613       return FAILURE;
5614     }
5615
5616   // Check if new directory structure (i.e., no pointer file)
5617   if (dbe_stat (path, &sbuf))
5618     {
5619       Emsg *m = new Emsg (CMSG_FATAL, GTXT ("*** Error: experiment not found"));
5620       errorq->append (m);
5621       status = FAILURE;
5622       return FAILURE;
5623     }
5624   if (S_ISDIR (sbuf.st_mode) == 0)
5625     {
5626       // ignore pointer-file experiments
5627       Emsg *m = new Emsg (CMSG_FATAL,
5628                           GTXT ("*** Error: experiment was recorded with an earlier version, and can not be read"));
5629       errorq->append (m);
5630       obsolete = 1;
5631       status = FAILURE;
5632       return FAILURE;
5633     }
5634   return SUCCESS;
5635 }
5636
5637 void
5638 Experiment::purge ()
5639 {
5640   // This routine will purge all of the caches of releasable storage.
5641   for (int i = 0; i < dataDscrs->size (); ++i)
5642     {
5643       DataDescriptor *dataDscr = dataDscrs->fetch (i);
5644       if (dataDscr == NULL)
5645         continue;
5646       dataDscr->reset ();
5647     }
5648   delete cstack;
5649   delete cstackShowHide;
5650   cstack = CallStack::getInstance (this);
5651   cstackShowHide = CallStack::getInstance (this);
5652 }
5653
5654 void
5655 Experiment::resetShowHideStack ()
5656 {
5657   delete cstackShowHide;
5658   cstackShowHide = CallStack::getInstance (this);
5659 }
5660
5661 #define GET_INT_VAL(v, s, len) \
5662     for (v = len = 0; isdigit(*s); s++, len++) { v = v * 10 + (*s -'0'); }
5663
5664 static int
5665 dir_name_cmp (const void *a, const void *b)
5666 {
5667   char *s1 = *((char **) a);
5668   char *s2 = *((char **) b);
5669   while (*s1)
5670     {
5671       if (isdigit (*s1) && isdigit (*s2))
5672         {
5673           int v1, v2, len1, len2;
5674           GET_INT_VAL (v1, s1, len1);
5675           GET_INT_VAL (v2, s2, len2);
5676           if (v1 != v2)
5677             return v1 - v2;
5678           if (len1 != len2)
5679             return len2 - len1;
5680           continue;
5681         }
5682       if (*s1 != *s2)
5683         break;
5684       s1++;
5685       s2++;
5686     }
5687   return *s1 - *s2;
5688 }
5689
5690 Vector<char*> *
5691 Experiment::get_descendants_names ()
5692 {
5693   char *dir_name = get_expt_name ();
5694   if (dir_name == NULL)
5695     return NULL;
5696   DIR *exp_dir = opendir (dir_name);
5697   if (exp_dir == NULL)
5698     return NULL;
5699   Vector<char*> *exp_names = new Vector<char*>();
5700   for (struct dirent *entry = readdir (exp_dir); entry;
5701           entry = readdir (exp_dir))
5702     {
5703       if (entry->d_name[0] == '_' || strncmp (entry->d_name, "M_r", 3) == 0)
5704         {
5705           char *dpath = dbe_sprintf (NTXT ("%s/%s"), dir_name, entry->d_name);
5706           struct stat64 sbuf;
5707           if (dbe_stat (dpath, &sbuf) == 0 && S_ISDIR (sbuf.st_mode))
5708             exp_names->append (dpath);
5709           else
5710             free (dpath);
5711         }
5712     }
5713   closedir (exp_dir);
5714   if (exp_names->size () == 0)
5715     {
5716       delete exp_names;
5717       return NULL;
5718     }
5719   exp_names->sort (dir_name_cmp);
5720   return exp_names;
5721 }
5722
5723 bool
5724 Experiment::create_dir (char *dname)
5725 {
5726   if (mkdir (dname, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) == 0)
5727     {
5728       return true;
5729     }
5730   struct stat64 sbuf;
5731   if (dbe_stat (dname, &sbuf) != 0 || S_ISDIR (sbuf.st_mode) == 0)
5732     {
5733       char *buf = dbe_sprintf (GTXT ("Unable to create directory `%s'\n"),
5734                                dname);
5735       errorq->append (new Emsg (CMSG_ERROR, buf));
5736       free (buf);
5737       return false;
5738     }
5739   return true;
5740 }
5741
5742 char *
5743 Experiment::get_arch_name ()
5744 {
5745   if (arch_name == NULL)
5746     {
5747       // Determine the master experiment directory.
5748       // omazur: should do it in a less hacky way. XXXX
5749       char *ptr = strstr_r (expt_name, DESCENDANT_EXPT_KEY);
5750       ptr = ptr ? ptr + 3 : expt_name + strlen (expt_name);
5751       arch_name = dbe_sprintf (NTXT ("%.*s/%s"), (int) (ptr - expt_name),
5752                                expt_name, SP_ARCHIVES_DIR);
5753     }
5754   return arch_name;
5755 }
5756
5757 char *
5758 Experiment::get_fndr_arch_name ()
5759 {
5760   if (fndr_arch_name == NULL)
5761     // Determine the founder experiment directory.
5762     fndr_arch_name = dbe_strdup (get_arch_name ());
5763   return fndr_arch_name;
5764 }
5765
5766 enum
5767 {
5768   HASH_NAME_LEN     = 11    // (64 / 6 + 1) = 11
5769 };
5770
5771 static char *
5772 get_hash_string (char buf[HASH_NAME_LEN + 1], uint64_t hash)
5773 {
5774   static const char *har =
5775           "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-_";
5776   for (int i = 0; i < HASH_NAME_LEN; i++)
5777     {
5778       buf[i] = har[hash & 0x3f];
5779       hash = hash >> 6;
5780     }
5781   buf[HASH_NAME_LEN] = 0;
5782   return buf;
5783 }
5784
5785 char *
5786 Experiment::getNameInArchive (const char *fname, bool archiveFile)
5787 {
5788   char *aname = get_archived_name (fname, archiveFile);
5789   char *ret = dbe_sprintf (NTXT ("%s/%s"), get_arch_name (), aname);
5790   free (aname);
5791   return ret;
5792 }
5793
5794 #define MAX_ARCHIVE_FILENAME_LEN    (256 - HASH_NAME_LEN - 2)
5795
5796 char *
5797 Experiment::get_archived_name (const char *fname, bool archiveFile)
5798 {
5799   char *bname = get_basename (fname);
5800
5801   // dirname_hash:
5802   char dirnameHash[HASH_NAME_LEN + 1];
5803   // Treat "a.out" and "./a.out" equally
5804   uint64_t hash = bname != fname ? crc64 (fname, bname - fname)
5805                                  : crc64 (NTXT ("./"), 2);
5806   get_hash_string (dirnameHash, hash);
5807
5808   char *ret;
5809   long bname_len = dbe_sstrlen (bname);
5810   if (bname_len > MAX_ARCHIVE_FILENAME_LEN)
5811     {
5812       char basenameHash[HASH_NAME_LEN + 1];
5813       hash = crc64 (bname, bname_len);
5814       get_hash_string (basenameHash, hash);
5815       ret = dbe_sprintf ("%.*s%c%s_%s",
5816                          MAX_ARCHIVE_FILENAME_LEN - HASH_NAME_LEN - 1,
5817                          bname, archiveFile ? '.' : '_',
5818                          dirnameHash, basenameHash);
5819     }
5820   else
5821     ret = dbe_sprintf ("%s%c%s", bname, archiveFile ? '.' : '_', dirnameHash);
5822   return ret;
5823 }
5824
5825 char *
5826 Experiment::checkFileInArchive (const char *fname, bool archiveFile)
5827 {
5828   if (archiveMap)
5829     {
5830       char *aname = get_archived_name (fname, archiveFile);
5831       DbeFile *df = archiveMap->get (aname);
5832       free (aname);
5833       if (df)
5834         return strdup (df->get_location ());
5835       return NULL;
5836     }
5837   if (founder_exp)
5838     return founder_exp->checkFileInArchive (fname, archiveFile);
5839   return NULL;
5840 }
5841
5842
5843 // Comparing SegMem
5844
5845 static int
5846 SegMemCmp (const void *a, const void *b)
5847 {
5848   SegMem *item1 = *((SegMem **) a);
5849   SegMem *item2 = *((SegMem **) b);
5850   return item1->unload_time > item2->unload_time ? 1 :
5851          item1->unload_time == item2->unload_time ? 0 : -1;
5852 }
5853
5854 SegMem*
5855 Experiment::update_ts_in_maps (Vaddr addr, hrtime_t ts)
5856 {
5857   Vector<SegMem *> *segMems = (Vector<SegMem *> *) maps->values ();
5858   if (!segMems->is_sorted ())
5859     {
5860       Dprintf (DEBUG_MAPS, NTXT ("update_ts_in_maps: segMems.size=%lld\n"), (long long) segMems->size ());
5861       segMems->sort (SegMemCmp);
5862     }
5863   for (int i = 0, sz = segMems ? segMems->size () : 0; i < sz; i++)
5864     {
5865       SegMem *sm = segMems->fetch (i);
5866       if (ts < sm->unload_time)
5867         {
5868           for (; i < sz; i++)
5869             {
5870               sm = segMems->fetch (i);
5871               if ((addr >= sm->base) && (addr < sm->base + sm->size))
5872                 {
5873                   Dprintf (DEBUG_MAPS,
5874                            "update_ts_in_maps: old:%u.%09u -> %u.%09u addr=0x%08llx size=%lld\n",
5875                            (unsigned) (sm->load_time / NANOSEC),
5876                            (unsigned) (sm->load_time % NANOSEC),
5877                            (unsigned) (ts / NANOSEC), (unsigned) (ts % NANOSEC),
5878                            (unsigned long long) sm->base, (long long) sm->size);
5879                   maps->remove (sm->base, sm->load_time);
5880                   sm->load_time = ts;
5881                   maps->insert (sm->base, ts, sm);
5882                   return sm;
5883                 }
5884             }
5885         }
5886     }
5887   Dprintf (DEBUG_MAPS, "update_ts_in_maps: NOT FOUND %u.%09u addr=0x%08llx\n",
5888            (unsigned) (ts / NANOSEC), (unsigned) (ts % NANOSEC),
5889            (unsigned long long) addr);
5890   return NULL;
5891 }
5892
5893 DbeInstr*
5894 Experiment::map_Vaddr_to_PC (Vaddr addr, hrtime_t ts)
5895 {
5896   // Look up in the hash table first
5897   int hash = (((int) addr) >> 8) & (HTableSize - 1);
5898   SegMem *si = smemHTable[hash];
5899   if (si == NULL || addr < si->base || addr >= si->base + si->size
5900       || ts < si->load_time || ts >= si->unload_time)
5901     {
5902       // Not in the hash table
5903       si = (SegMem*) maps->locate (addr, ts);
5904       if (si == NULL || addr < si->base || addr >= si->base + si->size
5905           || ts < si->load_time || ts >= si->unload_time)
5906         {
5907           si = update_ts_in_maps (addr, ts);
5908           if (si == NULL)
5909             return dbeSession->get_Unknown_Function ()->find_dbeinstr (PCInvlFlag, addr);
5910         }
5911       smemHTable[hash] = si;
5912     }
5913
5914   // Calculate the file offset of 'addr'
5915   uint64_t f_offset = si->get_file_offset () + (addr - si->base);
5916
5917   DbeInstr *instr;
5918   if (si->obj->get_type () == Histable::LOADOBJECT)
5919     {
5920       LoadObject *lo = (LoadObject*) si->obj;
5921       lo->sync_read_stabs ();
5922       instr = lo->find_dbeinstr (f_offset);
5923     }
5924   else
5925     {
5926       int hash2 = ((((int) addr) & 0xFFFC00) | (((int) f_offset) >> 2))
5927               & (HTableSize - 1);
5928       instr = instHTable[hash2];
5929       if (instr == NULL || instr->func != si->obj || instr->addr != f_offset)
5930         {
5931           // Not in the hash table
5932           Function *fp = (Function *) si->obj;
5933           instr = fp->find_dbeinstr (0, f_offset);
5934           instHTable[hash2] = instr;
5935         }
5936     }
5937   if (!instr->func->isUsed)
5938     {
5939       instr->func->isUsed = true;
5940       instr->func->module->isUsed = true;
5941       instr->func->module->loadobject->isUsed = true;
5942     }
5943   return instr;
5944 }
5945
5946 Sample *
5947 Experiment::map_event_to_Sample (hrtime_t ts)
5948 {
5949   Sample *sample;
5950   int index;
5951
5952   // Check if the last used sample is the right one,
5953   // if not then find it.
5954   if (sample_last_used && ts >= sample_last_used->start_time
5955       && ts <= sample_last_used->end_time)
5956     return sample_last_used;
5957
5958   Vec_loop (Sample*, samples, index, sample)
5959   {
5960     if ((ts >= sample->start_time) &&
5961         (ts <= sample->end_time))
5962       {
5963         sample_last_used = sample;
5964         return sample;
5965       }
5966   }
5967   return (Sample*) NULL;
5968 }
5969
5970 GCEvent *
5971 Experiment::map_event_to_GCEvent (hrtime_t ts)
5972 {
5973   GCEvent *gcevent;
5974   int index;
5975
5976   // Check if the last used sample is the right one,
5977   // if not then find it.
5978   if (gcevent_last_used && ts >= gcevent_last_used->start
5979       && ts <= gcevent_last_used->end)
5980     return gcevent_last_used;
5981   Vec_loop (GCEvent*, gcevents, index, gcevent)
5982   {
5983     if ((ts >= gcevent->start) &&
5984         (ts <= gcevent->end))
5985       {
5986         gcevent_last_used = gcevent;
5987         return gcevent;
5988       }
5989   }
5990   return (GCEvent*) NULL;
5991 }
5992
5993 DbeInstr*
5994 Experiment::map_jmid_to_PC (Vaddr mid, int bci, hrtime_t ts)
5995 {
5996   if (mid == 0 || jmaps == NULL)
5997     // special case: no Java stack was recorded, bci - error code
5998     return dbeSession->get_JUnknown_Function ()->find_dbeinstr (0, bci);
5999
6000   JMethod *jmthd = jmidHTable->get (mid);
6001   if (jmthd == NULL)
6002     {
6003       jmthd = (JMethod *) jmaps->locate_exact_match (mid, ts);
6004       if (jmthd)
6005         jmidHTable->put (mid, jmthd);
6006     }
6007   if (jmthd == NULL || jmthd->get_type () != Histable::FUNCTION)
6008     return dbeSession->get_JUnknown_Function ()->find_dbeinstr (0, (uint64_t) mid);
6009   return jmthd->find_dbeinstr (0, bci);
6010 }
6011
6012 Emsg *
6013 Experiment::fetch_comments ()
6014 {
6015   return commentq->fetch ();
6016 }
6017
6018 Emsg *
6019 Experiment::fetch_runlogq ()
6020 {
6021   return runlogq->fetch ();
6022 }
6023
6024 Emsg *
6025 Experiment::fetch_errors ()
6026 {
6027   return errorq->fetch ();
6028 }
6029
6030 Emsg *
6031 Experiment::fetch_warnings ()
6032 {
6033   return warnq->fetch ();
6034 }
6035
6036 Emsg *
6037 Experiment::fetch_notes ()
6038 {
6039   return notesq->fetch ();
6040 }
6041
6042 Emsg *
6043 Experiment::fetch_ifreq ()
6044 {
6045   return ifreqq->fetch ();
6046 }
6047
6048 Emsg *
6049 Experiment::fetch_pprocq ()
6050 {
6051   return pprocq->fetch ();
6052 }
6053
6054 int
6055 Experiment::read_dyntext_file ()
6056 {
6057   dyntext_name = dbe_sprintf ("%s/%s", expt_name, SP_DYNTEXT_FILE);
6058   Data_window *dwin = new Data_window (dyntext_name);
6059   if (dwin->not_opened ())
6060     {
6061       delete dwin;
6062       return 1;
6063     }
6064   dwin->need_swap_endian = need_swap_endian;
6065
6066   Function *fp = NULL;
6067   char *progress_msg = NULL; // Message for the progress bar
6068   for (int64_t offset = 0;;)
6069     {
6070       DT_common *cpckt = (DT_common *) dwin->bind (offset, sizeof (DT_common));
6071       if (cpckt == NULL)
6072         break;
6073       size_t cpcktsize = dwin->decode (cpckt->size);
6074       cpckt = (DT_common *) dwin->bind (offset, cpcktsize);
6075       if (cpckt == NULL)
6076         break;
6077       switch (dwin->decode (cpckt->type))
6078         {
6079         case DT_HEADER:
6080           {
6081             DT_header *hdr = (DT_header*) cpckt;
6082             hrtime_t ts = dwin->decode (hdr->time) + exp_start_time;
6083             SegMem *si = (SegMem*) maps->locate (dwin->decode (hdr->vaddr), ts);
6084             fp = si ? (Function *) si->obj : NULL;
6085             if (fp && (fp->get_type () != Histable::FUNCTION
6086                        || !(fp->flags & FUNC_FLAG_DYNAMIC)))
6087               fp = NULL;
6088             break;
6089           }
6090         case DT_CODE:
6091           if (fp)
6092             {
6093               fp->img_fname = dyntext_name;
6094               fp->img_offset = offset + sizeof (DT_common);
6095               if ((platform != Intel) && (platform != Amd64))
6096                 { //ARCH(SPARC)
6097                   // Find out 'save' instruction address for SPARC
6098                   char *ptr = ((char*) cpckt) + sizeof (DT_common);
6099                   size_t img_size = cpcktsize - sizeof (DT_common);
6100                   for (size_t i = 0; i < img_size; i += 4)
6101                     if (ptr[i] == (char) 0x9d && ptr[i + 1] == (char) 0xe3)
6102                       {
6103                         fp->save_addr = i;
6104                         break;
6105                       }
6106                 }
6107             }
6108           break;
6109         case DT_SRCFILE:
6110           if (fp)
6111             {
6112               char *srcname = dbe_strndup (((char*) cpckt) + sizeof (DT_common),
6113                                            cpcktsize - sizeof (DT_common));
6114               LoadObject *ds = fp->module ? fp->module->loadobject : NULL;
6115               assert (ds != NULL);
6116               Module *mod = dbeSession->createModule (ds, NULL);
6117               mod->set_file_name (srcname);
6118               //}
6119               if (fp->module)
6120                 {
6121                   // It's most likely (unknown). Remove fp from it.
6122                   long idx = fp->module->functions->find (fp);
6123                   if (idx >= 0)
6124                     fp->module->functions->remove (idx);
6125                 }
6126               fp->module = mod;
6127               mod->functions->append (fp);
6128             }
6129           break;
6130         case DT_LTABLE:
6131           if (fp)
6132             {
6133               DT_lineno *ltab = (DT_lineno*) ((char*) cpckt + sizeof (DT_common));
6134               size_t sz = (cpcktsize - sizeof (DT_common)) / sizeof (DT_lineno);
6135               if (sz <= 0)
6136                 break;
6137               // Take care of the progress bar
6138               static int percent = 0;
6139               static long deltaReport = sz / 100; // 1000;
6140               static long nextReport = 0;
6141               static long progress_count = 0;
6142               fp->pushSrcFile (fp->getDefSrc (), 0);
6143               for (size_t i = 0; i < sz; i++)
6144                 {
6145                   int lineno = dwin->decode (ltab[i].lineno);
6146                   if (fp->usrfunc != NULL)
6147                     {
6148                       // Update progress bar
6149                       if (dbeSession->is_interactive ())
6150                         {
6151                           if (progress_count == nextReport)
6152                             {
6153                               if (percent < 99)
6154                                 {
6155                                   percent++;
6156                                   if (NULL == progress_msg)
6157                                     {
6158                                       progress_msg = dbe_sprintf (GTXT ("Processing Dynamic Text: %s"),
6159                                                                   get_basename (expt_name));
6160                                     }
6161                                   theApplication->set_progress (percent, progress_msg);
6162                                   nextReport += deltaReport;
6163                                 }
6164                             }
6165                           progress_count++;
6166                         }
6167                       DbeLine *dbeline = fp->usrfunc->mapPCtoLine (lineno, NULL);
6168                       lineno = dbeline != NULL ? dbeline->lineno : -1;
6169                     }
6170                   fp->add_PC_info (dwin->decode (ltab[i].offset), lineno);
6171                 }
6172               fp->popSrcFile ();
6173             }
6174           break;
6175         default:
6176           // skip unknown records
6177           break;
6178         }
6179       offset += cpcktsize;
6180     }
6181   free (progress_msg);
6182   delete dwin;
6183   return 0;
6184 }
6185
6186 uint32_t
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*> *
6251 Experiment::getTagObjs (Prop_type prop)
6252 {
6253   return tagObjs->fetch (prop);
6254 }
6255
6256 Histable *
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 *
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*
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 *
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*> *
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 *
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 *
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 *
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
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
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
6414 Experiment::dump_stacks (FILE *outfile)
6415 {
6416   cstack->print (outfile);
6417 }
6418
6419 void
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
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
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
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 *
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 *
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 *
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*> *
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 *
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 *
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 }
This page took 0.408941 seconds and 4 git commands to generate.