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