|  | /* Copyright (C) 2021-2025 Free Software Foundation, Inc. | 
|  | Contributed by Oracle. | 
|  |  | 
|  | This file is part of GNU Binutils. | 
|  |  | 
|  | This program is free software; you can redistribute it and/or modify | 
|  | it under the terms of the GNU General Public License as published by | 
|  | the Free Software Foundation; either version 3, or (at your option) | 
|  | any later version. | 
|  |  | 
|  | This program is distributed in the hope that it will be useful, | 
|  | but WITHOUT ANY WARRANTY; without even the implied warranty of | 
|  | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
|  | GNU General Public License for more details. | 
|  |  | 
|  | You should have received a copy of the GNU General Public License | 
|  | along with this program; if not, write to the Free Software | 
|  | Foundation, 51 Franklin Street - Fifth Floor, Boston, | 
|  | MA 02110-1301, USA.  */ | 
|  |  | 
|  | #include "config.h" | 
|  | #include <errno.h> | 
|  | #include <utime.h> | 
|  | #include <alloca.h> | 
|  | #include <dirent.h> | 
|  | #include <ctype.h> | 
|  | #include <unistd.h> | 
|  | #include <stdio.h> | 
|  | #include <stdlib.h> | 
|  | #include <sys/param.h> | 
|  | #include <set> | 
|  |  | 
|  | #include "util.h" | 
|  | #include "CacheMap.h" | 
|  | #include "DbeFile.h" | 
|  | #include "DbeCacheMap.h" | 
|  | #include "DefaultHandler.h" | 
|  | #include "DefaultMap2D.h" | 
|  | #include "Emsg.h" | 
|  | #include "Elf.h" | 
|  | #include "SAXParser.h" | 
|  | #include "SAXParserFactory.h" | 
|  | #include "StringBuilder.h" | 
|  | #include "DbeSession.h" | 
|  | #include "DbeThread.h" | 
|  | #include "Application.h" | 
|  | #include "CallStack.h" | 
|  | #include "Experiment.h" | 
|  | #include "Exp_Layout.h" | 
|  | #include "DataStream.h" | 
|  | #include "Expression.h" | 
|  | #include "Function.h" | 
|  | #include "HeapMap.h" | 
|  | #include "LoadObject.h" | 
|  | #include "Module.h" | 
|  | #include "Ovw_data.h" | 
|  | #include "PRBTree.h" | 
|  | #include "Sample.h" | 
|  | #include "SegMem.h" | 
|  | #include "StringMap.h" | 
|  | #include "UserLabel.h" | 
|  | #include "Table.h" | 
|  | #include "dbe_types.h" | 
|  | #include "FileData.h" | 
|  | #include "cc_libcollector.h" | 
|  | #include "ExpGroup.h" | 
|  |  | 
|  | int nPush; | 
|  | int nPop; | 
|  | int pushCnt; | 
|  | int popCnt; | 
|  | int pushCnt3; | 
|  | int popCnt3; | 
|  |  | 
|  | struct Experiment::UIDnode | 
|  | { | 
|  | uint64_t uid; | 
|  | uint64_t val; | 
|  | UIDnode *next; | 
|  | }; | 
|  |  | 
|  | struct Experiment::RawFramePacket | 
|  | { | 
|  | uint64_t uid; | 
|  | UIDnode *uidn; | 
|  | UIDnode *uidj; | 
|  | UIDnode *omp_uid; | 
|  | uint32_t omp_state; | 
|  | }; | 
|  |  | 
|  | static hrtime_t | 
|  | parseTStamp (const char *s) | 
|  | { | 
|  | hrtime_t ts = (hrtime_t) 0; | 
|  | ts = (hrtime_t) atoi (s) * NANOSEC; | 
|  | s = strchr (s, '.'); | 
|  | if (s != NULL) | 
|  | ts += (hrtime_t) atoi (s + 1); | 
|  | return ts; | 
|  | } | 
|  |  | 
|  | class Experiment::ExperimentFile | 
|  | { | 
|  | public: | 
|  |  | 
|  | enum | 
|  | { | 
|  | EF_NOT_OPENED, | 
|  | EF_OPENED, | 
|  | EF_CLOSED, | 
|  | EF_FAILURE | 
|  | }; | 
|  |  | 
|  | ExperimentFile (Experiment *_exp, const char *_fname); | 
|  | ~ExperimentFile (); | 
|  |  | 
|  | bool open (bool new_open = false); | 
|  |  | 
|  | char * | 
|  | get_name () | 
|  | { | 
|  | return fname; | 
|  | } | 
|  |  | 
|  | inline int | 
|  | get_status () | 
|  | { | 
|  | return ef_status; | 
|  | } | 
|  |  | 
|  | char *fgets (); | 
|  | void close (); | 
|  |  | 
|  | FILE *fh; | 
|  |  | 
|  | private: | 
|  | Experiment *exp; | 
|  | char *fname; | 
|  | off64_t offset; | 
|  | int bufsz, ef_status; | 
|  | char *buffer; | 
|  | }; | 
|  |  | 
|  | class Experiment::ExperimentHandler : public DefaultHandler | 
|  | { | 
|  | public: | 
|  |  | 
|  | ExperimentHandler (Experiment *_exp); | 
|  | ~ExperimentHandler (); | 
|  |  | 
|  | void | 
|  | startDocument () { } | 
|  | void endDocument (); | 
|  | void startElement (char *uri, char *localName, char *qName, Attributes *attrs); | 
|  | void endElement (char *uri, char *localName, char *qName); | 
|  | void characters (char *ch, int start, int length); | 
|  |  | 
|  | void | 
|  | ignorableWhitespace (char*, int, int) { } | 
|  | void | 
|  | error (SAXParseException *e); | 
|  |  | 
|  | private: | 
|  |  | 
|  | enum Element | 
|  | { | 
|  | EL_NONE, | 
|  | EL_EXPERIMENT, | 
|  | EL_COLLECTOR, | 
|  | EL_SETTING, | 
|  | EL_PROCESS, | 
|  | EL_SYSTEM, | 
|  | EL_EVENT, | 
|  | EL_PROFILE, | 
|  | EL_DATAPTR, | 
|  | EL_PROFDATA, | 
|  | EL_PROFPCKT, | 
|  | EL_FIELD, | 
|  | EL_CPU, | 
|  | EL_STATE, | 
|  | EL_FREQUENCY, | 
|  | EL_POWERM, | 
|  | EL_DTRACEFATAL | 
|  | }; | 
|  |  | 
|  | static int toInt (Attributes *attrs, const char *atr); | 
|  | static char*toStr (Attributes *attrs, const char *atr); | 
|  | void pushElem (Element); | 
|  | void popElem (); | 
|  |  | 
|  | Experiment *exp; | 
|  | Element curElem; | 
|  | Vector<Element> *stack; | 
|  | Module *dynfuncModule; | 
|  | DataDescriptor *dDscr; | 
|  | PacketDescriptor *pDscr; | 
|  | PropDescr *propDscr; | 
|  | char *text; | 
|  | Cmsg_warn mkind; | 
|  | int mnum; | 
|  | int mec; | 
|  | }; | 
|  |  | 
|  |  | 
|  | // HTableSize is the size of smemHTable and instHTable | 
|  | // omazur: both HTableSize and the hash function haven't been tuned; | 
|  | static const int HTableSize = 8192; | 
|  |  | 
|  | //-------------------------------------------------- Experiment file handler | 
|  |  | 
|  | Experiment::ExperimentFile::ExperimentFile (Experiment *_exp, const char *_fname) | 
|  | { | 
|  | exp = _exp; | 
|  | fh = NULL; | 
|  | bufsz = 0; | 
|  | buffer = NULL; | 
|  | ef_status = EF_NOT_OPENED; | 
|  | offset = 0; | 
|  | fname = dbe_sprintf (NTXT ("%s/%s"), exp->expt_name, _fname); | 
|  | } | 
|  |  | 
|  | Experiment::ExperimentFile::~ExperimentFile () | 
|  | { | 
|  | close (); | 
|  | free (buffer); | 
|  | free (fname); | 
|  | } | 
|  |  | 
|  | bool | 
|  | Experiment::ExperimentFile::open (bool new_open) | 
|  | { | 
|  | if (fh == NULL) | 
|  | { | 
|  | fh = fopen64 (fname, NTXT ("r")); | 
|  | if (fh == NULL) | 
|  | { | 
|  | ef_status = EF_FAILURE; | 
|  | return false; | 
|  | } | 
|  | ef_status = EF_OPENED; | 
|  | if (new_open) | 
|  | offset = 0; | 
|  | if (offset != 0) | 
|  | fseeko64 (fh, offset, SEEK_SET); | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | char * | 
|  | Experiment::ExperimentFile::fgets () | 
|  | { | 
|  | if (bufsz == 0) | 
|  | { | 
|  | bufsz = 1024; | 
|  | buffer = (char *) xmalloc (bufsz); | 
|  | buffer[bufsz - 1] = (char) 1; // sentinel | 
|  | } | 
|  | char *res = ::fgets (buffer, bufsz, fh); | 
|  | if (res == NULL) | 
|  | return NULL; | 
|  | while (buffer[bufsz - 1] == (char) 0) | 
|  | { | 
|  | int newsz = bufsz + 1024; | 
|  | char *newbuf = (char *) xmalloc (newsz); | 
|  | memcpy (newbuf, buffer, bufsz); | 
|  | free (buffer); | 
|  | buffer = newbuf; | 
|  | buffer[newsz - 1] = (char) 1; // sentinel | 
|  | // we don't care about fgets result here | 
|  | ::fgets (buffer + bufsz - 1, newsz - bufsz + 1, fh); | 
|  | bufsz = newsz; | 
|  | } | 
|  | return buffer; | 
|  | } | 
|  |  | 
|  | void | 
|  | Experiment::ExperimentFile::close () | 
|  | { | 
|  | if (fh) | 
|  | { | 
|  | offset = ftello64 (fh); | 
|  | fclose (fh); | 
|  | ef_status = EF_CLOSED; | 
|  | fh = NULL; | 
|  | } | 
|  | } | 
|  |  | 
|  |  | 
|  | //-------------------------------------------------- Experiment XML parser | 
|  | int | 
|  | Experiment::ExperimentHandler::toInt (Attributes *attrs, const char *atr) | 
|  | { | 
|  | const char *str = attrs->getValue (atr); | 
|  | return str ? atoi (str) : 0; | 
|  | } | 
|  |  | 
|  | char * | 
|  | Experiment::ExperimentHandler::toStr (Attributes *attrs, const char *atr) | 
|  | { | 
|  | const char *str = attrs->getValue (atr); | 
|  | return dbe_strdup (str ? str : NTXT ("")); | 
|  | } | 
|  |  | 
|  | Experiment::ExperimentHandler::ExperimentHandler (Experiment *_exp) | 
|  | { | 
|  | exp = _exp; | 
|  | stack = new Vector<Element>; | 
|  | pushElem (EL_NONE); | 
|  | dynfuncModule = NULL; | 
|  | dDscr = NULL; | 
|  | pDscr = NULL; | 
|  | propDscr = NULL; | 
|  | text = NULL; | 
|  | mkind = CMSG_NONE; | 
|  | mnum = -1; | 
|  | mec = -1; | 
|  | } | 
|  |  | 
|  | Experiment::ExperimentHandler::~ExperimentHandler () | 
|  | { | 
|  | delete stack; | 
|  | free (text); | 
|  | } | 
|  |  | 
|  | void | 
|  | Experiment::ExperimentHandler::endDocument () | 
|  | { | 
|  | { // SP_TAG_STATE should be used to describe states, but it isn't | 
|  | // let's do it here: | 
|  | DataDescriptor *dd = exp->getDataDescriptor (DATA_HEAP); | 
|  | if (dd != NULL) | 
|  | { | 
|  | PropDescr *prop = dd->getProp (PROP_HTYPE); | 
|  | if (prop != NULL) | 
|  | { | 
|  | char * stateNames [HEAPTYPE_LAST] = HEAPTYPE_STATE_STRINGS; | 
|  | char * stateUNames[HEAPTYPE_LAST] = HEAPTYPE_STATE_USTRINGS; | 
|  | for (int ii = 0; ii < HEAPTYPE_LAST; ii++) | 
|  | prop->addState (ii, stateNames[ii], stateUNames[ii]); | 
|  | } | 
|  | } | 
|  | dd = exp->getDataDescriptor (DATA_IOTRACE); | 
|  | if (dd != NULL) | 
|  | { | 
|  | PropDescr *prop = dd->getProp (PROP_IOTYPE); | 
|  | if (prop != NULL) | 
|  | { | 
|  | char * stateNames [IOTRACETYPE_LAST] = IOTRACETYPE_STATE_STRINGS; | 
|  | char * stateUNames[IOTRACETYPE_LAST] = IOTRACETYPE_STATE_USTRINGS; | 
|  | for (int ii = 0; ii < IOTRACETYPE_LAST; ii++) | 
|  | prop->addState (ii, stateNames[ii], stateUNames[ii]); | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | void | 
|  | Experiment::ExperimentHandler::pushElem (Element elem) | 
|  | { | 
|  | curElem = elem; | 
|  | stack->append (curElem); | 
|  | } | 
|  |  | 
|  | void | 
|  | Experiment::ExperimentHandler::popElem () | 
|  | { | 
|  | curElem = stack->remove (stack->size () - 1); | 
|  | } | 
|  |  | 
|  | void | 
|  | Experiment::ExperimentHandler::startElement (char*, char*, char *qName, Attributes *attrs) | 
|  | { | 
|  | DEBUG_CODE if (DEBUG_SAXPARSER) dump_startElement (qName, attrs); | 
|  | if (strcmp (qName, SP_TAG_EXPERIMENT) == 0) | 
|  | { | 
|  | pushElem (EL_EXPERIMENT); | 
|  | const char *str = attrs->getValue (NTXT ("version")); | 
|  | if (str != NULL) | 
|  | { | 
|  | int major = atoi (str); | 
|  | str = strchr (str, '.'); | 
|  | int minor = str ? atoi (str + 1) : 0; | 
|  | exp->exp_maj_version = major; | 
|  | exp->exp_min_version = minor; | 
|  | if (major != SUNPERF_VERNUM || minor != SUNPERF_VERNUM_MINOR) | 
|  | { | 
|  | // not the current version, see if we support some earlier versions | 
|  | if (major < 12) | 
|  | { | 
|  | StringBuilder sb; | 
|  | 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"), | 
|  | exp->get_expt_name (), major, minor); | 
|  | // exp->errorq->append( new Emsg(CMSG_FATAL, sb) ); | 
|  | exp->status = FAILURE; | 
|  | exp->obsolete = 1; | 
|  | throw new SAXException (sb.toString ()); | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  | else if (strcmp (qName, SP_TAG_COLLECTOR) == 0) | 
|  | pushElem (EL_COLLECTOR); | 
|  | else if (strcmp (qName, SP_TAG_SETTING) == 0) | 
|  | { | 
|  | int found = 0; | 
|  | pushElem (EL_SETTING); | 
|  | const char *str = attrs->getValue (SP_JCMD_LIMIT); | 
|  | if (str != NULL) | 
|  | { | 
|  | found = 1; | 
|  | exp->coll_params.limit = atoi (str); | 
|  | } | 
|  | str = attrs->getValue (SP_JCMD_BLKSZ); | 
|  | if (str != NULL) | 
|  | { | 
|  | found = 1; | 
|  | exp->blksz = strtol (str, NULL, 0); | 
|  | } | 
|  | str = attrs->getValue (SP_JCMD_STACKBASE); | 
|  | if (str) | 
|  | { | 
|  | found = 1; | 
|  | exp->stack_base = strtoull (str, NULL, 0); | 
|  | } | 
|  | str = attrs->getValue (SP_JCMD_HWC_DEFAULT); | 
|  | if (str != NULL) | 
|  | { | 
|  | found = 1; | 
|  | exp->hwc_default = true; | 
|  | } | 
|  | str = attrs->getValue (SP_JCMD_NOIDLE); | 
|  | if (str != NULL) | 
|  | { | 
|  | found = 1; | 
|  | exp->commentq->append (new Emsg (CMSG_COMMENT, | 
|  | GTXT ("*** Note: experiment does not have events from idle CPUs"))); | 
|  | } | 
|  | str = attrs->getValue (SP_JCMD_FAKETIME); | 
|  | if (str != NULL) | 
|  | { | 
|  | found = 1; | 
|  | exp->timelineavail = false; | 
|  | exp->commentq->append (new Emsg (CMSG_COMMENT, | 
|  | GTXT ("*** Note: experiment does not have timestamps; timeline unavailable"))); | 
|  | } | 
|  | str = attrs->getValue (SP_JCMD_DELAYSTART); | 
|  | if (str != NULL) | 
|  | { | 
|  | found = 1; | 
|  | exp->coll_params.start_delay = xstrdup (str); | 
|  | } | 
|  | str = attrs->getValue (SP_JCMD_TERMINATE); | 
|  | if (str != NULL) | 
|  | { | 
|  | found = 1; | 
|  | exp->coll_params.terminate = xstrdup (str); | 
|  | } | 
|  | str = attrs->getValue (SP_JCMD_PAUSE_SIG); | 
|  | if (str != NULL) | 
|  | { | 
|  | found = 1; | 
|  | exp->coll_params.pause_sig = xstrdup (str); | 
|  | } | 
|  | str = attrs->getValue (SP_JCMD_SAMPLE_PERIOD); | 
|  | if (str != NULL) | 
|  | { | 
|  | found = 1; | 
|  | exp->coll_params.sample_periodic = 1; | 
|  | exp->coll_params.sample_timer = atoi (str); | 
|  | } | 
|  | str = attrs->getValue (SP_JCMD_SAMPLE_SIG); | 
|  | if (str != NULL) | 
|  | { | 
|  | found = 1; | 
|  | exp->coll_params.sample_sig = str; | 
|  | } | 
|  | str = attrs->getValue (SP_JCMD_SRCHPATH); | 
|  | if (str != NULL) | 
|  | { | 
|  | found = 1; | 
|  | StringBuilder sb; | 
|  | sb.sprintf (GTXT ("Search path: %s"), str); | 
|  | exp->runlogq->append (new Emsg (CMSG_COMMENT, sb)); | 
|  | dbeSession->add_classpath ((char*) str); | 
|  | } | 
|  | str = attrs->getValue (SP_JCMD_LINETRACE); | 
|  | if (str != NULL) | 
|  | { | 
|  | found = 1; | 
|  | exp->coll_params.linetrace = xstrdup (str); | 
|  | } | 
|  |  | 
|  | str = attrs->getValue (SP_JCMD_COLLENV); | 
|  | if (str != NULL) | 
|  | { | 
|  | found = 1; | 
|  | StringBuilder sb; | 
|  | sb.sprintf (GTXT ("  Data collection environment variable: %s"), str); | 
|  | exp->runlogq->append (new Emsg (CMSG_COMMENT, sb)); | 
|  | } | 
|  | if (found == 0) | 
|  | { | 
|  | int nattr = attrs->getLength (); | 
|  | if (nattr != 0) | 
|  | { | 
|  | fprintf (stderr, "XXX Unexpected setting found; %d attributes:\n", | 
|  | nattr); | 
|  | for (int k = 0; k < nattr; k++) | 
|  | { | 
|  | const char *qn = attrs->getQName (k); | 
|  | const char *vl = attrs->getValue (k); | 
|  | fprintf (stderr, "XXX      %s = %s\n", qn, vl); | 
|  | } | 
|  | } | 
|  | } | 
|  | // END OF CODE FOR "setting" | 
|  | } | 
|  | else if (strcmp (qName, SP_TAG_SYSTEM) == 0) | 
|  | { | 
|  | pushElem (EL_SYSTEM); | 
|  | const char *str = attrs->getValue (NTXT ("hostname")); | 
|  | if (str != NULL) | 
|  | exp->hostname = xstrdup (str); | 
|  | str = attrs->getValue (NTXT ("os")); | 
|  | if (str != NULL) | 
|  | { | 
|  | exp->os_version = xstrdup (str); | 
|  | /* For Linux experiments expect sparse thread ID's */ | 
|  | if (strncmp (str, NTXT ("SunOS"), 5) != 0) | 
|  | exp->sparse_threads = true; | 
|  | } | 
|  | str = attrs->getValue (NTXT ("arch")); | 
|  | if (str != NULL) | 
|  | { | 
|  | if (strcmp (str, "i86pc") == 0 || strcmp (str, "i686") == 0 | 
|  | || strcmp (str, "x86_64") == 0) | 
|  | exp->platform = Intel; | 
|  | else if (strcmp (str, "aarch64") == 0) | 
|  | exp->platform = Aarch64; | 
|  | else if (strcmp (str, "riscv64") == 0) | 
|  | exp->platform = RISCV; | 
|  | else | 
|  | exp->platform = Sparc; | 
|  | exp->architecture = xstrdup (str); | 
|  | } | 
|  | str = attrs->getValue (NTXT ("bigendian")); | 
|  | if (str != NULL) | 
|  | { | 
|  | exp->bigendian = *str == '1'; | 
|  | exp->need_swap_endian = DbeSession::is_bigendian () != exp->bigendian; | 
|  | } | 
|  | str = attrs->getValue (NTXT ("pagesz")); | 
|  | if (str != NULL) | 
|  | exp->page_size = atoi (str); | 
|  | str = attrs->getValue (NTXT ("npages")); | 
|  | if (str != NULL) | 
|  | exp->npages = atoi (str); | 
|  | } | 
|  | else if (strcmp (qName, SP_TAG_POWERM) == 0) | 
|  | pushElem (EL_POWERM); | 
|  | else if (strcmp (qName, SP_TAG_FREQUENCY) == 0) | 
|  | { | 
|  | pushElem (EL_FREQUENCY); | 
|  | const char *str = attrs->getValue (NTXT ("clk")); | 
|  | if (str != NULL) | 
|  | exp->set_clock (atoi (str)); | 
|  | // check for frequency_scaling or turbo_mode recorded from libcollector under dbx | 
|  | str = attrs->getValue (NTXT ("frequency_scaling")); | 
|  | const char *str2 = attrs->getValue (NTXT ("turbo_mode")); | 
|  | if (str != NULL || str2 != NULL) | 
|  | exp->varclock = 1; | 
|  | } | 
|  | else if (strcmp (qName, SP_TAG_CPU) == 0) | 
|  | { | 
|  | pushElem (EL_CPU); | 
|  | exp->ncpus++; | 
|  | const char *str = attrs->getValue (NTXT ("clk")); | 
|  | if (str != NULL) | 
|  | { | 
|  | int clk = atoi (str); | 
|  | if (exp->maxclock == 0) | 
|  | { | 
|  | exp->minclock = clk; | 
|  | exp->maxclock = clk; | 
|  | } | 
|  | else | 
|  | { | 
|  | if (clk < exp->minclock) | 
|  | exp->minclock = clk; | 
|  | if (clk > exp->maxclock) | 
|  | exp->maxclock = clk; | 
|  | } | 
|  | exp->clock = clk; | 
|  | } | 
|  | // check for frequency_scaling or turbo_mode | 
|  | str = attrs->getValue (NTXT ("frequency_scaling")); | 
|  | const char *str2 = attrs->getValue (NTXT ("turbo_mode")); | 
|  | if (str != NULL || str2 != NULL) | 
|  | exp->varclock = 1; | 
|  | } | 
|  | else if (strcmp (qName, SP_TAG_PROCESS) == 0) | 
|  | { | 
|  | pushElem (EL_PROCESS); | 
|  | const char *str = attrs->getValue (NTXT ("wsize")); | 
|  | if (str != NULL) | 
|  | { | 
|  | int wsz = atoi (str); | 
|  | if (wsz == 32) | 
|  | exp->wsize = W32; | 
|  | else if (wsz == 64) | 
|  | exp->wsize = W64; | 
|  | } | 
|  | str = attrs->getValue (NTXT ("pid")); | 
|  | if (str != NULL) | 
|  | exp->pid = atoi (str); | 
|  | str = attrs->getValue (NTXT ("ppid")); | 
|  | if (str != NULL) | 
|  | exp->ppid = atoi (str); | 
|  | str = attrs->getValue (NTXT ("pgrp")); | 
|  | if (str != NULL) | 
|  | exp->pgrp = atoi (str); | 
|  | str = attrs->getValue (NTXT ("sid")); | 
|  | if (str != NULL) | 
|  | exp->sid = atoi (str); | 
|  | str = attrs->getValue (NTXT ("cwd")); | 
|  | if (str != NULL) | 
|  | exp->ucwd = xstrdup (str); | 
|  | str = attrs->getValue (NTXT ("pagesz")); | 
|  | if (str != NULL) | 
|  | exp->page_size = atoi (str); | 
|  | } | 
|  | else if (strcmp (qName, SP_TAG_EVENT) == 0) | 
|  | { // Start code for event | 
|  | pushElem (EL_EVENT); | 
|  | hrtime_t ts = (hrtime_t) 0; | 
|  | const char *str = attrs->getValue (NTXT ("tstamp")); | 
|  | if (str != NULL) | 
|  | ts = parseTStamp (str); | 
|  | str = attrs->getValue (NTXT ("kind")); | 
|  | if (str != NULL) | 
|  | { | 
|  | if (strcmp (str, SP_JCMD_RUN) == 0) | 
|  | { | 
|  | exp->broken = 0; | 
|  | exp->exp_start_time = ts; | 
|  | str = attrs->getValue (NTXT ("time")); | 
|  | if (str != NULL) | 
|  | exp->start_sec = atoll (str); | 
|  | str = attrs->getValue (NTXT ("pid")); | 
|  | if (str != NULL) | 
|  | exp->pid = atoi (str); | 
|  | str = attrs->getValue (NTXT ("ppid")); | 
|  | if (str != NULL) | 
|  | exp->ppid = atoi (str); | 
|  | str = attrs->getValue (NTXT ("pgrp")); | 
|  | if (str != NULL) | 
|  | exp->pgrp = atoi (str); | 
|  | str = attrs->getValue (NTXT ("sid")); | 
|  | if (str != NULL) | 
|  | exp->sid = atoi (str); | 
|  | exp->status = Experiment::INCOMPLETE; | 
|  | } | 
|  | else if (strcmp (str, SP_JCMD_ARCHIVE) == 0) | 
|  | { | 
|  | StringBuilder sb; | 
|  | sb.sprintf (GTXT ("gprofng-archive run: XXXXXXX")); | 
|  | exp->pprocq->append (new Emsg (CMSG_WARN, sb)); | 
|  | } | 
|  | else if (strcmp (str, SP_JCMD_SAMPLE) == 0) | 
|  | { | 
|  | exp->update_last_event (exp->exp_start_time + ts); // ts is 0-based | 
|  | str = attrs->getValue (NTXT ("id")); | 
|  | int id = str ? atoi (str) : -1; | 
|  | char *label = dbe_strdup (attrs->getValue (NTXT ("label"))); | 
|  | exp->process_sample_cmd (NULL, ts, id, label); | 
|  | } | 
|  | else if (strcmp (str, SP_JCMD_EXIT) == 0) | 
|  | { | 
|  | // don't treat EXIT as an event w.r.t. last_event and non_paused_time | 
|  | exp->status = Experiment::SUCCESS; | 
|  | } | 
|  | else if (strcmp (str, SP_JCMD_CERROR) == 0) | 
|  | { | 
|  | mkind = CMSG_ERROR; | 
|  | str = attrs->getValue (NTXT ("id")); | 
|  | if (str != NULL) | 
|  | { | 
|  | mnum = atoi (str); | 
|  | } | 
|  | str = attrs->getValue (NTXT ("ec")); | 
|  | if (str != NULL) | 
|  | { | 
|  | mec = atoi (str); | 
|  | } | 
|  | } | 
|  | else if (strcmp (str, SP_JCMD_CWARN) == 0) | 
|  | { | 
|  | mkind = CMSG_WARN; | 
|  | str = attrs->getValue (NTXT ("id")); | 
|  | if (str != NULL) | 
|  | mnum = atoi (str); | 
|  | } | 
|  | else if (strcmp (str, SP_JCMD_COMMENT) == 0) | 
|  | { | 
|  | mkind = CMSG_COMMENT; | 
|  | str = attrs->getValue (NTXT ("id")); | 
|  | if (str != NULL) | 
|  | mnum = atoi (str); | 
|  | str = attrs->getValue (NTXT ("text")); | 
|  | if (str != NULL) | 
|  | { | 
|  | StringBuilder sb; | 
|  | sb.sprintf (GTXT ("*** Note: %s"), str); | 
|  | exp->commentq->append (new Emsg (CMSG_COMMENT, sb)); | 
|  | } | 
|  | } | 
|  | else if (strcmp (str, SP_JCMD_DESC_START) == 0) | 
|  | { | 
|  | char *variant = toStr (attrs, NTXT ("variant")); | 
|  | char *lineage = toStr (attrs, NTXT ("lineage")); | 
|  | int follow = toInt (attrs, NTXT ("follow")); | 
|  | char *msg = toStr (attrs, NTXT ("msg")); | 
|  | exp->process_desc_start_cmd (NULL, ts, variant, lineage, follow, msg); | 
|  | } | 
|  | else if (strcmp (str, SP_JCMD_DESC_STARTED) == 0) | 
|  | { | 
|  | char *variant = toStr (attrs, NTXT ("variant")); | 
|  | char *lineage = toStr (attrs, NTXT ("lineage")); | 
|  | int follow = toInt (attrs, NTXT ("follow")); | 
|  | char *msg = toStr (attrs, NTXT ("msg")); | 
|  | exp->process_desc_started_cmd (NULL, ts, variant, lineage, follow, msg); | 
|  | } | 
|  | else if (strcmp (str, SP_JCMD_EXEC_START) == 0) | 
|  | { | 
|  | // if successful, acts like experiment termination - no "exit" entry will follow | 
|  | exp->update_last_event (exp->exp_start_time + ts); // ts is 0-based | 
|  | char *variant = toStr (attrs, NTXT ("variant")); | 
|  | char *lineage = toStr (attrs, NTXT ("lineage")); | 
|  | int follow = toInt (attrs, NTXT ("follow")); | 
|  | char *msg = toStr (attrs, NTXT ("msg")); | 
|  | exp->process_desc_start_cmd (NULL, ts, variant, lineage, follow, msg); | 
|  | exp->exec_started = true; | 
|  | } | 
|  | else if (strcmp (str, SP_JCMD_EXEC_ERROR) == 0) | 
|  | { | 
|  | exp->update_last_event (exp->exp_start_time + ts); // ts is 0-based | 
|  | char *variant = toStr (attrs, NTXT ("variant")); | 
|  | char *lineage = toStr (attrs, NTXT ("lineage")); | 
|  | int follow = toInt (attrs, NTXT ("follow")); | 
|  | char *msg = toStr (attrs, NTXT ("msg")); | 
|  | exp->process_desc_started_cmd (NULL, ts, variant, lineage, follow, msg); | 
|  | exp->exec_started = false; | 
|  | } | 
|  | else if (strcmp (str, SP_JCMD_JTHRSTART) == 0) | 
|  | { | 
|  | char *name = dbe_strdup (attrs->getValue (NTXT ("name"))); | 
|  | char *grpname = dbe_strdup (attrs->getValue (NTXT ("grpname"))); | 
|  | char *prntname = dbe_strdup (attrs->getValue (NTXT ("prntname"))); | 
|  | str = attrs->getValue (NTXT ("tid")); | 
|  | uint64_t tid = str ? strtoull (str, NULL, 0) : 0; | 
|  | str = attrs->getValue (NTXT ("jthr")); | 
|  | Vaddr jthr = str ? strtoull (str, NULL, 0) : 0; | 
|  | str = attrs->getValue (NTXT ("jenv")); | 
|  | Vaddr jenv = str ? strtoull (str, NULL, 0) : 0; | 
|  | exp->process_jthr_start_cmd (NULL, name, grpname, prntname, tid, jthr, jenv, ts); | 
|  | } | 
|  | else if (strcmp (str, SP_JCMD_JTHREND) == 0) | 
|  | { | 
|  | str = attrs->getValue (NTXT ("tid")); | 
|  | uint64_t tid = str ? strtoull (str, NULL, 0) : 0; | 
|  | str = attrs->getValue (NTXT ("jthr")); | 
|  | Vaddr jthr = str ? strtoull (str, NULL, 0) : 0; | 
|  | str = attrs->getValue (NTXT ("jenv")); | 
|  | Vaddr jenv = str ? strtoull (str, NULL, 0) : 0; | 
|  | exp->process_jthr_end_cmd (NULL, tid, jthr, jenv, ts); | 
|  | } | 
|  | else if (strcmp (str, SP_JCMD_GCEND) == 0) | 
|  | { | 
|  | if (exp->getDataDescriptor (DATA_GCEVENT) == NULL) | 
|  | exp->newDataDescriptor (DATA_GCEVENT); | 
|  | exp->process_gc_end_cmd (ts); | 
|  | } | 
|  | else if (strcmp (str, SP_JCMD_GCSTART) == 0) | 
|  | { | 
|  | if (exp->getDataDescriptor (DATA_GCEVENT) == NULL) | 
|  | exp->newDataDescriptor (DATA_GCEVENT); | 
|  | exp->process_gc_start_cmd (ts); | 
|  | } | 
|  | else if (strcmp (str, SP_JCMD_PAUSE) == 0) | 
|  | { | 
|  | if (exp->resume_ts != MAX_TIME) | 
|  | { | 
|  | // data collection was active | 
|  | hrtime_t delta = ts - exp->resume_ts; | 
|  | exp->non_paused_time += delta; | 
|  | exp->resume_ts = MAX_TIME; // collection is paused | 
|  | } | 
|  | StringBuilder sb; | 
|  | str = attrs->getValue (NTXT ("name")); | 
|  | if (str == NULL) | 
|  | sb.sprintf (GTXT ("Pause: %ld.%09ld"), (long) (ts / NANOSEC), | 
|  | (long) (ts % NANOSEC)); | 
|  | else | 
|  | sb.sprintf (GTXT ("Pause (%s): %ld.%09ld"), str, | 
|  | (long) (ts / NANOSEC), (long) (ts % NANOSEC)); | 
|  | exp->runlogq->append (new Emsg (CMSG_COMMENT, sb)); | 
|  | } | 
|  | else if (strcmp (str, SP_JCMD_RESUME) == 0) | 
|  | { | 
|  | if (exp->resume_ts == MAX_TIME) | 
|  | // data collection was paused | 
|  | exp->resume_ts = ts; // remember start time | 
|  | StringBuilder sb; | 
|  | sb.sprintf (GTXT ("Resume: %ld.%09ld"), (long) (ts / NANOSEC), (long) (ts % NANOSEC)); | 
|  | exp->runlogq->append (new Emsg (CMSG_COMMENT, sb)); | 
|  | if (exp->exp_start_time == ZERO_TIME) | 
|  | exp->exp_start_time = ts; | 
|  | } | 
|  | else if (strcmp (str, SP_JCMD_THREAD_PAUSE) == 0) | 
|  | { | 
|  | str = attrs->getValue (NTXT ("tid")); | 
|  | uint64_t tid = str ? strtoull (str, NULL, 0) : 0; | 
|  | StringBuilder sb; | 
|  | sb.sprintf (GTXT ("Thread %llu pause: %ld.%09ld"), (unsigned long long) tid, | 
|  | (long) (ts / NANOSEC), (long) (ts % NANOSEC)); | 
|  | exp->runlogq->append (new Emsg (CMSG_COMMENT, sb)); | 
|  | } | 
|  | else if (strcmp (str, SP_JCMD_THREAD_RESUME) == 0) | 
|  | { | 
|  | str = attrs->getValue (NTXT ("tid")); | 
|  | uint64_t tid = str ? strtoull (str, NULL, 0) : 0; | 
|  | StringBuilder sb; | 
|  | sb.sprintf (GTXT ("Thread %llu resume: %ld.%09ld"), (unsigned long long) tid, | 
|  | (long) (ts / NANOSEC), (long) (ts % NANOSEC)); | 
|  | exp->runlogq->append (new Emsg (CMSG_COMMENT, sb)); | 
|  | } | 
|  | else if (strcmp (str, NTXT ("map")) == 0) | 
|  | { | 
|  | ts += exp->exp_start_time; | 
|  | str = attrs->getValue (NTXT ("vaddr")); | 
|  | Vaddr vaddr = str ? strtoull (str, NULL, 0) : 0; | 
|  | str = attrs->getValue (NTXT ("size")); | 
|  | int msize = str ? atoi (str) : 0; | 
|  | str = attrs->getValue (NTXT ("foffset")); | 
|  | int64_t offset = str ? strtoll (str, NULL, 0) : 0; | 
|  | str = attrs->getValue (NTXT ("modes")); | 
|  | int64_t modes = str ? strtoll (str, NULL, 0) : 0; | 
|  | str = attrs->getValue (NTXT ("chksum")); | 
|  | int64_t chksum = 0; | 
|  | if (str) | 
|  | chksum = Elf::normalize_checksum (strtoll (str, NULL, 0)); | 
|  | char *name = (char *) attrs->getValue (NTXT ("name")); | 
|  | str = attrs->getValue (NTXT ("object")); | 
|  | if (strcmp (str, NTXT ("segment")) == 0) | 
|  | { | 
|  | if (strcmp (name, NTXT ("LinuxKernel")) == 0) | 
|  | exp->process_Linux_kernel_cmd (ts); | 
|  | else | 
|  | exp->process_seg_map_cmd (NULL, ts, vaddr, msize, 0, | 
|  | offset, modes, chksum, name); | 
|  | } | 
|  | else if (strcmp (str, NTXT ("function")) == 0) | 
|  | { | 
|  | exp->process_fn_load_cmd (dynfuncModule, name, vaddr, msize, ts); | 
|  | dynfuncModule = NULL; | 
|  | } | 
|  | else if (strcmp (str, NTXT ("dynfunc")) == 0) | 
|  | { | 
|  | if (dynfuncModule == NULL) | 
|  | { | 
|  | dynfuncModule = dbeSession->createModule (exp->get_dynfunc_lo (DYNFUNC_SEGMENT), name); | 
|  | dynfuncModule->flags |= MOD_FLAG_UNKNOWN; | 
|  | dynfuncModule->set_file_name (dbe_strdup (dynfuncModule->getMainSrc ()->get_name ())); | 
|  | } | 
|  | (void) exp->create_dynfunc (dynfuncModule, | 
|  | (char*) attrs->getValue (NTXT ("funcname")), vaddr, msize); | 
|  | } | 
|  | else if (strcmp (str, NTXT ("jcm")) == 0) | 
|  | { | 
|  | str = attrs->getValue (NTXT ("methodId")); | 
|  | Vaddr mid = str ? strtoull (str, NULL, 0) : 0; | 
|  | exp->process_jcm_load_cmd (NULL, mid, vaddr, msize, ts); | 
|  | } | 
|  | } | 
|  | else if (strcmp (str, NTXT ("unmap")) == 0) | 
|  | { | 
|  | ts += exp->exp_start_time; | 
|  | str = attrs->getValue (NTXT ("vaddr")); | 
|  | Vaddr vaddr = str ? strtoull (str, NULL, 0) : 0; | 
|  | exp->process_seg_unmap_cmd (NULL, ts, vaddr); | 
|  | } | 
|  | } | 
|  | // end of code for event | 
|  | } | 
|  | else if (strcmp (qName, SP_TAG_PROFILE) == 0) | 
|  | { | 
|  | pushElem (EL_PROFILE); | 
|  | const char *str = attrs->getValue (NTXT ("name")); | 
|  | if (str == NULL) | 
|  | return; | 
|  | if (strcmp (str, NTXT ("profile")) == 0) | 
|  | { | 
|  | exp->coll_params.profile_mode = 1; | 
|  | str = attrs->getValue (NTXT ("numstates")); | 
|  | if (str != NULL) | 
|  | exp->coll_params.lms_magic_id = atoi (str); | 
|  | str = attrs->getValue (NTXT ("ptimer")); | 
|  | if (str != NULL) | 
|  | exp->coll_params.ptimer_usec = atoi (str); // microseconds | 
|  |  | 
|  | PropDescr *mstate_prop = NULL; | 
|  | char * stateNames [/*LMS_NUM_STATES*/] = LMS_STATE_STRINGS; | 
|  | char * stateUNames[/*LMS_NUM_STATES*/] = LMS_STATE_USTRINGS; | 
|  | { | 
|  | dDscr = exp->newDataDescriptor (DATA_CLOCK); | 
|  | PropDescr *prop = new PropDescr (PROP_MSTATE, NTXT ("MSTATE")); | 
|  | prop->uname = dbe_strdup (GTXT ("Thread state")); | 
|  | prop->vtype = TYPE_UINT32; | 
|  | // (states added below) | 
|  | dDscr->addProperty (prop); | 
|  | mstate_prop = prop; | 
|  |  | 
|  | prop = new PropDescr (PROP_NTICK, NTXT ("NTICK")); | 
|  | prop->uname = dbe_strdup (GTXT ("Number of Profiling Ticks")); | 
|  | prop->vtype = TYPE_UINT32; | 
|  | dDscr->addProperty (prop); | 
|  | } | 
|  |  | 
|  | switch (exp->coll_params.lms_magic_id) | 
|  | { | 
|  | case LMS_MAGIC_ID_SOLARIS: | 
|  | exp->register_metric (Metric::CP_TOTAL); | 
|  | exp->register_metric (Metric::CP_TOTAL_CPU); | 
|  | exp->register_metric (Metric::CP_LMS_USER); | 
|  | exp->register_metric (Metric::CP_LMS_SYSTEM); | 
|  | exp->register_metric (Metric::CP_LMS_TRAP); | 
|  | exp->register_metric (Metric::CP_LMS_DFAULT); | 
|  | exp->register_metric (Metric::CP_LMS_TFAULT); | 
|  | exp->register_metric (Metric::CP_LMS_KFAULT); | 
|  | exp->register_metric (Metric::CP_LMS_STOPPED); | 
|  | exp->register_metric (Metric::CP_LMS_WAIT_CPU); | 
|  | exp->register_metric (Metric::CP_LMS_SLEEP); | 
|  | exp->register_metric (Metric::CP_LMS_USER_LOCK); | 
|  | for (int ii = 0; ii < LMS_NUM_SOLARIS_MSTATES; ii++) | 
|  | mstate_prop->addState (ii, stateNames[ii], stateUNames[ii]); | 
|  | break; | 
|  | case LMS_MAGIC_ID_ERKERNEL_KERNEL: | 
|  | exp->register_metric (Metric::CP_KERNEL_CPU); | 
|  | { | 
|  | int ii = LMS_KERNEL_CPU; | 
|  | mstate_prop->addState (ii, stateNames[ii], stateUNames[ii]); | 
|  | } | 
|  | break; | 
|  | case LMS_MAGIC_ID_ERKERNEL_USER: | 
|  | exp->register_metric (Metric::CP_TOTAL_CPU); | 
|  | exp->register_metric (Metric::CP_LMS_USER); | 
|  | exp->register_metric (Metric::CP_LMS_SYSTEM); | 
|  | { | 
|  | int ii = LMS_KERNEL_CPU; | 
|  | mstate_prop->addState (ii, stateNames[ii], stateUNames[ii]); | 
|  | ii = LMS_USER; | 
|  | mstate_prop->addState (ii, stateNames[ii], stateUNames[ii]); | 
|  | ii = LMS_SYSTEM; | 
|  | mstate_prop->addState (ii, stateNames[ii], stateUNames[ii]); | 
|  | } | 
|  | break; | 
|  | case LMS_MAGIC_ID_LINUX: | 
|  | exp->register_metric (Metric::CP_TOTAL_CPU); | 
|  | { | 
|  | int ii = LMS_LINUX_CPU; | 
|  | mstate_prop->addState (ii, stateNames[ii], stateUNames[ii]); | 
|  | } | 
|  | break; | 
|  | default: | 
|  | // odd | 
|  | break; | 
|  | } | 
|  | } | 
|  | else if (strcmp (str, NTXT ("heaptrace")) == 0) | 
|  | { | 
|  | exp->coll_params.heap_mode = 1; | 
|  | exp->leaklistavail = true; | 
|  | exp->heapdataavail = true; | 
|  | exp->register_metric (Metric::HEAP_ALLOC_BYTES); | 
|  | exp->register_metric (Metric::HEAP_ALLOC_CNT); | 
|  | exp->register_metric (Metric::HEAP_LEAK_BYTES); | 
|  | exp->register_metric (Metric::HEAP_LEAK_CNT); | 
|  | dDscr = exp->newDataDescriptor (DATA_HEAP); | 
|  | } | 
|  | else if (strcmp (str, NTXT ("iotrace")) == 0) | 
|  | { | 
|  | exp->coll_params.io_mode = 1; | 
|  | exp->iodataavail = true; | 
|  | exp->register_metric (Metric::IO_READ_TIME); | 
|  | exp->register_metric (Metric::IO_READ_BYTES); | 
|  | exp->register_metric (Metric::IO_READ_CNT); | 
|  | exp->register_metric (Metric::IO_WRITE_TIME); | 
|  | exp->register_metric (Metric::IO_WRITE_BYTES); | 
|  | exp->register_metric (Metric::IO_WRITE_CNT); | 
|  | exp->register_metric (Metric::IO_OTHER_TIME); | 
|  | exp->register_metric (Metric::IO_OTHER_CNT); | 
|  | exp->register_metric (Metric::IO_ERROR_TIME); | 
|  | exp->register_metric (Metric::IO_ERROR_CNT); | 
|  | dDscr = exp->newDataDescriptor (DATA_IOTRACE); | 
|  | } | 
|  | else if (strcmp (str, NTXT ("synctrace")) == 0) | 
|  | { | 
|  | exp->coll_params.sync_mode = 1; | 
|  | str = attrs->getValue (NTXT ("threshold")); | 
|  | if (str != NULL) | 
|  | exp->coll_params.sync_threshold = atoi (str); | 
|  | str = attrs->getValue (NTXT ("scope")); | 
|  | if (str != NULL) | 
|  | exp->coll_params.sync_scope = atoi (str); | 
|  | else  // Should only happen with old experiments; use the old default | 
|  | exp->coll_params.sync_scope = SYNCSCOPE_NATIVE | SYNCSCOPE_JAVA; | 
|  | exp->register_metric (Metric::SYNC_WAIT_TIME); | 
|  | exp->register_metric (Metric::SYNC_WAIT_COUNT); | 
|  | dDscr = exp->newDataDescriptor (DATA_SYNCH); | 
|  | } | 
|  | else if (strcmp (str, NTXT ("omptrace")) == 0) | 
|  | { | 
|  | exp->coll_params.omp_mode = 1; | 
|  | dDscr = exp->newDataDescriptor (DATA_OMP, DDFLAG_NOSHOW); | 
|  | } | 
|  | else if (strcmp (str, NTXT ("hwcounter")) == 0) | 
|  | { | 
|  | str = attrs->getValue (NTXT ("cpuver")); | 
|  | int cpuver = str ? atoi (str) : 0; | 
|  | char *counter = dbe_strdup (attrs->getValue (NTXT ("hwcname"))); | 
|  | char *int_name = dbe_strdup (attrs->getValue (NTXT ("int_name"))); // may not be present | 
|  | str = attrs->getValue (NTXT ("interval")); | 
|  | int interval = str ? atoi (str) : 0; | 
|  | str = attrs->getValue (NTXT ("tag")); | 
|  | int tag = str ? atoi (str) : 0; | 
|  | str = attrs->getValue (NTXT ("memop")); | 
|  | int i_tpc = str ? atoi (str) : 0; | 
|  | char *modstr = dbe_strdup (attrs->getValue (NTXT ("modstr"))); | 
|  | exp->process_hwcounter_cmd (NULL, cpuver, counter, int_name, interval, tag, i_tpc, modstr); | 
|  | dDscr = exp->newDataDescriptor (DATA_HWC); | 
|  | } | 
|  | else if (strcmp (str, NTXT ("hwsimctr")) == 0) | 
|  | { | 
|  | int cpuver = toInt (attrs, NTXT ("cpuver")); | 
|  | char *hwcname = dbe_strdup (attrs->getValue (NTXT ("hwcname"))); | 
|  | char *int_name = dbe_strdup (attrs->getValue (NTXT ("int_name"))); | 
|  | char *metric = dbe_strdup (attrs->getValue (NTXT ("metric"))); | 
|  | int reg = toInt (attrs, NTXT ("reg_num")); | 
|  | int interval = toInt (attrs, NTXT ("interval")); | 
|  | int timecvt = toInt (attrs, NTXT ("timecvt")); | 
|  | int i_tpc = toInt (attrs, NTXT ("memop")); | 
|  | int tag = toInt (attrs, NTXT ("tag")); | 
|  | exp->process_hwsimctr_cmd (NULL, cpuver, hwcname, int_name, metric, reg, | 
|  | interval, timecvt, i_tpc, tag); | 
|  | dDscr = exp->newDataDescriptor (DATA_HWC); | 
|  | } | 
|  | else if (strcmp (str, NTXT ("dversion")) == 0) | 
|  | exp->dversion = dbe_strdup (attrs->getValue (NTXT ("version"))); | 
|  | else if (strcmp (str, NTXT ("jprofile")) == 0) | 
|  | { | 
|  | exp->has_java = true; | 
|  | str = attrs->getValue (NTXT ("jversion")); | 
|  | if (str != NULL) | 
|  | exp->jversion = xstrdup (str); | 
|  | } | 
|  | else if (strcmp (str, NTXT ("datarace")) == 0) | 
|  | { | 
|  | exp->coll_params.race_mode = 1; | 
|  | exp->racelistavail = true; | 
|  | str = attrs->getValue (NTXT ("scheme")); | 
|  | exp->coll_params.race_stack = str ? atoi (str) : 0; | 
|  | exp->register_metric (Metric::RACCESS); | 
|  | dDscr = exp->newDataDescriptor (DATA_RACE); | 
|  | } | 
|  | else if (strcmp (str, NTXT ("deadlock")) == 0) | 
|  | { | 
|  | exp->coll_params.deadlock_mode = 1; | 
|  | exp->deadlocklistavail = true; | 
|  | exp->register_metric (Metric::DEADLOCKS); | 
|  | dDscr = exp->newDataDescriptor (DATA_DLCK); | 
|  | } | 
|  | } | 
|  | /* XXX -- obsolete tag, but is still written to experiments */ | 
|  | else if (strcmp (qName, SP_TAG_DATAPTR) == 0) | 
|  | { | 
|  | pushElem (EL_DATAPTR); | 
|  | return; | 
|  | } | 
|  | else if (strcmp (qName, SP_TAG_PROFDATA) == 0) | 
|  | { | 
|  | pushElem (EL_PROFDATA); | 
|  | // SS12 HWC experiments are not well structured | 
|  | const char *fname = attrs->getValue (NTXT ("fname")); | 
|  | if (fname && strcmp (fname, SP_HWCNTR_FILE) == 0) | 
|  | dDscr = exp->newDataDescriptor (DATA_HWC); | 
|  | } | 
|  | else if (strcmp (qName, SP_TAG_PROFPCKT) == 0) | 
|  | { | 
|  | pushElem (EL_PROFPCKT); | 
|  | const char *str = attrs->getValue (NTXT ("kind")); // see Pckt_type | 
|  | int kind = str ? atoi (str) : -1; | 
|  | if (kind < 0) | 
|  | return; | 
|  | if (exp->coll_params.omp_mode == 1) | 
|  | { | 
|  | if (kind == OMP_PCKT) | 
|  | dDscr = exp->newDataDescriptor (DATA_OMP, DDFLAG_NOSHOW); | 
|  | else if (kind == OMP2_PCKT) | 
|  | dDscr = exp->newDataDescriptor (DATA_OMP2, DDFLAG_NOSHOW); | 
|  | else if (kind == OMP3_PCKT) | 
|  | dDscr = exp->newDataDescriptor (DATA_OMP3, DDFLAG_NOSHOW); | 
|  | else if (kind == OMP4_PCKT) | 
|  | dDscr = exp->newDataDescriptor (DATA_OMP4, DDFLAG_NOSHOW); | 
|  | else if (kind == OMP5_PCKT) | 
|  | dDscr = exp->newDataDescriptor (DATA_OMP5, DDFLAG_NOSHOW); | 
|  | } | 
|  | pDscr = exp->newPacketDescriptor (kind, dDscr); | 
|  | return; | 
|  | } | 
|  | else if (strcmp (qName, SP_TAG_FIELD) == 0) | 
|  | { | 
|  | pushElem (EL_FIELD); | 
|  | if (pDscr != NULL) | 
|  | { | 
|  | const char *name = attrs->getValue (NTXT ("name")); | 
|  | if (name == NULL) | 
|  | return; | 
|  | int propID = dbeSession->registerPropertyName (name); | 
|  | propDscr = new PropDescr (propID, name); | 
|  | FieldDescr *fldDscr = new FieldDescr (propID, name); | 
|  |  | 
|  | const char *str = attrs->getValue (NTXT ("type")); | 
|  | if (str) | 
|  | { | 
|  | if (strcmp (str, NTXT ("INT32")) == 0) | 
|  | fldDscr->vtype = TYPE_INT32; | 
|  | else if (strcmp (str, NTXT ("UINT32")) == 0) | 
|  | fldDscr->vtype = TYPE_UINT32; | 
|  | else if (strcmp (str, NTXT ("INT64")) == 0) | 
|  | fldDscr->vtype = TYPE_INT64; | 
|  | else if (strcmp (str, NTXT ("UINT64")) == 0) | 
|  | fldDscr->vtype = TYPE_UINT64; | 
|  | else if (strcmp (str, NTXT ("STRING")) == 0) | 
|  | fldDscr->vtype = TYPE_STRING; | 
|  | else if (strcmp (str, NTXT ("DOUBLE")) == 0) | 
|  | fldDscr->vtype = TYPE_DOUBLE; | 
|  | else if (strcmp (str, NTXT ("DATE")) == 0) | 
|  | { | 
|  | fldDscr->vtype = TYPE_DATE; | 
|  | const char *fmt = attrs->getValue (NTXT ("format")); | 
|  | fldDscr->format = xstrdup (fmt ? fmt : ""); | 
|  | } | 
|  | } | 
|  | propDscr->vtype = fldDscr->vtype; | 
|  |  | 
|  | // TYPE_DATE is converted to TYPE_UINT64 in propDscr | 
|  | if (fldDscr->vtype == TYPE_DATE) | 
|  | propDscr->vtype = TYPE_UINT64; | 
|  |  | 
|  | // Fix some types until they are fixed in libcollector | 
|  | if (propID == PROP_VIRTPC || propID == PROP_PHYSPC) | 
|  | { | 
|  | if (fldDscr->vtype == TYPE_INT32) | 
|  | propDscr->vtype = TYPE_UINT32; | 
|  | else if (fldDscr->vtype == TYPE_INT64) | 
|  | propDscr->vtype = TYPE_UINT64; | 
|  | } | 
|  |  | 
|  | // The following props get mapped to 32-bit values in readPacket | 
|  | if (propID == PROP_CPUID || propID == PROP_THRID | 
|  | || propID == PROP_LWPID) | 
|  | propDscr->vtype = TYPE_UINT32; // override experiment property | 
|  |  | 
|  | str = attrs->getValue (NTXT ("uname")); | 
|  | if (str) | 
|  | propDscr->uname = xstrdup (PTXT ((char*) str)); | 
|  | str = attrs->getValue (NTXT ("noshow")); | 
|  | if (str && atoi (str) != 0) | 
|  | propDscr->flags |= PRFLAG_NOSHOW; | 
|  |  | 
|  | if (dDscr == NULL) | 
|  | { | 
|  | StringBuilder sb; | 
|  | sb.sprintf (GTXT ("*** Error: data parsing failed. Log file is corrupted.")); | 
|  | exp->warnq->append (new Emsg (CMSG_ERROR, sb)); | 
|  | throw new SAXException (sb.toString ()); | 
|  | } | 
|  |  | 
|  | dDscr->addProperty (propDscr); | 
|  | str = attrs->getValue (NTXT ("offset")); | 
|  | if (str) | 
|  | fldDscr->offset = atoi (str); | 
|  | pDscr->addField (fldDscr); | 
|  | } | 
|  | } | 
|  | else if (strcmp (qName, SP_TAG_STATE) == 0) | 
|  | { | 
|  | pushElem (EL_STATE); | 
|  | if (propDscr != NULL) | 
|  | { | 
|  | const char *str = attrs->getValue (NTXT ("value")); | 
|  | int value = str ? atoi (str) : -1; | 
|  | str = attrs->getValue (NTXT ("name")); | 
|  | const char *ustr = attrs->getValue (NTXT ("uname")); | 
|  | propDscr->addState (value, str, ustr); | 
|  | } | 
|  | } | 
|  | else if (strcmp (qName, SP_TAG_DTRACEFATAL) == 0) | 
|  | pushElem (EL_DTRACEFATAL); | 
|  | else | 
|  | { | 
|  | StringBuilder sb; | 
|  | sb.sprintf (GTXT ("*** Warning: unrecognized element %s"), qName); | 
|  | exp->warnq->append (new Emsg (CMSG_WARN, sb)); | 
|  | pushElem (EL_NONE); | 
|  | } | 
|  | } | 
|  |  | 
|  | void | 
|  | Experiment::ExperimentHandler::characters (char *ch, int start, int length) | 
|  | { | 
|  | switch (curElem) | 
|  | { | 
|  | case EL_COLLECTOR: | 
|  | exp->cversion = dbe_strndup (ch + start, length); | 
|  | break; | 
|  | case EL_PROCESS: | 
|  | exp->process_arglist_cmd (NULL, dbe_strndup (ch + start, length)); | 
|  | break; | 
|  | case EL_EVENT: | 
|  | free (text); | 
|  | text = dbe_strndup (ch + start, length); | 
|  | break; | 
|  | default: | 
|  | break; | 
|  | } | 
|  | } | 
|  |  | 
|  | void | 
|  | Experiment::ExperimentHandler::endElement (char*, char*, char*) | 
|  | { | 
|  | if (curElem == EL_EVENT && mkind != CMSG_NONE && mnum >= 0) | 
|  | { | 
|  | char *str; | 
|  | if (mec > 0) | 
|  | str = dbe_sprintf ("%s -- %s", text != NULL ? text : "", strerror (mec)); | 
|  | else | 
|  | str = dbe_sprintf ("%s", text != NULL ? text : ""); | 
|  | Emsg *msg = new Emsg (mkind, mnum, str); | 
|  | if (mkind == CMSG_WARN) | 
|  | { | 
|  | if (mnum != COL_WARN_FSTYPE | 
|  | || dbeSession->check_ignore_fs_warn () == false) | 
|  | exp->warnq->append (msg); | 
|  | else | 
|  | exp->commentq->append (msg); | 
|  | } | 
|  | else if (mkind == CMSG_ERROR || mkind == CMSG_FATAL) | 
|  | exp->errorq->append (msg); | 
|  | else if (mkind == CMSG_COMMENT) | 
|  | exp->commentq->append (msg); | 
|  | else | 
|  | delete msg; | 
|  | mkind = CMSG_NONE; | 
|  | mnum = -1; | 
|  | mec = -1; | 
|  | } | 
|  | else if (curElem == EL_PROFILE) | 
|  | dDscr = NULL; | 
|  | else if (curElem == EL_PROFPCKT) | 
|  | pDscr = NULL; | 
|  | else if (curElem == EL_FIELD) | 
|  | propDscr = NULL; | 
|  | free (text); | 
|  | text = NULL; | 
|  | popElem (); | 
|  | } | 
|  |  | 
|  | void | 
|  | Experiment::ExperimentHandler::error (SAXParseException *e) | 
|  | { | 
|  | StringBuilder sb; | 
|  | sb.sprintf (GTXT ("%s at line %d, column %d"), | 
|  | e->getMessage (), e->getLineNumber (), e->getColumnNumber ()); | 
|  | char *msg = sb.toString (); | 
|  | SAXException *e1 = new SAXException (msg); | 
|  | free (msg); | 
|  | throw ( e1); | 
|  | } | 
|  |  | 
|  | //-------------------------------------------------- Experiment | 
|  |  | 
|  | Experiment::Experiment () | 
|  | { | 
|  | groupId = 0; | 
|  | userExpId = expIdx = -1; | 
|  | founder_exp = NULL; | 
|  | baseFounder = NULL; | 
|  | children_exps = new Vector<Experiment*>; | 
|  | loadObjs = new Vector<LoadObject*>; | 
|  | loadObjMap = new StringMap<LoadObject*>(128, 128); | 
|  | sourcesMap = NULL; | 
|  |  | 
|  | // Initialize configuration information. | 
|  | status = FAILURE; | 
|  | start_sec = 0; | 
|  | mtime = 0; | 
|  | hostname = NULL; | 
|  | username = NULL; | 
|  | architecture = NULL; | 
|  | os_version = NULL; | 
|  | uarglist = NULL; | 
|  | utargname = NULL; | 
|  | ucwd = NULL; | 
|  | cversion = NULL; | 
|  | dversion = NULL; | 
|  | jversion = NULL; | 
|  | exp_maj_version = 0; | 
|  | exp_min_version = 0; | 
|  | platform = Unknown; | 
|  | bigendian = DbeSession::is_bigendian();  // can be changed in log.xml reading | 
|  | wsize = Wnone; | 
|  | page_size = 4096; | 
|  | npages = 0; | 
|  | stack_base = 0xf0000000; | 
|  | broken = 1; | 
|  | obsolete = 0; | 
|  | hwc_bogus = 0; | 
|  | hwc_lost_int = 0; | 
|  | hwc_scanned = 0; | 
|  | hwc_default = false; | 
|  | invalid_packet = 0; | 
|  |  | 
|  | // clear HWC event stats | 
|  | dsevents = 0; | 
|  | dsnoxhwcevents = 0; | 
|  |  | 
|  | memset (&coll_params, 0, sizeof (coll_params)); | 
|  | ncpus = 0; | 
|  | minclock = 0; | 
|  | maxclock = 0; | 
|  | clock = 0; | 
|  | varclock = 0; | 
|  | exec_started = false; | 
|  | timelineavail = true; | 
|  | leaklistavail = false; | 
|  | heapdataavail = false; | 
|  | iodataavail = false; | 
|  | dataspaceavail = false; | 
|  | ifreqavail = false; | 
|  | racelistavail = false; | 
|  | deadlocklistavail = false; | 
|  | ompavail = false; | 
|  | tiny_threshold = -1; | 
|  | pid = 0; | 
|  | ppid = 0; | 
|  | pgrp = 0; | 
|  | sid = 0; | 
|  |  | 
|  | gc_duration = ZERO_TIME; | 
|  | exp_start_time = ZERO_TIME; // not known.  Wall-clock hrtime (not zero based) | 
|  | last_event = ZERO_TIME; // not known.  Wall-clock hrtime (not zero based) | 
|  | non_paused_time = 0; // 0 non-paused time (will sum as experiment is processed) | 
|  | resume_ts = 0; // by default, collection is "resumed" (not paused) from time=0 | 
|  | need_swap_endian = false; | 
|  | exp_rel_start_time_set = false; | 
|  | exp_rel_start_time = ZERO_TIME; | 
|  | has_java = false; | 
|  | hex_field_width = 8; | 
|  | hw_cpuver = CPUVER_UNDEFINED; | 
|  | machinemodel = NULL; | 
|  | expt_name = NULL; | 
|  | arch_name = NULL; | 
|  | fndr_arch_name = NULL; | 
|  | dyntext_name = NULL; | 
|  | logFile = NULL; | 
|  |  | 
|  | dataDscrs = new Vector<DataDescriptor*>; | 
|  | for (int i = 0; i < DATA_LAST; ++i) | 
|  | dataDscrs->append (NULL); | 
|  |  | 
|  | pcktDscrs = new Vector<PacketDescriptor*>; | 
|  | blksz = PROFILE_BUFFER_CHUNK; | 
|  | jthreads = new Vector<JThread*>; | 
|  | jthreads_idx = new Vector<JThread*>; | 
|  | gcevents = new Vector<GCEvent*>; | 
|  | gcevent_last_used = (GCEvent *) NULL; | 
|  | heapUnmapEvents = new Vector<UnmapChunk*>; | 
|  | cstack = NULL; | 
|  | cstackShowHide = NULL; | 
|  | frmpckts = new Vector<RawFramePacket*>; | 
|  | typedef DefaultMap2D<uint32_t, hrtime_t, uint64_t> OmpMap0; | 
|  | mapPRid = new OmpMap0 (OmpMap0::Interval); | 
|  | typedef DefaultMap2D<uint32_t, hrtime_t, void*> OmpMap; | 
|  | mapPReg = new OmpMap (OmpMap::Interval); | 
|  | mapTask = new OmpMap (OmpMap::Interval); | 
|  | openMPdata = NULL; | 
|  | archiveMap = NULL; | 
|  | nnodes = 0; | 
|  | nchunks = 0; | 
|  | chunks = NULL; | 
|  | uidHTable = NULL; | 
|  | uidnodes = new Vector<UIDnode*>; | 
|  | mrecs = new Vector<MapRecord*>; | 
|  | samples = new Vector<Sample*>; | 
|  | sample_last_used = (Sample *) NULL; | 
|  | first_sample_label = (char*) NULL; | 
|  | fDataMap = NULL; | 
|  | vFdMap = NULL; | 
|  | resolveFrameInfo = true; | 
|  | discardTiny = false; | 
|  | init (); | 
|  | } | 
|  |  | 
|  | Experiment::~Experiment () | 
|  | { | 
|  | fini (); | 
|  | free (coll_params.linetrace); | 
|  | for (int i = 0; i < MAX_HWCOUNT; i++) | 
|  | { | 
|  | free (coll_params.hw_aux_name[i]); | 
|  | free (coll_params.hw_username[i]); | 
|  | } | 
|  | free (hostname); | 
|  | free (username); | 
|  | free (architecture); | 
|  | free (os_version); | 
|  | free (uarglist); | 
|  | free (utargname); | 
|  | free (ucwd); | 
|  | free (cversion); | 
|  | free (dversion); | 
|  | free (jversion); | 
|  | delete logFile; | 
|  | free (expt_name); | 
|  | free (arch_name); | 
|  | free (fndr_arch_name); | 
|  | free (dyntext_name); | 
|  | delete jthreads_idx; | 
|  | delete cstack; | 
|  | delete cstackShowHide; | 
|  | delete mapPRid; | 
|  | delete mapPReg; | 
|  | delete mapTask; | 
|  | delete openMPdata; | 
|  | destroy_map (DbeFile *, archiveMap); | 
|  | delete[] uidHTable; | 
|  | delete uidnodes; | 
|  | delete mrecs; | 
|  | delete children_exps; | 
|  | delete loadObjs; | 
|  | delete loadObjMap; | 
|  | delete sourcesMap; | 
|  | free (first_sample_label); | 
|  | free (machinemodel); | 
|  |  | 
|  | dataDscrs->destroy (); | 
|  | delete dataDscrs; | 
|  | pcktDscrs->destroy (); | 
|  | delete pcktDscrs; | 
|  | jthreads->destroy (); | 
|  | delete jthreads; | 
|  | gcevents->destroy (); | 
|  | delete gcevents; | 
|  | heapUnmapEvents->destroy (); | 
|  | delete heapUnmapEvents; | 
|  | frmpckts->destroy (); | 
|  | delete frmpckts; | 
|  | samples->destroy (); | 
|  | delete samples; | 
|  | delete fDataMap; | 
|  | delete vFdMap; | 
|  |  | 
|  | for (long i = 0; i < nchunks; i++) | 
|  | delete[] chunks[i]; | 
|  | delete[] chunks; | 
|  | } | 
|  |  | 
|  | void | 
|  | Experiment::init_cache () | 
|  | { | 
|  | if (smemHTable) | 
|  | return; | 
|  | smemHTable = new SegMem*[HTableSize]; | 
|  | instHTable = new DbeInstr*[HTableSize]; | 
|  | for (int i = 0; i < HTableSize; i++) | 
|  | { | 
|  | smemHTable[i] = NULL; | 
|  | instHTable[i] = NULL; | 
|  | } | 
|  | uidHTable = new UIDnode*[HTableSize]; | 
|  | for (int i = 0; i < HTableSize; i++) | 
|  | uidHTable[i] = NULL; | 
|  |  | 
|  | cstack = CallStack::getInstance (this); | 
|  | cstackShowHide = CallStack::getInstance (this); | 
|  | } | 
|  |  | 
|  | void | 
|  | Experiment::init () | 
|  | { | 
|  | userLabels = NULL; | 
|  | seg_items = new Vector<SegMem*>; | 
|  | maps = new PRBTree (); | 
|  | jmaps = NULL; // used by JAVA_CLASSES only | 
|  | jmidHTable = NULL; | 
|  | smemHTable = NULL; | 
|  | instHTable = NULL; | 
|  | min_thread = (uint64_t) - 1; | 
|  | max_thread = 0; | 
|  | thread_cnt = 0; | 
|  | min_lwp = (uint64_t) - 1; | 
|  | max_lwp = 0; | 
|  | lwp_cnt = 0; | 
|  | min_cpu = (uint64_t) - 1; | 
|  | max_cpu = 0; | 
|  | cpu_cnt = 0; | 
|  |  | 
|  | commentq = new Emsgqueue (NTXT ("commentq")); | 
|  | runlogq = new Emsgqueue (NTXT ("runlogq")); | 
|  | errorq = new Emsgqueue (NTXT ("errorq")); | 
|  | warnq = new Emsgqueue (NTXT ("warnq")); | 
|  | notesq = new Emsgqueue (NTXT ("notesq")); | 
|  | pprocq = new Emsgqueue (NTXT ("pprocq")); | 
|  | ifreqq = NULL; | 
|  |  | 
|  | metrics = new Vector<BaseMetric*>; | 
|  | tagObjs = new Vector<Vector<Histable*>*>; | 
|  | tagObjs->store (PROP_THRID, new Vector<Histable*>); | 
|  | tagObjs->store (PROP_LWPID, new Vector<Histable*>); | 
|  | tagObjs->store (PROP_CPUID, new Vector<Histable*>); | 
|  | tagObjs->store (PROP_EXPID, new Vector<Histable*>); | 
|  | sparse_threads = false; | 
|  | } | 
|  |  | 
|  | void | 
|  | Experiment::fini () | 
|  | { | 
|  | seg_items->destroy (); | 
|  | delete seg_items; | 
|  | delete maps; | 
|  | delete jmaps; | 
|  | delete[] smemHTable; | 
|  | delete[] instHTable; | 
|  | delete jmidHTable; | 
|  | delete commentq; | 
|  | delete runlogq; | 
|  | delete errorq; | 
|  | delete warnq; | 
|  | delete notesq; | 
|  | delete pprocq; | 
|  | if (ifreqq != NULL) | 
|  | { | 
|  | delete ifreqq; | 
|  | ifreqq = NULL; | 
|  | } | 
|  |  | 
|  | int index; | 
|  | BaseMetric *mtr; | 
|  | Vec_loop (BaseMetric*, metrics, index, mtr) | 
|  | { | 
|  | dbeSession->drop_metric (mtr); | 
|  | } | 
|  | delete metrics; | 
|  | tagObjs->fetch (PROP_THRID)->destroy (); | 
|  | tagObjs->fetch (PROP_LWPID)->destroy (); | 
|  | tagObjs->fetch (PROP_CPUID)->destroy (); | 
|  | tagObjs->fetch (PROP_EXPID)->destroy (); | 
|  | tagObjs->destroy (); | 
|  | delete tagObjs; | 
|  | } | 
|  |  | 
|  | // These are the data files which can be read in parallel | 
|  | // for multiple sub-experiments. | 
|  | // Postpone calling resolve_frame_info() | 
|  | void | 
|  | Experiment::read_experiment_data (bool read_ahead) | 
|  | { | 
|  |  | 
|  | read_frameinfo_file (); | 
|  | if (read_ahead) | 
|  | { | 
|  | resolveFrameInfo = false; | 
|  | (void) get_profile_events (); | 
|  | resolveFrameInfo = true; | 
|  | } | 
|  | } | 
|  |  | 
|  | Experiment::Exp_status | 
|  | Experiment::open_epilogue () | 
|  | { | 
|  |  | 
|  | // set up mapping for tagObj(PROP_EXPID) | 
|  | (void) mapTagValue (PROP_EXPID, userExpId); | 
|  |  | 
|  | post_process (); | 
|  | if (last_event != ZERO_TIME) | 
|  | { // if last_event is known | 
|  | StringBuilder sb; | 
|  | hrtime_t ts = last_event - exp_start_time; | 
|  | sb.sprintf (GTXT ("Experiment Ended: %ld.%09ld\nData Collection Duration: %ld.%09ld"), | 
|  | (long) (ts / NANOSEC), (long) (ts % NANOSEC), | 
|  | (long) (non_paused_time / NANOSEC), | 
|  | (long) (non_paused_time % NANOSEC)); | 
|  | runlogq->append (new Emsg (CMSG_COMMENT, sb)); | 
|  | } | 
|  |  | 
|  | // Check for incomplete experiment, and inform the user | 
|  | if (status == INCOMPLETE) | 
|  | { | 
|  | if (exec_started == true) | 
|  | // experiment ended with the exec, not abnormally | 
|  | status = SUCCESS; | 
|  | else | 
|  | { | 
|  | char * cmnt = GTXT ("*** Note: experiment was not closed"); | 
|  | commentq->append (new Emsg (CMSG_COMMENT, cmnt)); | 
|  | // runlogq->append(new Emsg(CMSG_COMMENT, cmnt)); | 
|  | } | 
|  | } | 
|  | // write a descriptive header for the experiment | 
|  | write_header (); | 
|  | return status; | 
|  | } | 
|  |  | 
|  | Experiment::Exp_status | 
|  | Experiment::open (char *path) | 
|  | { | 
|  |  | 
|  | // Find experiment directory | 
|  | if (find_expdir (path) != SUCCESS) | 
|  | // message will have been queued and status set | 
|  | return status; | 
|  |  | 
|  | // Get creation time for experiment | 
|  | dbe_stat_t st; | 
|  | if (dbe_stat (path, &st) == 0) | 
|  | mtime = st.st_mtime; | 
|  |  | 
|  | // Read the warnings file | 
|  | read_warn_file (); | 
|  |  | 
|  | // Open the log file | 
|  | read_log_file (); | 
|  | if (status == SUCCESS && last_event // last event is initialized | 
|  | && (last_event - exp_start_time) / 1000000 < tiny_threshold) | 
|  | { | 
|  | // Process "tiny_threshold" (SP_ANALYZER_DISCARD_TINY_EXPERIMENTS) | 
|  | // At this point, we've only processed log.xml. | 
|  | // Note: if an experiment terminated abnormally, last_event will not yet | 
|  | //   represent events from clock profiling and other metrics. | 
|  | //   Other events will often have timestamps after the last log.xml entry. | 
|  | discardTiny = true; | 
|  | return status; | 
|  | } | 
|  | if (status == FAILURE) | 
|  | { | 
|  | if (logFile->get_status () == ExperimentFile::EF_FAILURE) | 
|  | { | 
|  | Emsg *m = new Emsg (CMSG_FATAL, GTXT ("*** Error: log file in experiment cannot be read")); | 
|  | errorq->append (m); | 
|  | } | 
|  | else if (fetch_errors () == NULL) | 
|  | { | 
|  | if (broken == 1) | 
|  | { | 
|  | Emsg *m = new Emsg (CMSG_FATAL, GTXT ("*** Error: log does not show target starting")); | 
|  | errorq->append (m); | 
|  | } | 
|  | else | 
|  | { | 
|  | Emsg *m = new Emsg (CMSG_FATAL, GTXT ("*** Error: log file in experiment could not be parsed")); | 
|  | errorq->append (m); | 
|  | } | 
|  | } | 
|  | return status; | 
|  | } | 
|  | init_cache (); | 
|  | if (varclock != 0) | 
|  | { | 
|  | StringBuilder sb; | 
|  | sb.sprintf ( | 
|  | GTXT ("*** Warning: system has variable clock frequency, which may cause variable execution times and inaccurate conversions of cycle counts into time.")); | 
|  | warnq->append (new Emsg (CMSG_WARN, sb)); | 
|  | } | 
|  |  | 
|  | // Read the notes file | 
|  | read_notes_file (); | 
|  | read_labels_file (); | 
|  | read_archives (); | 
|  |  | 
|  | // The log file shows experiment started | 
|  | read_java_classes_file (); | 
|  |  | 
|  | read_map_file (); | 
|  |  | 
|  | // Dyntext file has to be processed after loadobjects file | 
|  | // as we need to be able to map (vaddr,ts) to dynamic functions. | 
|  | read_dyntext_file (); | 
|  |  | 
|  | // Read the overview file and create samples. | 
|  | // Profiling data hasn't been read yet so we may have | 
|  | // events after the last recorded sample. | 
|  | // We'll create a fake sample to cover all those | 
|  | // events later. | 
|  | read_overview_file (); | 
|  |  | 
|  | // Check if instruction frequency data is available | 
|  | read_ifreq_file (); | 
|  |  | 
|  | // Check if OMP data is available | 
|  | read_omp_file (); | 
|  |  | 
|  | return status; | 
|  | } | 
|  |  | 
|  | /* XXX -- update() is a no-op now, but may be needed for auto-update */ | 
|  | Experiment::Exp_status | 
|  | Experiment::update () | 
|  | { | 
|  | return status; | 
|  | } | 
|  |  | 
|  | void | 
|  | Experiment::append (LoadObject *lo) | 
|  | { | 
|  | loadObjs->append (lo); | 
|  | char *obj_name = lo->get_pathname (); | 
|  | char *bname = get_basename (obj_name); | 
|  | loadObjMap->put (obj_name, lo); | 
|  | loadObjMap->put (bname, lo); | 
|  | if (lo->flags & SEG_FLAG_EXE) | 
|  | loadObjMap->put (COMP_EXE_NAME, lo); | 
|  | } | 
|  |  | 
|  | void | 
|  | Experiment::read_notes_file () | 
|  | { | 
|  | Emsg *m; | 
|  |  | 
|  | // Open log file: | 
|  | char *fname = dbe_sprintf (NTXT ("%s/%s"), expt_name, SP_NOTES_FILE); | 
|  | FILE *f = fopen (fname, NTXT ("r")); | 
|  | free (fname); | 
|  | if (f == NULL) | 
|  | return; | 
|  | if (!dbeSession->is_interactive ()) | 
|  | { | 
|  | m = new Emsg (CMSG_COMMENT, NTXT ("Notes:")); | 
|  | notesq->append (m); | 
|  | } | 
|  |  | 
|  | while (1) | 
|  | { | 
|  | char str[MAXPATHLEN]; | 
|  | char *e = fgets (str, ((int) sizeof (str)) - 1, f); | 
|  | if (e == NULL) | 
|  | { | 
|  | if (!dbeSession->is_interactive ()) | 
|  | { | 
|  | m = new Emsg (CMSG_COMMENT, | 
|  | "============================================================"); | 
|  | notesq->append (m); | 
|  | } | 
|  | break; | 
|  | } | 
|  | size_t i = strlen (str); | 
|  | if (i > 0 && str[i - 1] == '\n') | 
|  | // remove trailing nl | 
|  | str[i - 1] = 0; | 
|  | m = new Emsg (CMSG_COMMENT, str); | 
|  | notesq->append (m); | 
|  | } | 
|  | (void) fclose (f); | 
|  | } | 
|  |  | 
|  | int | 
|  | Experiment::save_notes (char* text, bool handle_file) | 
|  | { | 
|  | if (handle_file) | 
|  | { | 
|  | FILE *fnotes; | 
|  | char *fname = dbe_sprintf (NTXT ("%s/%s"), expt_name, SP_NOTES_FILE); | 
|  | fnotes = fopen (fname, NTXT ("w")); | 
|  | free (fname); | 
|  | if (fnotes != NULL) | 
|  | { | 
|  | (void) fprintf (fnotes, NTXT ("%s"), text); | 
|  | fclose (fnotes); | 
|  | } | 
|  | else | 
|  | return 1; // Cannot write file | 
|  | } | 
|  | notesq->clear (); | 
|  | Emsg *m = new Emsg (CMSG_COMMENT, text); | 
|  | notesq->append (m); | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | int | 
|  | Experiment::delete_notes (bool handle_file) | 
|  | { | 
|  | if (handle_file) | 
|  | { | 
|  | char *fname = dbe_sprintf (NTXT ("%s/%s"), expt_name, SP_NOTES_FILE); | 
|  | if (unlink (fname) != 0) | 
|  | { | 
|  | free (fname); | 
|  | return 1; // Cannot delete file | 
|  | } | 
|  | free (fname); | 
|  | } | 
|  | notesq->clear (); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | int | 
|  | Experiment::read_warn_file () | 
|  | { | 
|  | int local_status = SUCCESS; | 
|  |  | 
|  | ExperimentFile *warnFile = new ExperimentFile (this, SP_WARN_FILE); | 
|  | if (warnFile == NULL) | 
|  | return FAILURE; | 
|  | if (!warnFile->open ()) | 
|  | { | 
|  | delete warnFile; | 
|  | return FAILURE; | 
|  | } | 
|  | SAXParserFactory *factory = SAXParserFactory::newInstance (); | 
|  | SAXParser *saxParser = factory->newSAXParser (); | 
|  | DefaultHandler *dh = new ExperimentHandler (this); | 
|  | try | 
|  | { | 
|  | saxParser->parse ((File*) warnFile->fh, dh); | 
|  | } | 
|  | catch (SAXException *e) | 
|  | { | 
|  | // Fatal error in the parser | 
|  | StringBuilder sb; | 
|  | sb.sprintf (NTXT ("%s: %s"), SP_WARN_FILE, e->getMessage ()); | 
|  | char *str = sb.toString (); | 
|  | Emsg *m = new Emsg (CMSG_FATAL, str); | 
|  | errorq->append (m); | 
|  | local_status = FAILURE; | 
|  | delete e; | 
|  | } | 
|  | delete warnFile; | 
|  | delete dh; | 
|  | delete saxParser; | 
|  | delete factory; | 
|  |  | 
|  | return local_status; | 
|  | } | 
|  |  | 
|  | int | 
|  | Experiment::read_log_file () | 
|  | { | 
|  | if (logFile == NULL) | 
|  | logFile = new ExperimentFile (this, SP_LOG_FILE); | 
|  | if (!logFile->open ()) | 
|  | { | 
|  | status = FAILURE; | 
|  | return status; | 
|  | } | 
|  |  | 
|  | SAXParserFactory *factory = SAXParserFactory::newInstance (); | 
|  | SAXParser *saxParser = factory->newSAXParser (); | 
|  | DefaultHandler *dh = new ExperimentHandler (this); | 
|  | try | 
|  | { | 
|  | saxParser->parse ((File*) logFile->fh, dh); | 
|  | } | 
|  | catch (SAXException *e) | 
|  | { | 
|  | // Fatal error in the parser | 
|  | StringBuilder sb; | 
|  | if (obsolete == 1) | 
|  | sb.sprintf (NTXT ("%s"), e->getMessage ()); | 
|  | else | 
|  | sb.sprintf (NTXT ("%s: %s"), SP_LOG_FILE, e->getMessage ()); | 
|  | char *str = sb.toString (); | 
|  | Emsg *m = new Emsg (CMSG_FATAL, str); | 
|  | errorq->append (m); | 
|  | status = FAILURE; | 
|  | delete e; | 
|  | } | 
|  | logFile->close (); | 
|  | dbeSession->register_metric (GTXT ("IPC"), GTXT ("Instructions Per Cycle"), | 
|  | NTXT ("insts/cycles")); | 
|  | dbeSession->register_metric (GTXT ("CPI"), GTXT ("Cycles Per Instruction"), | 
|  | NTXT ("cycles/insts")); | 
|  | dbeSession->register_metric (GTXT ("K_IPC"), | 
|  | GTXT ("Kernel Instructions Per Cycle"), | 
|  | NTXT ("K_insts/K_cycles")); | 
|  | dbeSession->register_metric (GTXT ("K_CPI"), | 
|  | GTXT ("Kernel Cycles Per Instruction"), | 
|  | NTXT ("K_cycles/K_insts")); | 
|  |  | 
|  | delete dh; | 
|  | delete saxParser; | 
|  | delete factory; | 
|  |  | 
|  | return status; | 
|  | } | 
|  |  | 
|  | //////////////////////////////////////////////////////////////////////////////// | 
|  | //  class Experiment::ExperimentLabelsHandler | 
|  | // | 
|  |  | 
|  | class Experiment::ExperimentLabelsHandler : public DefaultHandler | 
|  | { | 
|  | public: | 
|  |  | 
|  | ExperimentLabelsHandler (Experiment *_exp) | 
|  | { | 
|  | exp = _exp; | 
|  | } | 
|  |  | 
|  | ~ExperimentLabelsHandler () { }; | 
|  | void startDocument () { } | 
|  | void endDocument () { } | 
|  | void endElement (char * /*uri*/, char * /*localName*/, char * /*qName*/) { } | 
|  | void characters (char * /*ch*/, int /*start*/, int /*length*/) { } | 
|  | void ignorableWhitespace (char*, int, int) { } | 
|  | void error (SAXParseException * /*e*/) { } | 
|  |  | 
|  | void startElement (char *uri, char *localName, char *qName, Attributes *attrs); | 
|  |  | 
|  | private: | 
|  |  | 
|  | inline const char * | 
|  | s2s (const char *s) | 
|  | { | 
|  | return s ? s : "NULL"; | 
|  | } | 
|  |  | 
|  | Experiment *exp; | 
|  | }; | 
|  |  | 
|  | void | 
|  | Experiment::ExperimentLabelsHandler::startElement (char*, char*, char *qName, | 
|  | Attributes *attrs) | 
|  | { | 
|  | DEBUG_CODE if (DEBUG_SAXPARSER) dump_startElement (qName, attrs); | 
|  | if (qName == NULL || strcmp (qName, NTXT ("id")) != 0) | 
|  | return; | 
|  | char *name = NULL, *all_times = NULL, *comment = NULL, *hostName = NULL; | 
|  | long startSec = 0; | 
|  | //    long tm_zone = 0; | 
|  | hrtime_t startHrtime = (hrtime_t) 0; | 
|  | long long lbl_ts = 0; | 
|  | int relative = 0; | 
|  | timeval start_tv; | 
|  | start_tv.tv_usec = start_tv.tv_sec = 0; | 
|  | for (int i = 0, sz = attrs ? attrs->getLength () : 0; i < sz; i++) | 
|  | { | 
|  | const char *qn = attrs->getQName (i); | 
|  | const char *vl = attrs->getValue (i); | 
|  | if (strcmp (qn, NTXT ("name")) == 0) | 
|  | name = dbe_xml2str (vl); | 
|  | else if (strcmp (qn, NTXT ("cmd")) == 0) | 
|  | all_times = dbe_xml2str (vl); | 
|  | else if (strcmp (qn, NTXT ("comment")) == 0) | 
|  | comment = dbe_xml2str (vl); | 
|  | else if (strcmp (qn, NTXT ("relative")) == 0) | 
|  | relative = atoi (vl); | 
|  | else if (strcmp (qn, NTXT ("hostname")) == 0) | 
|  | hostName = dbe_xml2str (vl); | 
|  | else if (strcmp (qn, NTXT ("time")) == 0) | 
|  | startSec = atol (vl); | 
|  | else if (strcmp (qn, NTXT ("tstamp")) == 0) | 
|  | startHrtime = parseTStamp (vl); | 
|  | else if (strcmp (qn, NTXT ("lbl_ts")) == 0) | 
|  | { | 
|  | if (*vl == '-') | 
|  | lbl_ts = -parseTStamp (vl + 1); | 
|  | else | 
|  | lbl_ts = parseTStamp (vl); | 
|  | } | 
|  | } | 
|  | if (name == NULL || hostName == NULL || (all_times == NULL && comment == NULL)) | 
|  | { | 
|  | free (name); | 
|  | free (hostName); | 
|  | free (all_times); | 
|  | free (comment); | 
|  | return; | 
|  | } | 
|  | UserLabel *lbl = new UserLabel (name); | 
|  | lbl->comment = comment; | 
|  | lbl->hostname = hostName; | 
|  | lbl->start_sec = startSec; | 
|  | lbl->start_hrtime = startHrtime; | 
|  | exp->userLabels->append (lbl); | 
|  | if (all_times) | 
|  | { | 
|  | lbl->all_times = all_times; | 
|  | lbl->start_tv = start_tv; | 
|  | lbl->relative = relative; | 
|  | if (relative == UserLabel::REL_TIME) | 
|  | lbl->atime = lbl_ts; | 
|  | else | 
|  | { // relative == UserLabel::CUR_TIME | 
|  | long long delta = 0; | 
|  | if (exp->hostname && strcmp (lbl->hostname, exp->hostname) == 0) | 
|  | delta = lbl_ts + (lbl->start_hrtime - exp->exp_start_time); | 
|  | else | 
|  | for (int i = 0; i < exp->userLabels->size (); i++) | 
|  | { | 
|  | UserLabel *firstLbl = exp->userLabels->fetch (i); | 
|  | if (strcmp (lbl->hostname, firstLbl->hostname) == 0) | 
|  | { | 
|  | delta = lbl_ts + (lbl->start_hrtime - firstLbl->start_hrtime) + | 
|  | ((long long) (firstLbl->start_sec - exp->start_sec)) * NANOSEC; | 
|  | break; | 
|  | } | 
|  | } | 
|  | lbl->atime = delta > 0 ? delta : 0; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | static int | 
|  | sortUserLabels (const void *a, const void *b) | 
|  | { | 
|  | UserLabel *l1 = *((UserLabel **) a); | 
|  | UserLabel *l2 = *((UserLabel **) b); | 
|  | int v = dbe_strcmp (l1->name, l2->name); | 
|  | if (v != 0) | 
|  | return v; | 
|  | if (l1->atime < l2->atime) | 
|  | return -1; | 
|  | else if (l1->atime > l2->atime) | 
|  | return 1; | 
|  | if (l1->id < l2->id) | 
|  | return -1; | 
|  | else if (l1->id > l2->id) | 
|  | return 1; | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static char * | 
|  | append_string (char *s, char *str) | 
|  | { | 
|  | if (s == NULL) | 
|  | return dbe_strdup (str); | 
|  | char *new_s = dbe_sprintf (NTXT ("%s %s"), s, str); | 
|  | free (s); | 
|  | return new_s; | 
|  | } | 
|  |  | 
|  | void | 
|  | Experiment::read_labels_file () | 
|  | { | 
|  | ExperimentFile *fp = new ExperimentFile (this, SP_LABELS_FILE); | 
|  | if (!fp->open ()) | 
|  | { | 
|  | delete fp; | 
|  | return; | 
|  | } | 
|  | userLabels = new Vector<UserLabel*>(); | 
|  | SAXParserFactory *factory = SAXParserFactory::newInstance (); | 
|  | SAXParser *saxParser = factory->newSAXParser (); | 
|  | DefaultHandler *dh = new ExperimentLabelsHandler (this); | 
|  | try | 
|  | { | 
|  | saxParser->parse ((File*) fp->fh, dh); | 
|  | } | 
|  | catch (SAXException *e) | 
|  | { | 
|  | // Fatal error in the parser | 
|  | StringBuilder sb; | 
|  | sb.sprintf (NTXT ("%s: %s"), SP_LABELS_FILE, e->getMessage ()); | 
|  | char *str = sb.toString (); | 
|  | Emsg *m = new Emsg (CMSG_FATAL, str); | 
|  | errorq->append (m); | 
|  | delete e; | 
|  | } | 
|  | fp->close (); | 
|  | delete fp; | 
|  | delete dh; | 
|  | delete saxParser; | 
|  | delete factory; | 
|  |  | 
|  | userLabels->sort (sortUserLabels); | 
|  | UserLabel::dump ("After sortUserLabels:", userLabels); | 
|  | UserLabel *ulbl = NULL; | 
|  | for (int i = 0, sz = userLabels->size (); i < sz; i++) | 
|  | { | 
|  | UserLabel *lbl = userLabels->fetch (i); | 
|  | if (ulbl == NULL) | 
|  | ulbl = new UserLabel (lbl->name); | 
|  | else if (dbe_strcmp (lbl->name, ulbl->name) != 0) | 
|  | { // new Label | 
|  | ulbl->register_user_label (groupId); | 
|  | if (ulbl->expr == NULL) | 
|  | delete ulbl; | 
|  | ulbl = new UserLabel (lbl->name); | 
|  | } | 
|  | if (lbl->all_times) | 
|  | { | 
|  | if (strncmp (lbl->all_times, NTXT ("start"), 5) == 0) | 
|  | { | 
|  | if (!ulbl->start_f) | 
|  | { | 
|  | ulbl->start_f = true; | 
|  | ulbl->timeStart = lbl->atime; | 
|  | } | 
|  | } | 
|  | else | 
|  | { // stop | 
|  | if (!ulbl->start_f) | 
|  | continue; | 
|  | ulbl->all_times = append_string (ulbl->all_times, lbl->all_times); | 
|  | ulbl->stop_f = true; | 
|  | ulbl->timeStop = lbl->atime; | 
|  | ulbl->gen_expr (); | 
|  | } | 
|  | } | 
|  | if (lbl->comment != NULL) | 
|  | ulbl->comment = append_string (ulbl->comment, lbl->comment); | 
|  | } | 
|  | if (ulbl) | 
|  | { | 
|  | ulbl->register_user_label (groupId); | 
|  | if (ulbl->expr == NULL) | 
|  | delete ulbl; | 
|  | } | 
|  | Destroy (userLabels); | 
|  | } | 
|  |  | 
|  | void | 
|  | Experiment::read_archives () | 
|  | { | 
|  | if (founder_exp) | 
|  | return; | 
|  | char *allocated_str = NULL; | 
|  | char *nm = get_arch_name (); | 
|  | DIR *exp_dir = opendir (nm); | 
|  | if (exp_dir == NULL) | 
|  | { | 
|  | if (founder_exp == NULL) | 
|  | { | 
|  | // Check if the user uses a subexperiment only | 
|  | nm = dbe_sprintf (NTXT ("%s/../%s"), expt_name, SP_ARCHIVES_DIR); | 
|  | exp_dir = opendir (nm); | 
|  | if (exp_dir == NULL) | 
|  | { | 
|  | free (nm); | 
|  | return; | 
|  | } | 
|  | allocated_str = nm; | 
|  | } | 
|  | else | 
|  | return; | 
|  | } | 
|  |  | 
|  | StringBuilder sb; | 
|  | sb.append (nm); | 
|  | sb.append ('/'); | 
|  | int dlen = sb.length (); | 
|  | free (allocated_str); | 
|  | archiveMap = new StringMap<DbeFile *>(); | 
|  |  | 
|  | struct dirent *entry = NULL; | 
|  | while ((entry = readdir (exp_dir)) != NULL) | 
|  | { | 
|  | char *dname = entry->d_name; | 
|  | if (dname[0] == '.' | 
|  | && (dname[1] == '\0' || (dname[1] == '.' && dname[2] == '\0'))) | 
|  | // skip links to ./ or ../ | 
|  | continue; | 
|  | sb.setLength (dlen); | 
|  | sb.append (dname); | 
|  | char *fnm = sb.toString (); | 
|  | DbeFile *df = new DbeFile (fnm); | 
|  | df->set_location (fnm); | 
|  | df->filetype |= DbeFile::F_FILE; | 
|  | df->inArchive = true; | 
|  | df->experiment = this; | 
|  | archiveMap->put (dname, df); | 
|  | free (fnm); | 
|  | } | 
|  | closedir (exp_dir); | 
|  | } | 
|  |  | 
|  | static char * | 
|  | gen_file_name (const char *packet_name, const char *src_name) | 
|  | { | 
|  | char *fnm, *bname = get_basename (packet_name); | 
|  | if (bname == packet_name) | 
|  | fnm = dbe_strdup (src_name); | 
|  | else | 
|  | fnm = dbe_sprintf ("%.*s%s", (int) (bname - packet_name), | 
|  | packet_name, src_name); | 
|  |  | 
|  | // convert "java.lang.Object/Integer.java" => "java/lang/Object/Integer.java" | 
|  | bname = get_basename (fnm); | 
|  | for (char *s = fnm; s < bname; s++) | 
|  | if (*s == '.') | 
|  | *s = '/'; | 
|  | return fnm; | 
|  | } | 
|  |  | 
|  | static char * | 
|  | get_jlass_name (const char *nm) | 
|  | { | 
|  | // Convert "Ljava/lang/Object;" => "java/lang/Object.class" | 
|  | if (*nm == 'L') | 
|  | { | 
|  | size_t len = strlen (nm); | 
|  | if (nm[len - 1] == ';') | 
|  | return dbe_sprintf ("%.*s.class", (int) (len - 2), nm + 1); | 
|  | } | 
|  | return dbe_strdup (nm); | 
|  | } | 
|  |  | 
|  | static char * | 
|  | get_jmodule_name (const char *nm) | 
|  | { | 
|  | // convert "Ljava/lang/Object;" => "java.lang.Object" | 
|  | if (*nm == 'L') | 
|  | { | 
|  | size_t len = strlen (nm); | 
|  | if (nm[len - 1] == ';') | 
|  | { | 
|  | char *mname = dbe_sprintf (NTXT ("%.*s"), (int) (len - 2), nm + 1); | 
|  | for (char *s = mname; *s; s++) | 
|  | if (*s == '/') | 
|  | *s = '.'; | 
|  | return mname; | 
|  | } | 
|  | } | 
|  | return dbe_strdup (nm); | 
|  | } | 
|  |  | 
|  | LoadObject * | 
|  | Experiment::get_j_lo (const char *className, const char *fileName) | 
|  | { | 
|  | char *class_name = get_jlass_name (className); | 
|  | Dprintf (DUMP_JCLASS_READER, | 
|  | "Experiment::get_j_lo: className='%s' class_name='%s' fileName='%s'\n", | 
|  | STR (className), STR (class_name), STR (fileName)); | 
|  | LoadObject *lo = loadObjMap->get (class_name); | 
|  | if (lo == NULL) | 
|  | { | 
|  | lo = createLoadObject (class_name, fileName); | 
|  | lo->type = LoadObject::SEG_TEXT; | 
|  | lo->mtime = (time_t) 0; | 
|  | lo->size = 0; | 
|  | lo->set_platform (Java, wsize); | 
|  | lo->dbeFile->filetype |= DbeFile::F_FILE | DbeFile::F_JAVACLASS; | 
|  | append (lo); | 
|  | Dprintf (DUMP_JCLASS_READER, | 
|  | "Experiment::get_j_lo: creates '%s' location='%s'\n", | 
|  | STR (lo->get_name ()), STR (lo->dbeFile->get_location (false))); | 
|  | } | 
|  | free (class_name); | 
|  | return lo; | 
|  | } | 
|  |  | 
|  | Module * | 
|  | Experiment::get_jclass (const char *className, const char *fileName) | 
|  | { | 
|  | LoadObject *lo = get_j_lo (className, NULL); | 
|  | char *mod_name = get_jmodule_name (className); | 
|  | Module *mod = lo->find_module (mod_name); | 
|  | if (mod == NULL) | 
|  | { | 
|  | mod = dbeSession->createClassFile (mod_name); | 
|  | mod->loadobject = lo; | 
|  | if (strcmp (fileName, NTXT ("<Unknown>")) != 0) | 
|  | mod->set_file_name (gen_file_name (lo->get_pathname (), fileName)); | 
|  | else | 
|  | mod->set_file_name (dbe_strdup (fileName)); | 
|  | lo->append_module (mod); | 
|  | mod_name = NULL; | 
|  | } | 
|  | else if (mod->file_name && (strcmp (mod->file_name, "<Unknown>") == 0) | 
|  | && strcmp (fileName, "<Unknown>") != 0) | 
|  | mod->set_file_name (gen_file_name (lo->get_pathname (), fileName)); | 
|  | Dprintf (DUMP_JCLASS_READER, | 
|  | "Experiment::get_jclass: class_name='%s' mod_name='%s' fileName='%s'\n", | 
|  | mod->loadobject->get_pathname (), mod->get_name (), mod->file_name); | 
|  | free (mod_name); | 
|  | return mod; | 
|  | } | 
|  |  | 
|  | #define ARCH_STRLEN(s) ( ( strlen(s) + 4 ) & ~0x3 ) | 
|  |  | 
|  | int | 
|  | Experiment::read_java_classes_file () | 
|  | { | 
|  | char *data_file_name = dbe_sprintf (NTXT ("%s/%s"), expt_name, SP_JCLASSES_FILE); | 
|  | Data_window *dwin = new Data_window (data_file_name); | 
|  | free (data_file_name); | 
|  | if (dwin->not_opened ()) | 
|  | { | 
|  | delete dwin; | 
|  | return INCOMPLETE; | 
|  | } | 
|  | dwin->need_swap_endian = need_swap_endian; | 
|  | jmaps = new PRBTree (); | 
|  | jmidHTable = new DbeCacheMap<unsigned long long, JMethod>; | 
|  |  | 
|  | hrtime_t cur_loaded = 0; | 
|  | Module *cur_mod = NULL; | 
|  | for (int64_t offset = 0;;) | 
|  | { | 
|  | CM_Packet *cpkt = (CM_Packet*) dwin->bind (offset, sizeof (CM_Packet)); | 
|  | if (cpkt == NULL) | 
|  | break; | 
|  | uint16_t v16 = (uint16_t) cpkt->tsize; | 
|  | size_t cpktsize = dwin->decode (v16); | 
|  | cpkt = (CM_Packet*) dwin->bind (offset, cpktsize); | 
|  | if ((cpkt == NULL) || (cpktsize == 0)) | 
|  | { | 
|  | char *buf = dbe_sprintf (GTXT ("archive file malformed %s"), | 
|  | arch_name); | 
|  | errorq->append (new Emsg (CMSG_ERROR, buf)); | 
|  | free (buf); | 
|  | break; | 
|  | } | 
|  | v16 = (uint16_t) cpkt->type; | 
|  | v16 = dwin->decode (v16); | 
|  | switch (v16) | 
|  | { | 
|  | case ARCH_JCLASS: | 
|  | { | 
|  | ARCH_jclass *ajcl = (ARCH_jclass*) cpkt; | 
|  | uint64_t class_id = dwin->decode (ajcl->class_id); | 
|  | char *className = ((char*) ajcl) + sizeof (*ajcl); | 
|  | char *fileName = className + ARCH_STRLEN (className); | 
|  | Dprintf (DUMP_JCLASS_READER, | 
|  | "read_java_classes_file: ARCH_JCLASS(Ox%x)" | 
|  | "class_id=Ox%llx className='%s' fileName='%s' \n", | 
|  | (int) v16, (long long) class_id, className, fileName); | 
|  | cur_mod = NULL; | 
|  | if (*className == 'L') | 
|  | { // Old libcollector generated '[' (one array dimension). | 
|  | cur_mod = get_jclass (className, fileName); | 
|  | cur_loaded = dwin->decode (ajcl->tstamp); | 
|  | jmaps->insert (class_id, cur_loaded, cur_mod); | 
|  | } | 
|  | break; | 
|  | } | 
|  | case ARCH_JCLASS_LOCATION: | 
|  | { | 
|  | ARCH_jclass_location *ajcl = (ARCH_jclass_location *) cpkt; | 
|  | uint64_t class_id = dwin->decode (ajcl->class_id); | 
|  | char *className = ((char*) ajcl) + sizeof (*ajcl); | 
|  | char *fileName = className + ARCH_STRLEN (className); | 
|  | Dprintf (DUMP_JCLASS_READER, | 
|  | "read_java_classes_file: ARCH_JCLASS_LOCATION(Ox%x)" | 
|  | "class_id=Ox%llx className='%s' fileName='%s' \n", | 
|  | (int) v16, (long long) class_id, className, fileName); | 
|  | get_j_lo (className, fileName); | 
|  | break; | 
|  | } | 
|  | case ARCH_JMETHOD: | 
|  | { | 
|  | if (cur_mod == NULL) | 
|  | break; | 
|  | ARCH_jmethod *ajmt = (ARCH_jmethod*) cpkt; | 
|  | uint64_t method_id = dwin->decode (ajmt->method_id); | 
|  | char *s_name = ((char*) ajmt) + sizeof (*ajmt); | 
|  | char *s_signature = s_name + ARCH_STRLEN (s_name); | 
|  | char *fullname = dbe_sprintf ("%s.%s", cur_mod->get_name (), s_name); | 
|  | Dprintf (DUMP_JCLASS_READER, | 
|  | "read_java_classes_file: ARCH_JMETHOD(Ox%x) " | 
|  | "method_id=Ox%llx name='%s' signature='%s' fullname='%s'\n", | 
|  | (int) v16, (long long) method_id, s_name, | 
|  | s_signature, fullname); | 
|  | JMethod *jmthd = cur_mod->find_jmethod (fullname, s_signature); | 
|  | if (jmthd == NULL) | 
|  | { | 
|  | jmthd = dbeSession->createJMethod (); | 
|  | jmthd->size = (unsigned) - 1; // unknown until later (maybe) | 
|  | jmthd->module = cur_mod; | 
|  | jmthd->set_signature (s_signature); | 
|  | jmthd->set_name (fullname); | 
|  | cur_mod->functions->append (jmthd); | 
|  | cur_mod->loadobject->functions->append (jmthd); | 
|  | Dprintf (DUMP_JCLASS_READER, | 
|  | "read_java_classes_file: ARCH_JMETHOD CREATE fullname=%s\n", | 
|  | fullname); | 
|  | } | 
|  | jmaps->insert (method_id, cur_loaded, jmthd); | 
|  | free (fullname); | 
|  | break; | 
|  | } | 
|  | default: | 
|  | Dprintf (DUMP_JCLASS_READER, | 
|  | "read_java_classes_file: type=Ox%x (%d) cpktsize=%d\n", | 
|  | (int) v16, (int) v16, (int) cpktsize); | 
|  | break; // ignore unknown packets | 
|  | } | 
|  | offset += cpktsize; | 
|  | } | 
|  | delete dwin; | 
|  | return SUCCESS; | 
|  | } | 
|  |  | 
|  | void | 
|  | Experiment::read_map_file () | 
|  | { | 
|  | ExperimentFile *mapFile = new ExperimentFile (this, SP_MAP_FILE); | 
|  | if (!mapFile->open ()) | 
|  | { | 
|  | delete mapFile; | 
|  | return; | 
|  | } | 
|  |  | 
|  | SAXParserFactory *factory = SAXParserFactory::newInstance (); | 
|  | SAXParser *saxParser = factory->newSAXParser (); | 
|  | DefaultHandler *dh = new ExperimentHandler (this); | 
|  | try | 
|  | { | 
|  | saxParser->parse ((File*) mapFile->fh, dh); | 
|  | } | 
|  | catch (SAXException *e) | 
|  | { | 
|  | // Fatal error in the parser | 
|  | StringBuilder sb; | 
|  | sb.sprintf (NTXT ("%s: %s"), SP_MAP_FILE, e->getMessage ()); | 
|  | char *str = sb.toString (); | 
|  | Emsg *m = new Emsg (CMSG_FATAL, str); | 
|  | errorq->append (m); | 
|  | status = FAILURE; | 
|  | free (str); | 
|  | delete e; | 
|  | } | 
|  | delete mapFile; | 
|  | delete dh; | 
|  | delete saxParser; | 
|  | delete factory; | 
|  |  | 
|  | for (int i = 0, sz = mrecs ? mrecs->size () : 0; i < sz; i++) | 
|  | { | 
|  | MapRecord *mrec = mrecs->fetch (i); | 
|  | SegMem *smem, *sm_lo, *sm_hi; | 
|  | switch (mrec->kind) | 
|  | { | 
|  | case MapRecord::LOAD: | 
|  | smem = new SegMem; | 
|  | smem->base = mrec->base; | 
|  | smem->size = mrec->size; | 
|  | smem->load_time = mrec->ts; | 
|  | smem->unload_time = MAX_TIME; | 
|  | smem->obj = mrec->obj; | 
|  | smem->set_file_offset (mrec->foff); | 
|  | seg_items->append (smem); // add to the master list | 
|  |  | 
|  | // Check if the new segment overlaps other active segments | 
|  | sm_lo = (SegMem*) maps->locate (smem->base, smem->load_time); | 
|  | if (sm_lo && sm_lo->base + sm_lo->size > smem->base) | 
|  | { | 
|  | // check to see if it is a duplicate record: same address and size, and | 
|  | if ((smem->base == sm_lo->base) && (smem->size == sm_lo->size)) | 
|  | { | 
|  | // addresses and sizes match, check name | 
|  | if (strstr (smem->obj->get_name (), sm_lo->obj->get_name ()) != NULL | 
|  | || strstr (sm_lo->obj->get_name (), smem->obj->get_name ()) != NULL) | 
|  | // this is a duplicate; just move on the the next map record | 
|  | continue; | 
|  | fprintf (stderr, | 
|  | GTXT ("*** Warning: Segment `%s' loaded with same address, size as `%s' [0x%llx-0x%llx]\n"), | 
|  | smem->obj->get_name (), sm_lo->obj->get_name (), | 
|  | sm_lo->base, sm_lo->base + sm_lo->size); | 
|  | } | 
|  |  | 
|  | // Not a duplicate; implicitly unload the old one | 
|  | //     Note: implicit unloading causes high <Unknown> | 
|  | //           when such overlapping is bogus | 
|  | StringBuilder sb; | 
|  | sb.sprintf (GTXT ("*** Warning: Segment %s [0x%llx-0x%llx] overlaps %s [0x%llx-0x%llx], which has been implicitly unloaded"), | 
|  | smem->obj->get_name (), smem->base, smem->base + smem->size, | 
|  | sm_lo->obj->get_name (), sm_lo->base, sm_lo->base + sm_lo->size); | 
|  | warnq->append (new Emsg (CMSG_WARN, sb)); | 
|  | } | 
|  |  | 
|  | // now look for other segments with which this might overlap | 
|  | sm_hi = (SegMem*) maps->locate_up (smem->base, smem->load_time); | 
|  | while (sm_hi && sm_hi->base < smem->base + smem->size) | 
|  | { | 
|  |  | 
|  | // Note: implicit unloading causes high <Unknown> when such overlapping is bogus | 
|  | // maps->remove( sm_hi->base, smem->load_time ); | 
|  | StringBuilder sb; | 
|  | sb.sprintf (GTXT ("*** Warning: Segment %s [0x%llx-0x%llx] overlaps %s [0x%llx-0x%llx], which has been implicitly unloaded"), | 
|  | smem->obj->get_name (), smem->base, | 
|  | smem->base + smem->size, sm_hi->obj->get_name (), | 
|  | sm_hi->base, sm_hi->base + sm_hi->size); | 
|  | warnq->append (new Emsg (CMSG_WARN, sb)); | 
|  | sm_hi = (SegMem*) maps->locate_up (sm_hi->base + sm_hi->size, | 
|  | smem->load_time); | 
|  | } | 
|  |  | 
|  | maps->insert (smem->base, smem->load_time, smem); | 
|  | break; | 
|  | case MapRecord::UNLOAD: | 
|  | smem = (SegMem*) maps->locate (mrec->base, mrec->ts); | 
|  | if (smem && smem->base == mrec->base) | 
|  | { | 
|  | smem->unload_time = mrec->ts; | 
|  | maps->remove (mrec->base, mrec->ts); | 
|  | } | 
|  | break; | 
|  | } | 
|  | } | 
|  | mrecs->destroy (); | 
|  |  | 
|  | // See if there are comments or warnings for a load object; | 
|  | // if so, queue them to Experiment | 
|  | for (long i = 0, sz = loadObjs ? loadObjs->size () : 0; i < sz; i++) | 
|  | { | 
|  | LoadObject *lo = loadObjs->get (i); | 
|  | for (Emsg *m = lo->fetch_warnings (); m; m = m->next) | 
|  | warnq->append (m->get_warn (), m->get_msg ()); | 
|  | for (Emsg *m = lo->fetch_comments (); m; m = m->next) | 
|  | commentq->append (m->get_warn (), m->get_msg ()); | 
|  | } | 
|  | } | 
|  |  | 
|  | void | 
|  | Experiment::read_frameinfo_file () | 
|  | { | 
|  | init_cache (); | 
|  | char *base_name = get_basename (expt_name); | 
|  | char *msg = dbe_sprintf (GTXT ("Loading CallStack Data: %s"), base_name); | 
|  | read_data_file ("data." SP_FRINFO_FILE, msg); | 
|  | free (msg); | 
|  | frmpckts->sort (frUidCmp); | 
|  | uidnodes->sort (uidNodeCmp); | 
|  | } | 
|  |  | 
|  | void | 
|  | Experiment::read_omp_preg () | 
|  | { | 
|  | // Parallel region descriptions | 
|  | DataDescriptor *pregDdscr = getDataDescriptor (DATA_OMP4); | 
|  | if (pregDdscr == NULL) | 
|  | return; | 
|  | DataView *pregData = pregDdscr->createView (); | 
|  | pregData->sort (PROP_CPRID); // omptrace PROP_CPRID | 
|  |  | 
|  | // OpenMP enter parreg events | 
|  | DataDescriptor *dDscr = getDataDescriptor (DATA_OMP2); | 
|  | if (dDscr == NULL || dDscr->getSize () == 0) | 
|  | { | 
|  | delete pregData; | 
|  | return; | 
|  | } | 
|  |  | 
|  | char *idxname = NTXT ("OMP_preg"); | 
|  | delete dbeSession->indxobj_define (idxname, GTXT ("OpenMP Parallel Region"), | 
|  | NTXT ("CPRID"), NULL, NULL); | 
|  | int idxtype = dbeSession->findIndexSpaceByName (idxname); | 
|  | if (idxtype < 0) | 
|  | { | 
|  | delete pregData; | 
|  | return; | 
|  | } | 
|  | ompavail = true; | 
|  |  | 
|  | // Pre-create parallel region with id == 0 | 
|  | Histable *preg0 = dbeSession->createIndexObject (idxtype, (int64_t) 0); | 
|  | preg0->set_name (dbe_strdup (GTXT ("Implicit OpenMP Parallel Region"))); | 
|  |  | 
|  | // Take care of the progress bar | 
|  | char *msg = dbe_sprintf (GTXT ("Processing OpenMP Parallel Region Data: %s"), | 
|  | get_basename (expt_name)); | 
|  | theApplication->set_progress (0, msg); | 
|  | free (msg); | 
|  | long deltaReport = 1000; | 
|  | long nextReport = 0; | 
|  | long errors_found = 0; | 
|  | Vector<Histable*> pregs; | 
|  |  | 
|  | long size = dDscr->getSize (); | 
|  | for (long i = 0; i < size; ++i) | 
|  | { | 
|  | if (i == nextReport) | 
|  | { | 
|  | int percent = (int) (i * 100 / size); | 
|  | if (percent > 0) | 
|  | theApplication->set_progress (percent, NULL); | 
|  | nextReport += deltaReport; | 
|  | } | 
|  |  | 
|  | uint32_t thrid = dDscr->getIntValue (PROP_THRID, i); | 
|  | hrtime_t tstamp = dDscr->getLongValue (PROP_TSTAMP, i); | 
|  | uint64_t cprid = dDscr->getLongValue (PROP_CPRID, i); // omptrace CPRID | 
|  | mapPRid->put (thrid, tstamp, cprid); | 
|  |  | 
|  | pregs.reset (); | 
|  | /* | 
|  | * We will use 2 pointers to make sure there is no loop. | 
|  | * First pointer "curpreg" goes to the next element, | 
|  | * second pointer "curpreg_loop_control" goes to the next->next element. | 
|  | * If these pointers have the same value - there is a loop. | 
|  | */ | 
|  | uint64_t curpreg_loop_control = cprid; | 
|  | Datum tval_loop_control; | 
|  | if (curpreg_loop_control != 0) | 
|  | { | 
|  | tval_loop_control.setUINT64 (curpreg_loop_control); | 
|  | long idx = pregData->getIdxByVals (&tval_loop_control, DataView::REL_EQ); | 
|  | if (idx < 0) | 
|  | curpreg_loop_control = 0; | 
|  | else | 
|  | curpreg_loop_control = pregData->getLongValue (PROP_PPRID, idx); | 
|  | } | 
|  | for (uint64_t curpreg = cprid; curpreg != 0;) | 
|  | { | 
|  | Histable *val = NULL; | 
|  | Datum tval; | 
|  | tval.setUINT64 (curpreg); | 
|  | long idx = pregData->getIdxByVals (&tval, DataView::REL_EQ); | 
|  | if (idx < 0) | 
|  | break; | 
|  | /* | 
|  | * Check if there is a loop | 
|  | */ | 
|  | if (0 != curpreg_loop_control) | 
|  | { | 
|  | if (curpreg == curpreg_loop_control) | 
|  | { | 
|  | errors_found++; | 
|  | if (1 == errors_found) | 
|  | { | 
|  | Emsg *m = new Emsg (CMSG_WARN, GTXT ("*** Warning: circular links in OMP regions; data may not be correct.")); | 
|  | warnq->append (m); | 
|  | } | 
|  | break; | 
|  | } | 
|  | } | 
|  | uint64_t pragmapc = pregData->getLongValue (PROP_PRPC, idx); | 
|  | DbeInstr *instr = map_Vaddr_to_PC (pragmapc, tstamp); | 
|  | if (instr == NULL) | 
|  | { | 
|  | break; | 
|  | } | 
|  | val = instr; | 
|  | DbeLine *dbeline = (DbeLine*) instr->convertto (Histable::LINE); | 
|  | if (dbeline->lineno > 0) | 
|  | { | 
|  | if (instr->func->usrfunc) | 
|  | dbeline = dbeline->sourceFile->find_dbeline | 
|  | (instr->func->usrfunc, dbeline->lineno); | 
|  | dbeline->set_flag (DbeLine::OMPPRAGMA); | 
|  | val = dbeline; | 
|  | } | 
|  | val = dbeSession->createIndexObject (idxtype, val); | 
|  | pregs.append (val); | 
|  |  | 
|  | curpreg = pregData->getLongValue (PROP_PPRID, idx); | 
|  | /* | 
|  | * Update curpreg_loop_control | 
|  | */ | 
|  | if (0 != curpreg_loop_control) | 
|  | { | 
|  | tval_loop_control.setUINT64 (curpreg_loop_control); | 
|  | idx = pregData->getIdxByVals | 
|  | (&tval_loop_control, DataView::REL_EQ); | 
|  | if (idx < 0) | 
|  | curpreg_loop_control = 0; | 
|  | else | 
|  | { | 
|  | curpreg_loop_control = pregData->getLongValue | 
|  | (PROP_PPRID, idx); | 
|  | tval_loop_control.setUINT64 (curpreg_loop_control); | 
|  | idx = pregData->getIdxByVals | 
|  | (&tval_loop_control, DataView::REL_EQ); | 
|  | if (idx < 0) | 
|  | curpreg_loop_control = 0; | 
|  | else | 
|  | curpreg_loop_control = pregData->getLongValue | 
|  | (PROP_PPRID, idx); | 
|  | } | 
|  | } | 
|  | } | 
|  | pregs.append (preg0); | 
|  | void *prstack = cstack->add_stack (&pregs); | 
|  | mapPReg->put (thrid, tstamp, prstack); | 
|  | } | 
|  | theApplication->set_progress (0, NTXT ("")); | 
|  | delete pregData; | 
|  | } | 
|  |  | 
|  | void | 
|  | Experiment::read_omp_task () | 
|  | { | 
|  | // Task description | 
|  | DataDescriptor *taskDataDdscr = getDataDescriptor (DATA_OMP5); | 
|  | if (taskDataDdscr == NULL) | 
|  | return; | 
|  |  | 
|  | //7035272: previously, DataView was global; now it's local...is this OK? | 
|  | DataView *taskData = taskDataDdscr->createView (); | 
|  | taskData->sort (PROP_TSKID); // omptrace PROP_TSKID | 
|  |  | 
|  | // OpenMP enter task events | 
|  | DataDescriptor *dDscr = getDataDescriptor (DATA_OMP3); | 
|  | if (dDscr == NULL || dDscr->getSize () == 0) | 
|  | { | 
|  | delete taskData; | 
|  | return; | 
|  | } | 
|  |  | 
|  | char *idxname = NTXT ("OMP_task"); | 
|  | // delete a possible error message. Ugly. | 
|  | delete dbeSession->indxobj_define (idxname, GTXT ("OpenMP Task"), NTXT ("TSKID"), NULL, NULL); | 
|  | int idxtype = dbeSession->findIndexSpaceByName (idxname); | 
|  | if (idxtype < 0) | 
|  | { | 
|  | delete taskData; | 
|  | return; | 
|  | } | 
|  | ompavail = true; | 
|  |  | 
|  | // Pre-create task with id == 0 | 
|  | Histable *task0 = dbeSession->createIndexObject (idxtype, (int64_t) 0); | 
|  | task0->set_name (dbe_strdup (GTXT ("OpenMP Task from Implicit Parallel Region"))); | 
|  |  | 
|  | // Take care of the progress bar | 
|  | char *msg = dbe_sprintf (GTXT ("Processing OpenMP Task Data: %s"), get_basename (expt_name)); | 
|  | theApplication->set_progress (0, msg); | 
|  | free (msg); | 
|  | long deltaReport = 1000; | 
|  | long nextReport = 0; | 
|  |  | 
|  | Vector<Histable*> tasks; | 
|  | long size = dDscr->getSize (); | 
|  | long errors_found = 0; | 
|  | for (long i = 0; i < size; ++i) | 
|  | { | 
|  | if (i == nextReport) | 
|  | { | 
|  | int percent = (int) (i * 100 / size); | 
|  | if (percent > 0) | 
|  | theApplication->set_progress (percent, NULL); | 
|  | nextReport += deltaReport; | 
|  | } | 
|  |  | 
|  | uint32_t thrid = dDscr->getIntValue (PROP_THRID, i); | 
|  | hrtime_t tstamp = dDscr->getLongValue (PROP_TSTAMP, i); | 
|  | uint64_t tskid = dDscr->getLongValue (PROP_TSKID, i); //omptrace TSKID | 
|  | tasks.reset (); | 
|  | /* | 
|  | * We will use 2 pointers to make sure there is no loop. | 
|  | * First pointer "curtsk" goes to the next element, | 
|  | * second pointer "curtsk_loop_control" goes to the next->next element. | 
|  | * If these pointers have the same value - there is a loop. | 
|  | */ | 
|  | uint64_t curtsk_loop_control = tskid; | 
|  | Datum tval_loop_control; | 
|  | if (curtsk_loop_control != 0) | 
|  | { | 
|  | tval_loop_control.setUINT64 (curtsk_loop_control); | 
|  | long idx = taskData->getIdxByVals (&tval_loop_control, DataView::REL_EQ); | 
|  | if (idx < 0) | 
|  | curtsk_loop_control = 0; | 
|  | else | 
|  | curtsk_loop_control = taskData->getLongValue (PROP_PTSKID, idx); | 
|  | } | 
|  | for (uint64_t curtsk = tskid; curtsk != 0;) | 
|  | { | 
|  | Histable *val = NULL; | 
|  |  | 
|  | Datum tval; | 
|  | tval.setUINT64 (curtsk); | 
|  | long idx = taskData->getIdxByVals (&tval, DataView::REL_EQ); | 
|  | if (idx < 0) | 
|  | break; | 
|  | /* | 
|  | * Check if there is a loop | 
|  | */ | 
|  | if (0 != curtsk_loop_control) | 
|  | { | 
|  | if (curtsk == curtsk_loop_control) | 
|  | { | 
|  | errors_found++; | 
|  | if (1 == errors_found) | 
|  | { | 
|  | Emsg *m = new Emsg (CMSG_WARN, GTXT ("*** Warning: circular links in OMP tasks; data may not be correct.")); | 
|  | warnq->append (m); | 
|  | } | 
|  | break; | 
|  | } | 
|  | } | 
|  | uint64_t pragmapc = taskData->getLongValue (PROP_PRPC, idx); | 
|  | DbeInstr *instr = map_Vaddr_to_PC (pragmapc, tstamp); | 
|  | if (instr == NULL) | 
|  | break; | 
|  | val = instr; | 
|  | DbeLine *dbeline = (DbeLine*) instr->convertto (Histable::LINE); | 
|  | if (dbeline->lineno > 0) | 
|  | { | 
|  | if (instr->func->usrfunc) | 
|  | dbeline = dbeline->sourceFile->find_dbeline | 
|  | (instr->func->usrfunc, dbeline->lineno); | 
|  | dbeline->set_flag (DbeLine::OMPPRAGMA); | 
|  | val = dbeline; | 
|  | } | 
|  | val = dbeSession->createIndexObject (idxtype, val); | 
|  | tasks.append (val); | 
|  |  | 
|  | curtsk = taskData->getLongValue (PROP_PTSKID, idx); | 
|  | /* | 
|  | * Update curtsk_loop_control | 
|  | */ | 
|  | if (0 != curtsk_loop_control) | 
|  | { | 
|  | tval_loop_control.setUINT64 (curtsk_loop_control); | 
|  | idx = taskData->getIdxByVals (&tval_loop_control, DataView::REL_EQ); | 
|  | if (idx < 0) | 
|  | curtsk_loop_control = 0; | 
|  | else | 
|  | { | 
|  | curtsk_loop_control = taskData->getLongValue (PROP_PTSKID, idx); | 
|  | tval_loop_control.setUINT64 (curtsk_loop_control); | 
|  | idx = taskData->getIdxByVals (&tval_loop_control, | 
|  | DataView::REL_EQ); | 
|  | if (idx < 0) | 
|  | curtsk_loop_control = 0; | 
|  | else | 
|  | curtsk_loop_control = taskData->getLongValue (PROP_PTSKID, | 
|  | idx); | 
|  | } | 
|  | } | 
|  | } | 
|  | tasks.append (task0); | 
|  | void *tskstack = cstack->add_stack (&tasks); | 
|  | mapTask->put (thrid, tstamp, tskstack); | 
|  | } | 
|  | theApplication->set_progress (0, NTXT ("")); | 
|  | delete taskData; | 
|  | } | 
|  |  | 
|  | void | 
|  | Experiment::read_omp_file () | 
|  | { | 
|  | // DATA_OMP2 table is common between OpenMP 2.5 and 3.0 profiling | 
|  | DataDescriptor *dDscr = getDataDescriptor (DATA_OMP2); | 
|  | if (dDscr == NULL) | 
|  | return; | 
|  | if (dDscr->getSize () == 0) | 
|  | { | 
|  | char *base_name = get_basename (expt_name); | 
|  | char *msg = dbe_sprintf (GTXT ("Loading OpenMP Data: %s"), base_name); | 
|  | read_data_file (SP_OMPTRACE_FILE, msg); | 
|  | free (msg); | 
|  |  | 
|  | // OpenMP fork events | 
|  | dDscr = getDataDescriptor (DATA_OMP); | 
|  | long sz = dDscr->getSize (); | 
|  | if (sz > 0) | 
|  | { | 
|  | // progress bar | 
|  | msg = dbe_sprintf (GTXT ("Processing OpenMP Parallel Region Data: %s"), | 
|  | base_name); | 
|  | theApplication->set_progress (0, msg); | 
|  | free (msg); | 
|  | long deltaReport = 5000; | 
|  | long nextReport = 0; | 
|  | for (int i = 0; i < sz; ++i) | 
|  | { | 
|  | if (i == nextReport) | 
|  | { | 
|  | int percent = (int) (i * 100 / sz); | 
|  | if (percent > 0) | 
|  | theApplication->set_progress (percent, NULL); | 
|  | nextReport += deltaReport; | 
|  | } | 
|  | uint32_t thrid = dDscr->getIntValue (PROP_THRID, i); | 
|  | hrtime_t tstamp = dDscr->getLongValue (PROP_TSTAMP, i); | 
|  | uint64_t cprid = dDscr->getLongValue (PROP_CPRID, i); //omptrace | 
|  | mapPRid->put (thrid, tstamp, cprid); | 
|  | } | 
|  | theApplication->set_progress (0, NTXT ("")); | 
|  |  | 
|  | ompavail = true; | 
|  | openMPdata = dDscr->createView (); | 
|  | openMPdata->sort (PROP_CPRID); // omptrace PROP_CPRID | 
|  |  | 
|  | // thread enters parreg events | 
|  | dDscr = getDataDescriptor (DATA_OMP2); | 
|  | sz = dDscr->getSize (); | 
|  |  | 
|  | // progress bar | 
|  | msg = dbe_sprintf (GTXT ("Processing OpenMP Parallel Region Data: %s"), | 
|  | base_name); | 
|  | theApplication->set_progress (0, msg); | 
|  | free (msg); | 
|  | deltaReport = 5000; | 
|  | nextReport = 0; | 
|  |  | 
|  | for (int i = 0; i < sz; ++i) | 
|  | { | 
|  | if (i == nextReport) | 
|  | { | 
|  | int percent = (int) (i * 100 / sz); | 
|  | if (percent > 0) | 
|  | theApplication->set_progress (percent, NULL); | 
|  | nextReport += deltaReport; | 
|  | } | 
|  | uint32_t thrid = dDscr->getIntValue (PROP_THRID, i); | 
|  | hrtime_t tstamp = dDscr->getLongValue (PROP_TSTAMP, i); | 
|  | uint64_t cprid = dDscr->getLongValue (PROP_CPRID, i); //omptrace | 
|  | mapPRid->put (thrid, tstamp, cprid); | 
|  | } | 
|  | theApplication->set_progress (0, NTXT ("")); | 
|  | } | 
|  | else | 
|  | { | 
|  | read_omp_preg (); | 
|  | read_omp_task (); | 
|  | } | 
|  | if (ompavail && coll_params.profile_mode) | 
|  | { | 
|  | dbeSession->status_ompavail = 1; | 
|  | register_metric (Metric::OMP_WORK); | 
|  | register_metric (Metric::OMP_WAIT); | 
|  | register_metric (Metric::OMP_OVHD); | 
|  | if (coll_params.lms_magic_id == LMS_MAGIC_ID_SOLARIS) | 
|  | register_metric (Metric::OMP_MASTER_THREAD); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | void | 
|  | Experiment::read_ifreq_file () | 
|  | { | 
|  | char *fname = dbe_sprintf (NTXT ("%s/%s"), expt_name, SP_IFREQ_FILE); | 
|  | FILE *f = fopen (fname, NTXT ("r")); | 
|  | free (fname); | 
|  | if (f == NULL) | 
|  | { | 
|  | ifreqavail = false; | 
|  | return; | 
|  | } | 
|  | ifreqavail = true; | 
|  | ifreqq = new Emsgqueue (NTXT ("ifreqq")); | 
|  |  | 
|  | while (1) | 
|  | { | 
|  | Emsg *m; | 
|  | char str[MAXPATHLEN]; | 
|  | char *e = fgets (str, ((int) sizeof (str)) - 1, f); | 
|  | if (e == NULL) | 
|  | { | 
|  | // end the list from the experiment | 
|  | m = new Emsg (CMSG_COMMENT, | 
|  | GTXT ("============================================================")); | 
|  | ifreqq->append (m); | 
|  | break; | 
|  | } | 
|  | // get the string | 
|  | size_t i = strlen (str); | 
|  | if (i > 0 && str[i - 1] == '\n') | 
|  | // remove trailing nl | 
|  | str[i - 1] = 0; | 
|  | // and append it | 
|  | m = new Emsg (CMSG_COMMENT, str); | 
|  | ifreqq->append (m); | 
|  | } | 
|  | (void) fclose (f); | 
|  | } | 
|  |  | 
|  | Experiment * | 
|  | Experiment::getBaseFounder () | 
|  | { | 
|  | if (baseFounder) | 
|  | return baseFounder; | 
|  | Experiment *founder = this; | 
|  | Experiment *parent = founder->founder_exp; | 
|  | while (parent) | 
|  | { | 
|  | founder = parent; | 
|  | parent = founder->founder_exp; | 
|  | } | 
|  | baseFounder = founder; | 
|  | return baseFounder; | 
|  | } | 
|  |  | 
|  | hrtime_t | 
|  | Experiment::getRelativeStartTime () | 
|  | { | 
|  | if (exp_rel_start_time_set) | 
|  | return exp_rel_start_time; | 
|  | Experiment *founder = getBaseFounder (); | 
|  | hrtime_t child_start = this->getStartTime (); | 
|  | hrtime_t founder_start = founder->getStartTime (); | 
|  | exp_rel_start_time = child_start - founder_start; | 
|  | if (child_start == 0 && founder_start) | 
|  | exp_rel_start_time = 0;     // when descendents have incomplete log.xml | 
|  | exp_rel_start_time_set = true; | 
|  | return exp_rel_start_time; | 
|  | } | 
|  |  | 
|  | DataDescriptor * | 
|  | Experiment::get_raw_events (int data_id) | 
|  | { | 
|  | DataDescriptor *dDscr; | 
|  | switch (data_id) | 
|  | { | 
|  | case DATA_CLOCK: | 
|  | dDscr = get_profile_events (); | 
|  | break; | 
|  | case DATA_SYNCH: | 
|  | dDscr = get_sync_events (); | 
|  | break; | 
|  | case DATA_HWC: | 
|  | dDscr = get_hwc_events (); | 
|  | break; | 
|  | case DATA_HEAP: | 
|  | dDscr = get_heap_events (); | 
|  | break; | 
|  | case DATA_HEAPSZ: | 
|  | dDscr = get_heapsz_events (); | 
|  | break; | 
|  | case DATA_IOTRACE: | 
|  | dDscr = get_iotrace_events (); | 
|  | break; | 
|  | case DATA_RACE: | 
|  | dDscr = get_race_events (); | 
|  | break; | 
|  | case DATA_DLCK: | 
|  | dDscr = get_deadlock_events (); | 
|  | break; | 
|  | case DATA_SAMPLE: | 
|  | dDscr = get_sample_events (); | 
|  | break; | 
|  | case DATA_GCEVENT: | 
|  | dDscr = get_gc_events (); | 
|  | break; | 
|  | default: | 
|  | dDscr = NULL; | 
|  | break; | 
|  | } | 
|  | return dDscr; | 
|  | } | 
|  |  | 
|  | int | 
|  | Experiment::base_data_id (int data_id) | 
|  | { | 
|  | switch (data_id) | 
|  | { | 
|  | case DATA_HEAPSZ: | 
|  | return DATA_HEAP; // DATA_HEAPSZ DataView is based on DATA_HEAP's DataView | 
|  | default: | 
|  | break; | 
|  | } | 
|  | return data_id; | 
|  | } | 
|  |  | 
|  | DataView * | 
|  | Experiment::create_derived_data_view (int data_id, DataView *dview) | 
|  | { | 
|  | // dview contains filtered packets | 
|  | switch (data_id) | 
|  | { | 
|  | case DATA_HEAPSZ: | 
|  | return create_heapsz_data_view (dview); | 
|  | default: | 
|  | break; | 
|  | } | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | DataDescriptor * | 
|  | Experiment::get_profile_events () | 
|  | { | 
|  | DataDescriptor *dDscr = getDataDescriptor (DATA_CLOCK); | 
|  | if (dDscr == NULL) | 
|  | return NULL; | 
|  | if (dDscr->getSize () == 0) | 
|  | { | 
|  | char *base_name = get_basename (expt_name); | 
|  | char *msg = dbe_sprintf (GTXT ("Loading Profile Data: %s"), base_name); | 
|  | read_data_file (SP_PROFILE_FILE, msg); | 
|  | free (msg); | 
|  | add_evt_time_to_profile_events (dDscr); | 
|  | resolve_frame_info (dDscr); | 
|  | } | 
|  | else if (!dDscr->isResolveFrInfoDone ()) | 
|  | resolve_frame_info (dDscr); | 
|  | return dDscr; | 
|  | } | 
|  |  | 
|  | void | 
|  | Experiment::add_evt_time_to_profile_events (DataDescriptor *dDscr) | 
|  | { | 
|  | if (coll_params.lms_magic_id != LMS_MAGIC_ID_SOLARIS) | 
|  | return; | 
|  |  | 
|  | DataView *dview = dDscr->createView (); | 
|  | dview->sort (PROP_THRID, PROP_TSTAMP); | 
|  |  | 
|  | // add PROP_EVT_TIME | 
|  | PropDescr* tmp_propDscr = new PropDescr (PROP_EVT_TIME, "EVT_TIME"); | 
|  | tmp_propDscr->uname = dbe_strdup (GTXT ("Event duration")); | 
|  | tmp_propDscr->vtype = TYPE_INT64; | 
|  | dDscr->addProperty (tmp_propDscr); | 
|  |  | 
|  | long sz = dview->getSize (); | 
|  | long long ptimer_usec = get_params ()->ptimer_usec; | 
|  | for (long i = 0; i < sz; i++) | 
|  | { | 
|  | int next_sample; | 
|  | int jj; | 
|  | { | 
|  | hrtime_t this_tstamp = dview->getLongValue (PROP_TSTAMP, i); | 
|  | long this_thrid = dview->getLongValue (PROP_THRID, i); | 
|  | for (jj = i + 1; jj < sz; jj++) | 
|  | { | 
|  | hrtime_t tmp_tstamp = dview->getLongValue (PROP_TSTAMP, jj); | 
|  | if (tmp_tstamp != this_tstamp) | 
|  | break; | 
|  | long tmp_thrid = dview->getLongValue (PROP_THRID, jj); | 
|  | if (tmp_thrid != this_thrid) | 
|  | break; | 
|  | } | 
|  | next_sample = jj; | 
|  | } | 
|  |  | 
|  | long nticks = 0; | 
|  | for (jj = i; jj < next_sample; jj++) | 
|  | nticks += dview->getLongValue (PROP_NTICK, jj); | 
|  | if (nticks <= 1) | 
|  | continue; // no duration | 
|  |  | 
|  | nticks--; | 
|  | hrtime_t duration = ptimer_usec * 1000LL * nticks; // nanoseconds | 
|  | for (jj = i; jj < next_sample; jj++) | 
|  | dview->setValue (PROP_EVT_TIME, jj, duration); | 
|  | i = jj - 1; | 
|  | } | 
|  | delete dview; | 
|  | } | 
|  |  | 
|  | DataDescriptor * | 
|  | Experiment::get_sync_events () | 
|  | { | 
|  | DataDescriptor *dDscr = getDataDescriptor (DATA_SYNCH); | 
|  | if (dDscr == NULL) | 
|  | return NULL; | 
|  | if (dDscr->getSize () > 0) | 
|  | return dDscr; | 
|  |  | 
|  | // fetch data | 
|  | { | 
|  | char *base_name = get_basename (expt_name); | 
|  | char *msg = dbe_sprintf (GTXT ("Loading Synctrace Data: %s"), base_name); | 
|  | read_data_file (SP_SYNCTRACE_FILE, msg); | 
|  | free (msg); | 
|  | resolve_frame_info (dDscr); | 
|  | } | 
|  |  | 
|  | // check for PROP_EVT_TIME | 
|  | PropDescr *tmp_propDscr = dDscr->getProp (PROP_EVT_TIME); | 
|  | if (tmp_propDscr) | 
|  | return dDscr; | 
|  |  | 
|  | // add PROP_EVT_TIME | 
|  | tmp_propDscr = new PropDescr (PROP_EVT_TIME, "EVT_TIME"); | 
|  | tmp_propDscr->uname = dbe_strdup (GTXT ("Event duration")); | 
|  | tmp_propDscr->vtype = TYPE_INT64; | 
|  | dDscr->addProperty (tmp_propDscr); | 
|  |  | 
|  | long sz = dDscr->getSize (); | 
|  | for (long i = 0; i < sz; i++) | 
|  | { | 
|  | uint64_t event_duration = dDscr->getLongValue (PROP_TSTAMP, i); | 
|  | event_duration -= dDscr->getLongValue (PROP_SRQST, i); | 
|  | dDscr->setValue (PROP_EVT_TIME, i, event_duration); | 
|  | } | 
|  | return dDscr; | 
|  | } | 
|  |  | 
|  | DataDescriptor * | 
|  | Experiment::get_hwc_events () | 
|  | { | 
|  | DataDescriptor *dDscr = getDataDescriptor (DATA_HWC); | 
|  | if (dDscr == NULL) | 
|  | return NULL; | 
|  | if (dDscr->getSize () == 0) | 
|  | { | 
|  | char *base_name = get_basename (expt_name); | 
|  | char *msg = dbe_sprintf (GTXT ("Loading HW Profile Data: %s"), base_name); | 
|  |  | 
|  | // clear HWC event stats | 
|  | dsevents = 0; | 
|  | dsnoxhwcevents = 0; | 
|  | read_data_file (SP_HWCNTR_FILE, msg); | 
|  | free (msg); | 
|  | resolve_frame_info (dDscr); | 
|  |  | 
|  | // describe the HW counters in PropDescr | 
|  | PropDescr *prop = dDscr->getProp (PROP_HWCTAG); | 
|  | if (prop) | 
|  | { | 
|  | Collection_params *cparam = get_params (); | 
|  | if (cparam->hw_mode != 0) | 
|  | for (int aux = 0; aux < MAX_HWCOUNT; aux++) | 
|  | if (cparam->hw_aux_name[aux]) | 
|  | { | 
|  | const char* cmdname = cparam->hw_aux_name[aux]; | 
|  | const char* uname = cparam->hw_username[aux]; | 
|  | prop->addState (aux, cmdname, uname); | 
|  | } | 
|  | } | 
|  | else | 
|  | assert (0); | 
|  |  | 
|  | double dserrrate = 100.0 * ((double) dsnoxhwcevents) / ((double) dsevents); | 
|  | if ((dsevents > 0) && (dserrrate > 10.0)) | 
|  | { | 
|  | // warn the user that rate is high | 
|  | StringBuilder sb; | 
|  | if (dbeSession->check_ignore_no_xhwcprof ()) | 
|  | sb.sprintf ( | 
|  | 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"), | 
|  | base_name, dserrrate, (long long) dsnoxhwcevents, | 
|  | (long long) dsevents); | 
|  | else | 
|  | sb.sprintf ( | 
|  | 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"), | 
|  | base_name, dserrrate, (long long) dsnoxhwcevents, | 
|  | (long long) dsevents); | 
|  | errorq->append (new Emsg (CMSG_WARN, sb)); | 
|  | } | 
|  |  | 
|  | // see if we've scanned the data | 
|  | if (hwc_scanned == 0) | 
|  | { | 
|  | // no, scan the packets to see how many are bogus, or represent lost interrupts | 
|  | long hwc_cnt = 0; | 
|  |  | 
|  | // loop over the packets, counting the bad ones | 
|  | if (hwc_bogus != 0 || hwc_lost_int != 0) | 
|  | { | 
|  | // hwc counter data had bogus packets and/or packets reflecting lost interrupts | 
|  | double bogus_rate = 100. * (double) hwc_bogus / (double) hwc_cnt; | 
|  | if (bogus_rate > 5.) | 
|  | { | 
|  | StringBuilder sb; | 
|  | sb.sprintf ( | 
|  | GTXT ("WARNING: Too many invalid HW counter profile events (%ld/%ld = %3.2f%%) in experiment %d (`%s'); data may be unreliable"), | 
|  | (long) hwc_bogus, (long) hwc_cnt, bogus_rate, | 
|  | (int) userExpId, base_name); | 
|  | Emsg *m = new Emsg (CMSG_WARN, sb); | 
|  | warnq->append (m); | 
|  | } | 
|  | hwc_scanned = 1; | 
|  | } | 
|  | } | 
|  | } | 
|  | return dDscr; | 
|  | } | 
|  |  | 
|  | DataDescriptor * | 
|  | Experiment::get_iotrace_events () | 
|  | { | 
|  | DataDescriptor *dDscr = getDataDescriptor (DATA_IOTRACE); | 
|  | if (dDscr == NULL) | 
|  | return NULL; | 
|  |  | 
|  | if (dDscr->getSize () > 0) | 
|  | return dDscr; | 
|  |  | 
|  | char *base_name = get_basename (expt_name); | 
|  | char *msg = dbe_sprintf (GTXT ("Loading IO Trace Data: %s"), base_name); | 
|  | read_data_file (SP_IOTRACE_FILE, msg); | 
|  | free (msg); | 
|  |  | 
|  | if (dDscr->getSize () == 0) | 
|  | return dDscr; | 
|  | resolve_frame_info (dDscr); | 
|  |  | 
|  | // check for PROP_EVT_TIME | 
|  | PropDescr *tmp_propDscr = dDscr->getProp (PROP_EVT_TIME); | 
|  | if (tmp_propDscr) | 
|  | return dDscr; | 
|  |  | 
|  | // add PROP_EVT_TIME | 
|  | tmp_propDscr = new PropDescr (PROP_EVT_TIME, "EVT_TIME"); | 
|  | tmp_propDscr->uname = dbe_strdup (GTXT ("Event duration")); | 
|  | tmp_propDscr->vtype = TYPE_INT64; | 
|  | dDscr->addProperty (tmp_propDscr); | 
|  |  | 
|  | // add PROP_IOVFD | 
|  | tmp_propDscr = new PropDescr (PROP_IOVFD, "IOVFD"); | 
|  | tmp_propDscr->uname = dbe_strdup (GTXT ("Virtual File Descriptor")); | 
|  | tmp_propDscr->vtype = TYPE_INT64; | 
|  | dDscr->addProperty (tmp_propDscr); | 
|  |  | 
|  | delete fDataMap; | 
|  | fDataMap = new DefaultMap<int64_t, FileData*>; | 
|  |  | 
|  | delete vFdMap; | 
|  | vFdMap = new DefaultMap<int, int64_t>; | 
|  |  | 
|  | static int64_t virtualFd = 0; | 
|  |  | 
|  | FileData *fData; | 
|  | virtualFd += 10; | 
|  | fData = fDataMap->get (VIRTUAL_FD_STDIN); | 
|  | if (fData == NULL) | 
|  | { | 
|  | fData = new FileData (STDIN_FILENAME); | 
|  | fData->setVirtualFd (VIRTUAL_FD_STDIN); | 
|  | fData->id = VIRTUAL_FD_STDIN; | 
|  | fData->setFileDes (STDIN_FD); | 
|  | fDataMap->put (VIRTUAL_FD_STDIN, fData); | 
|  | vFdMap->put (STDIN_FD, VIRTUAL_FD_STDIN); | 
|  | } | 
|  |  | 
|  | fData = fDataMap->get (VIRTUAL_FD_STDOUT); | 
|  | if (fData == NULL) | 
|  | { | 
|  | fData = new FileData (STDOUT_FILENAME); | 
|  | fData->setVirtualFd (VIRTUAL_FD_STDOUT); | 
|  | fData->id = VIRTUAL_FD_STDOUT; | 
|  | fData->setFileDes (STDOUT_FD); | 
|  | fDataMap->put (VIRTUAL_FD_STDOUT, fData); | 
|  | vFdMap->put (STDOUT_FD, VIRTUAL_FD_STDOUT); | 
|  | } | 
|  |  | 
|  | fData = fDataMap->get (VIRTUAL_FD_STDERR); | 
|  | if (fData == NULL) | 
|  | { | 
|  | fData = new FileData (STDERR_FILENAME); | 
|  | fData->setVirtualFd (VIRTUAL_FD_STDERR); | 
|  | fData->id = VIRTUAL_FD_STDERR; | 
|  | fData->setFileDes (STDERR_FD); | 
|  | fDataMap->put (VIRTUAL_FD_STDERR, fData); | 
|  | vFdMap->put (STDERR_FD, VIRTUAL_FD_STDERR); | 
|  | } | 
|  |  | 
|  | fData = fDataMap->get (VIRTUAL_FD_OTHERIO); | 
|  | if (fData == NULL) | 
|  | { | 
|  | fData = new FileData (OTHERIO_FILENAME); | 
|  | fData->setVirtualFd (VIRTUAL_FD_OTHERIO); | 
|  | fData->id = VIRTUAL_FD_OTHERIO; | 
|  | fData->setFileDes (OTHERIO_FD); | 
|  | fDataMap->put (VIRTUAL_FD_OTHERIO, fData); | 
|  | } | 
|  |  | 
|  | DataView *dview = dDscr->createView (); | 
|  | dview->sort (PROP_TSTAMP); | 
|  | long sz = dview->getSize (); | 
|  | for (long i = 0; i < sz; i++) | 
|  | { | 
|  | hrtime_t event_duration = dview->getLongValue (PROP_TSTAMP, i); | 
|  | hrtime_t event_start = dview->getLongValue (PROP_IORQST, i); | 
|  | if (event_start > 0) | 
|  | event_duration -= event_start; | 
|  | else | 
|  | event_duration = 0; | 
|  | dview->setValue (PROP_EVT_TIME, i, event_duration); | 
|  |  | 
|  | int32_t fd = -1; | 
|  | int64_t vFd = VIRTUAL_FD_NONE; | 
|  | char *fName = NULL; | 
|  | int32_t origFd = -1; | 
|  | StringBuilder *sb = NULL; | 
|  | FileData *fDataOrig = NULL; | 
|  | FileSystem_type fsType; | 
|  |  | 
|  | IOTrace_type ioType = (IOTrace_type) dview->getIntValue (PROP_IOTYPE, i); | 
|  | switch (ioType) | 
|  | { | 
|  | case READ_TRACE: | 
|  | case WRITE_TRACE: | 
|  | case READ_TRACE_ERROR: | 
|  | case WRITE_TRACE_ERROR: | 
|  | fd = dview->getIntValue (PROP_IOFD, i); | 
|  | vFd = vFdMap->get (fd); | 
|  | if (vFd == 0 || vFd == VIRTUAL_FD_NONE | 
|  | || (fData = fDataMap->get (vFd)) == NULL) | 
|  | { | 
|  | fData = new FileData (UNKNOWNFD_FILENAME); | 
|  | fData->setVirtualFd (virtualFd); | 
|  | fData->setFsType ("N/A"); | 
|  | fData->setFileDes (fd); | 
|  | fDataMap->put (virtualFd, fData); | 
|  | vFdMap->put (fd, virtualFd); | 
|  | vFd = virtualFd; | 
|  | virtualFd++; | 
|  | } | 
|  | dview->setValue (PROP_IOVFD, i, vFd); | 
|  | break; | 
|  | case OPEN_TRACE: | 
|  | fName = NULL; | 
|  | sb = (StringBuilder*) dview->getObjValue (PROP_IOFNAME, i); | 
|  | if (sb != NULL && sb->length () > 0) | 
|  | fName = sb->toString (); | 
|  | fd = dview->getIntValue (PROP_IOFD, i); | 
|  | origFd = dview->getIntValue (PROP_IOOFD, i); | 
|  | fsType = (FileSystem_type) dview->getIntValue (PROP_IOFSTYPE, i); | 
|  |  | 
|  | if (fName != NULL) | 
|  | { | 
|  | fData = new FileData (fName); | 
|  | fDataMap->put (virtualFd, fData); | 
|  | vFdMap->put (fd, virtualFd); | 
|  | fData->setFileDes (fd); | 
|  | fData->setFsType (fsType); | 
|  | fData->setVirtualFd (virtualFd); | 
|  | vFd = virtualFd; | 
|  | virtualFd++; | 
|  | } | 
|  | else if (origFd > 0) | 
|  | { | 
|  | vFd = vFdMap->get (origFd); | 
|  | if (vFd == 0 || vFd == VIRTUAL_FD_NONE) | 
|  | { | 
|  | Dprintf (DEBUG_IO, | 
|  | "*** Error I/O tracing: (open) cannot get the virtual file descriptor, fd=%d  origFd=%d\n", | 
|  | fd, origFd); | 
|  | continue; | 
|  | } | 
|  | else if ((fDataOrig = fDataMap->get (vFd)) == NULL) | 
|  | { | 
|  | Dprintf (DEBUG_IO, | 
|  | "*** Error IO tracing: (open) cannot get original FileData object, fd=%d  origFd=%d\n", | 
|  | fd, origFd); | 
|  | continue; | 
|  | } | 
|  | else | 
|  | { | 
|  | fName = fDataOrig->getFileName (); | 
|  | fData = new FileData (fName); | 
|  | fData->setFileDes (fd); | 
|  | fData->setFsType (fDataOrig->getFsType ()); | 
|  | fData->setVirtualFd (virtualFd); | 
|  | fDataMap->put (virtualFd, fData); | 
|  | vFdMap->put (fd, virtualFd); | 
|  | vFd = virtualFd; | 
|  | virtualFd++; | 
|  | } | 
|  | } | 
|  | else if (fd >= 0) | 
|  | { | 
|  | vFd = vFdMap->get (fd); | 
|  | if (vFd == 0 || vFd == VIRTUAL_FD_NONE | 
|  | || (fData = fDataMap->get (vFd)) == NULL) | 
|  | { | 
|  | fData = new FileData (UNKNOWNFD_FILENAME); | 
|  | fData->setVirtualFd (virtualFd); | 
|  | fData->setFsType ("N/A"); | 
|  | fData->setFileDes (fd); | 
|  | fDataMap->put (virtualFd, fData); | 
|  | vFdMap->put (fd, virtualFd); | 
|  | vFd = virtualFd; | 
|  | virtualFd++; | 
|  | } | 
|  | } | 
|  | else | 
|  | { | 
|  | Dprintf (DEBUG_IO, | 
|  | NTXT ("*** Error IO tracing: (open) unknown open IO type, fd=%d  origFd=%d\n"), fd, origFd); | 
|  | continue; | 
|  | } | 
|  |  | 
|  | dview->setValue (PROP_IOVFD, i, vFd); | 
|  | break; | 
|  |  | 
|  | case OPEN_TRACE_ERROR: | 
|  | fName = NULL; | 
|  |  | 
|  | sb = (StringBuilder*) dview->getObjValue (PROP_IOFNAME, i); | 
|  | if (sb != NULL && sb->length () > 0) | 
|  | fName = sb->toString (); | 
|  | fd = dview->getIntValue (PROP_IOFD, i); | 
|  | origFd = dview->getIntValue (PROP_IOOFD, i); | 
|  | fsType = (FileSystem_type) dview->getIntValue (PROP_IOFSTYPE, i); | 
|  |  | 
|  | if (fName != NULL) | 
|  | { | 
|  | fData = new FileData (fName); | 
|  | fDataMap->put (virtualFd, fData); | 
|  | fData->setFileDes (fd); | 
|  | fData->setFsType (fsType); | 
|  | fData->setVirtualFd (virtualFd); | 
|  | vFd = virtualFd; | 
|  | virtualFd++; | 
|  | } | 
|  | else if (origFd > 0) | 
|  | { | 
|  | vFd = vFdMap->get (origFd); | 
|  | if (vFd == 0 || vFd == VIRTUAL_FD_NONE) | 
|  | { | 
|  | Dprintf (DEBUG_IO, | 
|  | "*** Error IO tracing: (open error) cannot get the virtual file descriptor, fd=%d  origFd=%d\n", | 
|  | fd, origFd); | 
|  | continue; | 
|  | } | 
|  | else if ((fDataOrig = fDataMap->get (vFd)) == NULL) | 
|  | { | 
|  | Dprintf (DEBUG_IO, | 
|  | "*** Error IO tracing: (open error) cannot get original FileData object, fd=%d  origFd=%d\n", | 
|  | fd, origFd); | 
|  | continue; | 
|  | } | 
|  | else | 
|  | { | 
|  | fName = fDataOrig->getFileName (); | 
|  | fData = new FileData (fName); | 
|  | fData->setFileDes (fd); | 
|  | fData->setFsType (fDataOrig->getFsType ()); | 
|  | fData->setVirtualFd (virtualFd); | 
|  | fDataMap->put (virtualFd, fData); | 
|  | vFd = virtualFd; | 
|  | virtualFd++; | 
|  | } | 
|  | } | 
|  |  | 
|  | dview->setValue (PROP_IOVFD, i, vFd); | 
|  | break; | 
|  |  | 
|  | case CLOSE_TRACE: | 
|  | case CLOSE_TRACE_ERROR: | 
|  | fd = dview->getIntValue (PROP_IOFD, i); | 
|  | vFd = vFdMap->get (fd); | 
|  | if (vFd == 0 || vFd == VIRTUAL_FD_NONE) | 
|  | { | 
|  | Dprintf (DEBUG_IO, | 
|  | "*** Error IO tracing: (close) cannot get the virtual file descriptor, fd=%d\n", | 
|  | fd); | 
|  | continue; | 
|  | } | 
|  | fData = fDataMap->get (vFd); | 
|  | if (fData == NULL) | 
|  | { | 
|  | Dprintf (DEBUG_IO, | 
|  | "*** Error IO tracing: (close) cannot get the FileData object, fd=%d\n", | 
|  | fd); | 
|  | continue; | 
|  | } | 
|  |  | 
|  | vFdMap->put (fd, VIRTUAL_FD_NONE); | 
|  | dview->setValue (PROP_IOVFD, i, vFd); | 
|  | break; | 
|  |  | 
|  | case OTHERIO_TRACE: | 
|  | case OTHERIO_TRACE_ERROR: | 
|  | vFd = VIRTUAL_FD_OTHERIO; | 
|  | fData = fDataMap->get (vFd); | 
|  | if (fData == NULL) | 
|  | { | 
|  | Dprintf (DEBUG_IO, | 
|  | "*** Error IO tracing: (other IO) cannot get the FileData object\n"); | 
|  | continue; | 
|  | } | 
|  |  | 
|  | dview->setValue (PROP_IOVFD, i, vFd); | 
|  | break; | 
|  | case IOTRACETYPE_LAST: | 
|  | break; | 
|  | } | 
|  | } | 
|  |  | 
|  | delete dview; | 
|  |  | 
|  | return dDscr; | 
|  | } | 
|  |  | 
|  | DataDescriptor * | 
|  | Experiment::get_heap_events () | 
|  | { | 
|  | DataDescriptor *dDscr = getDataDescriptor (DATA_HEAP); | 
|  | if (dDscr == NULL) | 
|  | return NULL; | 
|  | if (dDscr->getSize () > 0) | 
|  | return dDscr; | 
|  |  | 
|  | char *base_name = get_basename (expt_name); | 
|  | char *msg = dbe_sprintf (GTXT ("Loading Heap Trace Data: %s"), base_name); | 
|  | read_data_file (SP_HEAPTRACE_FILE, msg); | 
|  | free (msg); | 
|  |  | 
|  | if (dDscr->getSize () == 0) | 
|  | return dDscr; | 
|  | resolve_frame_info (dDscr); | 
|  |  | 
|  | // Match FREE to MALLOC | 
|  | PropDescr *prop = new PropDescr (PROP_HLEAKED, NTXT ("HLEAKED")); | 
|  | prop->uname = dbe_strdup (GTXT ("Bytes Leaked")); | 
|  | prop->vtype = TYPE_UINT64; | 
|  | dDscr->addProperty (prop); | 
|  |  | 
|  | prop = new PropDescr (PROP_HMEM_USAGE, NTXT ("HMEM_USAGE")); | 
|  | prop->uname = dbe_strdup (GTXT ("Heap Memory Usage")); | 
|  | prop->vtype = TYPE_UINT64; | 
|  | dDscr->addProperty (prop); | 
|  |  | 
|  | prop = new PropDescr (PROP_HFREED, NTXT ("HFREED")); | 
|  | prop->uname = dbe_strdup (GTXT ("Bytes Freed")); | 
|  | prop->vtype = TYPE_UINT64; | 
|  | dDscr->addProperty (prop); | 
|  |  | 
|  | prop = new PropDescr (PROP_HCUR_ALLOCS, NTXT ("HCUR_ALLOCS")); | 
|  | prop->uname = dbe_strdup (GTXT ("Net Bytes Allocated")); | 
|  | prop->vtype = TYPE_INT64; | 
|  | dDscr->addProperty (prop); | 
|  |  | 
|  | prop = new PropDescr (PROP_HCUR_LEAKS, NTXT ("HCUR_LEAKS")); | 
|  | prop->uname = dbe_strdup (GTXT ("Net Bytes Leaked")); | 
|  | prop->vtype = TYPE_UINT64; | 
|  | dDscr->addProperty (prop); | 
|  |  | 
|  | prop = new PropDescr (PROP_HCUR_NET_ALLOC, NTXT ("HCUR_NET_ALLOC")); | 
|  | prop->vtype = TYPE_INT64; | 
|  | prop->flags = DDFLAG_NOSHOW; | 
|  | dDscr->addProperty (prop); | 
|  |  | 
|  | prop = new PropDescr (PROP_DDSCR_LNK, NTXT ("DDSCR_LNK")); | 
|  | prop->vtype = TYPE_UINT64; | 
|  | prop->flags = DDFLAG_NOSHOW; | 
|  | dDscr->addProperty (prop); | 
|  |  | 
|  | prop = new PropDescr (PROP_VOIDP_OBJ, NTXT ("VOIDP_OBJ")); | 
|  | prop->vtype = TYPE_OBJ; | 
|  | prop->flags = DDFLAG_NOSHOW; | 
|  | dDscr->addProperty (prop); | 
|  |  | 
|  | prop = new PropDescr (PROP_TSTAMP2, NTXT ("TSTAMP2")); | 
|  | prop->uname = dbe_strdup (GTXT ("End Timestamp (nanoseconds)")); | 
|  | prop->vtype = TYPE_UINT64; | 
|  | prop->flags = DDFLAG_NOSHOW; | 
|  | dDscr->addProperty (prop); | 
|  |  | 
|  | DataView *dview = dDscr->createView (); | 
|  | dview->sort (PROP_TSTAMP); | 
|  |  | 
|  | // Keep track of memory usage | 
|  | Size memoryUsage = 0; | 
|  |  | 
|  | HeapMap *heapmap = new HeapMap (); | 
|  | long sz = dview->getSize (); | 
|  | for (long i = 0; i < sz; i++) | 
|  | { | 
|  |  | 
|  | Heap_type mtype = (Heap_type) dview->getIntValue (PROP_HTYPE, i); | 
|  | Vaddr vaddr = dview->getULongValue (PROP_HVADDR, i); | 
|  | Vaddr ovaddr = dview->getULongValue (PROP_HOVADDR, i); | 
|  | Size hsize = dview->getULongValue (PROP_HSIZE, i); | 
|  | hrtime_t tstamp = dview->getLongValue (PROP_TSTAMP, i); | 
|  |  | 
|  | switch (mtype) | 
|  | { | 
|  | case MALLOC_TRACE: | 
|  | dview->setValue (PROP_TSTAMP2, i, (uint64_t) MAX_TIME); | 
|  | if (vaddr) | 
|  | { | 
|  | dview->setValue (PROP_HLEAKED, i, hsize); | 
|  | heapmap->allocate (vaddr, i + 1); | 
|  |  | 
|  | // Increase heap size | 
|  | memoryUsage += hsize; | 
|  | dview->setValue (PROP_HMEM_USAGE, i, memoryUsage); | 
|  | } | 
|  | break; | 
|  |  | 
|  | case FREE_TRACE: | 
|  | if (vaddr) | 
|  | { | 
|  | long idx = heapmap->deallocate (vaddr) - 1; | 
|  | if (idx >= 0) | 
|  | { | 
|  | // Decrease heap size | 
|  | Size leaked = dview->getLongValue (PROP_HLEAKED, idx); | 
|  | memoryUsage -= leaked; | 
|  | dview->setValue (PROP_HMEM_USAGE, i, memoryUsage); | 
|  |  | 
|  | Size alloc = dview->getLongValue (PROP_HSIZE, idx); | 
|  | // update allocation | 
|  | dview->setValue (PROP_HLEAKED, idx, (uint64_t) 0); | 
|  | dview->setValue (PROP_TSTAMP2, idx, tstamp); | 
|  | dview->setValue (PROP_DDSCR_LNK, idx, dview->getIdByIdx (i) + 1); | 
|  | // update this event | 
|  | dview->setValue (PROP_HFREED, i, alloc); | 
|  | } | 
|  | } | 
|  | break; | 
|  |  | 
|  | case REALLOC_TRACE: | 
|  | dview->setValue (PROP_TSTAMP2, i, (uint64_t) MAX_TIME); | 
|  | if (ovaddr) | 
|  | { | 
|  | long idx = heapmap->deallocate (ovaddr) - 1; | 
|  | if (idx >= 0) | 
|  | { | 
|  | // Decrease heap size | 
|  | Size leaked = dview->getLongValue (PROP_HLEAKED, idx); | 
|  | memoryUsage -= leaked; | 
|  | dview->setValue (PROP_HMEM_USAGE, i, memoryUsage); | 
|  |  | 
|  | Size alloc = dview->getLongValue (PROP_HSIZE, idx); | 
|  | // update allocation | 
|  | dview->setValue (PROP_HLEAKED, idx, (uint64_t) 0); | 
|  | dview->setValue (PROP_TSTAMP2, idx, tstamp); | 
|  | dview->setValue (PROP_DDSCR_LNK, idx, dview->getIdByIdx (i) + 1); | 
|  | // update this event | 
|  | dview->setValue (PROP_HFREED, i, alloc); | 
|  | } | 
|  | } | 
|  | if (vaddr) | 
|  | { | 
|  | dview->setValue (PROP_HLEAKED, i, hsize); | 
|  | heapmap->allocate (vaddr, i + 1); | 
|  |  | 
|  | // Increase heap size | 
|  | memoryUsage += hsize; | 
|  | dview->setValue (PROP_HMEM_USAGE, i, memoryUsage); | 
|  | } | 
|  | break; | 
|  | case MMAP_TRACE: | 
|  | case MUNMAP_TRACE: | 
|  | // Adjust the size to be multiple of page_size | 
|  | //hsize = (( hsize - 1 ) / page_size + 1 ) * page_size; | 
|  | if (vaddr) | 
|  | { | 
|  | UnmapChunk *list; | 
|  | if (mtype == MMAP_TRACE) | 
|  | { | 
|  | dview->setValue (PROP_TSTAMP2, i, (uint64_t) MAX_TIME); | 
|  | dview->setValue (PROP_HLEAKED, i, hsize); | 
|  | list = heapmap->mmap (vaddr, hsize, i); | 
|  |  | 
|  | // Increase heap size | 
|  | memoryUsage += hsize; | 
|  | dview->setValue (PROP_HMEM_USAGE, i, memoryUsage); | 
|  | } | 
|  | else | 
|  | { // MUNMAP_TRACE | 
|  | list = heapmap->munmap (vaddr, hsize); | 
|  |  | 
|  | // Set allocation size to zero | 
|  | // Note: We're currently reusing PROP_HSIZE to mean allocation size | 
|  | // If we ever need to save the original HSIZE, we'll need to | 
|  | // create a new PROP_* to represent event allocation size | 
|  | // | 
|  | //	For now, tuck the original size away as HOVADDR | 
|  | dview->setValue (PROP_HOVADDR, i, (uint64_t) hsize); | 
|  | dview->setValue (PROP_HSIZE, i, (uint64_t) 0); | 
|  | } | 
|  | Size total_freed = 0; | 
|  | while (list) | 
|  | { | 
|  | long idx = list->val; | 
|  | total_freed += list->size; | 
|  | Size leaked = dview->getLongValue (PROP_HLEAKED, idx); | 
|  |  | 
|  | // Decrease heap size | 
|  | memoryUsage -= list->size; | 
|  | dview->setValue (PROP_HMEM_USAGE, i, memoryUsage); | 
|  |  | 
|  | Size leak_update = leaked - list->size; | 
|  | // update allocation | 
|  | dview->setValue (PROP_HLEAKED, idx, leak_update); | 
|  | // update allocation's list of frees | 
|  | { | 
|  | UnmapChunk *copy = new UnmapChunk; | 
|  | heapUnmapEvents->append (copy); | 
|  | copy->val = dview->getIdByIdx (i); | 
|  | copy->size = list->size; | 
|  | copy->next = (UnmapChunk *) dview->getObjValue (PROP_VOIDP_OBJ, idx); | 
|  | dview->setObjValue (PROP_VOIDP_OBJ, idx, copy); | 
|  | } | 
|  | if (leak_update <= 0) | 
|  | if (leak_update == 0) | 
|  | dview->setValue (PROP_TSTAMP2, idx, tstamp); | 
|  | UnmapChunk *t = list; | 
|  | list = list->next; | 
|  | delete t; | 
|  | } | 
|  | // update this event | 
|  | if (total_freed) | 
|  | // only need to write value if it is non-zero | 
|  | dview->setValue (PROP_HFREED, i, total_freed); | 
|  | } | 
|  | break; | 
|  | // ignoring HEAPTYPE_LAST, which will never be recorded | 
|  | case HEAPTYPE_LAST: | 
|  | break; | 
|  | } | 
|  | } | 
|  | delete heapmap; | 
|  | delete dview; | 
|  |  | 
|  | return dDscr; | 
|  | } | 
|  |  | 
|  | DataDescriptor * | 
|  | Experiment::get_heapsz_events () | 
|  | { | 
|  | DataDescriptor *dDscr = getDataDescriptor (DATA_HEAPSZ); | 
|  | if (dDscr) | 
|  | return dDscr; | 
|  | dDscr = get_heap_events (); // derived from DATA_HEAP | 
|  | if (dDscr == NULL) | 
|  | return NULL; | 
|  | dDscr = newDataDescriptor (DATA_HEAPSZ, 0, dDscr); | 
|  | return dDscr; | 
|  | } | 
|  |  | 
|  | static void | 
|  | update_heapsz_packet (std::set<long> &pkt_id_set, DataView *dview, | 
|  | long alloc_pkt_id, int64_t net_alloc, uint64_t leaks) | 
|  | { | 
|  | // pkt_id_set: set is updated to include packet | 
|  | // alloc_pkt_id: data descriptor id (NOT dview idx) | 
|  | // net_alloc: adjustment to net allocation for this packet (note: signed value) | 
|  | // leaks: leak bytes to attribute to alloc_pkt_id | 
|  | std::pair < std::set<long>::iterator, bool> ret; | 
|  | ret = pkt_id_set.insert (alloc_pkt_id); // add to set | 
|  | bool new_to_set = ret.second; // was not in set | 
|  | if (!new_to_set) | 
|  | { | 
|  | // Has been seen before, update values | 
|  | net_alloc += dview->getDataDescriptorValue (PROP_HCUR_NET_ALLOC, alloc_pkt_id); | 
|  | if (leaks) | 
|  | { | 
|  | uint64_t old = dview->getDataDescriptorValue (PROP_HCUR_LEAKS, alloc_pkt_id); | 
|  | if (old != 0) | 
|  | leaks = old; | 
|  | } | 
|  | } | 
|  | dview->setDataDescriptorValue (PROP_HCUR_NET_ALLOC, alloc_pkt_id, net_alloc); | 
|  | dview->setDataDescriptorValue (PROP_HCUR_LEAKS, alloc_pkt_id, leaks); | 
|  | } | 
|  |  | 
|  | DataView * | 
|  | Experiment::create_heapsz_data_view (DataView *heap_dview) | 
|  | { | 
|  | // heap_dview has DATA_HEAP _filtered_ packets. | 
|  | // This creates, populates, and returns DATA_HEAPSZ DataView | 
|  | DataDescriptor *dDscr = get_heapsz_events (); | 
|  | if (dDscr == NULL) | 
|  | return NULL; | 
|  | std::set<long> pkt_id_set; | 
|  | DataView *dview = heap_dview; | 
|  | long sz = dview->getSize (); | 
|  | for (long i = 0; i < sz; i++) | 
|  | { | 
|  | int64_t hsize = (int64_t) dview->getULongValue (PROP_HSIZE, i); | 
|  | uint64_t leaks = dview->getULongValue (PROP_HLEAKED, i); | 
|  | long alloc_pkt_id = dview->getIdByIdx (i); | 
|  | update_heapsz_packet (pkt_id_set, dview, alloc_pkt_id, hsize, leaks); | 
|  |  | 
|  | // linked free | 
|  | UnmapChunk *mmap_frees = (UnmapChunk *) dview->getObjValue (PROP_VOIDP_OBJ, i); // mmap metadata | 
|  | if (mmap_frees) | 
|  | { | 
|  | // mmap: all frees associated with this packet | 
|  | while (mmap_frees) | 
|  | { | 
|  | long free_pkt_id = mmap_frees->val; | 
|  | int64_t free_sz = mmap_frees->size; | 
|  | update_heapsz_packet (pkt_id_set, dview, free_pkt_id, -free_sz, 0); | 
|  | mmap_frees = mmap_frees->next; | 
|  | } | 
|  | } | 
|  | else | 
|  | { | 
|  | // malloc: check for associated free | 
|  | long free_pkt_id = dview->getLongValue (PROP_DDSCR_LNK, i) - 1; | 
|  | if (free_pkt_id >= 0) | 
|  | update_heapsz_packet (pkt_id_set, dview, free_pkt_id, -hsize, 0); | 
|  | } | 
|  | } | 
|  |  | 
|  | // create a new DataView based on the filtered-in and associated free events | 
|  | std::set<long>::iterator it; | 
|  | DataView *heapsz_dview = dDscr->createExtManagedView (); | 
|  | for (it = pkt_id_set.begin (); it != pkt_id_set.end (); ++it) | 
|  | { | 
|  | long ddscr_pkt_id = *it; | 
|  | heapsz_dview->appendDataDescriptorId (ddscr_pkt_id); | 
|  | } | 
|  | compute_heapsz_data_view (heapsz_dview); | 
|  | return heapsz_dview; | 
|  | } | 
|  |  | 
|  | void | 
|  | Experiment::compute_heapsz_data_view (DataView *heapsz_dview) | 
|  | { | 
|  | DataView *dview = heapsz_dview; | 
|  |  | 
|  | // Keep track of memory usage | 
|  | int64_t currentAllocs = 0; | 
|  | Size currentLeaks = 0; | 
|  | dview->sort (PROP_TSTAMP); | 
|  | long sz = dview->getSize (); | 
|  | for (long i = 0; i < sz; i++) | 
|  | { | 
|  | int64_t net_alloc = dview->getLongValue (PROP_HCUR_NET_ALLOC, i); | 
|  | currentAllocs += net_alloc; | 
|  | dview->setValue (PROP_HCUR_ALLOCS, i, currentAllocs); | 
|  |  | 
|  | Size leaks = dview->getULongValue (PROP_HCUR_LEAKS, i); | 
|  | currentLeaks += leaks; | 
|  | dview->setValue (PROP_HCUR_LEAKS, i, currentLeaks); | 
|  | } | 
|  | } | 
|  |  | 
|  | void | 
|  | Experiment::DBG_memuse (Sample * s) | 
|  | { | 
|  | DataDescriptor *dDscr = getDataDescriptor (DATA_HEAP); | 
|  | if (dDscr == NULL || dDscr->getSize () == 0) | 
|  | return; | 
|  |  | 
|  | DataView *dview = dDscr->createView (); | 
|  | dview->sort (PROP_TSTAMP); | 
|  | hrtime_t ts1 = s->get_start_time (); | 
|  | hrtime_t ts2 = s->get_end_time (); | 
|  |  | 
|  | HeapMap *heapmap = new HeapMap (); | 
|  | long sz = dview->getSize (); | 
|  | Size maxSize = 0; | 
|  | Size curSize = 0; | 
|  | hrtime_t maxTime = 0; | 
|  | for (long i = 0; i < sz; i++) | 
|  | { | 
|  | hrtime_t tstamp = dview->getLongValue (PROP_TSTAMP, i); | 
|  | if (tstamp < ts1) | 
|  | continue; | 
|  | if (tstamp >= ts2) | 
|  | break; | 
|  |  | 
|  | Heap_type mtype = (Heap_type) dview->getIntValue (PROP_HTYPE, i); | 
|  | Vaddr vaddr = dview->getULongValue (PROP_HVADDR, i); | 
|  | Vaddr ovaddr = dview->getULongValue (PROP_HOVADDR, i); | 
|  | switch (mtype) | 
|  | { | 
|  | case REALLOC_TRACE: | 
|  | break; | 
|  | case MALLOC_TRACE: | 
|  | ovaddr = 0; | 
|  | break; | 
|  | case FREE_TRACE: | 
|  | ovaddr = vaddr; | 
|  | vaddr = 0; | 
|  | break; | 
|  | default: | 
|  | vaddr = 0; | 
|  | ovaddr = 0; | 
|  | break; | 
|  | } | 
|  | if (ovaddr) | 
|  | { | 
|  | long idx = heapmap->deallocate (ovaddr) - 1; | 
|  | if (idx >= 0) | 
|  | curSize -= dview->getULongValue (PROP_HSIZE, idx); | 
|  | } | 
|  | if (vaddr) | 
|  | { | 
|  | heapmap->allocate (vaddr, i + 1); | 
|  | curSize += dview->getULongValue (PROP_HSIZE, i); | 
|  | if (curSize > maxSize) | 
|  | { | 
|  | maxSize = curSize; | 
|  | maxTime = tstamp; | 
|  | } | 
|  | } | 
|  | } | 
|  | printf ("SAMPLE=%s (id=%d) MEMUSE=%lld TSTAMP=%lld\n", s->get_start_label (), | 
|  | s->get_number (), maxSize, maxTime - getStartTime ()); | 
|  | delete dview; | 
|  | delete heapmap; | 
|  | } | 
|  |  | 
|  | void | 
|  | Experiment::DBG_memuse (const char *sname) | 
|  | { | 
|  | for (int i = 0; i < samples->size (); ++i) | 
|  | { | 
|  | Sample *sample = samples->fetch (i); | 
|  | if (streq (sname, sample->get_start_label ())) | 
|  | { | 
|  | DBG_memuse (sample); | 
|  | break; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | DataDescriptor * | 
|  | Experiment::get_race_events () | 
|  | { | 
|  | DataDescriptor *dDscr = getDataDescriptor (DATA_RACE); | 
|  | if (dDscr == NULL) | 
|  | return NULL; | 
|  | if (dDscr->getSize () == 0) | 
|  | { | 
|  | char *base_name = get_basename (expt_name); | 
|  | char *msg = dbe_sprintf (GTXT ("Loading Race Data: %s"), base_name); | 
|  | read_data_file (SP_RACETRACE_FILE, msg); | 
|  | free (msg); | 
|  | resolve_frame_info (dDscr); | 
|  | } | 
|  | return dDscr; | 
|  | } | 
|  |  | 
|  | DataDescriptor * | 
|  | Experiment::get_deadlock_events () | 
|  | { | 
|  | DataDescriptor *dDscr = getDataDescriptor (DATA_DLCK); | 
|  | if (dDscr == NULL) | 
|  | return NULL; | 
|  | if (dDscr->getSize () == 0) | 
|  | { | 
|  | char *base_name = get_basename (expt_name); | 
|  | char *msg = dbe_sprintf (GTXT ("Loading Deadlocks Data: %s"), base_name); | 
|  | read_data_file (SP_DEADLOCK_FILE, msg); | 
|  | free (msg); | 
|  | resolve_frame_info (dDscr); | 
|  | } | 
|  | return dDscr; | 
|  | } | 
|  |  | 
|  | DataDescriptor * | 
|  | Experiment::get_sample_events () | 
|  | { | 
|  | DataDescriptor *dDscr = getDataDescriptor (DATA_SAMPLE); | 
|  | if (dDscr == NULL) | 
|  | return NULL; | 
|  | if (dDscr->getSize () > 0) | 
|  | return dDscr; | 
|  |  | 
|  | // read_overview_file(); //YXXX do this here at some point instead of: | 
|  | PropDescr *tmp_propDscr; | 
|  | tmp_propDscr = new PropDescr (PROP_SMPLOBJ, NTXT ("SMPLOBJ")); | 
|  | tmp_propDscr->uname = NULL; | 
|  | tmp_propDscr->vtype = TYPE_OBJ; | 
|  | dDscr->addProperty (tmp_propDscr); | 
|  |  | 
|  | tmp_propDscr = new PropDescr (PROP_TSTAMP, NTXT ("TSTAMP")); | 
|  | tmp_propDscr->uname = dbe_strdup ("High resolution timestamp"); | 
|  | tmp_propDscr->vtype = TYPE_UINT64; | 
|  | dDscr->addProperty (tmp_propDscr); | 
|  |  | 
|  | tmp_propDscr = new PropDescr (PROP_SAMPLE, NTXT ("SAMPLE")); | 
|  | tmp_propDscr->uname = dbe_strdup ("Sample number"); | 
|  | tmp_propDscr->vtype = TYPE_UINT64; | 
|  | dDscr->addProperty (tmp_propDscr); | 
|  |  | 
|  | tmp_propDscr = new PropDescr (PROP_EVT_TIME, NTXT ("EVT_TIME")); | 
|  | tmp_propDscr->uname = dbe_strdup ("Event duration"); | 
|  | tmp_propDscr->vtype = TYPE_UINT64; | 
|  | dDscr->addProperty (tmp_propDscr); | 
|  |  | 
|  | long ssize = samples->size (); | 
|  | for (long ii = 0; ii < ssize; ii++) | 
|  | { | 
|  | Sample * sample = samples->fetch (ii); | 
|  | long recn = dDscr->addRecord (); | 
|  | hrtime_t sduration = sample->get_end_time () - sample->get_start_time (); | 
|  | dDscr->setObjValue (PROP_SMPLOBJ, recn, sample); | 
|  | dDscr->setValue (PROP_SAMPLE, recn, sample->get_number ()); | 
|  | dDscr->setValue (PROP_TSTAMP, recn, sample->get_end_time ()); | 
|  | dDscr->setValue (PROP_EVT_TIME, recn, sduration); | 
|  | } | 
|  | return dDscr; | 
|  | } | 
|  |  | 
|  | DataDescriptor * | 
|  | Experiment::get_gc_events () | 
|  | { | 
|  | DataDescriptor *dDscr = getDataDescriptor (DATA_GCEVENT); | 
|  | if (dDscr == NULL) | 
|  | return NULL; | 
|  | if (dDscr->getSize () > 0) | 
|  | return dDscr; | 
|  |  | 
|  | // read_overview_file(); //YXXX do this here at some point instead of: | 
|  | PropDescr *tmp_propDscr; | 
|  | tmp_propDscr = new PropDescr (PROP_GCEVENTOBJ, NTXT ("GCEVENTOBJ")); | 
|  | tmp_propDscr->uname = NULL; | 
|  | tmp_propDscr->vtype = TYPE_OBJ; | 
|  | dDscr->addProperty (tmp_propDscr); | 
|  |  | 
|  | tmp_propDscr = new PropDescr (PROP_TSTAMP, NTXT ("TSTAMP")); | 
|  | tmp_propDscr->uname = dbe_strdup ("High resolution timestamp"); | 
|  | tmp_propDscr->vtype = TYPE_UINT64; | 
|  | dDscr->addProperty (tmp_propDscr); | 
|  |  | 
|  | tmp_propDscr = new PropDescr (PROP_GCEVENT, NTXT ("GCEVENT")); | 
|  | tmp_propDscr->uname = dbe_strdup ("GCEvent number"); | 
|  | tmp_propDscr->vtype = TYPE_UINT64; | 
|  | dDscr->addProperty (tmp_propDscr); | 
|  |  | 
|  | tmp_propDscr = new PropDescr (PROP_EVT_TIME, NTXT ("EVT_TIME")); | 
|  | tmp_propDscr->uname = dbe_strdup ("Event duration"); | 
|  | tmp_propDscr->vtype = TYPE_UINT64; | 
|  | dDscr->addProperty (tmp_propDscr); | 
|  |  | 
|  | long ssize = gcevents->size (); | 
|  | for (long ii = 0; ii < ssize; ii++) | 
|  | { | 
|  | GCEvent * gcevent = gcevents->fetch (ii); | 
|  | long recn = dDscr->addRecord (); | 
|  | hrtime_t sduration = gcevent->end - gcevent->start; | 
|  | dDscr->setObjValue (PROP_GCEVENTOBJ, recn, gcevent); | 
|  | dDscr->setValue (PROP_GCEVENT, recn, gcevent->id); | 
|  | dDscr->setValue (PROP_TSTAMP, recn, gcevent->end); | 
|  | dDscr->setValue (PROP_EVT_TIME, recn, sduration); | 
|  | } | 
|  | return dDscr; | 
|  | } | 
|  |  | 
|  | void | 
|  | Experiment::update_last_event (hrtime_t ts/*wall_ts*/) | 
|  | { | 
|  | if (last_event == ZERO_TIME) | 
|  | { | 
|  | // not yet initialized | 
|  | last_event = ts; | 
|  | } | 
|  | if (last_event - exp_start_time < ts - exp_start_time) | 
|  | // compare deltas to avoid hrtime_t wrap | 
|  | last_event = ts; | 
|  | } | 
|  |  | 
|  | void | 
|  | Experiment::write_header () | 
|  | { | 
|  | StringBuilder sb; | 
|  |  | 
|  | // write commentary to the experiment, describing the parameters | 
|  | if (dbeSession->ipc_mode || dbeSession->rdt_mode) | 
|  | { | 
|  | // In GUI: print start time at the beginning | 
|  | time_t t = (time_t) start_sec; | 
|  | char *start_time = ctime (&t); | 
|  | if (start_time != NULL) | 
|  | { | 
|  | sb.setLength (0); | 
|  | sb.sprintf (GTXT ("Experiment started %s"), start_time); | 
|  | commentq->append (new Emsg (CMSG_COMMENT, sb)); | 
|  | } | 
|  | } | 
|  | // write message with target arglist | 
|  | if (uarglist != NULL) | 
|  | { | 
|  | sb.setLength (0); | 
|  | sb.sprintf (GTXT ("\nTarget command (%s): '%s'"), | 
|  | (wsize == W32 ? "32-bit" : "64-bit"), uarglist); | 
|  | commentq->append (new Emsg (CMSG_COMMENT, sb)); | 
|  | } | 
|  |  | 
|  | sb.setLength (0); | 
|  | sb.sprintf (GTXT ("Process pid %d, ppid %d, pgrp %d, sid %d"), | 
|  | pid, ppid, pgrp, sid); | 
|  | commentq->append (new Emsg (CMSG_COMMENT, sb)); | 
|  |  | 
|  | // add comment for user name, if set | 
|  | if (username != NULL) | 
|  | { | 
|  | sb.setLength (0); | 
|  | sb.sprintf (GTXT ("User: `%s'"), username); | 
|  | commentq->append (new Emsg (CMSG_COMMENT, sb)); | 
|  | } | 
|  |  | 
|  | // add comment for current working directory | 
|  | if (ucwd != NULL) | 
|  | { | 
|  | sb.setLength (0); | 
|  | sb.sprintf (GTXT ("Current working directory: %s"), ucwd); | 
|  | commentq->append (new Emsg (CMSG_COMMENT, sb)); | 
|  | } | 
|  |  | 
|  | // add comment for collector version string | 
|  | if (cversion != NULL) | 
|  | { | 
|  | char *wstring; | 
|  | switch (wsize) | 
|  | { | 
|  | case Wnone: | 
|  | wstring = NTXT ("?"); | 
|  | break; | 
|  | case W32: | 
|  | wstring = GTXT ("32-bit"); | 
|  | break; | 
|  | case W64: | 
|  | wstring = GTXT ("64-bit"); | 
|  | break; | 
|  | default: | 
|  | wstring = NTXT ("??"); | 
|  | break; | 
|  | } | 
|  | sb.setLength (0); | 
|  | sb.sprintf (GTXT ("Collector version: `%s'; experiment version %d.%d (%s)"), | 
|  | cversion, exp_maj_version, exp_min_version, wstring); | 
|  | commentq->append (new Emsg (CMSG_COMMENT, sb)); | 
|  | } | 
|  |  | 
|  | // add comment for driver version string (er_kernel) | 
|  | if (dversion != NULL) | 
|  | { | 
|  | sb.setLength (0); | 
|  | sb.sprintf (GTXT ("Kernel driver version: `%s'"), dversion); | 
|  | commentq->append (new Emsg (CMSG_COMMENT, sb)); | 
|  | } | 
|  |  | 
|  | if (jversion != NULL) | 
|  | { | 
|  | sb.setLength (0); | 
|  | sb.sprintf (GTXT ("JVM version: `%s'"), jversion); | 
|  | commentq->append (new Emsg (CMSG_COMMENT, sb)); | 
|  | } | 
|  |  | 
|  | // add comment for hostname, parameters | 
|  | if (hostname == NULL) | 
|  | hostname = dbe_strdup (GTXT ("unknown")); | 
|  | if (os_version == NULL) | 
|  | os_version = dbe_strdup (GTXT ("unknown")); | 
|  | if (architecture == NULL) | 
|  | architecture = dbe_strdup (GTXT ("unknown")); | 
|  | sb.setLength (0); | 
|  | sb.sprintf (GTXT ("Host `%s', OS `%s', page size %d, architecture `%s'"), | 
|  | hostname, os_version, page_size, architecture); | 
|  | commentq->append (new Emsg (CMSG_COMMENT, sb)); | 
|  |  | 
|  | sb.setLength (0); | 
|  | if (maxclock != minclock) | 
|  | { | 
|  | clock = maxclock; | 
|  | sb.sprintf ( | 
|  | GTXT ("  %d CPUs, with clocks ranging from %d to %d MHz.; max of %d MHz. assumed"), | 
|  | ncpus, minclock, maxclock, clock); | 
|  | } | 
|  | else | 
|  | sb.sprintf (GTXT ("  %d CPU%s, clock speed %d MHz."), | 
|  | ncpus, (ncpus == 1 ? NTXT ("") : "s"), clock); | 
|  | commentq->append (new Emsg (CMSG_COMMENT, sb)); | 
|  |  | 
|  | // add comment for machine memory size | 
|  | if (page_size > 0 && npages > 0) | 
|  | { | 
|  | long long memsize = ((long long) npages * page_size) / (1024 * 1024); | 
|  | sb.setLength (0); | 
|  | sb.sprintf (GTXT ("  Memory: %d pages @  %d = %lld MB."), | 
|  | npages, page_size, memsize); | 
|  | commentq->append (new Emsg (CMSG_COMMENT, sb)); | 
|  | } | 
|  |  | 
|  | // add comment for machine memory size | 
|  | if (machinemodel != NULL) | 
|  | { | 
|  | sb.setLength (0); | 
|  | sb.sprintf (GTXT ("  Machine model: %s"), machinemodel); | 
|  | commentq->append (new Emsg (CMSG_COMMENT, sb)); | 
|  | } | 
|  |  | 
|  | // add comment for start time | 
|  | time_t t = (time_t) start_sec; | 
|  | char *p = ctime (&t); | 
|  | sb.setLength (0); | 
|  | if (p != NULL) | 
|  | sb.sprintf (GTXT ("Experiment started %s"), p); | 
|  | else | 
|  | sb.sprintf (GTXT ("\nExperiment start not recorded")); | 
|  | write_coll_params (); | 
|  | commentq->append (new Emsg (CMSG_COMMENT, sb)); | 
|  | commentq->appendqueue (runlogq); | 
|  | runlogq->mark_clear (); | 
|  | } | 
|  |  | 
|  | void | 
|  | Experiment::write_coll_params () | 
|  | { | 
|  | StringBuilder sb; | 
|  |  | 
|  | // now write the various collection parameters as comments | 
|  | sb.setLength (0); | 
|  | sb.append (GTXT ("Data collection parameters:")); | 
|  | commentq->append (new Emsg (CMSG_COMMENT, sb)); | 
|  | if (coll_params.profile_mode == 1) | 
|  | { | 
|  | sb.setLength (0); | 
|  | sb.sprintf (GTXT ("  Clock-profiling, interval = %d microsecs."), | 
|  | (int) (coll_params.ptimer_usec)); | 
|  | commentq->append (new Emsg (CMSG_COMMENT, sb)); | 
|  | } | 
|  | if (coll_params.sync_mode == 1) | 
|  | { | 
|  | sb.setLength (0); | 
|  | char *scope_str = NTXT (""); | 
|  | switch (coll_params.sync_scope) | 
|  | { | 
|  | case 0: | 
|  | scope_str = GTXT ("Native- and Java-APIs"); | 
|  | break; | 
|  | case SYNCSCOPE_JAVA: | 
|  | scope_str = GTXT ("JAVA-APIs"); | 
|  | break; | 
|  | case SYNCSCOPE_NATIVE: | 
|  | scope_str = GTXT ("Native-APIs"); | 
|  | break; | 
|  | case SYNCSCOPE_JAVA | SYNCSCOPE_NATIVE: | 
|  | scope_str = GTXT ("Native- and Java-APIs"); | 
|  | break; | 
|  | } | 
|  | if (coll_params.sync_threshold < 0) | 
|  | sb.sprintf (GTXT ("  Synchronization tracing, threshold = %d microsecs. (calibrated); %s"), | 
|  | -coll_params.sync_threshold, scope_str); | 
|  | else | 
|  | sb.sprintf (GTXT ("  Synchronization tracing, threshold = %d microsecs.; %s"), | 
|  | coll_params.sync_threshold, scope_str); | 
|  | commentq->append (new Emsg (CMSG_COMMENT, sb)); | 
|  | } | 
|  | if (coll_params.heap_mode == 1) | 
|  | { | 
|  | sb.setLength (0); | 
|  | sb.append (GTXT ("  Heap tracing")); | 
|  | commentq->append (new Emsg (CMSG_COMMENT, sb)); | 
|  | } | 
|  | if (coll_params.io_mode == 1) | 
|  | { | 
|  | sb.setLength (0); | 
|  | sb.append (GTXT ("  IO tracing")); | 
|  | commentq->append (new Emsg (CMSG_COMMENT, sb)); | 
|  | } | 
|  | if (coll_params.race_mode == 1) | 
|  | { | 
|  | sb.setLength (0); | 
|  | char *race_stack_name; | 
|  | switch (coll_params.race_stack) | 
|  | { | 
|  | case 0: | 
|  | race_stack_name = GTXT ("dual-stack"); | 
|  | break; | 
|  | case 1: | 
|  | race_stack_name = GTXT ("single-stack"); | 
|  | break; | 
|  | case 2: | 
|  | race_stack_name = GTXT ("leaf"); | 
|  | break; | 
|  | default: | 
|  | abort (); | 
|  | } | 
|  | sb.sprintf (GTXT ("  Datarace detection, %s"), race_stack_name); | 
|  | commentq->append (new Emsg (CMSG_COMMENT, sb)); | 
|  | } | 
|  | if (coll_params.deadlock_mode == 1) | 
|  | { | 
|  | sb.setLength (0); | 
|  | sb.append (GTXT ("  Deadlock detection")); | 
|  | commentq->append (new Emsg (CMSG_COMMENT, sb)); | 
|  | } | 
|  | if (coll_params.hw_mode == 1) | 
|  | { | 
|  | sb.setLength (0); | 
|  | if (hwc_default == true) | 
|  | sb.append (GTXT ("  HW counter-profiling (default); counters:")); | 
|  | else | 
|  | sb.append (GTXT ("  HW counter-profiling; counters:")); | 
|  | commentq->append (new Emsg (CMSG_COMMENT, sb)); | 
|  | for (int i = 0; i < MAX_HWCOUNT; i++) | 
|  | { | 
|  | if (!coll_params.hw_aux_name[i]) | 
|  | continue; | 
|  | sb.setLength (0); | 
|  | sb.sprintf (GTXT ("    %s, tag %d, interval %d, memop %d"), | 
|  | coll_params.hw_aux_name[i], i, | 
|  | coll_params.hw_interval[i], coll_params.hw_tpc[i]); | 
|  | commentq->append (new Emsg (CMSG_COMMENT, sb)); | 
|  | } | 
|  | } | 
|  | if (coll_params.sample_periodic == 1) | 
|  | { | 
|  | sb.setLength (0); | 
|  | sb.sprintf (GTXT ("  Periodic sampling, %d secs."), | 
|  | coll_params.sample_timer); | 
|  | commentq->append (new Emsg (CMSG_COMMENT, sb)); | 
|  | } | 
|  | if (coll_params.limit != 0) | 
|  | { | 
|  | sb.setLength (0); | 
|  | sb.sprintf (GTXT ("  Experiment size limit, %d"), | 
|  | coll_params.limit); | 
|  | commentq->append (new Emsg (CMSG_COMMENT, sb)); | 
|  | } | 
|  | if (coll_params.linetrace != NULL) | 
|  | { | 
|  | sb.setLength (0); | 
|  | sb.sprintf (GTXT ("  Follow descendant processes from: %s"), | 
|  | coll_params.linetrace); | 
|  | commentq->append (new Emsg (CMSG_COMMENT, sb)); | 
|  | } | 
|  | if (coll_params.pause_sig != NULL) | 
|  | { | 
|  | sb.setLength (0); | 
|  | sb.sprintf (GTXT ("  Pause signal %s"), coll_params.pause_sig); | 
|  | commentq->append (new Emsg (CMSG_COMMENT, sb)); | 
|  | } | 
|  | if (coll_params.sample_sig != NULL) | 
|  | { | 
|  | sb.setLength (0); | 
|  | sb.sprintf (GTXT ("  Sample signal %s"), coll_params.sample_sig); | 
|  | commentq->append (new Emsg (CMSG_COMMENT, sb)); | 
|  | } | 
|  | if (coll_params.start_delay != NULL) | 
|  | { | 
|  | sb.setLength (0); | 
|  | sb.sprintf (GTXT ("  Data collection delay start %s seconds"), coll_params.start_delay); | 
|  | commentq->append (new Emsg (CMSG_COMMENT, sb)); | 
|  | } | 
|  | if (coll_params.terminate != NULL) | 
|  | { | 
|  | sb.setLength (0); | 
|  | sb.sprintf (GTXT ("  Data collection termination after %s seconds"), coll_params.terminate); | 
|  | commentq->append (new Emsg (CMSG_COMMENT, sb)); | 
|  | } | 
|  | // add a blank line after data description | 
|  | commentq->append (new Emsg (CMSG_COMMENT, NTXT (""))); | 
|  | } | 
|  |  | 
|  |  | 
|  | /* | 
|  | *    Raw packet processing | 
|  | */ | 
|  | static int | 
|  | check_mstate (char *ptr, PacketDescriptor *pDscr, int arg) | 
|  | { | 
|  | switch (arg) | 
|  | { | 
|  | case PROP_UCPU: | 
|  | case PROP_SCPU: | 
|  | case PROP_TRAP: | 
|  | case PROP_TFLT: | 
|  | case PROP_DFLT: | 
|  | case PROP_KFLT: | 
|  | case PROP_ULCK: | 
|  | case PROP_TSLP: | 
|  | case PROP_WCPU: | 
|  | case PROP_TSTP: | 
|  | break; | 
|  | default: | 
|  | return 0; | 
|  | } | 
|  | Vector<FieldDescr*> *fields = pDscr->getFields (); | 
|  | for (int i = 0, sz = fields->size (); i < sz; i++) | 
|  | { | 
|  | FieldDescr *fDscr = fields->fetch (i); | 
|  | if (fDscr->propID == arg) | 
|  | return *((int*) (ptr + fDscr->offset)); | 
|  | } | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | #define PACKET_ALIGNMENT 4 | 
|  |  | 
|  | uint64_t | 
|  | Experiment::readPacket (Data_window *dwin, Data_window::Span *span) | 
|  | { | 
|  | Common_packet *rcp = (Common_packet *) dwin->bind (span, | 
|  | sizeof (CommonHead_packet)); | 
|  | uint16_t v16; | 
|  | uint64_t size = 0; | 
|  | if (rcp) | 
|  | { | 
|  | if ((((long) rcp) % PACKET_ALIGNMENT) != 0) | 
|  | { | 
|  | invalid_packet++; | 
|  | size = PROFILE_BUFFER_CHUNK - span->offset % PROFILE_BUFFER_CHUNK; | 
|  | return size; | 
|  | } | 
|  | v16 = (uint16_t) rcp->tsize; | 
|  | size = dwin->decode (v16); | 
|  | if (size == 0) | 
|  | { | 
|  | size = PROFILE_BUFFER_CHUNK - span->offset % PROFILE_BUFFER_CHUNK; | 
|  | return size; | 
|  | } | 
|  | rcp = (Common_packet *) dwin->bind (span, size); | 
|  | } | 
|  | if (rcp == NULL) | 
|  | return 0; | 
|  |  | 
|  | if ((((long) rcp) % PACKET_ALIGNMENT) != 0) | 
|  | { | 
|  | invalid_packet++; | 
|  | size = PROFILE_BUFFER_CHUNK - span->offset % PROFILE_BUFFER_CHUNK; | 
|  | return size; | 
|  | } | 
|  | v16 = (uint16_t) rcp->type; | 
|  | uint32_t rcptype = dwin->decode (v16); | 
|  | if (rcptype == EMPTY_PCKT) | 
|  | return size; | 
|  | if (rcptype == FRAME_PCKT) | 
|  | { | 
|  | RawFramePacket *fp = new RawFramePacket; | 
|  | fp->uid = dwin->decode (((Frame_packet*) rcp)->uid); | 
|  | fp->uidn = NULL; | 
|  | fp->uidj = NULL; | 
|  | fp->omp_uid = NULL; | 
|  | fp->omp_state = 0; | 
|  | char *ptr = (char*) rcp + dwin->decode (((Frame_packet*) rcp)->hsize); | 
|  | if ((((long) ptr) % PACKET_ALIGNMENT) != 0) | 
|  | { | 
|  | invalid_packet++; | 
|  | delete fp; | 
|  | return size; | 
|  | } | 
|  | v16 = (uint16_t) ((Frame_packet*) rcp)->tsize; | 
|  | char *end = (char*) rcp + dwin->decode (v16); | 
|  | for (; ptr < end;) | 
|  | { | 
|  | Common_info *cinfo = (Common_info*) ptr; | 
|  | uint32_t hsize = dwin->decode (cinfo->hsize); | 
|  | if (hsize == 0 || ptr + hsize > end) | 
|  | break; | 
|  | int kind = dwin->decode (cinfo->kind); | 
|  | bool compressed = false; | 
|  | if (kind & COMPRESSED_INFO) | 
|  | { | 
|  | compressed = true; | 
|  | kind &= ~COMPRESSED_INFO; | 
|  | } | 
|  | switch (kind) | 
|  | { | 
|  | case STACK_INFO: | 
|  | { | 
|  | char *stack = ptr + sizeof (Stack_info); | 
|  | size_t stack_size = hsize - sizeof (Stack_info); | 
|  | uint64_t uidn = dwin->decode (((Stack_info*) cinfo)->uid); | 
|  | if (stack_size <= 0) | 
|  | { | 
|  | fp->uidn = get_uid_node (uidn); | 
|  | break; | 
|  | } | 
|  | uint64_t link_uid = (uint64_t) 0; | 
|  | if (compressed) | 
|  | { | 
|  | stack_size -= sizeof (uint64_t); | 
|  | unsigned char *s = (unsigned char*) (stack + stack_size); | 
|  | int shift = 0; | 
|  | for (size_t i = 0; i<sizeof (link_uid); i++) | 
|  | { | 
|  | link_uid |= (uint64_t) * s++ << shift; | 
|  | shift += 8; | 
|  | } | 
|  | } | 
|  | if (wsize == W32) | 
|  | fp->uidn = add_uid (dwin, uidn, | 
|  | (int) (stack_size / sizeof (uint32_t)), | 
|  | (uint32_t*) stack, link_uid); | 
|  | else | 
|  | fp->uidn = add_uid (dwin, uidn, | 
|  | (int) (stack_size / sizeof (uint64_t)), | 
|  | (uint64_t*) stack, link_uid); | 
|  | break; | 
|  | } | 
|  | case JAVA_INFO: | 
|  | { | 
|  | char *stack = ptr + sizeof (Java_info); | 
|  | size_t stack_size = hsize - sizeof (Java_info); | 
|  | uint64_t uidj = dwin->decode (((Java_info*) cinfo)->uid); | 
|  | if (stack_size <= 0) | 
|  | { | 
|  | fp->uidj = get_uid_node (uidj); | 
|  | break; | 
|  | } | 
|  |  | 
|  | uint64_t link_uid = (uint64_t) 0; | 
|  | if (compressed) | 
|  | { | 
|  | stack_size -= sizeof (uint64_t); | 
|  | unsigned char *s = (unsigned char*) (stack + stack_size); | 
|  | int shift = 0; | 
|  | for (size_t i = 0; i<sizeof (link_uid); i++) | 
|  | { | 
|  | link_uid |= (uint64_t) * s++ << shift; | 
|  | shift += 8; | 
|  | } | 
|  | } | 
|  | if (wsize == W32) | 
|  | fp->uidj = add_uid (dwin, uidj, | 
|  | (int) (stack_size / sizeof (uint32_t)), | 
|  | (uint32_t*) stack, link_uid); | 
|  | else | 
|  | { | 
|  | // bug 6909545: garbage in 64-bit JAVA_INFO | 
|  | char *nstack = (char*) xmalloc (stack_size); | 
|  | char *dst = nstack; | 
|  | char *srcmax = stack + stack_size - sizeof (uint64_t); | 
|  | for (char *src = stack; src <= srcmax;) | 
|  | { | 
|  | int64_t val = dwin->decode (*(int32_t*) src); | 
|  | *(uint64_t*) dst = dwin->decode (val); | 
|  | src += sizeof (uint64_t); | 
|  | dst += sizeof (uint64_t); | 
|  | if (src > srcmax) | 
|  | { | 
|  | fprintf (stderr, "er_print: Experiment::readPacket: Error in data: src=%llx greater than %llx\n", | 
|  | (long long) src, (long long) srcmax); | 
|  | break; | 
|  | } | 
|  | *(uint64_t*) dst = *(uint64_t*) src; | 
|  | src += sizeof (uint64_t); | 
|  | dst += sizeof (uint64_t); | 
|  | } | 
|  | fp->uidj = add_uid (dwin, uidj, | 
|  | (int) (stack_size / sizeof (uint64_t)), | 
|  | (uint64_t*) nstack, link_uid); | 
|  | free (nstack); | 
|  | } | 
|  | break; | 
|  | } | 
|  | case OMP_INFO: | 
|  | fp->omp_state = dwin->decode (((OMP_info*) ptr)->omp_state); | 
|  | break; | 
|  | case OMP2_INFO: | 
|  | { | 
|  | uint64_t omp_uid = dwin->decode (((OMP2_info*) ptr)->uid); | 
|  | fp->omp_uid = get_uid_node (omp_uid); | 
|  | fp->omp_state = dwin->decode (((OMP2_info*) ptr)->omp_state); | 
|  | break; | 
|  | } | 
|  | default: | 
|  | break; | 
|  | } | 
|  | ptr += hsize; | 
|  | } | 
|  | frmpckts->append (fp); | 
|  | return size; | 
|  | } | 
|  | else if (rcptype == UID_PCKT) | 
|  | { | 
|  | Uid_packet *uidp = (Uid_packet*) rcp; | 
|  | uint64_t uid = dwin->decode (uidp->uid); | 
|  | char *arr_bytes = (char*) (uidp + 1); | 
|  | v16 = (uint16_t) rcp->tsize; | 
|  | size_t arr_length = dwin->decode (v16) - sizeof (Uid_packet); | 
|  | if (arr_length <= 0) | 
|  | return size; | 
|  | uint64_t link_uid = (uint64_t) 0; | 
|  | if (dwin->decode (uidp->flags) & COMPRESSED_INFO) | 
|  | { | 
|  | arr_length -= sizeof (uint64_t); | 
|  | unsigned char *s = (unsigned char*) (arr_bytes + arr_length); | 
|  | int shift = 0; | 
|  | for (size_t i = 0; i<sizeof (link_uid); i++) | 
|  | { | 
|  | link_uid |= (uint64_t) * s++ << shift; | 
|  | shift += 8; | 
|  | } | 
|  | } | 
|  | if (wsize == W32) | 
|  | add_uid (dwin, uid, (int) (arr_length / sizeof (uint32_t)), | 
|  | (uint32_t*) arr_bytes, link_uid); | 
|  | else | 
|  | add_uid (dwin, uid, (int) (arr_length / sizeof (uint64_t)), | 
|  | (uint64_t*) arr_bytes, link_uid); | 
|  | return size; | 
|  | } | 
|  |  | 
|  | PacketDescriptor *pcktDescr = getPacketDescriptor (rcptype); | 
|  | if (pcktDescr == NULL) | 
|  | return size; | 
|  | DataDescriptor *dataDescr = pcktDescr->getDataDescriptor (); | 
|  | if (dataDescr == NULL) | 
|  | return size; | 
|  |  | 
|  | /* omazur: TBR START -- old experiment */ | 
|  | if (rcptype == PROF_PCKT) | 
|  | { | 
|  | // For backward compatibility with older SS12 experiments | 
|  | int numstates = get_params ()->lms_magic_id; // ugly, for old experiments | 
|  | if (numstates > LMS_NUM_SOLARIS_MSTATES) | 
|  | numstates = LMS_NUM_SOLARIS_MSTATES; | 
|  | for (int i = 0; i < numstates; i++) | 
|  | if (check_mstate ((char*) rcp, pcktDescr, PROP_UCPU + i)) | 
|  | readPacket (dwin, (char*) rcp, pcktDescr, dataDescr, PROP_UCPU + i, | 
|  | size); | 
|  | } | 
|  | else | 
|  | readPacket (dwin, (char*) rcp, pcktDescr, dataDescr, 0, size); | 
|  | return size; | 
|  | } | 
|  |  | 
|  | static uint32_t get_v32(char *p) | 
|  | { | 
|  | uint32_t v; | 
|  | memcpy (&v, p, sizeof(uint32_t)); | 
|  | return v; | 
|  | } | 
|  |  | 
|  | static uint64_t get_v64(char *p) | 
|  | { | 
|  | uint64_t v; | 
|  | memcpy (&v, p, sizeof(uint64_t)); | 
|  | return v; | 
|  | } | 
|  |  | 
|  | void | 
|  | Experiment::readPacket (Data_window *dwin, char *ptr, PacketDescriptor *pDscr, | 
|  | DataDescriptor *dDscr, int arg, uint64_t pktsz) | 
|  | { | 
|  | long recn = dDscr->addRecord (); | 
|  | Vector<FieldDescr*> *fields = pDscr->getFields (); | 
|  | uint32_t v32; | 
|  | uint64_t v64; | 
|  | int sz = fields->size (); | 
|  | for (int i = 0; i < sz; i++) | 
|  | { | 
|  | FieldDescr *field = fields->fetch (i); | 
|  | if (field->propID == arg) | 
|  | { | 
|  | v32 = get_v32(ptr + field->offset); | 
|  | dDscr->setValue (PROP_NTICK, recn, dwin->decode (v32)); | 
|  | dDscr->setValue (PROP_MSTATE, recn, (uint32_t) (field->propID - PROP_UCPU)); | 
|  | } | 
|  | if (field->propID == PROP_THRID || field->propID == PROP_LWPID | 
|  | || field->propID == PROP_CPUID) | 
|  | { | 
|  | uint64_t tmp64 = 0; | 
|  | switch (field->vtype) | 
|  | { | 
|  | case TYPE_INT32: | 
|  | case TYPE_UINT32: | 
|  | v32 = get_v32 (ptr + field->offset); | 
|  | tmp64 = dwin->decode (v32); | 
|  | break; | 
|  | case TYPE_INT64: | 
|  | case TYPE_UINT64: | 
|  | v64 = get_v64 (ptr + field->offset); | 
|  | tmp64 = dwin->decode (v64); | 
|  | break; | 
|  | case TYPE_STRING: | 
|  | case TYPE_DOUBLE: | 
|  | case TYPE_OBJ: | 
|  | case TYPE_DATE: | 
|  | case TYPE_BOOL: | 
|  | case TYPE_ENUM: | 
|  | case TYPE_LAST: | 
|  | case TYPE_NONE: | 
|  | break; | 
|  | } | 
|  | uint32_t tag = mapTagValue ((Prop_type) field->propID, tmp64); | 
|  | dDscr->setValue (field->propID, recn, tag); | 
|  | } | 
|  | else | 
|  | { | 
|  | switch (field->vtype) | 
|  | { | 
|  | case TYPE_INT32: | 
|  | case TYPE_UINT32: | 
|  | v32 = get_v32 (ptr + field->offset); | 
|  | dDscr->setValue (field->propID, recn, dwin->decode (v32)); | 
|  | break; | 
|  | case TYPE_INT64: | 
|  | case TYPE_UINT64: | 
|  | v64 = get_v64 (ptr + field->offset); | 
|  | dDscr->setValue (field->propID, recn, dwin->decode (v64)); | 
|  | break; | 
|  | case TYPE_STRING: | 
|  | { | 
|  | int len = (int) (pktsz - field->offset); | 
|  | if ((len > 0) && (ptr[field->offset] != 0)) | 
|  | { | 
|  | StringBuilder *sb = new StringBuilder (); | 
|  | sb->append (ptr + field->offset, 0, len); | 
|  | dDscr->setObjValue (field->propID, recn, sb); | 
|  | } | 
|  | break; | 
|  | } | 
|  | // ignoring the following cases (why?) | 
|  | case TYPE_DOUBLE: | 
|  | case TYPE_OBJ: | 
|  | case TYPE_DATE: | 
|  | case TYPE_BOOL: | 
|  | case TYPE_ENUM: | 
|  | case TYPE_LAST: | 
|  | case TYPE_NONE: | 
|  | break; | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | #define PROG_BYTE 102400 // update progress bar every PROG_BYTE bytes | 
|  |  | 
|  | void | 
|  | Experiment::read_data_file (const char *fname, const char *msg) | 
|  | { | 
|  | Data_window::Span span; | 
|  | off64_t total_len, remain_len; | 
|  | char *progress_bar_msg; | 
|  | int progress_bar_percent = -1; | 
|  |  | 
|  | char *data_file_name = dbe_sprintf (NTXT ("%s/%s"), expt_name, fname); | 
|  | Data_window *dwin = new Data_window (data_file_name); | 
|  | // Here we can call stat(data_file_name) to get file size, | 
|  | // and call a function to reallocate vectors for clock profiling data | 
|  | free (data_file_name); | 
|  | if (dwin->not_opened ()) | 
|  | { | 
|  | delete dwin; | 
|  | return; | 
|  | } | 
|  | dwin->need_swap_endian = need_swap_endian; | 
|  |  | 
|  | span.offset = 0; | 
|  | span.length = dwin->get_fsize (); | 
|  | total_len = remain_len = span.length; | 
|  | progress_bar_msg = dbe_sprintf (NTXT ("%s %s"), NTXT ("  "), msg); | 
|  | invalid_packet = 0; | 
|  | for (;;) | 
|  | { | 
|  | uint64_t pcktsz = readPacket (dwin, &span); | 
|  | if (pcktsz == 0) | 
|  | break; | 
|  | // Update progress bar | 
|  | if ((span.length <= remain_len) && (remain_len > 0)) | 
|  | { | 
|  | int percent = (int) (100 * (total_len - remain_len) / total_len); | 
|  | if (percent > progress_bar_percent) | 
|  | { | 
|  | progress_bar_percent += 10; | 
|  | theApplication->set_progress (percent, progress_bar_msg); | 
|  | } | 
|  | remain_len -= PROG_BYTE; | 
|  | } | 
|  | span.length -= pcktsz; | 
|  | span.offset += pcktsz; | 
|  | } | 
|  | delete dwin; | 
|  |  | 
|  | if (invalid_packet) | 
|  | { | 
|  | StringBuilder sb; | 
|  | sb.sprintf (GTXT ("WARNING: There are %d invalid packet(s) in the %s file"), | 
|  | invalid_packet, fname); | 
|  | Emsg *m = new Emsg (CMSG_WARN, sb); | 
|  | warnq->append (m); | 
|  | } | 
|  |  | 
|  | theApplication->set_progress (0, NTXT ("")); | 
|  | free (progress_bar_msg); | 
|  | } | 
|  |  | 
|  | int | 
|  | Experiment::read_overview_file () | 
|  | { | 
|  | char *data_file_name = dbe_sprintf ("%s/%s", expt_name, SP_OVERVIEW_FILE); | 
|  | Data_window *dwin = new Data_window (data_file_name); | 
|  | free (data_file_name); | 
|  | if (dwin->not_opened ()) | 
|  | { | 
|  | delete dwin; | 
|  | return 0; | 
|  | } | 
|  | dwin->need_swap_endian = need_swap_endian; | 
|  | newDataDescriptor (DATA_SAMPLE); | 
|  |  | 
|  | Data_window::Span span; | 
|  | span.offset = 0; | 
|  | span.length = dwin->get_fsize (); | 
|  |  | 
|  | PrUsage *data = NULL, *data_prev = NULL; | 
|  | Sample *sample; | 
|  | int sample_number = 1; | 
|  |  | 
|  | int64_t prDataSize; | 
|  | if (wsize == W32) | 
|  | prDataSize = PrUsage::bind32Size (); | 
|  | else | 
|  | prDataSize = PrUsage::bind64Size (); | 
|  |  | 
|  | while (span.length > 0) | 
|  | { | 
|  | data_prev = data; | 
|  | data = new PrUsage (); | 
|  |  | 
|  | void *dw = dwin->bind (&span, prDataSize); | 
|  | if ((dw == NULL) || (prDataSize > span.length)) | 
|  | { | 
|  | Emsg *m = new Emsg (CMSG_ERROR, GTXT ("Warning: overview data file can't be read")); | 
|  | warnq->append (m); | 
|  | status = FAILURE; | 
|  | delete dwin; | 
|  | return status; | 
|  | } | 
|  |  | 
|  | if (wsize == W32) | 
|  | data->bind32 (dw, need_swap_endian); | 
|  | else | 
|  | data->bind64 (dw, need_swap_endian); | 
|  | span.length -= prDataSize; | 
|  | span.offset += prDataSize; | 
|  |  | 
|  | // Skip the first packet | 
|  | if (data_prev == NULL) | 
|  | continue; | 
|  | if (sample_number > samples->size ()) | 
|  | { // inconsistent log/overview | 
|  | sample = new Sample (sample_number); | 
|  | char * label = GTXT ("<unknown>"); | 
|  | sample->start_label = dbe_strdup (label); | 
|  | sample->end_label = dbe_strdup (label); | 
|  | samples->append (sample); | 
|  | } | 
|  | else | 
|  | sample = samples->fetch (sample_number - 1); | 
|  | sample_number++; | 
|  | sample->start_time = data_prev->pr_tstamp + 1; | 
|  | sample->end_time = data->pr_tstamp; | 
|  | sample->prusage = data_prev; | 
|  |  | 
|  | data_prev->pr_rtime = data->pr_rtime - data_prev->pr_rtime; | 
|  | data_prev->pr_utime = data->pr_utime - data_prev->pr_utime; | 
|  | data_prev->pr_stime = data->pr_stime - data_prev->pr_stime; | 
|  | data_prev->pr_ttime = data->pr_ttime - data_prev->pr_ttime; | 
|  | data_prev->pr_tftime = data->pr_tftime - data_prev->pr_tftime; | 
|  | data_prev->pr_dftime = data->pr_dftime - data_prev->pr_dftime; | 
|  | data_prev->pr_kftime = data->pr_kftime - data_prev->pr_kftime; | 
|  | data_prev->pr_ltime = data->pr_ltime - data_prev->pr_ltime; | 
|  | data_prev->pr_slptime = data->pr_slptime - data_prev->pr_slptime; | 
|  | data_prev->pr_wtime = data->pr_wtime - data_prev->pr_wtime; | 
|  | data_prev->pr_stoptime = data->pr_stoptime - data_prev->pr_stoptime; | 
|  | data_prev->pr_minf = data->pr_minf - data_prev->pr_minf; | 
|  | data_prev->pr_majf = data->pr_majf - data_prev->pr_majf; | 
|  | data_prev->pr_nswap = data->pr_nswap - data_prev->pr_nswap; | 
|  | data_prev->pr_inblk = data->pr_inblk - data_prev->pr_inblk; | 
|  | data_prev->pr_oublk = data->pr_oublk - data_prev->pr_oublk; | 
|  | data_prev->pr_msnd = data->pr_msnd - data_prev->pr_msnd; | 
|  | data_prev->pr_mrcv = data->pr_mrcv - data_prev->pr_mrcv; | 
|  | data_prev->pr_sigs = data->pr_sigs - data_prev->pr_sigs; | 
|  | data_prev->pr_vctx = data->pr_vctx - data_prev->pr_vctx; | 
|  | data_prev->pr_ictx = data->pr_ictx - data_prev->pr_ictx; | 
|  | data_prev->pr_sysc = data->pr_sysc - data_prev->pr_sysc; | 
|  | data_prev->pr_ioch = data->pr_ioch - data_prev->pr_ioch; | 
|  | sample->get_usage (); // force validation | 
|  | } | 
|  |  | 
|  | for (long smpNum = samples->size (); smpNum >= sample_number; smpNum--) | 
|  | { | 
|  | // overview file was truncated | 
|  | sample = samples->remove (smpNum - 1); | 
|  | delete sample; | 
|  | } | 
|  |  | 
|  | if (data) | 
|  | { | 
|  | // Update last_event so that getEndTime() covers | 
|  | // all loadobjects, too. | 
|  | update_last_event (data->pr_tstamp); | 
|  | delete data; | 
|  | } | 
|  | delete dwin; | 
|  | return SUCCESS; | 
|  | } | 
|  |  | 
|  | int | 
|  | Experiment::uidNodeCmp (const void *a, const void *b) | 
|  | { | 
|  | UIDnode *nd1 = *(UIDnode**) a; | 
|  | UIDnode *nd2 = *(UIDnode**) b; | 
|  | if (nd1->uid == nd2->uid) | 
|  | return 0; | 
|  | return nd1->uid < nd2->uid ? -1 : 1; | 
|  | } | 
|  |  | 
|  | static uint64_t | 
|  | funcAddr (uint32_t val) | 
|  | { | 
|  | if (val == (uint32_t) SP_LEAF_CHECK_MARKER) | 
|  | return (uint64_t) SP_LEAF_CHECK_MARKER; | 
|  | if (val == (uint32_t) SP_TRUNC_STACK_MARKER) | 
|  | return (uint64_t) SP_TRUNC_STACK_MARKER; | 
|  | if (val == (uint32_t) SP_FAILED_UNWIND_MARKER) | 
|  | return (uint64_t) SP_FAILED_UNWIND_MARKER; | 
|  | return val; | 
|  | } | 
|  |  | 
|  | Experiment::UIDnode * | 
|  | Experiment::add_uid (Data_window *dwin, uint64_t uid, int size, | 
|  | uint32_t *array, uint64_t link_uid) | 
|  | { | 
|  | if (uid == (uint64_t) 0) | 
|  | return NULL; | 
|  | uint64_t val = funcAddr (dwin->decode (array[0])); | 
|  | UIDnode *node = NULL; | 
|  | UIDnode *res = get_uid_node (uid, val); | 
|  | UIDnode *next = res; | 
|  | for (int i = 0; i < size; i++) | 
|  | { | 
|  | val = funcAddr (dwin->decode (array[i])); | 
|  | if (next == NULL) | 
|  | { | 
|  | next = get_uid_node ((uint64_t) 0, val); | 
|  | if (node != NULL) | 
|  | node->next = next; | 
|  | } | 
|  | node = next; | 
|  | next = node->next; | 
|  | if (node->val == 0) | 
|  | node->val = val; | 
|  | else if (node->val != val)   // Algorithmic error (should never happen) | 
|  | node->val = (uint64_t) SP_LEAF_CHECK_MARKER; | 
|  | } | 
|  | if (next == NULL && link_uid != (uint64_t) 0 && node != NULL) | 
|  | node->next = get_uid_node (link_uid); | 
|  | return res; | 
|  | } | 
|  |  | 
|  | Experiment::UIDnode * | 
|  | Experiment::add_uid (Data_window *dwin, uint64_t uid, int size, uint64_t *array, uint64_t link_uid) | 
|  | { | 
|  | if (uid == (uint64_t) 0) | 
|  | return NULL; | 
|  | UIDnode *node = NULL; | 
|  | uint64_t val = dwin->decode (array[0]); | 
|  | UIDnode *res = get_uid_node (uid, val); | 
|  | UIDnode *next = res; | 
|  | for (int i = 0; i < size; i++) | 
|  | { | 
|  | val = dwin->decode (array[i]); | 
|  | if (next == NULL) | 
|  | { | 
|  | next = get_uid_node ((uint64_t) 0, val); | 
|  | if (node != NULL) | 
|  | node->next = next; | 
|  | } | 
|  | node = next; | 
|  | next = node->next; | 
|  | if (node->val == (uint64_t) 0) | 
|  | node->val = val; | 
|  | else if (node->val != val)   // Algorithmic error (should never happen) | 
|  | node->val = (uint64_t) - 1; | 
|  | } | 
|  | if (next == NULL && link_uid != (uint64_t) 0 && node != NULL) | 
|  | node->next = get_uid_node (link_uid); | 
|  | return res; | 
|  | } | 
|  |  | 
|  | Experiment::UIDnode * | 
|  | Experiment::new_uid_node (uint64_t uid, uint64_t val) | 
|  | { | 
|  | #define NCHUNKSTEP 1024 | 
|  | if (nnodes >= nchunks * CHUNKSZ) | 
|  | { | 
|  | // Reallocate Node chunk array | 
|  | UIDnode** old_chunks = chunks; | 
|  | chunks = new UIDnode*[nchunks + NCHUNKSTEP]; | 
|  | if (old_chunks) | 
|  | memcpy (chunks, old_chunks, nchunks * sizeof (UIDnode*)); | 
|  | nchunks += NCHUNKSTEP; | 
|  | delete[] old_chunks; | 
|  | // Clean future pointers | 
|  | memset (&chunks[nchunks - NCHUNKSTEP], 0, NCHUNKSTEP * sizeof (UIDnode*)); | 
|  | } | 
|  |  | 
|  | if (NULL == chunks[nnodes / CHUNKSZ])   // Allocate new chunk for nodes. | 
|  | chunks[nnodes / CHUNKSZ] = new UIDnode[CHUNKSZ]; | 
|  | UIDnode *node = &chunks[nnodes / CHUNKSZ][nnodes % CHUNKSZ]; | 
|  | node->uid = uid; | 
|  | node->val = val; | 
|  | node->next = NULL; | 
|  | nnodes++; | 
|  | return node; | 
|  | } | 
|  |  | 
|  | Experiment::UIDnode * | 
|  | Experiment::get_uid_node (uint64_t uid, uint64_t val) | 
|  | { | 
|  | int hash = (((int) uid) >> 4) & (HTableSize - 1); | 
|  | if (uid != (uint64_t) 0) | 
|  | { | 
|  | UIDnode *node = uidHTable[hash]; | 
|  | if (node && node->uid == uid) | 
|  | return node; | 
|  | } | 
|  | UIDnode *node = new_uid_node (uid, val); | 
|  | if (uid != (uint64_t) 0) | 
|  | { | 
|  | uidHTable[hash] = node; | 
|  | uidnodes->append (node); | 
|  | } | 
|  | return node; | 
|  | } | 
|  |  | 
|  | Experiment::UIDnode * | 
|  | Experiment::get_uid_node (uint64_t uid) | 
|  | { | 
|  | if (uid == (uint64_t) 0) | 
|  | return NULL; | 
|  | int hash = (((int) uid) >> 4) & (HTableSize - 1); | 
|  | UIDnode *node = uidHTable[hash]; | 
|  | if (node && node->uid == uid) | 
|  | return node; | 
|  | node = new_uid_node (uid, (uint64_t) 0); | 
|  | node->next = node; | 
|  | return node; | 
|  | } | 
|  |  | 
|  | Experiment::UIDnode * | 
|  | Experiment::find_uid_node (uint64_t uid) | 
|  | { | 
|  | int hash = (((int) uid) >> 4) & (HTableSize - 1); | 
|  | UIDnode *node = uidHTable[hash]; | 
|  | if (node && node->uid == uid) | 
|  | return node; | 
|  | int lt = 0; | 
|  | int rt = uidnodes->size () - 1; | 
|  | while (lt <= rt) | 
|  | { | 
|  | int md = (lt + rt) / 2; | 
|  | node = uidnodes->fetch (md); | 
|  | if (node->uid < uid) | 
|  | lt = md + 1; | 
|  | else if (node->uid > uid) | 
|  | rt = md - 1; | 
|  | else | 
|  | { | 
|  | uidHTable[hash] = node; | 
|  | return node; | 
|  | } | 
|  | } | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | int | 
|  | Experiment::frUidCmp (const void *a, const void *b) | 
|  | { | 
|  | RawFramePacket *fp1 = *(RawFramePacket**) a; | 
|  | RawFramePacket *fp2 = *(RawFramePacket**) b; | 
|  | if (fp1->uid == fp2->uid) | 
|  | return 0; | 
|  | return fp1->uid < fp2->uid ? -1 : 1; | 
|  | } | 
|  |  | 
|  | Experiment::RawFramePacket * | 
|  | Experiment::find_frame_packet (uint64_t uid) | 
|  | { | 
|  | int lt = 0; | 
|  | int rt = frmpckts->size () - 1; | 
|  | while (lt <= rt) | 
|  | { | 
|  | int md = (lt + rt) / 2; | 
|  | RawFramePacket *fp = frmpckts->fetch (md); | 
|  | if (fp->uid < uid) | 
|  | lt = md + 1; | 
|  | else if (fp->uid > uid) | 
|  | rt = md - 1; | 
|  | else | 
|  | return fp; | 
|  | } | 
|  |  | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | #define FRINFO_CACHEOPT_SIZE_LIMIT  4000000 | 
|  | #define FRINFO_PIPELINE_SIZE_LIMIT  500000 | 
|  | #define FRINFO_PIPELINE_NUM_STAGES  3 | 
|  |  | 
|  | // Pipelined execution of resolve_frame_info() and add_stack(). | 
|  | // Since this is the largest time consuming part of loading an experiment (especially | 
|  | // so for large java experiments) - executing this part as a 3 stage pipeline can | 
|  | // give significant performance gain - and this concept can be aggressively applied | 
|  | // to enhance the gain further in future. The three stages are: | 
|  | // Phase 1:  resolve_frame_info() | 
|  | // Phase 2:  first part of add_stack() where the native stack is built | 
|  | // Phase 3:  second part og add_stack() where the java stack is built | 
|  | // Phase 4:   insert the native and java stacks into the stack map | 
|  | // The main thread operates in the first Phase and the other stages are | 
|  | // operated by a ssplib sequential queue - The threads working on the queues run concurrently | 
|  | // with each other and with the main thread. But within a particular queue, jobs are | 
|  | // executed sequentially | 
|  |  | 
|  |  | 
|  | // This is the second phase of the pipeline of resolve_frame_info and add_stack | 
|  | //  It works on a chunk of iterations (size CSTCTX_CHUNK_SZ) and invokes add_stack() | 
|  | // for each one of them | 
|  |  | 
|  | void | 
|  | Experiment::resolve_frame_info (DataDescriptor *dDscr) | 
|  | { | 
|  | if (!resolveFrameInfo) | 
|  | return; | 
|  | if (NULL == cstack) | 
|  | return; | 
|  | dDscr->setResolveFrInfoDone (); | 
|  |  | 
|  | // Check for TSTAMP | 
|  | int propID = dbeSession->getPropIdByName (NTXT ("TSTAMP")); | 
|  | Data *dataTStamp = dDscr->getData (propID); | 
|  | if (dataTStamp == NULL) | 
|  | return; | 
|  |  | 
|  | propID = dbeSession->getPropIdByName (NTXT ("FRINFO")); | 
|  | Data *dataFrinfo = dDscr->getData (propID); | 
|  |  | 
|  | propID = dbeSession->getPropIdByName (NTXT ("THRID")); | 
|  | Data *dataThrId = dDscr->getData (propID); | 
|  |  | 
|  | // We can get frame info either by FRINFO or by [THRID,STKIDX] | 
|  | if (dataFrinfo == NULL) | 
|  | return; | 
|  |  | 
|  | char *propName = NTXT ("MSTACK"); | 
|  | propID = dbeSession->getPropIdByName (propName); | 
|  | PropDescr *prMStack = new PropDescr (propID, propName); | 
|  | prMStack->uname = dbe_strdup (GTXT ("Machine Call Stack")); | 
|  | prMStack->vtype = TYPE_OBJ; | 
|  | dDscr->addProperty (prMStack); | 
|  |  | 
|  | propName = NTXT ("USTACK"); | 
|  | propID = dbeSession->getPropIdByName (propName); | 
|  | PropDescr *prUStack = new PropDescr (propID, propName); | 
|  | prUStack->uname = dbe_strdup (GTXT ("User Call Stack")); | 
|  | prUStack->vtype = TYPE_OBJ; | 
|  | dDscr->addProperty (prUStack); | 
|  |  | 
|  | propName = NTXT ("XSTACK"); | 
|  | propID = dbeSession->getPropIdByName (propName); | 
|  | PropDescr *prXStack = new PropDescr (propID, propName); | 
|  | prXStack->uname = dbe_strdup (GTXT ("Expert Call Stack")); | 
|  | prXStack->vtype = TYPE_OBJ; | 
|  | dDscr->addProperty (prXStack); | 
|  |  | 
|  | propName = NTXT ("HSTACK"); | 
|  | propID = dbeSession->getPropIdByName (propName); | 
|  | PropDescr *prHStack = new PropDescr (propID, propName); | 
|  | prHStack->uname = dbe_strdup (GTXT ("ShowHide Call Stack")); | 
|  | prHStack->vtype = TYPE_OBJ; | 
|  | dDscr->addProperty (prHStack); | 
|  |  | 
|  | if (has_java) | 
|  | { | 
|  | propName = NTXT ("JTHREAD"); | 
|  | propID = dbeSession->getPropIdByName (propName); | 
|  | PropDescr *prJThread = new PropDescr (propID, propName); | 
|  | prJThread->uname = dbe_strdup (GTXT ("Java Thread")); | 
|  | prJThread->vtype = TYPE_OBJ; | 
|  | dDscr->addProperty (prJThread); | 
|  | } | 
|  |  | 
|  | if (ompavail) | 
|  | { | 
|  | PropDescr *prop = new PropDescr (PROP_OMPSTATE, NTXT ("OMPSTATE")); | 
|  | prop->uname = dbe_strdup (GTXT ("OpenMP state")); | 
|  | prop->vtype = TYPE_UINT32; | 
|  | char * stateNames [OMP_LAST_STATE] = OMP_THR_STATE_STRINGS; | 
|  | char * stateUNames[OMP_LAST_STATE] = OMP_THR_STATE_USTRINGS; | 
|  | for (int ii = 0; ii < OMP_LAST_STATE; ii++) | 
|  | prop->addState (ii, stateNames[ii], stateUNames[ii]); | 
|  | dDscr->addProperty (prop); | 
|  |  | 
|  | // add PROP_CPRID to profiling data (not same as omptrace's PROP_CPRID) | 
|  | prop = dDscr->getProp (PROP_CPRID); | 
|  | if (prop) | 
|  | { | 
|  | VType_type type = prop->vtype; | 
|  | assert (type == TYPE_OBJ); //see 7040526 | 
|  | } | 
|  | prop = new PropDescr (PROP_CPRID, NTXT ("CPRID")); //profiling PROP_CPRID | 
|  | prop->uname = dbe_strdup (GTXT ("OpenMP parallel region")); | 
|  | prop->vtype = TYPE_OBJ; | 
|  | dDscr->addProperty (prop); | 
|  |  | 
|  | // add PROP_TSKID to profiling data (not same as omptrace's PROP_TSKID) | 
|  | prop = dDscr->getProp (PROP_TSKID); | 
|  | if (prop) | 
|  | { | 
|  | VType_type type = prop->vtype; | 
|  | assert (type == TYPE_OBJ); //see 7040526 | 
|  | } | 
|  | prop = new PropDescr (PROP_TSKID, NTXT ("TSKID")); //profiling PROP_TSKID | 
|  | prop->uname = dbe_strdup (GTXT ("OpenMP task")); | 
|  | prop->vtype = TYPE_OBJ; | 
|  | dDscr->addProperty (prop); | 
|  | } | 
|  | char *progress_bar_msg = dbe_sprintf (NTXT ("%s %s: %s"), NTXT ("  "), | 
|  | GTXT ("Processing CallStack Data"), | 
|  | get_basename (expt_name)); | 
|  | int progress_bar_percent = -1; | 
|  | long deltaReport = 5000; | 
|  | long nextReport = 0; | 
|  |  | 
|  | long size = dDscr->getSize (); | 
|  | //    bool resolve_frinfo_pipelined = size > FRINFO_PIPELINE_SIZE_LIMIT && !ompavail; | 
|  | bool resolve_frinfo_pipelined = false; | 
|  |  | 
|  | Map<uint64_t, uint64_t> *nodeCache = NULL; | 
|  | Map<uint64_t, uint64_t> *frameInfoCache = NULL; | 
|  | if (size > FRINFO_CACHEOPT_SIZE_LIMIT && dversion == NULL) | 
|  | { | 
|  | frameInfoCache = new CacheMap<uint64_t, uint64_t>; | 
|  | nodeCache = new CacheMap<uint64_t, uint64_t>; | 
|  | } | 
|  |  | 
|  | pushCnt = popCnt = pushCnt3 = popCnt3 = 0; | 
|  | nPush = nPop = 0; | 
|  |  | 
|  | FramePacket *fp = NULL; | 
|  | //    DbeThreadPool * threadPool = new DbeThreadPool(5); | 
|  | fp = new FramePacket; | 
|  | fp->stack = new Vector<Vaddr>; | 
|  | fp->jstack = new Vector<Vaddr>; | 
|  | fp->ompstack = new Vector<Vaddr>; | 
|  | fp->omp_state = 0; | 
|  | fp->mpi_state = 0; | 
|  |  | 
|  | // piggyback on post-processing to calculate exp->last_event | 
|  | const hrtime_t _exp_start_time = getStartTime (); // wall clock time | 
|  | hrtime_t exp_duration = getLastEvent () == ZERO_TIME ? 0 | 
|  | : getLastEvent () - _exp_start_time; // zero-based | 
|  |  | 
|  | int missed_fi = 0; | 
|  | int total_fi = 0; | 
|  |  | 
|  | for (long i = 0; i < size; i++) | 
|  | { | 
|  | if (i == nextReport) | 
|  | { | 
|  | int percent = (int) (i * 100 / size); | 
|  | if (percent > progress_bar_percent) | 
|  | { | 
|  | progress_bar_percent += 10; | 
|  | theApplication->set_progress (percent, progress_bar_msg); | 
|  | } | 
|  | nextReport += deltaReport; | 
|  | } | 
|  |  | 
|  | uint32_t thrid = (uint32_t) dataThrId->fetchInt (i); | 
|  | hrtime_t tstamp = (hrtime_t) dataTStamp->fetchLong (i); | 
|  |  | 
|  | // piggyback on post-processing to calculate exp->last_event | 
|  | { | 
|  | hrtime_t relative_timestamp = tstamp - _exp_start_time; | 
|  | if (exp_duration < relative_timestamp) | 
|  | exp_duration = relative_timestamp; | 
|  | } | 
|  | uint64_t frinfo = (uint64_t) dataFrinfo->fetchLong (i); | 
|  |  | 
|  | RawFramePacket *rfp = NULL; | 
|  | if (frinfo) | 
|  | { | 
|  | // CacheMap does not work with NULL key | 
|  | if (frameInfoCache != NULL) | 
|  | rfp = (RawFramePacket *) frameInfoCache->get (frinfo); | 
|  | } | 
|  | if (rfp == 0) | 
|  | { | 
|  | rfp = find_frame_packet (frinfo); | 
|  | if (rfp != 0) | 
|  | { | 
|  | if (frameInfoCache != NULL) | 
|  | frameInfoCache->put (frinfo, (uint64_t) rfp); | 
|  | } | 
|  | else | 
|  | missed_fi++; | 
|  | total_fi++; | 
|  | } | 
|  |  | 
|  | // Process OpenMP properties | 
|  | if (ompavail) | 
|  | { | 
|  | fp->omp_state = rfp ? rfp->omp_state : 0; | 
|  | dDscr->setValue (PROP_OMPSTATE, i, fp->omp_state); | 
|  |  | 
|  | fp->omp_cprid = mapPRid->get (thrid, tstamp, mapPRid->REL_EQLE); | 
|  | void *omp_preg = mapPReg->get (thrid, tstamp, mapPReg->REL_EQLE); | 
|  | if (!omp_preg) | 
|  | { | 
|  | char *idxname = NTXT ("OMP_preg"); | 
|  | int idxtype = dbeSession->findIndexSpaceByName (idxname); | 
|  | if (idxtype != -1) | 
|  | { | 
|  | Histable *preg0 = dbeSession->findObjectById (Histable::INDEXOBJ, idxtype, (int64_t) 0); | 
|  | if (preg0) | 
|  | { | 
|  | Vector<Histable*> pregs; | 
|  | pregs.append (preg0); | 
|  | omp_preg = cstack->add_stack (&pregs); | 
|  | mapPReg->put (thrid, tstamp, omp_preg); | 
|  | } | 
|  | } | 
|  | } | 
|  | dDscr->setObjValue (PROP_CPRID, i, omp_preg); //profiling PROP_CPRID | 
|  | void *omp_task = mapTask->get (thrid, tstamp, mapTask->REL_EQLE); | 
|  | if (!omp_task) | 
|  | { | 
|  | char *idxname = NTXT ("OMP_task"); | 
|  | int idxtype = dbeSession->findIndexSpaceByName (idxname); | 
|  | if (idxtype != -1) | 
|  | { | 
|  | Histable *task0 = dbeSession->findObjectById (Histable::INDEXOBJ, idxtype, (int64_t) 0); | 
|  | if (task0) | 
|  | { | 
|  | Vector<Histable*> tasks; | 
|  | tasks.append (task0); | 
|  | omp_task = cstack->add_stack (&tasks); | 
|  | mapTask->put (thrid, tstamp, omp_task); | 
|  | } | 
|  | } | 
|  | } | 
|  | dDscr->setObjValue (PROP_TSKID, i, omp_task); //profiling PROP_TSKID | 
|  | } | 
|  | else | 
|  | { | 
|  | fp->omp_state = 0; | 
|  | fp->omp_cprid = 0; | 
|  | } | 
|  |  | 
|  | // Construct the native stack | 
|  | fp->stack->reset (); | 
|  | Vaddr leafpc = dDscr->getULongValue (PROP_LEAFPC, i); | 
|  | if (leafpc) | 
|  | fp->stack->append (leafpc); | 
|  | UIDnode *node = rfp ? rfp->uidn : NULL; | 
|  | while (node) | 
|  | { | 
|  | if (node->next == node) | 
|  | // this node contains link_uid | 
|  | node = find_uid_node (node->uid); | 
|  | else | 
|  | { | 
|  | fp->stack->append (node->val); | 
|  | node = node->next; | 
|  | } | 
|  | } | 
|  | fp->truncated = 0; | 
|  | int last = fp->stack->size () - 1; | 
|  | if (last >= 0) | 
|  | { | 
|  | switch (fp->stack->fetch (last)) | 
|  | { | 
|  | case SP_TRUNC_STACK_MARKER: | 
|  | fp->truncated = (Vaddr) SP_TRUNC_STACK_MARKER; | 
|  | fp->stack->remove (last); | 
|  | break; | 
|  | case SP_FAILED_UNWIND_MARKER: | 
|  | fp->truncated = (Vaddr) SP_FAILED_UNWIND_MARKER; | 
|  | fp->stack->remove (last); | 
|  | break; | 
|  | } | 
|  | } | 
|  |  | 
|  | // Construct the Java stack | 
|  | fp->jstack->reset (); | 
|  | node = rfp ? rfp->uidj : NULL; | 
|  | while (node) | 
|  | { | 
|  | if (node->next == node) | 
|  | { | 
|  | // this node contains link_uid | 
|  | UIDnode *n = NULL; | 
|  | if (node->uid) | 
|  | { | 
|  | // CacheMap does not work with NULL key | 
|  | if (nodeCache != NULL) | 
|  | n = (UIDnode *) nodeCache->get (node->uid); | 
|  | } | 
|  | if (n == NULL) | 
|  | { | 
|  | n = find_uid_node (node->uid); | 
|  | if (n != NULL) | 
|  | { | 
|  | if (nodeCache != NULL) | 
|  | nodeCache->put (node->uid, (uint64_t) n); | 
|  | } | 
|  | } | 
|  | node = n; | 
|  | } | 
|  | else | 
|  | { | 
|  | fp->jstack->append (node->val); | 
|  | node = node->next; | 
|  | } | 
|  | } | 
|  | fp->jtruncated = false; | 
|  | last = fp->jstack->size () - 1; | 
|  | if (last >= 1 && fp->jstack->fetch (last) == SP_TRUNC_STACK_MARKER) | 
|  | { | 
|  | fp->jtruncated = true; | 
|  | fp->jstack->remove (last); | 
|  | fp->jstack->remove (last - 1); | 
|  | } | 
|  |  | 
|  | // Construct the OpenMP stack | 
|  | if (ompavail) | 
|  | { | 
|  | fp->ompstack->reset (); | 
|  | if (rfp && rfp->omp_uid) | 
|  | { | 
|  | if (leafpc) | 
|  | fp->ompstack->append (leafpc); | 
|  | node = rfp->omp_uid; | 
|  | while (node) | 
|  | { | 
|  | if (node->next == node) | 
|  | // this node contains link_uid | 
|  | node = find_uid_node (node->uid); | 
|  | else | 
|  | { | 
|  | fp->ompstack->append (node->val); | 
|  | node = node->next; | 
|  | } | 
|  | } | 
|  | fp->omptruncated = false; | 
|  | last = fp->ompstack->size () - 1; | 
|  | if (last >= 0) | 
|  | { | 
|  | switch (fp->ompstack->fetch (last)) | 
|  | { | 
|  | case SP_TRUNC_STACK_MARKER: | 
|  | fp->omptruncated = (Vaddr) SP_TRUNC_STACK_MARKER; | 
|  | fp->ompstack->remove (last); | 
|  | break; | 
|  | case SP_FAILED_UNWIND_MARKER: | 
|  | fp->omptruncated = (Vaddr) SP_FAILED_UNWIND_MARKER; | 
|  | fp->ompstack->remove (last); | 
|  | break; | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  | cstack->add_stack (dDscr, i, fp, NULL); | 
|  | } | 
|  |  | 
|  | // piggyback on post-processing to calculate exp->last_event | 
|  | { | 
|  | hrtime_t exp_end_time = _exp_start_time + exp_duration; | 
|  | update_last_event (exp_end_time); | 
|  | } | 
|  |  | 
|  | if (missed_fi > 0) | 
|  | { | 
|  | StringBuilder sb; | 
|  | sb.sprintf ( | 
|  | GTXT ("*** Warning: %d frameinfo packets are missing from total of %d when resolving %s."), | 
|  | missed_fi, total_fi, dDscr->getName ()); | 
|  | warnq->append (new Emsg (CMSG_WARN, sb)); | 
|  | } | 
|  |  | 
|  | //    threadPool->wait_group(); | 
|  | //    delete threadPool; | 
|  | theApplication->set_progress (0, NTXT ("")); | 
|  | free (progress_bar_msg); | 
|  | if (!resolve_frinfo_pipelined && fp != NULL) | 
|  | { | 
|  | delete fp->ompstack; | 
|  | delete fp->jstack; | 
|  | delete fp->stack; | 
|  | delete fp; | 
|  | } | 
|  | delete frameInfoCache; | 
|  | frameInfoCache = NULL; | 
|  | delete nodeCache; | 
|  | nodeCache = NULL; | 
|  | } | 
|  |  | 
|  | void | 
|  | Experiment::post_process () | 
|  | { | 
|  | // update non_paused_time after final update to "last_event" | 
|  | if (resume_ts != MAX_TIME && last_event) | 
|  | { | 
|  | hrtime_t ts = last_event - exp_start_time; | 
|  | hrtime_t delta = ts - resume_ts; | 
|  | non_paused_time += delta; | 
|  | resume_ts = MAX_TIME; // collection is paused | 
|  | } | 
|  |  | 
|  | // GC: prune events outside of experiment duration, calculate GC duration, update indices | 
|  | int index; | 
|  | GCEvent * gcevent; | 
|  | gc_duration = ZERO_TIME; | 
|  | if (gcevents != NULL) | 
|  | { | 
|  | // delete events that finish before exp_start_time or start after last_event | 
|  | for (int ii = 0; ii < gcevents->size ();) | 
|  | { | 
|  | gcevent = gcevents->fetch (ii); | 
|  | if (gcevent->end - exp_start_time < 0 | 
|  | || last_event - gcevent->start < 0) | 
|  | delete gcevents->remove (ii); | 
|  | else | 
|  | ii++; | 
|  | } | 
|  | } | 
|  | Vec_loop (GCEvent*, gcevents, index, gcevent) | 
|  | { | 
|  | gcevent->id = index + 1; // renumber to account for any deleted events | 
|  | if (gcevent->start - exp_start_time < 0 || gcevent->start == ZERO_TIME) | 
|  | // truncate events that start before experiment start | 
|  | gcevent->start = exp_start_time; | 
|  | if (last_event - gcevent->end < 0) | 
|  | // truncate events that end after experiment end | 
|  | gcevent->end = last_event; | 
|  | gc_duration += gcevent->end - gcevent->start; | 
|  | } | 
|  | } | 
|  |  | 
|  | Experiment::Exp_status | 
|  | Experiment::find_expdir (char *path) | 
|  | { | 
|  | // This function checks that the experiment directory | 
|  | // is of the proper form, and accessible | 
|  | dbe_stat_t sbuf; | 
|  |  | 
|  | // Save the name | 
|  | expt_name = dbe_strdup (path); | 
|  |  | 
|  | // Check that the name ends in .er | 
|  | size_t i = strlen (path); | 
|  | if (i > 0 && path[i - 1] == '/') | 
|  | path[--i] = '\0'; | 
|  |  | 
|  | if (i < 4 || strcmp (&path[i - 3], NTXT (".er")) != 0) | 
|  | { | 
|  | Emsg *m = new Emsg (CMSG_FATAL, | 
|  | GTXT ("*** Error: not a valid experiment name")); | 
|  | errorq->append (m); | 
|  | status = FAILURE; | 
|  | return FAILURE; | 
|  | } | 
|  |  | 
|  | // Check if new directory structure (i.e., no pointer file) | 
|  | if (dbe_stat (path, &sbuf)) | 
|  | { | 
|  | Emsg *m = new Emsg (CMSG_FATAL, GTXT ("*** Error: experiment not found")); | 
|  | errorq->append (m); | 
|  | status = FAILURE; | 
|  | return FAILURE; | 
|  | } | 
|  | if (S_ISDIR (sbuf.st_mode) == 0) | 
|  | { | 
|  | // ignore pointer-file experiments | 
|  | Emsg *m = new Emsg (CMSG_FATAL, | 
|  | GTXT ("*** Error: experiment was recorded with an earlier version, and can not be read")); | 
|  | errorq->append (m); | 
|  | obsolete = 1; | 
|  | status = FAILURE; | 
|  | return FAILURE; | 
|  | } | 
|  | return SUCCESS; | 
|  | } | 
|  |  | 
|  | void | 
|  | Experiment::purge () | 
|  | { | 
|  | // This routine will purge all of the caches of releasable storage. | 
|  | for (int i = 0; i < dataDscrs->size (); ++i) | 
|  | { | 
|  | DataDescriptor *dataDscr = dataDscrs->fetch (i); | 
|  | if (dataDscr == NULL) | 
|  | continue; | 
|  | dataDscr->reset (); | 
|  | } | 
|  | delete cstack; | 
|  | delete cstackShowHide; | 
|  | cstack = CallStack::getInstance (this); | 
|  | cstackShowHide = CallStack::getInstance (this); | 
|  | } | 
|  |  | 
|  | void | 
|  | Experiment::resetShowHideStack () | 
|  | { | 
|  | delete cstackShowHide; | 
|  | cstackShowHide = CallStack::getInstance (this); | 
|  | } | 
|  |  | 
|  | #define GET_INT_VAL(v, s, len) \ | 
|  | for (v = len = 0; isdigit(*s); s++, len++) { v = v * 10 + (*s -'0'); } | 
|  |  | 
|  | static int | 
|  | dir_name_cmp (const void *a, const void *b) | 
|  | { | 
|  | char *s1 = *((char **) a); | 
|  | char *s2 = *((char **) b); | 
|  | while (*s1) | 
|  | { | 
|  | if (isdigit (*s1) && isdigit (*s2)) | 
|  | { | 
|  | int v1, v2, len1, len2; | 
|  | GET_INT_VAL (v1, s1, len1); | 
|  | GET_INT_VAL (v2, s2, len2); | 
|  | if (v1 != v2) | 
|  | return v1 - v2; | 
|  | if (len1 != len2) | 
|  | return len2 - len1; | 
|  | continue; | 
|  | } | 
|  | if (*s1 != *s2) | 
|  | break; | 
|  | s1++; | 
|  | s2++; | 
|  | } | 
|  | return *s1 - *s2; | 
|  | } | 
|  |  | 
|  | Vector<char*> * | 
|  | Experiment::get_descendants_names () | 
|  | { | 
|  | char *dir_name = get_expt_name (); | 
|  | if (dir_name == NULL) | 
|  | return NULL; | 
|  | DIR *exp_dir = opendir (dir_name); | 
|  | if (exp_dir == NULL) | 
|  | return NULL; | 
|  | Vector<char*> *exp_names = new Vector<char*>(); | 
|  | for (struct dirent *entry = readdir (exp_dir); entry; | 
|  | entry = readdir (exp_dir)) | 
|  | { | 
|  | if (entry->d_name[0] == '_' || strncmp (entry->d_name, "M_r", 3) == 0) | 
|  | { | 
|  | char *dpath = dbe_sprintf (NTXT ("%s/%s"), dir_name, entry->d_name); | 
|  | dbe_stat_t sbuf; | 
|  | if (dbe_stat (dpath, &sbuf) == 0 && S_ISDIR (sbuf.st_mode)) | 
|  | exp_names->append (dpath); | 
|  | else | 
|  | free (dpath); | 
|  | } | 
|  | } | 
|  | closedir (exp_dir); | 
|  | if (exp_names->size () == 0) | 
|  | { | 
|  | delete exp_names; | 
|  | return NULL; | 
|  | } | 
|  | exp_names->sort (dir_name_cmp); | 
|  | return exp_names; | 
|  | } | 
|  |  | 
|  | bool | 
|  | Experiment::create_dir (char *dname) | 
|  | { | 
|  | if (mkdir (dname, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) == 0) | 
|  | { | 
|  | return true; | 
|  | } | 
|  | dbe_stat_t sbuf; | 
|  | if (dbe_stat (dname, &sbuf) != 0 || S_ISDIR (sbuf.st_mode) == 0) | 
|  | { | 
|  | char *buf = dbe_sprintf (GTXT ("Unable to create directory `%s'\n"), | 
|  | dname); | 
|  | errorq->append (new Emsg (CMSG_ERROR, buf)); | 
|  | free (buf); | 
|  | return false; | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | char * | 
|  | Experiment::get_arch_name () | 
|  | { | 
|  | if (arch_name == NULL) | 
|  | { | 
|  | // Determine the master experiment directory. | 
|  | // omazur: should do it in a less hacky way. XXXX | 
|  | char *ptr = strstr_r (expt_name, DESCENDANT_EXPT_KEY); | 
|  | ptr = ptr ? ptr + 3 : expt_name + strlen (expt_name); | 
|  | arch_name = dbe_sprintf (NTXT ("%.*s/%s"), (int) (ptr - expt_name), | 
|  | expt_name, SP_ARCHIVES_DIR); | 
|  | } | 
|  | return arch_name; | 
|  | } | 
|  |  | 
|  | char * | 
|  | Experiment::get_fndr_arch_name () | 
|  | { | 
|  | if (fndr_arch_name == NULL) | 
|  | // Determine the founder experiment directory. | 
|  | fndr_arch_name = dbe_strdup (get_arch_name ()); | 
|  | return fndr_arch_name; | 
|  | } | 
|  |  | 
|  | enum | 
|  | { | 
|  | HASH_NAME_LEN     = 11    // (64 / 6 + 1) = 11 | 
|  | }; | 
|  |  | 
|  | static char * | 
|  | get_hash_string (char buf[HASH_NAME_LEN + 1], uint64_t hash) | 
|  | { | 
|  | static const char *har = | 
|  | "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-_"; | 
|  | for (int i = 0; i < HASH_NAME_LEN; i++) | 
|  | { | 
|  | buf[i] = har[hash & 0x3f]; | 
|  | hash = hash >> 6; | 
|  | } | 
|  | buf[HASH_NAME_LEN] = 0; | 
|  | return buf; | 
|  | } | 
|  |  | 
|  | char * | 
|  | Experiment::getNameInArchive (const char *fname, bool archiveFile) | 
|  | { | 
|  | char *aname = get_archived_name (fname, archiveFile); | 
|  | char *ret = dbe_sprintf (NTXT ("%s/%s"), get_arch_name (), aname); | 
|  | free (aname); | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | #define MAX_ARCHIVE_FILENAME_LEN    (256 - HASH_NAME_LEN - 2) | 
|  |  | 
|  | char * | 
|  | Experiment::get_archived_name (const char *fname, bool archiveFile) | 
|  | { | 
|  | char *bname = get_basename (fname); | 
|  |  | 
|  | // dirname_hash: | 
|  | char dirnameHash[HASH_NAME_LEN + 1]; | 
|  | // Treat "a.out" and "./a.out" equally | 
|  | uint64_t hash = bname != fname ? crc64 (fname, bname - fname) | 
|  | : crc64 (NTXT ("./"), 2); | 
|  | get_hash_string (dirnameHash, hash); | 
|  |  | 
|  | char *ret; | 
|  | long bname_len = dbe_sstrlen (bname); | 
|  | if (bname_len > MAX_ARCHIVE_FILENAME_LEN) | 
|  | { | 
|  | char basenameHash[HASH_NAME_LEN + 1]; | 
|  | hash = crc64 (bname, bname_len); | 
|  | get_hash_string (basenameHash, hash); | 
|  | ret = dbe_sprintf ("%.*s%c%s_%s", | 
|  | MAX_ARCHIVE_FILENAME_LEN - HASH_NAME_LEN - 1, | 
|  | bname, archiveFile ? '.' : '_', | 
|  | dirnameHash, basenameHash); | 
|  | } | 
|  | else | 
|  | ret = dbe_sprintf ("%s%c%s", bname, archiveFile ? '.' : '_', dirnameHash); | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | char * | 
|  | Experiment::checkFileInArchive (const char *fname, bool archiveFile) | 
|  | { | 
|  | if (archiveMap) | 
|  | { | 
|  | char *aname = get_archived_name (fname, archiveFile); | 
|  | DbeFile *df = archiveMap->get (aname); | 
|  | free (aname); | 
|  | if (df) | 
|  | return xstrdup (df->get_location ()); | 
|  | return NULL; | 
|  | } | 
|  | if (founder_exp) | 
|  | return founder_exp->checkFileInArchive (fname, archiveFile); | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  |  | 
|  | // Comparing SegMem | 
|  |  | 
|  | static int | 
|  | SegMemCmp (const void *a, const void *b) | 
|  | { | 
|  | SegMem *item1 = *((SegMem **) a); | 
|  | SegMem *item2 = *((SegMem **) b); | 
|  | return item1->unload_time > item2->unload_time ? 1 : | 
|  | item1->unload_time == item2->unload_time ? 0 : -1; | 
|  | } | 
|  |  | 
|  | SegMem* | 
|  | Experiment::update_ts_in_maps (Vaddr addr, hrtime_t ts) | 
|  | { | 
|  | Vector<void *> *segMems = maps->values (); | 
|  | if (segMems && !segMems->is_sorted ()) | 
|  | { | 
|  | Dprintf (DEBUG_MAPS, NTXT ("update_ts_in_maps: segMems.size=%lld\n"), (long long) segMems->size ()); | 
|  | segMems->sort (SegMemCmp); | 
|  | } | 
|  | for (int i = 0, sz = segMems ? segMems->size () : 0; i < sz; i++) | 
|  | { | 
|  | SegMem *sm = (SegMem *) segMems->fetch (i); | 
|  | if (ts < sm->unload_time) | 
|  | { | 
|  | for (; i < sz; i++) | 
|  | { | 
|  | sm = (SegMem *) segMems->fetch (i); | 
|  | if ((addr >= sm->base) && (addr < sm->base + sm->size)) | 
|  | { | 
|  | Dprintf (DEBUG_MAPS, | 
|  | "update_ts_in_maps: old:%u.%09u -> %u.%09u addr=0x%08llx size=%lld\n", | 
|  | (unsigned) (sm->load_time / NANOSEC), | 
|  | (unsigned) (sm->load_time % NANOSEC), | 
|  | (unsigned) (ts / NANOSEC), (unsigned) (ts % NANOSEC), | 
|  | (unsigned long long) sm->base, (long long) sm->size); | 
|  | maps->remove (sm->base, sm->load_time); | 
|  | sm->load_time = ts; | 
|  | maps->insert (sm->base, ts, sm); | 
|  | return sm; | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  | Dprintf (DEBUG_MAPS, "update_ts_in_maps: NOT FOUND %u.%09u addr=0x%08llx\n", | 
|  | (unsigned) (ts / NANOSEC), (unsigned) (ts % NANOSEC), | 
|  | (unsigned long long) addr); | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | DbeInstr* | 
|  | Experiment::map_Vaddr_to_PC (Vaddr addr, hrtime_t ts) | 
|  | { | 
|  | // Look up in the hash table first | 
|  | int hash = (((int) addr) >> 8) & (HTableSize - 1); | 
|  | SegMem *si = smemHTable[hash]; | 
|  | if (si == NULL || addr < si->base || addr >= si->base + si->size | 
|  | || ts < si->load_time || ts >= si->unload_time) | 
|  | { | 
|  | // Not in the hash table | 
|  | si = (SegMem*) maps->locate (addr, ts); | 
|  | if (si == NULL || addr < si->base || addr >= si->base + si->size | 
|  | || ts < si->load_time || ts >= si->unload_time) | 
|  | { | 
|  | si = update_ts_in_maps (addr, ts); | 
|  | if (si == NULL) | 
|  | return dbeSession->get_Unknown_Function ()->find_dbeinstr (PCInvlFlag, addr); | 
|  | } | 
|  | smemHTable[hash] = si; | 
|  | } | 
|  |  | 
|  | // Calculate the file offset of 'addr' | 
|  | uint64_t f_offset = si->get_file_offset () + (addr - si->base); | 
|  |  | 
|  | DbeInstr *instr; | 
|  | if (si->obj->get_type () == Histable::LOADOBJECT) | 
|  | { | 
|  | LoadObject *lo = (LoadObject*) si->obj; | 
|  | lo->sync_read_stabs (); | 
|  | instr = lo->find_dbeinstr (f_offset); | 
|  | } | 
|  | else | 
|  | { | 
|  | int hash2 = ((((int) addr) & 0xFFFC00) | (((int) f_offset) >> 2)) | 
|  | & (HTableSize - 1); | 
|  | instr = instHTable[hash2]; | 
|  | if (instr == NULL || instr->func != si->obj || instr->addr != f_offset) | 
|  | { | 
|  | // Not in the hash table | 
|  | Function *fp = (Function *) si->obj; | 
|  | instr = fp->find_dbeinstr (0, f_offset); | 
|  | instHTable[hash2] = instr; | 
|  | } | 
|  | } | 
|  | if (!instr->func->isUsed) | 
|  | { | 
|  | instr->func->isUsed = true; | 
|  | instr->func->module->isUsed = true; | 
|  | instr->func->module->loadobject->isUsed = true; | 
|  | } | 
|  | return instr; | 
|  | } | 
|  |  | 
|  | Sample * | 
|  | Experiment::map_event_to_Sample (hrtime_t ts) | 
|  | { | 
|  | Sample *sample; | 
|  | int index; | 
|  |  | 
|  | // Check if the last used sample is the right one, | 
|  | // if not then find it. | 
|  | if (sample_last_used && ts >= sample_last_used->start_time | 
|  | && ts <= sample_last_used->end_time) | 
|  | return sample_last_used; | 
|  |  | 
|  | Vec_loop (Sample*, samples, index, sample) | 
|  | { | 
|  | if ((ts >= sample->start_time) && | 
|  | (ts <= sample->end_time)) | 
|  | { | 
|  | sample_last_used = sample; | 
|  | return sample; | 
|  | } | 
|  | } | 
|  | return (Sample*) NULL; | 
|  | } | 
|  |  | 
|  | GCEvent * | 
|  | Experiment::map_event_to_GCEvent (hrtime_t ts) | 
|  | { | 
|  | GCEvent *gcevent; | 
|  | int index; | 
|  |  | 
|  | // Check if the last used sample is the right one, | 
|  | // if not then find it. | 
|  | if (gcevent_last_used && ts >= gcevent_last_used->start | 
|  | && ts <= gcevent_last_used->end) | 
|  | return gcevent_last_used; | 
|  | Vec_loop (GCEvent*, gcevents, index, gcevent) | 
|  | { | 
|  | if ((ts >= gcevent->start) && | 
|  | (ts <= gcevent->end)) | 
|  | { | 
|  | gcevent_last_used = gcevent; | 
|  | return gcevent; | 
|  | } | 
|  | } | 
|  | return (GCEvent*) NULL; | 
|  | } | 
|  |  | 
|  | DbeInstr* | 
|  | Experiment::map_jmid_to_PC (Vaddr mid, int bci, hrtime_t ts) | 
|  | { | 
|  | if (mid == 0 || jmaps == NULL) | 
|  | // special case: no Java stack was recorded, bci - error code | 
|  | return dbeSession->get_JUnknown_Function ()->find_dbeinstr (0, bci); | 
|  |  | 
|  | JMethod *jmthd = jmidHTable->get (mid); | 
|  | if (jmthd == NULL) | 
|  | { | 
|  | jmthd = (JMethod *) jmaps->locate_exact_match (mid, ts); | 
|  | if (jmthd) | 
|  | jmidHTable->put (mid, jmthd); | 
|  | } | 
|  | if (jmthd == NULL || jmthd->get_type () != Histable::FUNCTION) | 
|  | return dbeSession->get_JUnknown_Function ()->find_dbeinstr (0, (uint64_t) mid); | 
|  | return jmthd->find_dbeinstr (0, bci); | 
|  | } | 
|  |  | 
|  | Emsg * | 
|  | Experiment::fetch_comments () | 
|  | { | 
|  | return commentq->fetch (); | 
|  | } | 
|  |  | 
|  | Emsg * | 
|  | Experiment::fetch_runlogq () | 
|  | { | 
|  | return runlogq->fetch (); | 
|  | } | 
|  |  | 
|  | Emsg * | 
|  | Experiment::fetch_errors () | 
|  | { | 
|  | return errorq->fetch (); | 
|  | } | 
|  |  | 
|  | Emsg * | 
|  | Experiment::fetch_warnings () | 
|  | { | 
|  | return warnq->fetch (); | 
|  | } | 
|  |  | 
|  | Emsg * | 
|  | Experiment::fetch_notes () | 
|  | { | 
|  | return notesq->fetch (); | 
|  | } | 
|  |  | 
|  | Emsg * | 
|  | Experiment::fetch_ifreq () | 
|  | { | 
|  | return ifreqq->fetch (); | 
|  | } | 
|  |  | 
|  | Emsg * | 
|  | Experiment::fetch_pprocq () | 
|  | { | 
|  | return pprocq->fetch (); | 
|  | } | 
|  |  | 
|  | int | 
|  | Experiment::read_dyntext_file () | 
|  | { | 
|  | dyntext_name = dbe_sprintf ("%s/%s", expt_name, SP_DYNTEXT_FILE); | 
|  | Data_window *dwin = new Data_window (dyntext_name); | 
|  | if (dwin->not_opened ()) | 
|  | { | 
|  | delete dwin; | 
|  | return 1; | 
|  | } | 
|  | dwin->need_swap_endian = need_swap_endian; | 
|  |  | 
|  | Function *fp = NULL; | 
|  | char *progress_msg = NULL; // Message for the progress bar | 
|  | for (int64_t offset = 0;;) | 
|  | { | 
|  | DT_common *cpckt = (DT_common *) dwin->bind (offset, sizeof (DT_common)); | 
|  | if (cpckt == NULL) | 
|  | break; | 
|  | size_t cpcktsize = dwin->decode (cpckt->size); | 
|  | cpckt = (DT_common *) dwin->bind (offset, cpcktsize); | 
|  | if (cpckt == NULL) | 
|  | break; | 
|  | switch (dwin->decode (cpckt->type)) | 
|  | { | 
|  | case DT_HEADER: | 
|  | { | 
|  | DT_header *hdr = (DT_header*) cpckt; | 
|  | hrtime_t ts = dwin->decode (hdr->time) + exp_start_time; | 
|  | SegMem *si = (SegMem*) maps->locate (dwin->decode (hdr->vaddr), ts); | 
|  | fp = si ? (Function *) si->obj : NULL; | 
|  | if (fp && (fp->get_type () != Histable::FUNCTION | 
|  | || !(fp->flags & FUNC_FLAG_DYNAMIC))) | 
|  | fp = NULL; | 
|  | break; | 
|  | } | 
|  | case DT_CODE: | 
|  | if (fp) | 
|  | { | 
|  | fp->img_fname = dyntext_name; | 
|  | fp->img_offset = offset + sizeof (DT_common); | 
|  | if ((platform != Intel) && (platform != Amd64)) | 
|  | { //ARCH(SPARC) | 
|  | // Find out 'save' instruction address for SPARC | 
|  | char *ptr = ((char*) cpckt) + sizeof (DT_common); | 
|  | size_t img_size = cpcktsize - sizeof (DT_common); | 
|  | for (size_t i = 0; i < img_size; i += 4) | 
|  | if (ptr[i] == (char) 0x9d && ptr[i + 1] == (char) 0xe3) | 
|  | { | 
|  | fp->save_addr = i; | 
|  | break; | 
|  | } | 
|  | } | 
|  | } | 
|  | break; | 
|  | case DT_SRCFILE: | 
|  | if (fp) | 
|  | { | 
|  | char *srcname = dbe_strndup (((char*) cpckt) + sizeof (DT_common), | 
|  | cpcktsize - sizeof (DT_common)); | 
|  | LoadObject *ds = fp->module ? fp->module->loadobject : NULL; | 
|  | assert (ds != NULL); | 
|  | Module *mod = dbeSession->createModule (ds, NULL); | 
|  | mod->set_file_name (srcname); | 
|  | //} | 
|  | if (fp->module) | 
|  | { | 
|  | // It's most likely (unknown). Remove fp from it. | 
|  | long idx = fp->module->functions->find (fp); | 
|  | if (idx >= 0) | 
|  | fp->module->functions->remove (idx); | 
|  | } | 
|  | fp->module = mod; | 
|  | mod->functions->append (fp); | 
|  | } | 
|  | break; | 
|  | case DT_LTABLE: | 
|  | if (fp) | 
|  | { | 
|  | DT_lineno *ltab = (DT_lineno*) ((char*) cpckt + sizeof (DT_common)); | 
|  | size_t sz = (cpcktsize - sizeof (DT_common)) / sizeof (DT_lineno); | 
|  | if (sz <= 0) | 
|  | break; | 
|  | // Take care of the progress bar | 
|  | static int percent = 0; | 
|  | static long deltaReport = sz / 100; // 1000; | 
|  | static long nextReport = 0; | 
|  | static long progress_count = 0; | 
|  | fp->pushSrcFile (fp->getDefSrc (), 0); | 
|  | for (size_t i = 0; i < sz; i++) | 
|  | { | 
|  | int lineno = dwin->decode (ltab[i].lineno); | 
|  | if (fp->usrfunc != NULL) | 
|  | { | 
|  | // Update progress bar | 
|  | if (dbeSession->is_interactive ()) | 
|  | { | 
|  | if (progress_count == nextReport) | 
|  | { | 
|  | if (percent < 99) | 
|  | { | 
|  | percent++; | 
|  | if (NULL == progress_msg) | 
|  | { | 
|  | progress_msg = dbe_sprintf (GTXT ("Processing Dynamic Text: %s"), | 
|  | get_basename (expt_name)); | 
|  | } | 
|  | theApplication->set_progress (percent, progress_msg); | 
|  | nextReport += deltaReport; | 
|  | } | 
|  | } | 
|  | progress_count++; | 
|  | } | 
|  | DbeLine *dbeline = fp->usrfunc->mapPCtoLine (lineno, NULL); | 
|  | lineno = dbeline != NULL ? dbeline->lineno : -1; | 
|  | } | 
|  | fp->add_PC_info (dwin->decode (ltab[i].offset), lineno); | 
|  | } | 
|  | fp->popSrcFile (); | 
|  | } | 
|  | break; | 
|  | default: | 
|  | // skip unknown records | 
|  | break; | 
|  | } | 
|  | offset += cpcktsize; | 
|  | } | 
|  | free (progress_msg); | 
|  | delete dwin; | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | uint32_t | 
|  | Experiment::mapTagValue (Prop_type prop, uint64_t value) | 
|  | { | 
|  | Vector<Histable*> *objs = tagObjs->fetch (prop); | 
|  | int lt = 0; | 
|  | int rt = objs->size () - 1; | 
|  | while (lt <= rt) | 
|  | { | 
|  | int md = (lt + rt) / 2; | 
|  | Other *obj = (Other*) objs->fetch (md); | 
|  | if (obj->value64 < value) | 
|  | lt = md + 1; | 
|  | else if (obj->value64 > value) | 
|  | rt = md - 1; | 
|  | else | 
|  | return obj->tag; | 
|  | } | 
|  |  | 
|  | uint32_t tag; | 
|  | if (sparse_threads && (prop == PROP_THRID || prop == PROP_LWPID)) | 
|  | tag = objs->size () + 1; // "+ 1" related to 7038295 | 
|  | else | 
|  | tag = (int) value; // truncation; See 6788767 | 
|  |  | 
|  | Other *obj = new Other (); | 
|  | obj->value64 = value; | 
|  | obj->tag = tag; | 
|  | if (lt == objs->size ()) | 
|  | objs->append (obj); | 
|  | else | 
|  | objs->insert (lt, obj); | 
|  |  | 
|  | // Update min and max tags | 
|  | if (prop == PROP_LWPID) | 
|  | { | 
|  | if ((uint64_t) tag < min_lwp) | 
|  | min_lwp = (uint64_t) tag; | 
|  | if ((uint64_t) tag > max_lwp) | 
|  | max_lwp = (uint64_t) tag; | 
|  | lwp_cnt++; | 
|  | } | 
|  | else if (prop == PROP_THRID) | 
|  | { | 
|  | if ((uint64_t) tag < min_thread) | 
|  | min_thread = (uint64_t) tag; | 
|  | if ((uint64_t) tag > max_thread) | 
|  | max_thread = (uint64_t) tag; | 
|  | thread_cnt++; | 
|  | } | 
|  | else if (prop == PROP_CPUID) | 
|  | { | 
|  | // On Solaris 8, we don't get CPU id -- don't change | 
|  | if (value != (uint64_t) - 1) | 
|  | {//YXXX is this related only to solaris 8? | 
|  | if ((uint64_t) tag < min_cpu) | 
|  | min_cpu = (uint64_t) tag; | 
|  | if ((uint64_t) tag > max_cpu) | 
|  | max_cpu = (uint64_t) tag; | 
|  | } | 
|  | cpu_cnt++; | 
|  | } | 
|  | return obj->tag; | 
|  | } | 
|  |  | 
|  | Vector<Histable*> * | 
|  | Experiment::getTagObjs (Prop_type prop) | 
|  | { | 
|  | return tagObjs->fetch (prop); | 
|  | } | 
|  |  | 
|  | Histable * | 
|  | Experiment::getTagObj (Prop_type prop, uint32_t tag) | 
|  | { | 
|  | Vector<Histable*> *objs = tagObjs->fetch (prop); | 
|  | if (objs == NULL) | 
|  | return NULL; | 
|  | for (int i = 0; i < objs->size (); i++) | 
|  | { | 
|  | Other *obj = (Other*) objs->fetch (i); | 
|  | if (obj->tag == tag) | 
|  | return obj; | 
|  | } | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | JThread * | 
|  | Experiment::map_pckt_to_Jthread (uint32_t tid, hrtime_t tstamp) | 
|  | { | 
|  | if (!has_java) | 
|  | return JTHREAD_DEFAULT; | 
|  | int lt = 0; | 
|  | int rt = jthreads_idx->size () - 1; | 
|  | while (lt <= rt) | 
|  | { | 
|  | int md = (lt + rt) / 2; | 
|  | JThread *jthread = jthreads_idx->fetch (md); | 
|  | if (jthread->tid < tid) | 
|  | lt = md + 1; | 
|  | else if (jthread->tid > tid) | 
|  | rt = md - 1; | 
|  | else | 
|  | { | 
|  | for (; jthread; jthread = jthread->next) | 
|  | if (tstamp >= jthread->start && tstamp < jthread->end) | 
|  | return jthread; | 
|  | break; | 
|  | } | 
|  | } | 
|  |  | 
|  | return JTHREAD_NONE; | 
|  | } | 
|  |  | 
|  | JThread* | 
|  | Experiment::get_jthread (uint32_t tid) | 
|  | { | 
|  | if (!has_java) | 
|  | return JTHREAD_DEFAULT; | 
|  | int lt = 0; | 
|  | int rt = jthreads_idx->size () - 1; | 
|  | while (lt <= rt) | 
|  | { | 
|  | int md = (lt + rt) / 2; | 
|  | JThread *jthread = jthreads_idx->fetch (md); | 
|  | if (jthread->tid < tid) | 
|  | lt = md + 1; | 
|  | else if (jthread->tid > tid) | 
|  | rt = md - 1; | 
|  | else | 
|  | { | 
|  | JThread *jthread_first = jthread; | 
|  | while ((jthread = jthread->next) != NULL) | 
|  | if (!jthread->is_system () && | 
|  | jthread->jthr_id < jthread_first->jthr_id) | 
|  | jthread_first = jthread; | 
|  | return jthread_first; | 
|  | } | 
|  | } | 
|  |  | 
|  | return JTHREAD_NONE; | 
|  | } | 
|  |  | 
|  | // SS12 experiment | 
|  | DataDescriptor * | 
|  | Experiment::newDataDescriptor (int data_id, int flags, | 
|  | DataDescriptor *master_dDscr) | 
|  | { | 
|  | DataDescriptor *dataDscr = NULL; | 
|  | if (data_id >= 0 && data_id < dataDscrs->size ()) | 
|  | { | 
|  | dataDscr = dataDscrs->fetch (data_id); | 
|  | if (dataDscr != NULL) | 
|  | return dataDscr; | 
|  | } | 
|  |  | 
|  | assert (data_id >= 0 && data_id < DATA_LAST); | 
|  | const char *nm = get_prof_data_type_name (data_id); | 
|  | const char *uname = get_prof_data_type_uname (data_id); | 
|  |  | 
|  | if (master_dDscr) | 
|  | dataDscr = new DataDescriptor (data_id, nm, uname, master_dDscr); | 
|  | else | 
|  | dataDscr = new DataDescriptor (data_id, nm, uname, flags); | 
|  | dataDscrs->store (data_id, dataDscr); | 
|  | return dataDscr; | 
|  | } | 
|  |  | 
|  | Vector<DataDescriptor*> * | 
|  | Experiment::getDataDescriptors () | 
|  | { | 
|  | Vector<DataDescriptor*> *result = new Vector<DataDescriptor*>; | 
|  | for (int i = 0; i < dataDscrs->size (); ++i) | 
|  | { | 
|  | DataDescriptor *dd; | 
|  | dd = get_raw_events (i); // force data fetch | 
|  | if (dd != NULL) | 
|  | result->append (dd); | 
|  | } | 
|  | return result; | 
|  | } | 
|  |  | 
|  | DataDescriptor * | 
|  | Experiment::getDataDescriptor (int data_id) | 
|  | { | 
|  | if (data_id < 0 || data_id >= dataDscrs->size ()) | 
|  | return NULL; | 
|  | return dataDscrs->fetch (data_id); | 
|  | } | 
|  |  | 
|  | PacketDescriptor * | 
|  | Experiment::newPacketDescriptor (int kind, DataDescriptor *dDscr) | 
|  | { | 
|  | PacketDescriptor *pDscr = new PacketDescriptor (dDscr); | 
|  | pcktDscrs->store (kind, pDscr); | 
|  | return pDscr; | 
|  | } | 
|  |  | 
|  | PacketDescriptor * | 
|  | Experiment::getPacketDescriptor (int kind) | 
|  | { | 
|  | if (kind < 0 || kind >= pcktDscrs->size ()) | 
|  | return NULL; | 
|  | return pcktDscrs->fetch (kind); | 
|  | } | 
|  |  | 
|  | void | 
|  | Experiment::set_clock (int clk) | 
|  | { | 
|  | if (clk > 0) | 
|  | { | 
|  | if (maxclock < clk) | 
|  | { | 
|  | maxclock = clk; | 
|  | clock = maxclock; | 
|  | } | 
|  | if (minclock == 0 || minclock > clk) | 
|  | minclock = clk; | 
|  | } | 
|  | } | 
|  |  | 
|  | bool | 
|  | JThread::is_system () | 
|  | { | 
|  | if (group_name == NULL) | 
|  | return false; | 
|  | return strcmp (group_name, NTXT ("system")) == 0; | 
|  | } | 
|  |  | 
|  | void | 
|  | Experiment::dump_stacks (FILE *outfile) | 
|  | { | 
|  | cstack->print (outfile); | 
|  | } | 
|  |  | 
|  | void | 
|  | Experiment::dump_map (FILE *outfile) | 
|  | { | 
|  | int index; | 
|  | SegMem *s; | 
|  | fprintf (outfile, GTXT ("Experiment %s\n"), get_expt_name ()); | 
|  | fprintf (outfile, GTXT ("Address         Size (hex)              Load time     Unload time    Checksum  Name\n")); | 
|  | Vec_loop (SegMem*, seg_items, index, s) | 
|  | { | 
|  | timestruc_t load; | 
|  | timestruc_t unload; | 
|  | hr2timestruc (&load, (s->load_time - exp_start_time)); | 
|  | if (load.tv_nsec < 0) | 
|  | { | 
|  | load.tv_sec--; | 
|  | load.tv_nsec += NANOSEC; | 
|  | } | 
|  | if (s->unload_time == MAX_TIME) | 
|  | { | 
|  | unload.tv_sec = 0; | 
|  | unload.tv_nsec = 0; | 
|  | } | 
|  | else | 
|  | hr2timestruc (&unload, (s->unload_time - exp_start_time)); | 
|  | if (load.tv_nsec < 0) | 
|  | { | 
|  | load.tv_sec--; | 
|  | load.tv_nsec += NANOSEC; | 
|  | } | 
|  | fprintf (outfile, | 
|  | "0x%08llx  %8lld (0x%08llx) %5lld.%09lld %5lld.%09lld  \"%s\"\n", | 
|  | (long long) s->base, (long long) s->size, (long long) s->size, | 
|  | (long long) load.tv_sec, (long long) load.tv_nsec, | 
|  | (long long) unload.tv_sec, (long long) unload.tv_nsec, | 
|  | s->obj->get_name ()); | 
|  | } | 
|  | fprintf (outfile, NTXT ("\n")); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Copy file to archive | 
|  | * @param name | 
|  | * @param aname | 
|  | * @param hide_msg | 
|  | * @return 0 - success, 1 - error | 
|  | */ | 
|  | int | 
|  | Experiment::copy_file_to_archive (const char *name, const char *aname, int hide_msg) | 
|  | { | 
|  | errno = 0; | 
|  | int fd_w = ::open64 (aname, O_WRONLY | O_CREAT | O_EXCL, 0644); | 
|  | if (fd_w == -1) | 
|  | { | 
|  | if (errno == EEXIST) | 
|  | return 0; | 
|  | fprintf (stderr, GTXT ("gprofng-archive: unable to copy `%s': %s\n"), | 
|  | name, STR (strerror (errno))); | 
|  | return 1; | 
|  | } | 
|  |  | 
|  | if (dbe_stat_file (name, NULL) != 0) | 
|  | { | 
|  | fprintf (stderr, GTXT ("gprofng-archive: cannot access file `%s': %s\n"), | 
|  | name, STR (strerror (errno))); | 
|  | close (fd_w); | 
|  | return 1; | 
|  | } | 
|  |  | 
|  | int fd_r = ::open64 (name, O_RDONLY); | 
|  | if (fd_r == -1) | 
|  | { | 
|  | fprintf (stderr, GTXT ("gprofng-archive: unable to open `%s': %s\n"), | 
|  | name, strerror (errno)); | 
|  | close (fd_w); | 
|  | unlink (aname); | 
|  | return 1; | 
|  | } | 
|  |  | 
|  | if (!hide_msg) | 
|  | fprintf (stderr, GTXT ("Copying `%s'  to `%s'\n"), name, aname); | 
|  | bool do_unlink = false; | 
|  | for (;;) | 
|  | { | 
|  | unsigned char buf[65536]; | 
|  | int n, n1; | 
|  | n = (int) read (fd_r, (void *) buf, sizeof (buf)); | 
|  | if (n <= 0) | 
|  | break; | 
|  | n1 = (int) write (fd_w, buf, n); | 
|  | if (n != n1) | 
|  | { | 
|  | fprintf (stderr, GTXT ("gprofng-archive: unable to write %d bytes to `%s': %s\n"), | 
|  | n, aname, STR (strerror (errno))); | 
|  | do_unlink = true; | 
|  | break; | 
|  | } | 
|  | } | 
|  | close (fd_w); | 
|  |  | 
|  | dbe_stat_t s_buf; | 
|  | if (fstat64 (fd_r, &s_buf) == 0) | 
|  | { | 
|  | struct utimbuf u_buf; | 
|  | u_buf.actime = s_buf.st_atime; | 
|  | u_buf.modtime = s_buf.st_mtime; | 
|  | utime (aname, &u_buf); | 
|  | } | 
|  | close (fd_r); | 
|  | if (do_unlink) | 
|  | { | 
|  | if (!hide_msg) | 
|  | fprintf (stderr, GTXT ("gprofng-archive: remove %s\n"), aname); | 
|  | unlink (aname); | 
|  | return 1; | 
|  | } | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Copy file to common archive | 
|  | * Algorithm: | 
|  | * Calculate checksum | 
|  | * Generate file name to be created in common archive | 
|  | * Check if it is not in common archive yet | 
|  | * Copy file to the common archive directory if it is not there yet | 
|  | * Create symbolic link: "aname" -> "caname", where "caname" is the name in common archive | 
|  | * @param name - original file name | 
|  | * @param aname - file name in experiment archive | 
|  | * @param common_archive - common archive directory | 
|  | * @return 0 - success, 1 - error | 
|  | */ | 
|  | int | 
|  | Experiment::copy_file_to_common_archive (const char *name, const char *aname, | 
|  | int hide_msg, | 
|  | const char *common_archive, | 
|  | int relative_path) | 
|  | { | 
|  | if (!name || !aname || !common_archive) | 
|  | { | 
|  | if (!name) | 
|  | fprintf (stderr, GTXT ("gprofng-archive: Internal error: file name is NULL\n")); | 
|  | if (!aname) | 
|  | fprintf (stderr, GTXT ("gprofng-archive: Internal error: file name in archive is NULL\n")); | 
|  | if (!common_archive) | 
|  | fprintf (stderr, GTXT ("gprofng-archive: Internal error: path to common archive is NULL\n")); | 
|  | return 1; | 
|  | } | 
|  | // Check if file is already archived | 
|  | if (dbe_stat (aname, NULL) == 0) | 
|  | return 0; // File is already archived | 
|  | // Generate full path to common archive directory | 
|  | char *cad = NULL; | 
|  | char *abs_aname = NULL; | 
|  | if ((common_archive[0] != '/') || (aname[0] != '/')) | 
|  | { | 
|  | long size = pathconf (NTXT ("."), _PC_PATH_MAX); | 
|  | if (size < 0) | 
|  | { | 
|  | fprintf (stderr, GTXT ("gprofng-archive: Fatal error: pathconf(\".\", _PC_PATH_MAX) failed\n")); | 
|  | return 1; | 
|  | } | 
|  | char *buf = (char *) xmalloc ((size_t) size); | 
|  | char *ptr = getcwd (buf, (size_t) size); | 
|  | if (ptr == NULL) | 
|  | { | 
|  | fprintf (stderr, GTXT ("gprofng-archive: Fatal error: cannot determine current directory\n")); | 
|  | free (buf); | 
|  | return 1; | 
|  | } | 
|  | if (common_archive[0] != '/') | 
|  | cad = dbe_sprintf (NTXT ("%s/%s"), ptr, common_archive); | 
|  | else | 
|  | cad = dbe_strdup (common_archive); | 
|  | if (aname[0] != '/') | 
|  | abs_aname = dbe_sprintf (NTXT ("%s/%s"), ptr, aname); | 
|  | else | 
|  | abs_aname = dbe_strdup (aname); | 
|  | free (buf); | 
|  | } | 
|  | else | 
|  | { | 
|  | cad = dbe_strdup (common_archive); | 
|  | abs_aname = dbe_strdup (aname); | 
|  | } | 
|  | // Calculate checksum | 
|  | char * errmsg = NULL; | 
|  | uint32_t crcval = get_cksum (name, &errmsg); | 
|  | if (0 == crcval) | 
|  | { // error | 
|  | free (cad); | 
|  | free (abs_aname); | 
|  | if (NULL != errmsg) | 
|  | { | 
|  | fprintf (stderr, GTXT ("gprofng-archive: Fatal error: %s\n"), errmsg); | 
|  | free (errmsg); | 
|  | return 1; | 
|  | } | 
|  | fprintf (stderr, | 
|  | GTXT ("gprofng-archive: Fatal error: get_cksum(%s) returned %d\n"), | 
|  | name, crcval); | 
|  | return 1; | 
|  | } | 
|  | // Generate file name to be created in common archive | 
|  | char *fname = get_basename (name); | 
|  | char *abs_caname = dbe_sprintf (NTXT ("%s/%u_%s"), cad, crcval, fname); | 
|  | if (abs_caname == NULL) | 
|  | { | 
|  | free (cad); | 
|  | free (abs_aname); | 
|  | fprintf (stderr, | 
|  | GTXT ("gprofng-archive: Fatal error: unable to allocate memory\n")); | 
|  | return 1; | 
|  | } | 
|  | // Check if full name is not too long | 
|  | long len = dbe_sstrlen (abs_caname); | 
|  | long max = pathconf (cad, _PC_PATH_MAX); | 
|  | if ((max < 0) || (len <= 0)) | 
|  | { // unknown error | 
|  | fprintf (stderr, GTXT ("gprofng-archive: Fatal error: pathconf(%s, _PC_PATH_MAX) failed\n"), | 
|  | cad); | 
|  | free (abs_caname); | 
|  | free (cad); | 
|  | free (abs_aname); | 
|  | return 1; | 
|  | } | 
|  | if (len >= max) | 
|  | { | 
|  | // Try to truncate the name | 
|  | if ((len - max) <= dbe_sstrlen (fname)) | 
|  | { | 
|  | // Yes, we can do it | 
|  | abs_caname[max - 1] = 0; | 
|  | if (!hide_msg) | 
|  | fprintf (stderr, GTXT ("gprofng-archive: file path is too long - truncated:%s\n"), | 
|  | abs_caname); | 
|  | } | 
|  | } | 
|  | // Check if file name is not too long | 
|  | char *cafname = get_basename (abs_caname); | 
|  | len = dbe_sstrlen (cafname); | 
|  | max = pathconf (cad, _PC_NAME_MAX); | 
|  | if ((max < 0) || (len <= 0)) | 
|  | { // unknown error | 
|  | fprintf (stderr, GTXT ("gprofng-archive: Fatal error: pathconf(%s, _PC_NAME_MAX) failed\n"), | 
|  | cad); | 
|  | free (abs_caname); | 
|  | free (cad); | 
|  | free (abs_aname); | 
|  | return 1; | 
|  | } | 
|  | if (len >= max) | 
|  | { | 
|  | // Try to truncate the name | 
|  | if ((len - max) <= dbe_sstrlen (fname)) | 
|  | { | 
|  | // Yes, we can do it | 
|  | cafname[max - 1] = 0; | 
|  | if (!hide_msg) | 
|  | fprintf (stderr, GTXT ("gprofng-archive: file name is too long - truncated:%s\n"), | 
|  | abs_caname); | 
|  | } | 
|  | } | 
|  | // Copy file to the common archive directory if it is not there yet | 
|  | int res = 0; | 
|  | if (dbe_stat_file (abs_caname, NULL) != 0) | 
|  | { | 
|  | // Use temporary file to avoid synchronization problems | 
|  | char *t = dbe_sprintf ("%s/archive_%llx", cad, (unsigned long long) gethrtime()); | 
|  | free (cad); | 
|  | // Copy file to temporary file | 
|  | res = copy_file_to_archive (name, t, hide_msg); // hide messages | 
|  | if (res != 0) | 
|  | { | 
|  | fprintf (stderr, GTXT ("gprofng-archive: Fatal error: cannot copy file %s to temporary file: %s\n"), | 
|  | name, t); | 
|  | unlink (t); | 
|  | free (t); | 
|  | free (abs_caname); | 
|  | free (abs_aname); | 
|  | return 1; | 
|  | } | 
|  | // Set read-only permissions | 
|  | dbe_stat_t statbuf; | 
|  | if (0 == dbe_stat_file (name, &statbuf)) | 
|  | { | 
|  | mode_t mask = S_IRUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH; | 
|  | mode_t mode = statbuf.st_mode & mask; | 
|  | chmod (t, mode); | 
|  | } | 
|  | // Try to rename temporary file "t" to "abs_caname" | 
|  | // res = link(t, abs_caname); // link() fails on some f/s - use rename() | 
|  | res = rename (t, abs_caname); | 
|  | if (res != 0) | 
|  | { | 
|  | if (errno != EEXIST) | 
|  | { | 
|  | fprintf (stderr, GTXT ("gprofng-archive: Fatal error: rename(%s, %s) returned error: %d\n"), | 
|  | t, abs_caname, res); | 
|  | unlink (t); | 
|  | free (t); | 
|  | free (abs_caname); | 
|  | free (abs_aname); | 
|  | return 1; | 
|  | } | 
|  | // File "abs_caname" is already there - continue | 
|  | } | 
|  | unlink (t); | 
|  | free (t); | 
|  | } | 
|  | else | 
|  | free (cad); | 
|  | char *lname = NULL; | 
|  | if (relative_path) | 
|  | { | 
|  | if (common_archive[0] != '/' && aname[0] != '/') | 
|  | { | 
|  | // compare one relative path to another and find common beginning | 
|  | char *rel_caname = dbe_sprintf ("%s/%s", common_archive, cafname); | 
|  | if (rel_caname == NULL) | 
|  | { | 
|  | fprintf (stderr, GTXT ("gprofng-archive: Fatal error: unable to allocate memory\n")); | 
|  | return 1; | 
|  | } | 
|  | lname = get_relative_link (rel_caname, aname); | 
|  | free (rel_caname); | 
|  | } | 
|  | else | 
|  | { | 
|  | if (abs_aname == NULL) | 
|  | { | 
|  | fprintf (stderr, GTXT ("gprofng-archive: Fatal error: unable to allocate memory\n")); | 
|  | return 1; | 
|  | } | 
|  | lname = get_relative_link (abs_caname, abs_aname); | 
|  | } | 
|  | } | 
|  | else  // absolute path | 
|  | lname = dbe_strdup (abs_caname); | 
|  | free (abs_aname); | 
|  | if (lname == NULL) | 
|  | { | 
|  | fprintf (stderr, GTXT ("gprofng-archive: Fatal error: unable to allocate memory\n")); | 
|  | return 1; | 
|  | } | 
|  | // Create symbolic link: aname -> lname | 
|  | if (dbe_stat_file (abs_caname, NULL) == 0) | 
|  | { | 
|  | res = symlink (lname, aname); | 
|  | if (res != 0) | 
|  | { | 
|  | fprintf (stderr, GTXT ("gprofng-archive: Fatal error: symlink(%s, %s) returned error: %d (errno=%s)\n"), | 
|  | lname, aname, res, strerror (errno)); | 
|  | free (abs_caname); | 
|  | free (lname); | 
|  | return 1; | 
|  | } | 
|  | if (!hide_msg) | 
|  | fprintf (stderr, GTXT ("Created symbolic link %s to file in common archive: %s\n"), | 
|  | aname, lname); | 
|  | } | 
|  | else | 
|  | { | 
|  | fprintf (stderr, GTXT ("gprofng-archive: Internal error: file does not exist in common archive: %s\n"), | 
|  | abs_caname); | 
|  | res = 1; | 
|  | } | 
|  | free (abs_caname); | 
|  | free (lname); | 
|  | return res; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Copy file to archive | 
|  | * @param name | 
|  | * @param aname | 
|  | * @param hide_msg | 
|  | * @param common_archive | 
|  | * @return 0 - success | 
|  | */ | 
|  | int | 
|  | Experiment::copy_file (const char *name, const char *aname, int hide_msg, | 
|  | const char *common_archive, int relative_path) | 
|  | { | 
|  | if (common_archive) | 
|  | { | 
|  | if (0 == copy_file_to_common_archive (name, aname, hide_msg, | 
|  | common_archive, relative_path)) | 
|  | return 0; | 
|  | // Error. For now - fatal error. Message is already printed. | 
|  | fprintf (stderr, GTXT ("gprofng-archive: Fatal error: cannot copy file %s to common archive %s\n"), | 
|  | name, common_archive); | 
|  | return 1; | 
|  | } | 
|  | return (copy_file_to_archive (name, aname, hide_msg)); | 
|  | } | 
|  |  | 
|  | LoadObject * | 
|  | Experiment::createLoadObject (const char *path, uint64_t chksum) | 
|  | { | 
|  | LoadObject *lo = dbeSession->createLoadObject (path, chksum); | 
|  | if (lo->firstExp == NULL) | 
|  | lo->firstExp = this; | 
|  | return lo; | 
|  | } | 
|  |  | 
|  | LoadObject * | 
|  | Experiment::createLoadObject (const char *path, const char *runTimePath) | 
|  | { | 
|  | DbeFile *df = findFileInArchive (path, runTimePath); | 
|  | if (df && (df->get_stat () == NULL)) | 
|  | df = NULL; // No access to file | 
|  | LoadObject *lo = dbeSession->createLoadObject (path, runTimePath, df); | 
|  | if (df && (lo->dbeFile->get_location (false) == NULL)) | 
|  | { | 
|  | lo->dbeFile->set_location (df->get_location ()); | 
|  | lo->dbeFile->inArchive = df->inArchive; | 
|  | lo->dbeFile->sbuf = df->sbuf; | 
|  | lo->dbeFile->experiment = df->experiment; | 
|  | lo->firstExp = df->experiment; | 
|  | } | 
|  | if (lo->firstExp == NULL) | 
|  | { | 
|  | lo->firstExp = this; | 
|  | lo->dbeFile->experiment = this; | 
|  | } | 
|  | return lo; | 
|  | } | 
|  |  | 
|  | SourceFile * | 
|  | Experiment::get_source (const char *path) | 
|  | { | 
|  | if (founder_exp && (founder_exp != this)) | 
|  | return founder_exp->get_source (path); | 
|  | if (sourcesMap == NULL) | 
|  | sourcesMap = new StringMap<SourceFile*>(1024, 1024); | 
|  | if (strncmp (path, NTXT ("./"), 2) == 0) | 
|  | path += 2; | 
|  | SourceFile *sf = sourcesMap->get (path); | 
|  | if (sf) | 
|  | return sf; | 
|  | char *fnm = checkFileInArchive (path, false); | 
|  | if (fnm) | 
|  | { | 
|  | sf = new SourceFile (path); | 
|  | dbeSession->append (sf); | 
|  | DbeFile *df = sf->dbeFile; | 
|  | df->set_location (fnm); | 
|  | df->inArchive = true; | 
|  | df->check_access (fnm); // init 'sbuf' | 
|  | df->sbuf.st_mtime = 0; // Don't check timestamps | 
|  | free (fnm); | 
|  | } | 
|  | else | 
|  | sf = dbeSession->createSourceFile (path); | 
|  | sourcesMap->put (path, sf); | 
|  | return sf; | 
|  | } | 
|  |  | 
|  | Vector<Histable*> * | 
|  | Experiment::get_comparable_objs () | 
|  | { | 
|  | update_comparable_objs (); | 
|  | if (comparable_objs || dbeSession->expGroups->size () <= 1) | 
|  | return comparable_objs; | 
|  | comparable_objs = new Vector<Histable*>(dbeSession->expGroups->size ()); | 
|  | for (long i = 0, sz = dbeSession->expGroups->size (); i < sz; i++) | 
|  | { | 
|  | ExpGroup *gr = dbeSession->expGroups->get (i); | 
|  | if (groupId == gr->groupId) | 
|  | { | 
|  | comparable_objs->append (this); | 
|  | continue; | 
|  | } | 
|  | Histable *h = NULL; | 
|  | for (long i1 = 0, sz1 = gr->exps ? gr->exps->size () : 0; i1 < sz1; i1++) | 
|  | { | 
|  | Experiment *exp = gr->exps->get (i1); | 
|  | if ((exp->comparable_objs == NULL) && (dbe_strcmp (utargname, exp->utargname) == 0)) | 
|  | { | 
|  | exp->phaseCompareIdx = phaseCompareIdx; | 
|  | h = exp; | 
|  | h->comparable_objs = comparable_objs; | 
|  | break; | 
|  | } | 
|  | } | 
|  | comparable_objs->append (h); | 
|  | } | 
|  | dump_comparable_objs (); | 
|  | return comparable_objs; | 
|  | } | 
|  |  | 
|  | DbeFile * | 
|  | Experiment::findFileInArchive (const char *fname) | 
|  | { | 
|  | if (archiveMap) | 
|  | { | 
|  | char *aname = get_archived_name (fname); | 
|  | DbeFile *df = archiveMap->get (aname); | 
|  | free (aname); | 
|  | return df; | 
|  | } | 
|  | if (founder_exp) | 
|  | return founder_exp->findFileInArchive (fname); | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | DbeFile * | 
|  | Experiment::findFileInArchive (const char *className, const char *runTimePath) | 
|  | { | 
|  | DbeFile *df = NULL; | 
|  | if (runTimePath) | 
|  | { | 
|  | const char *fnm = NULL; | 
|  | if (strncmp (runTimePath, NTXT ("zip:"), 4) == 0) | 
|  | fnm = runTimePath + 4; | 
|  | else if (strncmp (runTimePath, NTXT ("jar:file:"), 9) == 0) | 
|  | fnm = runTimePath + 9; | 
|  | if (fnm) | 
|  | { | 
|  | const char *s = strchr (fnm, '!'); | 
|  | if (s) | 
|  | { | 
|  | char *s1 = dbe_strndup (fnm, s - fnm); | 
|  | df = findFileInArchive (s1); | 
|  | free (s1); | 
|  | } | 
|  | else | 
|  | df = findFileInArchive (fnm); | 
|  | if (df) | 
|  | df->filetype |= DbeFile::F_JAR_FILE; | 
|  | } | 
|  | else if (strncmp (runTimePath, NTXT ("file:"), 5) == 0) | 
|  | { | 
|  | fnm = runTimePath + 5; | 
|  | df = findFileInArchive (fnm); | 
|  | } | 
|  | else | 
|  | df = findFileInArchive (runTimePath); | 
|  | } | 
|  | if (df == NULL) | 
|  | df = findFileInArchive (className); | 
|  | return df; | 
|  | } |