/* Copyright (C) 2021-2024 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 #include #include #include #include #include #include #include #include #include #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 *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; 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->need_swap_endian = (DbeSession::platform == Sparc) ? (exp->platform != Sparc) : (exp->platform == Sparc); exp->architecture = xstrdup (str); } 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; loadObjs = new Vector; loadObjMap = new StringMap(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; 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; for (int i = 0; i < DATA_LAST; ++i) dataDscrs->append (NULL); pcktDscrs = new Vector; blksz = PROFILE_BUFFER_CHUNK; jthreads = new Vector; jthreads_idx = new Vector; gcevents = new Vector; gcevent_last_used = (GCEvent *) NULL; heapUnmapEvents = new Vector; cstack = NULL; cstackShowHide = NULL; frmpckts = new Vector; typedef DefaultMap2D OmpMap0; mapPRid = new OmpMap0 (OmpMap0::Interval); typedef DefaultMap2D 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; mrecs = new Vector; samples = new Vector; 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; 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; tagObjs = new Vector*>; tagObjs->store (PROP_THRID, new Vector); tagObjs->store (PROP_LWPID, new Vector); tagObjs->store (PROP_CPUID, new Vector); tagObjs->store (PROP_EXPID, new Vector); 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(); 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(); 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 ("")) != 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, "") == 0) && strcmp (fileName, "") != 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; 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 // 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 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 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 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; delete vFdMap; vFdMap = new DefaultMap; 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 &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::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 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::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 *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; iuidn = 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; iuidj = 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; igetDataDescriptor (); 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 *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 (""); 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 *nodeCache = NULL; Map *frameInfoCache = NULL; if (size > FRINFO_CACHEOPT_SIZE_LIMIT && dversion == NULL) { frameInfoCache = new CacheMap; nodeCache = new CacheMap; } pushCnt = popCnt = pushCnt3 = popCnt3 = 0; nPush = nPop = 0; FramePacket *fp = NULL; // DbeThreadPool * threadPool = new DbeThreadPool(5); fp = new FramePacket; fp->stack = new Vector; fp->jstack = new Vector; fp->ompstack = new Vector; 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 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 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 * 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 *exp_names = new Vector(); 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 *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 *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 * Experiment::getTagObjs (Prop_type prop) { return tagObjs->fetch (prop); } Histable * Experiment::getTagObj (Prop_type prop, uint32_t tag) { Vector *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 * Experiment::getDataDescriptors () { Vector *result = new Vector; 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 (char *name, char *aname, int hide_msg, 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(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 * Experiment::get_comparable_objs () { update_comparable_objs (); if (comparable_objs || dbeSession->expGroups->size () <= 1) return comparable_objs; comparable_objs = new Vector(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; }