| /* Copyright (C) 2021-2023 Free Software Foundation, Inc. |
| Contributed by Oracle. |
| |
| This file is part of GNU Binutils. |
| |
| This program is free software; you can redistribute it and/or modify |
| it under the terms of the GNU General Public License as published by |
| the Free Software Foundation; either version 3, or (at your option) |
| any later version. |
| |
| This program is distributed in the hope that it will be useful, |
| but WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| GNU General Public License for more details. |
| |
| You should have received a copy of the GNU General Public License |
| along with this program; if not, write to the Free Software |
| Foundation, 51 Franklin Street - Fifth Floor, Boston, |
| MA 02110-1301, USA. */ |
| |
| #include "config.h" |
| #include <errno.h> |
| #include <utime.h> |
| #include <alloca.h> |
| #include <dirent.h> |
| #include <ctype.h> |
| #include <unistd.h> |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <sys/param.h> |
| #include <set> |
| |
| #include "util.h" |
| #include "CacheMap.h" |
| #include "DbeFile.h" |
| #include "DbeCacheMap.h" |
| #include "DefaultHandler.h" |
| #include "DefaultMap2D.h" |
| #include "Emsg.h" |
| #include "Elf.h" |
| #include "SAXParser.h" |
| #include "SAXParserFactory.h" |
| #include "StringBuilder.h" |
| #include "DbeSession.h" |
| #include "DbeThread.h" |
| #include "Application.h" |
| #include "CallStack.h" |
| #include "Experiment.h" |
| #include "Exp_Layout.h" |
| #include "DataStream.h" |
| #include "Expression.h" |
| #include "Function.h" |
| #include "HeapMap.h" |
| #include "LoadObject.h" |
| #include "Module.h" |
| #include "Ovw_data.h" |
| #include "PRBTree.h" |
| #include "Sample.h" |
| #include "SegMem.h" |
| #include "StringMap.h" |
| #include "UserLabel.h" |
| #include "Table.h" |
| #include "dbe_types.h" |
| #include "FileData.h" |
| #include "cc_libcollector.h" |
| #include "ExpGroup.h" |
| |
| int nPush; |
| int nPop; |
| int pushCnt; |
| int popCnt; |
| int pushCnt3; |
| int popCnt3; |
| |
| struct Experiment::UIDnode |
| { |
| uint64_t uid; |
| uint64_t val; |
| UIDnode *next; |
| }; |
| |
| struct Experiment::RawFramePacket |
| { |
| uint64_t uid; |
| UIDnode *uidn; |
| UIDnode *uidj; |
| UIDnode *omp_uid; |
| uint32_t omp_state; |
| }; |
| |
| static hrtime_t |
| parseTStamp (const char *s) |
| { |
| hrtime_t ts = (hrtime_t) 0; |
| ts = (hrtime_t) atoi (s) * NANOSEC; |
| s = strchr (s, '.'); |
| if (s != NULL) |
| ts += (hrtime_t) atoi (s + 1); |
| return ts; |
| } |
| |
| class Experiment::ExperimentFile |
| { |
| public: |
| |
| enum |
| { |
| EF_NOT_OPENED, |
| EF_OPENED, |
| EF_CLOSED, |
| EF_FAILURE |
| }; |
| |
| ExperimentFile (Experiment *_exp, const char *_fname); |
| ~ExperimentFile (); |
| |
| bool open (bool new_open = false); |
| |
| char * |
| get_name () |
| { |
| return fname; |
| } |
| |
| inline int |
| get_status () |
| { |
| return ef_status; |
| } |
| |
| char *fgets (); |
| void close (); |
| |
| FILE *fh; |
| |
| private: |
| Experiment *exp; |
| char *fname; |
| off64_t offset; |
| int bufsz, ef_status; |
| char *buffer; |
| }; |
| |
| class Experiment::ExperimentHandler : public DefaultHandler |
| { |
| public: |
| |
| ExperimentHandler (Experiment *_exp); |
| ~ExperimentHandler (); |
| |
| void |
| startDocument () { } |
| void endDocument (); |
| void startElement (char *uri, char *localName, char *qName, Attributes *attrs); |
| void endElement (char *uri, char *localName, char *qName); |
| void characters (char *ch, int start, int length); |
| |
| void |
| ignorableWhitespace (char*, int, int) { } |
| void |
| error (SAXParseException *e); |
| |
| private: |
| |
| enum Element |
| { |
| EL_NONE, |
| EL_EXPERIMENT, |
| EL_COLLECTOR, |
| EL_SETTING, |
| EL_PROCESS, |
| EL_SYSTEM, |
| EL_EVENT, |
| EL_PROFILE, |
| EL_DATAPTR, |
| EL_PROFDATA, |
| EL_PROFPCKT, |
| EL_FIELD, |
| EL_CPU, |
| EL_STATE, |
| EL_FREQUENCY, |
| EL_POWERM, |
| EL_DTRACEFATAL |
| }; |
| |
| static int toInt (Attributes *attrs, const char *atr); |
| static char*toStr (Attributes *attrs, const char *atr); |
| void pushElem (Element); |
| void popElem (); |
| |
| Experiment *exp; |
| Element curElem; |
| Vector<Element> *stack; |
| Module *dynfuncModule; |
| DataDescriptor *dDscr; |
| PacketDescriptor *pDscr; |
| PropDescr *propDscr; |
| char *text; |
| Cmsg_warn mkind; |
| int mnum; |
| int mec; |
| }; |
| |
| |
| // HTableSize is the size of smemHTable and instHTable |
| // omazur: both HTableSize and the hash function haven't been tuned; |
| static const int HTableSize = 8192; |
| |
| //-------------------------------------------------- Experiment file handler |
| |
| Experiment::ExperimentFile::ExperimentFile (Experiment *_exp, const char *_fname) |
| { |
| exp = _exp; |
| fh = NULL; |
| bufsz = 0; |
| buffer = NULL; |
| ef_status = EF_NOT_OPENED; |
| offset = 0; |
| fname = dbe_sprintf (NTXT ("%s/%s"), exp->expt_name, _fname); |
| } |
| |
| Experiment::ExperimentFile::~ExperimentFile () |
| { |
| close (); |
| free (buffer); |
| free (fname); |
| } |
| |
| bool |
| Experiment::ExperimentFile::open (bool new_open) |
| { |
| if (fh == NULL) |
| { |
| fh = fopen64 (fname, NTXT ("r")); |
| if (fh == NULL) |
| { |
| ef_status = EF_FAILURE; |
| return false; |
| } |
| ef_status = EF_OPENED; |
| if (new_open) |
| offset = 0; |
| if (offset != 0) |
| fseeko64 (fh, offset, SEEK_SET); |
| } |
| return true; |
| } |
| |
| char * |
| Experiment::ExperimentFile::fgets () |
| { |
| if (bufsz == 0) |
| { |
| bufsz = 1024; |
| buffer = (char *) malloc (bufsz); |
| if (buffer == NULL) |
| return NULL; |
| 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 *) malloc (newsz); |
| if (newbuf == NULL) |
| return NULL; |
| memcpy (newbuf, buffer, bufsz); |
| free (buffer); |
| buffer = newbuf; |
| buffer[newsz - 1] = (char) 1; // sentinel |
| // we don't care about fgets result here |
| ::fgets (buffer + bufsz - 1, newsz - bufsz + 1, fh); |
| bufsz = newsz; |
| } |
| return buffer; |
| } |
| |
| void |
| Experiment::ExperimentFile::close () |
| { |
| if (fh) |
| { |
| offset = ftello64 (fh); |
| fclose (fh); |
| ef_status = EF_CLOSED; |
| fh = NULL; |
| } |
| } |
| |
| |
| //-------------------------------------------------- Experiment XML parser |
| int |
| Experiment::ExperimentHandler::toInt (Attributes *attrs, const char *atr) |
| { |
| const char *str = attrs->getValue (atr); |
| return str ? atoi (str) : 0; |
| } |
| |
| char * |
| Experiment::ExperimentHandler::toStr (Attributes *attrs, const char *atr) |
| { |
| const char *str = attrs->getValue (atr); |
| return dbe_strdup (str ? str : NTXT ("")); |
| } |
| |
| Experiment::ExperimentHandler::ExperimentHandler (Experiment *_exp) |
| { |
| exp = _exp; |
| stack = new Vector<Element>; |
| pushElem (EL_NONE); |
| dynfuncModule = NULL; |
| dDscr = NULL; |
| pDscr = NULL; |
| propDscr = NULL; |
| text = NULL; |
| mkind = (Cmsg_warn) - 1; // 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 () |
| { |
| stack->remove (stack->size () - 1); |
| curElem = stack->fetch (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 = strdup (str); |
| } |
| str = attrs->getValue (SP_JCMD_TERMINATE); |
| if (str != NULL) |
| { |
| found = 1; |
| exp->coll_params.terminate = strdup (str); |
| } |
| str = attrs->getValue (SP_JCMD_PAUSE_SIG); |
| if (str != NULL) |
| { |
| found = 1; |
| exp->coll_params.pause_sig = strdup (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 = strdup (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 = strdup (str); |
| str = attrs->getValue (NTXT ("os")); |
| if (str != NULL) |
| { |
| exp->os_version = strdup (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 |
| exp->platform = Sparc; |
| exp->need_swap_endian = (DbeSession::platform == Sparc) ? |
| (exp->platform != Sparc) : (exp->platform == Sparc); |
| exp->architecture = strdup (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 = strdup (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 ("gp-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 = strdup (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 = strdup (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 = strdup (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 >= 0 && 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_warn) - 1; |
| mnum = -1; |
| mec = -1; |
| } |
| else if (curElem == EL_PROFILE) |
| dDscr = NULL; |
| else if (curElem == EL_PROFPCKT) |
| pDscr = NULL; |
| else if (curElem == EL_FIELD) |
| propDscr = NULL; |
| free (text); |
| text = NULL; |
| popElem (); |
| } |
| |
| void |
| Experiment::ExperimentHandler::error (SAXParseException *e) |
| { |
| StringBuilder sb; |
| sb.sprintf (GTXT ("%s at line %d, column %d"), |
| e->getMessage (), e->getLineNumber (), e->getColumnNumber ()); |
| char *msg = sb.toString (); |
| SAXException *e1 = new SAXException (msg); |
| free (msg); |
| throw ( e1); |
| } |
| |
| //-------------------------------------------------- Experiment |
| |
| Experiment::Experiment () |
| { |
| groupId = 0; |
| userExpId = expIdx = -1; |
| founder_exp = NULL; |
| baseFounder = NULL; |
| children_exps = new Vector<Experiment*>; |
| loadObjs = new Vector<LoadObject*>; |
| loadObjMap = new StringMap<LoadObject*>(128, 128); |
| sourcesMap = NULL; |
| |
| // Initialize configuration information. |
| status = FAILURE; |
| start_sec = 0; |
| mtime = 0; |
| hostname = NULL; |
| username = NULL; |
| architecture = NULL; |
| os_version = NULL; |
| uarglist = NULL; |
| utargname = NULL; |
| ucwd = NULL; |
| cversion = NULL; |
| dversion = NULL; |
| jversion = NULL; |
| exp_maj_version = 0; |
| exp_min_version = 0; |
| platform = Unknown; |
| wsize = Wnone; |
| page_size = 4096; |
| npages = 0; |
| stack_base = 0xf0000000; |
| broken = 1; |
| obsolete = 0; |
| hwc_bogus = 0; |
| hwc_lost_int = 0; |
| hwc_scanned = 0; |
| hwc_default = false; |
| invalid_packet = 0; |
| |
| // clear HWC event stats |
| dsevents = 0; |
| dsnoxhwcevents = 0; |
| |
| memset (&coll_params, 0, sizeof (coll_params)); |
| ncpus = 0; |
| minclock = 0; |
| maxclock = 0; |
| clock = 0; |
| varclock = 0; |
| exec_started = false; |
| timelineavail = true; |
| leaklistavail = false; |
| heapdataavail = false; |
| iodataavail = false; |
| dataspaceavail = false; |
| ifreqavail = false; |
| racelistavail = false; |
| deadlocklistavail = false; |
| ompavail = false; |
| tiny_threshold = -1; |
| pid = 0; |
| ppid = 0; |
| pgrp = 0; |
| sid = 0; |
| |
| gc_duration = ZERO_TIME; |
| exp_start_time = ZERO_TIME; // not known. Wall-clock hrtime (not zero based) |
| last_event = ZERO_TIME; // not known. Wall-clock hrtime (not zero based) |
| non_paused_time = 0; // 0 non-paused time (will sum as experiment is processed) |
| resume_ts = 0; // by default, collection is "resumed" (not paused) from time=0 |
| need_swap_endian = false; |
| exp_rel_start_time_set = false; |
| exp_rel_start_time = ZERO_TIME; |
| has_java = false; |
| hex_field_width = 8; |
| hw_cpuver = CPUVER_UNDEFINED; |
| machinemodel = NULL; |
| expt_name = NULL; |
| arch_name = NULL; |
| fndr_arch_name = NULL; |
| dyntext_name = NULL; |
| logFile = NULL; |
| |
| dataDscrs = new Vector<DataDescriptor*>; |
| for (int i = 0; i < DATA_LAST; ++i) |
| dataDscrs->append (NULL); |
| |
| pcktDscrs = new Vector<PacketDescriptor*>; |
| blksz = PROFILE_BUFFER_CHUNK; |
| jthreads = new Vector<JThread*>; |
| jthreads_idx = new Vector<JThread*>; |
| gcevents = new Vector<GCEvent*>; |
| gcevent_last_used = (GCEvent *) NULL; |
| heapUnmapEvents = new Vector<UnmapChunk*>; |
| cstack = NULL; |
| cstackShowHide = NULL; |
| frmpckts = new Vector<RawFramePacket*>; |
| typedef DefaultMap2D<uint32_t, hrtime_t, uint64_t> OmpMap0; |
| mapPRid = new OmpMap0 (OmpMap0::Interval); |
| typedef DefaultMap2D<uint32_t, hrtime_t, void*> OmpMap; |
| mapPReg = new OmpMap (OmpMap::Interval); |
| mapTask = new OmpMap (OmpMap::Interval); |
| openMPdata = NULL; |
| archiveMap = NULL; |
| nnodes = 0; |
| nchunks = 0; |
| chunks = 0; |
| uidHTable = NULL; |
| uidnodes = new Vector<UIDnode*>; |
| mrecs = new Vector<MapRecord*>; |
| samples = new Vector<Sample*>; |
| sample_last_used = (Sample *) NULL; |
| first_sample_label = (char*) NULL; |
| fDataMap = NULL; |
| vFdMap = NULL; |
| resolveFrameInfo = true; |
| discardTiny = false; |
| init (); |
| } |
| |
| Experiment::~Experiment () |
| { |
| fini (); |
| free (coll_params.linetrace); |
| for (int i = 0; i < MAX_HWCOUNT; i++) |
| { |
| free (coll_params.hw_aux_name[i]); |
| free (coll_params.hw_username[i]); |
| } |
| free (hostname); |
| free (username); |
| free (architecture); |
| free (os_version); |
| free (uarglist); |
| free (utargname); |
| free (ucwd); |
| free (cversion); |
| free (dversion); |
| free (jversion); |
| delete logFile; |
| free (expt_name); |
| free (arch_name); |
| free (fndr_arch_name); |
| free (dyntext_name); |
| delete jthreads_idx; |
| delete cstack; |
| delete cstackShowHide; |
| delete mapPRid; |
| delete mapPReg; |
| delete mapTask; |
| delete openMPdata; |
| destroy_map (DbeFile *, archiveMap); |
| delete[] uidHTable; |
| delete uidnodes; |
| delete mrecs; |
| delete children_exps; |
| delete loadObjs; |
| delete loadObjMap; |
| delete sourcesMap; |
| free (first_sample_label); |
| free (machinemodel); |
| |
| dataDscrs->destroy (); |
| delete dataDscrs; |
| pcktDscrs->destroy (); |
| delete pcktDscrs; |
| jthreads->destroy (); |
| delete jthreads; |
| gcevents->destroy (); |
| delete gcevents; |
| heapUnmapEvents->destroy (); |
| delete heapUnmapEvents; |
| frmpckts->destroy (); |
| delete frmpckts; |
| samples->destroy (); |
| delete samples; |
| delete fDataMap; |
| delete vFdMap; |
| |
| for (long i = 0; i < nchunks; i++) |
| delete[] chunks[i]; |
| delete[] chunks; |
| } |
| |
| void |
| Experiment::init_cache () |
| { |
| if (smemHTable) |
| return; |
| smemHTable = new SegMem*[HTableSize]; |
| instHTable = new DbeInstr*[HTableSize]; |
| for (int i = 0; i < HTableSize; i++) |
| { |
| smemHTable[i] = NULL; |
| instHTable[i] = NULL; |
| } |
| uidHTable = new UIDnode*[HTableSize]; |
| for (int i = 0; i < HTableSize; i++) |
| uidHTable[i] = NULL; |
| |
| cstack = CallStack::getInstance (this); |
| cstackShowHide = CallStack::getInstance (this); |
| } |
| |
| void |
| Experiment::init () |
| { |
| userLabels = NULL; |
| seg_items = new Vector<SegMem*>; |
| maps = new PRBTree (); |
| jmaps = NULL; // used by JAVA_CLASSES only |
| jmidHTable = NULL; |
| smemHTable = NULL; |
| instHTable = NULL; |
| min_thread = (uint64_t) - 1; |
| max_thread = 0; |
| thread_cnt = 0; |
| min_lwp = (uint64_t) - 1; |
| max_lwp = 0; |
| lwp_cnt = 0; |
| min_cpu = (uint64_t) - 1; |
| max_cpu = 0; |
| cpu_cnt = 0; |
| |
| commentq = new Emsgqueue (NTXT ("commentq")); |
| runlogq = new Emsgqueue (NTXT ("runlogq")); |
| errorq = new Emsgqueue (NTXT ("errorq")); |
| warnq = new Emsgqueue (NTXT ("warnq")); |
| notesq = new Emsgqueue (NTXT ("notesq")); |
| pprocq = new Emsgqueue (NTXT ("pprocq")); |
| ifreqq = NULL; |
| |
| metrics = new Vector<BaseMetric*>; |
| tagObjs = new Vector<Vector<Histable*>*>; |
| tagObjs->store (PROP_THRID, new Vector<Histable*>); |
| tagObjs->store (PROP_LWPID, new Vector<Histable*>); |
| tagObjs->store (PROP_CPUID, new Vector<Histable*>); |
| tagObjs->store (PROP_EXPID, new Vector<Histable*>); |
| sparse_threads = false; |
| } |
| |
| void |
| Experiment::fini () |
| { |
| seg_items->destroy (); |
| delete seg_items; |
| delete maps; |
| delete jmaps; |
| delete[] smemHTable; |
| delete[] instHTable; |
| delete jmidHTable; |
| delete commentq; |
| delete runlogq; |
| delete errorq; |
| delete warnq; |
| delete notesq; |
| delete pprocq; |
| if (ifreqq != NULL) |
| { |
| delete ifreqq; |
| ifreqq = NULL; |
| } |
| |
| int index; |
| BaseMetric *mtr; |
| Vec_loop (BaseMetric*, metrics, index, mtr) |
| { |
| dbeSession->drop_metric (mtr); |
| } |
| delete metrics; |
| tagObjs->fetch (PROP_THRID)->destroy (); |
| tagObjs->fetch (PROP_LWPID)->destroy (); |
| tagObjs->fetch (PROP_CPUID)->destroy (); |
| tagObjs->fetch (PROP_EXPID)->destroy (); |
| tagObjs->destroy (); |
| delete tagObjs; |
| } |
| |
| // These are the data files which can be read in parallel |
| // for multiple sub-experiments. |
| // Postpone calling resolve_frame_info() |
| void |
| Experiment::read_experiment_data (bool read_ahead) |
| { |
| |
| read_frameinfo_file (); |
| if (read_ahead) |
| { |
| resolveFrameInfo = false; |
| (void) get_profile_events (); |
| resolveFrameInfo = true; |
| } |
| } |
| |
| Experiment::Exp_status |
| Experiment::open_epilogue () |
| { |
| |
| // set up mapping for tagObj(PROP_EXPID) |
| (void) mapTagValue (PROP_EXPID, userExpId); |
| |
| post_process (); |
| if (last_event != ZERO_TIME) |
| { // if last_event is known |
| StringBuilder sb; |
| hrtime_t ts = last_event - exp_start_time; |
| sb.sprintf (GTXT ("Experiment Ended: %ld.%09ld\nData Collection Duration: %ld.%09ld"), |
| (long) (ts / NANOSEC), (long) (ts % NANOSEC), |
| (long) (non_paused_time / NANOSEC), |
| (long) (non_paused_time % NANOSEC)); |
| runlogq->append (new Emsg (CMSG_COMMENT, sb)); |
| } |
| |
| // Check for incomplete experiment, and inform the user |
| if (status == INCOMPLETE) |
| { |
| if (exec_started == true) |
| // experiment ended with the exec, not abnormally |
| status = SUCCESS; |
| else |
| { |
| char * cmnt = GTXT ("*** Note: experiment was not closed"); |
| commentq->append (new Emsg (CMSG_COMMENT, cmnt)); |
| // runlogq->append(new Emsg(CMSG_COMMENT, cmnt)); |
| } |
| } |
| // write a descriptive header for the experiment |
| write_header (); |
| return status; |
| } |
| |
| Experiment::Exp_status |
| Experiment::open (char *path) |
| { |
| |
| // Find experiment directory |
| if (find_expdir (path) != SUCCESS) |
| // message will have been queued and status set |
| return status; |
| |
| // Get creation time for experiment |
| struct stat64 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; |
| char *hostname; |
| hrtime_t time, tstamp; |
| }; |
| |
| void |
| Experiment::ExperimentLabelsHandler::startElement (char*, char*, char *qName, |
| Attributes *attrs) |
| { |
| DEBUG_CODE if (DEBUG_SAXPARSER) dump_startElement (qName, attrs); |
| if (qName == NULL || strcmp (qName, NTXT ("id")) != 0) |
| return; |
| char *name = NULL, *all_times = NULL, *comment = NULL, *hostName = NULL; |
| long startSec = 0; |
| // long tm_zone = 0; |
| hrtime_t startHrtime = (hrtime_t) 0; |
| long long lbl_ts = 0; |
| int relative = 0; |
| timeval start_tv; |
| start_tv.tv_usec = start_tv.tv_sec = 0; |
| for (int i = 0, sz = attrs ? attrs->getLength () : 0; i < sz; i++) |
| { |
| const char *qn = attrs->getQName (i); |
| const char *vl = attrs->getValue (i); |
| if (strcmp (qn, NTXT ("name")) == 0) |
| name = dbe_xml2str (vl); |
| else if (strcmp (qn, NTXT ("cmd")) == 0) |
| all_times = dbe_xml2str (vl); |
| else if (strcmp (qn, NTXT ("comment")) == 0) |
| comment = dbe_xml2str (vl); |
| else if (strcmp (qn, NTXT ("relative")) == 0) |
| relative = atoi (vl); |
| else if (strcmp (qn, NTXT ("hostname")) == 0) |
| hostName = dbe_xml2str (vl); |
| else if (strcmp (qn, NTXT ("time")) == 0) |
| startSec = atol (vl); |
| else if (strcmp (qn, NTXT ("tstamp")) == 0) |
| startHrtime = parseTStamp (vl); |
| else if (strcmp (qn, NTXT ("lbl_ts")) == 0) |
| { |
| if (*vl == '-') |
| lbl_ts = -parseTStamp (vl + 1); |
| else |
| lbl_ts = parseTStamp (vl); |
| } |
| } |
| if (name == NULL || hostName == NULL || (all_times == NULL && comment == NULL)) |
| { |
| free (name); |
| free (hostName); |
| free (all_times); |
| free (comment); |
| return; |
| } |
| UserLabel *lbl = new UserLabel (name); |
| lbl->comment = comment; |
| lbl->hostname = hostName; |
| lbl->start_sec = startSec; |
| lbl->start_hrtime = startHrtime; |
| exp->userLabels->append (lbl); |
| if (all_times) |
| { |
| lbl->all_times = all_times; |
| lbl->start_tv = start_tv; |
| lbl->relative = relative; |
| if (relative == UserLabel::REL_TIME) |
| lbl->atime = lbl_ts; |
| else |
| { // relative == UserLabel::CUR_TIME |
| long long delta = 0; |
| if (exp->hostname && strcmp (lbl->hostname, exp->hostname) == 0) |
| delta = lbl_ts + (lbl->start_hrtime - exp->exp_start_time); |
| else |
| for (int i = 0; i < exp->userLabels->size (); i++) |
| { |
| UserLabel *firstLbl = exp->userLabels->fetch (i); |
| if (strcmp (lbl->hostname, firstLbl->hostname) == 0) |
| { |
| delta = lbl_ts + (lbl->start_hrtime - firstLbl->start_hrtime) + |
| ((long long) (firstLbl->start_sec - exp->start_sec)) * NANOSEC; |
| break; |
| } |
| } |
| lbl->atime = delta > 0 ? delta : 0; |
| } |
| } |
| } |
| |
| static int |
| sortUserLabels (const void *a, const void *b) |
| { |
| UserLabel *l1 = *((UserLabel **) a); |
| UserLabel *l2 = *((UserLabel **) b); |
| int v = dbe_strcmp (l1->name, l2->name); |
| if (v != 0) |
| return v; |
| if (l1->atime < l2->atime) |
| return -1; |
| else if (l1->atime > l2->atime) |
| return 1; |
| if (l1->id < l2->id) |
| return -1; |
| else if (l1->id > l2->id) |
| return 1; |
| return 0; |
| } |
| |
| static char * |
| append_string (char *s, char *str) |
| { |
| if (s == NULL) |
| return dbe_strdup (str); |
| char *new_s = dbe_sprintf (NTXT ("%s %s"), s, str); |
| free (s); |
| return new_s; |
| } |
| |
| void |
| Experiment::read_labels_file () |
| { |
| ExperimentFile *fp = new ExperimentFile (this, SP_LABELS_FILE); |
| if (!fp->open ()) |
| { |
| delete fp; |
| return; |
| } |
| userLabels = new Vector<UserLabel*>(); |
| SAXParserFactory *factory = SAXParserFactory::newInstance (); |
| SAXParser *saxParser = factory->newSAXParser (); |
| DefaultHandler *dh = new ExperimentLabelsHandler (this); |
| try |
| { |
| saxParser->parse ((File*) fp->fh, dh); |
| } |
| catch (SAXException *e) |
| { |
| // Fatal error in the parser |
| StringBuilder sb; |
| sb.sprintf (NTXT ("%s: %s"), SP_LABELS_FILE, e->getMessage ()); |
| char *str = sb.toString (); |
| Emsg *m = new Emsg (CMSG_FATAL, str); |
| errorq->append (m); |
| delete e; |
| } |
| fp->close (); |
| delete fp; |
| delete dh; |
| delete saxParser; |
| delete factory; |
| |
| userLabels->sort (sortUserLabels); |
| UserLabel::dump ("After sortUserLabels:", userLabels); |
| UserLabel *ulbl = NULL; |
| for (int i = 0, sz = userLabels->size (); i < sz; i++) |
| { |
| UserLabel *lbl = userLabels->fetch (i); |
| if (ulbl == NULL) |
| ulbl = new UserLabel (lbl->name); |
| else if (dbe_strcmp (lbl->name, ulbl->name) != 0) |
| { // new Label |
| ulbl->register_user_label (groupId); |
| if (ulbl->expr == NULL) |
| delete ulbl; |
| ulbl = new UserLabel (lbl->name); |
| } |
| if (lbl->all_times) |
| { |
| if (strncmp (lbl->all_times, NTXT ("start"), 5) == 0) |
| { |
| if (!ulbl->start_f) |
| { |
| ulbl->start_f = true; |
| ulbl->timeStart = lbl->atime; |
| } |
| } |
| else |
| { // stop |
| if (!ulbl->start_f) |
| continue; |
| ulbl->all_times = append_string (ulbl->all_times, lbl->all_times); |
| ulbl->stop_f = true; |
| ulbl->timeStop = lbl->atime; |
| ulbl->gen_expr (); |
| } |
| } |
| if (lbl->comment != NULL) |
| ulbl->comment = append_string (ulbl->comment, lbl->comment); |
| } |
| if (ulbl) |
| { |
| ulbl->register_user_label (groupId); |
| if (ulbl->expr == NULL) |
| delete ulbl; |
| } |
| Destroy (userLabels); |
| } |
| |
| void |
| Experiment::read_archives () |
| { |
| if (founder_exp) |
| return; |
| char *allocated_str = NULL; |
| char *nm = get_arch_name (); |
| DIR *exp_dir = opendir (nm); |
| if (exp_dir == NULL) |
| { |
| if (founder_exp == NULL) |
| { |
| // Check if the user uses a subexperiment only |
| nm = dbe_sprintf (NTXT ("%s/../%s"), expt_name, SP_ARCHIVES_DIR); |
| exp_dir = opendir (nm); |
| if (exp_dir == NULL) |
| { |
| free (nm); |
| return; |
| } |
| allocated_str = nm; |
| } |
| else |
| return; |
| } |
| |
| StringBuilder sb; |
| sb.append (nm); |
| sb.append ('/'); |
| int dlen = sb.length (); |
| free (allocated_str); |
| archiveMap = new StringMap<DbeFile *>(); |
| |
| struct dirent *entry = NULL; |
| while ((entry = readdir (exp_dir)) != NULL) |
| { |
| char *dname = entry->d_name; |
| if (dname[0] == '.' |
| && (dname[1] == '\0' || (dname[1] == '.' && dname[2] == '\0'))) |
| // skip links to ./ or ../ |
| continue; |
| sb.setLength (dlen); |
| sb.append (dname); |
| char *fnm = sb.toString (); |
| DbeFile *df = new DbeFile (fnm); |
| df->set_location (fnm); |
| df->filetype |= DbeFile::F_FILE; |
| df->inArchive = true; |
| df->experiment = this; |
| archiveMap->put (dname, df); |
| free (fnm); |
| } |
| closedir (exp_dir); |
| } |
| |
| static char * |
| gen_file_name (const char *packet_name, const char *src_name) |
| { |
| char *fnm, *bname = get_basename (packet_name); |
| if (bname == packet_name) |
| fnm = dbe_strdup (src_name); |
| else |
| fnm = dbe_sprintf ("%.*s%s", (int) (bname - packet_name), |
| packet_name, src_name); |
| |
| // convert "java.lang.Object/Integer.java" => "java/lang/Object/Integer.java" |
| bname = get_basename (fnm); |
| for (char *s = fnm; s < bname; s++) |
| if (*s == '.') |
| *s = '/'; |
| return fnm; |
| } |
| |
| static char * |
| get_jlass_name (const char *nm) |
| { |
| // Convert "Ljava/lang/Object;" => "java/lang/Object.class" |
| if (*nm == 'L') |
| { |
| size_t len = strlen (nm); |
| if (nm[len - 1] == ';') |
| return dbe_sprintf ("%.*s.class", (int) (len - 2), nm + 1); |
| } |
| return dbe_strdup (nm); |
| } |
| |
| static char * |
| get_jmodule_name (const char *nm) |
| { |
| // convert "Ljava/lang/Object;" => "java.lang.Object" |
| if (*nm == 'L') |
| { |
| size_t len = strlen (nm); |
| if (nm[len - 1] == ';') |
| { |
| char *mname = dbe_sprintf (NTXT ("%.*s"), (int) (len - 2), nm + 1); |
| for (char *s = mname; *s; s++) |
| if (*s == '/') |
| *s = '.'; |
| return mname; |
| } |
| } |
| return dbe_strdup (nm); |
| } |
| |
| LoadObject * |
| Experiment::get_j_lo (const char *className, const char *fileName) |
| { |
| char *class_name = get_jlass_name (className); |
| Dprintf (DUMP_JCLASS_READER, |
| "Experiment::get_j_lo: className='%s' class_name='%s' fileName='%s'\n", |
| STR (className), STR (class_name), STR (fileName)); |
| LoadObject *lo = loadObjMap->get (class_name); |
| if (lo == NULL) |
| { |
| lo = createLoadObject (class_name, fileName); |
| lo->type = LoadObject::SEG_TEXT; |
| lo->mtime = (time_t) 0; |
| lo->size = 0; |
| lo->set_platform (Java, wsize); |
| lo->dbeFile->filetype |= DbeFile::F_FILE | DbeFile::F_JAVACLASS; |
| append (lo); |
| Dprintf (DUMP_JCLASS_READER, |
| "Experiment::get_j_lo: creates '%s' location='%s'\n", |
| STR (lo->get_name ()), STR (lo->dbeFile->get_location (false))); |
| } |
| free (class_name); |
| return lo; |
| } |
| |
| Module * |
| Experiment::get_jclass (const char *className, const char *fileName) |
| { |
| LoadObject *lo = get_j_lo (className, NULL); |
| char *mod_name = get_jmodule_name (className); |
| Module *mod = lo->find_module (mod_name); |
| if (mod == NULL) |
| { |
| mod = dbeSession->createClassFile (mod_name); |
| mod->loadobject = lo; |
| if (strcmp (fileName, NTXT ("<Unknown>")) != 0) |
| mod->set_file_name (gen_file_name (lo->get_pathname (), fileName)); |
| else |
| mod->set_file_name (dbe_strdup (fileName)); |
| lo->append_module (mod); |
| mod_name = NULL; |
| } |
| else if (mod->file_name && (strcmp (mod->file_name, "<Unknown>") == 0) |
| && strcmp (fileName, "<Unknown>") != 0) |
| mod->set_file_name (gen_file_name (lo->get_pathname (), fileName)); |
| Dprintf (DUMP_JCLASS_READER, |
| "Experiment::get_jclass: class_name='%s' mod_name='%s' fileName='%s'\n", |
| mod->loadobject->get_pathname (), mod->get_name (), mod->file_name); |
| free (mod_name); |
| return mod; |
| } |
| |
| #define ARCH_STRLEN(s) ( ( strlen(s) + 4 ) & ~0x3 ) |
| |
| int |
| Experiment::read_java_classes_file () |
| { |
| char *data_file_name = dbe_sprintf (NTXT ("%s/%s"), expt_name, SP_JCLASSES_FILE); |
| Data_window *dwin = new Data_window (data_file_name); |
| free (data_file_name); |
| if (dwin->not_opened ()) |
| { |
| delete dwin; |
| return INCOMPLETE; |
| } |
| dwin->need_swap_endian = need_swap_endian; |
| jmaps = new PRBTree (); |
| jmidHTable = new DbeCacheMap<unsigned long long, JMethod>; |
| |
| hrtime_t cur_loaded = 0; |
| Module *cur_mod = NULL; |
| for (int64_t offset = 0;;) |
| { |
| CM_Packet *cpkt = (CM_Packet*) dwin->bind (offset, sizeof (CM_Packet)); |
| if (cpkt == NULL) |
| break; |
| uint16_t v16 = (uint16_t) cpkt->tsize; |
| size_t cpktsize = dwin->decode (v16); |
| cpkt = (CM_Packet*) dwin->bind (offset, cpktsize); |
| if ((cpkt == NULL) || (cpktsize == 0)) |
| { |
| char *buf = dbe_sprintf (GTXT ("archive file malformed %s"), |
| arch_name); |
| errorq->append (new Emsg (CMSG_ERROR, buf)); |
| free (buf); |
| break; |
| } |
| v16 = (uint16_t) cpkt->type; |
| v16 = dwin->decode (v16); |
| switch (v16) |
| { |
| case ARCH_JCLASS: |
| { |
| ARCH_jclass *ajcl = (ARCH_jclass*) cpkt; |
| uint64_t class_id = dwin->decode (ajcl->class_id); |
| char *className = ((char*) ajcl) + sizeof (*ajcl); |
| char *fileName = className + ARCH_STRLEN (className); |
| Dprintf (DUMP_JCLASS_READER, |
| "read_java_classes_file: ARCH_JCLASS(Ox%x)" |
| "class_id=Ox%llx className='%s' fileName='%s' \n", |
| (int) v16, (long long) class_id, className, fileName); |
| cur_mod = NULL; |
| if (*className == 'L') |
| { // Old libcollector generated '[' (one array dimension). |
| cur_mod = get_jclass (className, fileName); |
| cur_loaded = dwin->decode (ajcl->tstamp); |
| jmaps->insert (class_id, cur_loaded, cur_mod); |
| } |
| break; |
| } |
| case ARCH_JCLASS_LOCATION: |
| { |
| ARCH_jclass_location *ajcl = (ARCH_jclass_location *) cpkt; |
| uint64_t class_id = dwin->decode (ajcl->class_id); |
| char *className = ((char*) ajcl) + sizeof (*ajcl); |
| char *fileName = className + ARCH_STRLEN (className); |
| Dprintf (DUMP_JCLASS_READER, |
| "read_java_classes_file: ARCH_JCLASS_LOCATION(Ox%x)" |
| "class_id=Ox%llx className='%s' fileName='%s' \n", |
| (int) v16, (long long) class_id, className, fileName); |
| get_j_lo (className, fileName); |
| break; |
| } |
| case ARCH_JMETHOD: |
| { |
| if (cur_mod == NULL) |
| break; |
| ARCH_jmethod *ajmt = (ARCH_jmethod*) cpkt; |
| uint64_t method_id = dwin->decode (ajmt->method_id); |
| char *s_name = ((char*) ajmt) + sizeof (*ajmt); |
| char *s_signature = s_name + ARCH_STRLEN (s_name); |
| char *fullname = dbe_sprintf ("%s.%s", cur_mod->get_name (), s_name); |
| Dprintf (DUMP_JCLASS_READER, |
| "read_java_classes_file: ARCH_JMETHOD(Ox%x) " |
| "method_id=Ox%llx name='%s' signature='%s' fullname='%s'\n", |
| (int) v16, (long long) method_id, s_name, |
| s_signature, fullname); |
| JMethod *jmthd = cur_mod->find_jmethod (fullname, s_signature); |
| if (jmthd == NULL) |
| { |
| jmthd = dbeSession->createJMethod (); |
| jmthd->size = (unsigned) - 1; // unknown until later (maybe) |
| jmthd->module = cur_mod; |
| jmthd->set_signature (s_signature); |
| jmthd->set_name (fullname); |
| cur_mod->functions->append (jmthd); |
| cur_mod->loadobject->functions->append (jmthd); |
| Dprintf (DUMP_JCLASS_READER, |
| "read_java_classes_file: ARCH_JMETHOD CREATE fullname=%s\n", |
| fullname); |
| } |
| jmaps->insert (method_id, cur_loaded, jmthd); |
| free (fullname); |
| break; |
| } |
| default: |
| Dprintf (DUMP_JCLASS_READER, |
| "read_java_classes_file: type=Ox%x (%d) cpktsize=%d\n", |
| (int) v16, (int) v16, (int) cpktsize); |
| break; // ignore unknown packets |
| } |
| offset += cpktsize; |
| } |
| delete dwin; |
| return SUCCESS; |
| } |
| |
| void |
| Experiment::read_map_file () |
| { |
| ExperimentFile *mapFile = new ExperimentFile (this, SP_MAP_FILE); |
| if (!mapFile->open ()) |
| { |
| delete mapFile; |
| return; |
| } |
| |
| SAXParserFactory *factory = SAXParserFactory::newInstance (); |
| SAXParser *saxParser = factory->newSAXParser (); |
| DefaultHandler *dh = new ExperimentHandler (this); |
| try |
| { |
| saxParser->parse ((File*) mapFile->fh, dh); |
| } |
| catch (SAXException *e) |
| { |
| // Fatal error in the parser |
| StringBuilder sb; |
| sb.sprintf (NTXT ("%s: %s"), SP_MAP_FILE, e->getMessage ()); |
| char *str = sb.toString (); |
| Emsg *m = new Emsg (CMSG_FATAL, str); |
| errorq->append (m); |
| status = FAILURE; |
| free (str); |
| delete e; |
| } |
| delete mapFile; |
| delete dh; |
| delete saxParser; |
| delete factory; |
| |
| for (int i = 0, sz = mrecs ? mrecs->size () : 0; i < sz; i++) |
| { |
| MapRecord *mrec = mrecs->fetch (i); |
| SegMem *smem, *sm_lo, *sm_hi; |
| switch (mrec->kind) |
| { |
| case MapRecord::LOAD: |
| smem = new SegMem; |
| smem->base = mrec->base; |
| smem->size = mrec->size; |
| smem->load_time = mrec->ts; |
| smem->unload_time = MAX_TIME; |
| smem->obj = mrec->obj; |
| smem->set_file_offset (mrec->foff); |
| seg_items->append (smem); // add to the master list |
| |
| // Check if the new segment overlaps other active segments |
| sm_lo = (SegMem*) maps->locate (smem->base, smem->load_time); |
| if (sm_lo && sm_lo->base + sm_lo->size > smem->base) |
| { |
| // check to see if it is a duplicate record: same address and size, and |
| if ((smem->base == sm_lo->base) && (smem->size == sm_lo->size)) |
| { |
| // addresses and sizes match, check name |
| if (strstr (smem->obj->get_name (), sm_lo->obj->get_name ()) != NULL |
| || strstr (sm_lo->obj->get_name (), smem->obj->get_name ()) != NULL) |
| // this is a duplicate; just move on the the next map record |
| continue; |
| fprintf (stderr, |
| GTXT ("*** Warning: Segment `%s' loaded with same address, size as `%s' [0x%llx-0x%llx]\n"), |
| smem->obj->get_name (), sm_lo->obj->get_name (), |
| sm_lo->base, sm_lo->base + sm_lo->size); |
| } |
| |
| // Not a duplicate; implicitly unload the old one |
| // Note: implicit unloading causes high <Unknown> |
| // when such overlapping is bogus |
| StringBuilder sb; |
| sb.sprintf (GTXT ("*** Warning: Segment %s [0x%llx-0x%llx] overlaps %s [0x%llx-0x%llx], which has been implicitly unloaded"), |
| smem->obj->get_name (), smem->base, smem->base + smem->size, |
| sm_lo->obj->get_name (), sm_lo->base, sm_lo->base + sm_lo->size); |
| warnq->append (new Emsg (CMSG_WARN, sb)); |
| } |
| |
| // now look for other segments with which this might overlap |
| sm_hi = (SegMem*) maps->locate_up (smem->base, smem->load_time); |
| while (sm_hi && sm_hi->base < smem->base + smem->size) |
| { |
| |
| // Note: implicit unloading causes high <Unknown> when such overlapping is bogus |
| // maps->remove( sm_hi->base, smem->load_time ); |
| StringBuilder sb; |
| sb.sprintf (GTXT ("*** Warning: Segment %s [0x%llx-0x%llx] overlaps %s [0x%llx-0x%llx], which has been implicitly unloaded"), |
| smem->obj->get_name (), smem->base, |
| smem->base + smem->size, sm_hi->obj->get_name (), |
| sm_hi->base, sm_hi->base + sm_hi->size); |
| warnq->append (new Emsg (CMSG_WARN, sb)); |
| sm_hi = (SegMem*) maps->locate_up (sm_hi->base + sm_hi->size, |
| smem->load_time); |
| } |
| |
| maps->insert (smem->base, smem->load_time, smem); |
| break; |
| case MapRecord::UNLOAD: |
| smem = (SegMem*) maps->locate (mrec->base, mrec->ts); |
| if (smem && smem->base == mrec->base) |
| { |
| smem->unload_time = mrec->ts; |
| maps->remove (mrec->base, mrec->ts); |
| } |
| break; |
| } |
| } |
| mrecs->destroy (); |
| |
| // See if there are comments or warnings for a load object; |
| // if so, queue them to Experiment |
| for (long i = 0, sz = loadObjs ? loadObjs->size () : 0; i < sz; i++) |
| { |
| LoadObject *lo = loadObjs->get (i); |
| for (Emsg *m = lo->fetch_warnings (); m; m = m->next) |
| warnq->append (m->get_warn (), m->get_msg ()); |
| for (Emsg *m = lo->fetch_comments (); m; m = m->next) |
| commentq->append (m->get_warn (), m->get_msg ()); |
| } |
| } |
| |
| void |
| Experiment::read_frameinfo_file () |
| { |
| init_cache (); |
| char *base_name = get_basename (expt_name); |
| char *msg = dbe_sprintf (GTXT ("Loading CallStack Data: %s"), base_name); |
| read_data_file ("data." SP_FRINFO_FILE, msg); |
| free (msg); |
| frmpckts->sort (frUidCmp); |
| uidnodes->sort (uidNodeCmp); |
| } |
| |
| void |
| Experiment::read_omp_preg () |
| { |
| // Parallel region descriptions |
| DataDescriptor *pregDdscr = getDataDescriptor (DATA_OMP4); |
| if (pregDdscr == NULL) |
| return; |
| DataView *pregData = pregDdscr->createView (); |
| pregData->sort (PROP_CPRID); // omptrace PROP_CPRID |
| |
| // OpenMP enter parreg events |
| DataDescriptor *dDscr = getDataDescriptor (DATA_OMP2); |
| if (dDscr == NULL || dDscr->getSize () == 0) |
| { |
| delete pregData; |
| return; |
| } |
| |
| char *idxname = NTXT ("OMP_preg"); |
| delete dbeSession->indxobj_define (idxname, GTXT ("OpenMP Parallel Region"), |
| NTXT ("CPRID"), NULL, NULL); |
| int idxtype = dbeSession->findIndexSpaceByName (idxname); |
| if (idxtype < 0) |
| { |
| delete pregData; |
| return; |
| } |
| ompavail = true; |
| |
| // Pre-create parallel region with id == 0 |
| Histable *preg0 = dbeSession->createIndexObject (idxtype, (int64_t) 0); |
| preg0->set_name (dbe_strdup (GTXT ("Implicit OpenMP Parallel Region"))); |
| |
| // Take care of the progress bar |
| char *msg = dbe_sprintf (GTXT ("Processing OpenMP Parallel Region Data: %s"), |
| get_basename (expt_name)); |
| theApplication->set_progress (0, msg); |
| free (msg); |
| long deltaReport = 1000; |
| long nextReport = 0; |
| long errors_found = 0; |
| Vector<Histable*> pregs; |
| |
| long size = dDscr->getSize (); |
| for (long i = 0; i < size; ++i) |
| { |
| if (i == nextReport) |
| { |
| int percent = (int) (i * 100 / size); |
| if (percent > 0) |
| theApplication->set_progress (percent, NULL); |
| nextReport += deltaReport; |
| } |
| |
| uint32_t thrid = dDscr->getIntValue (PROP_THRID, i); |
| hrtime_t tstamp = dDscr->getLongValue (PROP_TSTAMP, i); |
| uint64_t cprid = dDscr->getLongValue (PROP_CPRID, i); // omptrace CPRID |
| mapPRid->put (thrid, tstamp, cprid); |
| |
| pregs.reset (); |
| /* |
| * We will use 2 pointers to make sure there is no loop. |
| * First pointer "curpreg" goes to the next element, |
| * second pointer "curpreg_loop_control" goes to the next->next element. |
| * If these pointers have the same value - there is a loop. |
| */ |
| uint64_t curpreg_loop_control = cprid; |
| Datum tval_loop_control; |
| if (curpreg_loop_control != 0) |
| { |
| tval_loop_control.setUINT64 (curpreg_loop_control); |
| long idx = pregData->getIdxByVals (&tval_loop_control, DataView::REL_EQ); |
| if (idx < 0) |
| curpreg_loop_control = 0; |
| else |
| curpreg_loop_control = pregData->getLongValue (PROP_PPRID, idx); |
| } |
| for (uint64_t curpreg = cprid; curpreg != 0;) |
| { |
| Histable *val = NULL; |
| Datum tval; |
| tval.setUINT64 (curpreg); |
| long idx = pregData->getIdxByVals (&tval, DataView::REL_EQ); |
| if (idx < 0) |
| break; |
| /* |
| * Check if there is a loop |
| */ |
| if (0 != curpreg_loop_control) |
| { |
| if (curpreg == curpreg_loop_control) |
| { |
| errors_found++; |
| if (1 == errors_found) |
| { |
| Emsg *m = new Emsg (CMSG_WARN, GTXT ("*** Warning: circular links in OMP regions; data may not be correct.")); |
| warnq->append (m); |
| } |
| break; |
| } |
| } |
| uint64_t pragmapc = pregData->getLongValue (PROP_PRPC, idx); |
| DbeInstr *instr = map_Vaddr_to_PC (pragmapc, tstamp); |
| if (instr == NULL) |
| { |
| break; |
| } |
| val = instr; |
| DbeLine *dbeline = (DbeLine*) instr->convertto (Histable::LINE); |
| if (dbeline->lineno > 0) |
| { |
| if (instr->func->usrfunc) |
| dbeline = dbeline->sourceFile->find_dbeline |
| (instr->func->usrfunc, dbeline->lineno); |
| dbeline->set_flag (DbeLine::OMPPRAGMA); |
| val = dbeline; |
| } |
| val = dbeSession->createIndexObject (idxtype, val); |
| pregs.append (val); |
| |
| curpreg = pregData->getLongValue (PROP_PPRID, idx); |
| /* |
| * Update curpreg_loop_control |
| */ |
| if (0 != curpreg_loop_control) |
| { |
| tval_loop_control.setUINT64 (curpreg_loop_control); |
| idx = pregData->getIdxByVals |
| (&tval_loop_control, DataView::REL_EQ); |
| if (idx < 0) |
| curpreg_loop_control = 0; |
| else |
| { |
| curpreg_loop_control = pregData->getLongValue |
| (PROP_PPRID, idx); |
| tval_loop_control.setUINT64 (curpreg_loop_control); |
| idx = pregData->getIdxByVals |
| (&tval_loop_control, DataView::REL_EQ); |
| if (idx < 0) |
| curpreg_loop_control = 0; |
| else |
| curpreg_loop_control = pregData->getLongValue |
| (PROP_PPRID, idx); |
| } |
| } |
| } |
| pregs.append (preg0); |
| void *prstack = cstack->add_stack (&pregs); |
| mapPReg->put (thrid, tstamp, prstack); |
| } |
| theApplication->set_progress (0, NTXT ("")); |
| delete pregData; |
| } |
| |
| void |
| Experiment::read_omp_task () |
| { |
| // Task description |
| DataDescriptor *taskDataDdscr = getDataDescriptor (DATA_OMP5); |
| if (taskDataDdscr == NULL) |
| return; |
| |
| //7035272: previously, DataView was global; now it's local...is this OK? |
| DataView *taskData = taskDataDdscr->createView (); |
| taskData->sort (PROP_TSKID); // omptrace PROP_TSKID |
| |
| // OpenMP enter task events |
| DataDescriptor *dDscr = getDataDescriptor (DATA_OMP3); |
| if (dDscr == NULL || dDscr->getSize () == 0) |
| { |
| delete taskData; |
| return; |
| } |
| |
| char *idxname = NTXT ("OMP_task"); |
| // delete a possible error message. Ugly. |
| delete dbeSession->indxobj_define (idxname, GTXT ("OpenMP Task"), NTXT ("TSKID"), NULL, NULL); |
| int idxtype = dbeSession->findIndexSpaceByName (idxname); |
| if (idxtype < 0) |
| { |
| delete taskData; |
| return; |
| } |
| ompavail = true; |
| |
| // Pre-create task with id == 0 |
| Histable *task0 = dbeSession->createIndexObject (idxtype, (int64_t) 0); |
| task0->set_name (dbe_strdup (GTXT ("OpenMP Task from Implicit Parallel Region"))); |
| |
| // Take care of the progress bar |
| char *msg = dbe_sprintf (GTXT ("Processing OpenMP Task Data: %s"), get_basename (expt_name)); |
| theApplication->set_progress (0, msg); |
| free (msg); |
| long deltaReport = 1000; |
| long nextReport = 0; |
| |
| Vector<Histable*> tasks; |
| long size = dDscr->getSize (); |
| long errors_found = 0; |
| for (long i = 0; i < size; ++i) |
| { |
| if (i == nextReport) |
| { |
| int percent = (int) (i * 100 / size); |
| if (percent > 0) |
| theApplication->set_progress (percent, NULL); |
| nextReport += deltaReport; |
| } |
| |
| uint32_t thrid = dDscr->getIntValue (PROP_THRID, i); |
| hrtime_t tstamp = dDscr->getLongValue (PROP_TSTAMP, i); |
| uint64_t tskid = dDscr->getLongValue (PROP_TSKID, i); //omptrace TSKID |
| tasks.reset (); |
| /* |
| * We will use 2 pointers to make sure there is no loop. |
| * First pointer "curtsk" goes to the next element, |
| * second pointer "curtsk_loop_control" goes to the next->next element. |
| * If these pointers have the same value - there is a loop. |
| */ |
| uint64_t curtsk_loop_control = tskid; |
| Datum tval_loop_control; |
| if (c
|