blob: 1378ad5ce073032735961b51d459afc77b1b806a [file] [log] [blame]
/* 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