mirror of
https://sourceware.org/git/binutils-gdb.git
synced 2025-02-17 13:10:12 +08:00
gprofng/ChangeLog 2022-05-27 Vladimir Mezentsev <vladimir.mezentsev@oracle.com> PR gprofng/28983 PR gprofng/29143 * src/Experiment.cc (write_header): Fix argument for ctime. Fix -Wformat= warnings. * src/Dbe.cc: Likewise. * src/DwarfLib.h: Fix [-Wsign-compare] warnings. * src/Experiment.h: Likewise. * src/ipc.cc: Fix -Wformat= warnings.
6966 lines
189 KiB
C++
6966 lines
189 KiB
C++
/* Copyright (C) 2021 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 ("er_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;
|
|
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);
|
|
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 (curtsk_loop_control != 0)
|
|
{
|
|
tval_loop_control.setUINT64 (curtsk_loop_control);
|
|
long idx = taskData->getIdxByVals (&tval_loop_control, DataView::REL_EQ);
|
|
if (idx < 0)
|
|
curtsk_loop_control = 0;
|
|
else
|
|
curtsk_loop_control = taskData->getLongValue (PROP_PTSKID, idx);
|
|
}
|
|
for (uint64_t curtsk = tskid; curtsk != 0;)
|
|
{
|
|
Histable *val = NULL;
|
|
|
|
Datum tval;
|
|
tval.setUINT64 (curtsk);
|
|
long idx = taskData->getIdxByVals (&tval, DataView::REL_EQ);
|
|
if (idx < 0)
|
|
break;
|
|
/*
|
|
* Check if there is a loop
|
|
*/
|
|
if (0 != curtsk_loop_control)
|
|
{
|
|
if (curtsk == curtsk_loop_control)
|
|
{
|
|
errors_found++;
|
|
if (1 == errors_found)
|
|
{
|
|
Emsg *m = new Emsg (CMSG_WARN, GTXT ("*** Warning: circular links in OMP tasks; data may not be correct."));
|
|
warnq->append (m);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
uint64_t pragmapc = taskData->getLongValue (PROP_PRPC, idx);
|
|
DbeInstr *instr = map_Vaddr_to_PC (pragmapc, tstamp);
|
|
if (instr == NULL)
|
|
break;
|
|
val = instr;
|
|
DbeLine *dbeline = (DbeLine*) instr->convertto (Histable::LINE);
|
|
if (dbeline->lineno > 0)
|
|
{
|
|
if (instr->func->usrfunc)
|
|
dbeline = dbeline->sourceFile->find_dbeline
|
|
(instr->func->usrfunc, dbeline->lineno);
|
|
dbeline->set_flag (DbeLine::OMPPRAGMA);
|
|
val = dbeline;
|
|
}
|
|
val = dbeSession->createIndexObject (idxtype, val);
|
|
tasks.append (val);
|
|
|
|
curtsk = taskData->getLongValue (PROP_PTSKID, idx);
|
|
/*
|
|
* Update curtsk_loop_control
|
|
*/
|
|
if (0 != curtsk_loop_control)
|
|
{
|
|
tval_loop_control.setUINT64 (curtsk_loop_control);
|
|
idx = taskData->getIdxByVals (&tval_loop_control, DataView::REL_EQ);
|
|
if (idx < 0)
|
|
curtsk_loop_control = 0;
|
|
else
|
|
{
|
|
curtsk_loop_control = taskData->getLongValue (PROP_PTSKID, idx);
|
|
tval_loop_control.setUINT64 (curtsk_loop_control);
|
|
idx = taskData->getIdxByVals (&tval_loop_control,
|
|
DataView::REL_EQ);
|
|
if (idx < 0)
|
|
curtsk_loop_control = 0;
|
|
else
|
|
curtsk_loop_control = taskData->getLongValue (PROP_PTSKID,
|
|
idx);
|
|
}
|
|
}
|
|
}
|
|
tasks.append (task0);
|
|
void *tskstack = cstack->add_stack (&tasks);
|
|
mapTask->put (thrid, tstamp, tskstack);
|
|
}
|
|
theApplication->set_progress (0, NTXT (""));
|
|
delete taskData;
|
|
}
|
|
|
|
void
|
|
Experiment::read_omp_file ()
|
|
{
|
|
// DATA_OMP2 table is common between OpenMP 2.5 and 3.0 profiling
|
|
DataDescriptor *dDscr = getDataDescriptor (DATA_OMP2);
|
|
if (dDscr == NULL)
|
|
return;
|
|
if (dDscr->getSize () == 0)
|
|
{
|
|
char *base_name = get_basename (expt_name);
|
|
char *msg = dbe_sprintf (GTXT ("Loading OpenMP Data: %s"), base_name);
|
|
read_data_file (SP_OMPTRACE_FILE, msg);
|
|
free (msg);
|
|
|
|
// OpenMP fork events
|
|
dDscr = getDataDescriptor (DATA_OMP);
|
|
long sz = dDscr->getSize ();
|
|
if (sz > 0)
|
|
{
|
|
// progress bar
|
|
msg = dbe_sprintf (GTXT ("Processing OpenMP Parallel Region Data: %s"),
|
|
base_name);
|
|
theApplication->set_progress (0, msg);
|
|
free (msg);
|
|
long deltaReport = 5000;
|
|
long nextReport = 0;
|
|
for (int i = 0; i < sz; ++i)
|
|
{
|
|
if (i == nextReport)
|
|
{
|
|
int percent = (int) (i * 100 / sz);
|
|
if (percent > 0)
|
|
theApplication->set_progress (percent, NULL);
|
|
nextReport += deltaReport;
|
|
}
|
|
uint32_t thrid = dDscr->getIntValue (PROP_THRID, i);
|
|
hrtime_t tstamp = dDscr->getLongValue (PROP_TSTAMP, i);
|
|
uint64_t cprid = dDscr->getLongValue (PROP_CPRID, i); //omptrace
|
|
mapPRid->put (thrid, tstamp, cprid);
|
|
}
|
|
theApplication->set_progress (0, NTXT (""));
|
|
|
|
ompavail = true;
|
|
openMPdata = dDscr->createView ();
|
|
openMPdata->sort (PROP_CPRID); // omptrace PROP_CPRID
|
|
|
|
// thread enters parreg events
|
|
dDscr = getDataDescriptor (DATA_OMP2);
|
|
sz = dDscr->getSize ();
|
|
|
|
// progress bar
|
|
msg = dbe_sprintf (GTXT ("Processing OpenMP Parallel Region Data: %s"),
|
|
base_name);
|
|
theApplication->set_progress (0, msg);
|
|
free (msg);
|
|
deltaReport = 5000;
|
|
nextReport = 0;
|
|
|
|
for (int i = 0; i < sz; ++i)
|
|
{
|
|
if (i == nextReport)
|
|
{
|
|
int percent = (int) (i * 100 / sz);
|
|
if (percent > 0)
|
|
theApplication->set_progress (percent, NULL);
|
|
nextReport += deltaReport;
|
|
}
|
|
uint32_t thrid = dDscr->getIntValue (PROP_THRID, i);
|
|
hrtime_t tstamp = dDscr->getLongValue (PROP_TSTAMP, i);
|
|
uint64_t cprid = dDscr->getLongValue (PROP_CPRID, i); //omptrace
|
|
mapPRid->put (thrid, tstamp, cprid);
|
|
}
|
|
theApplication->set_progress (0, NTXT (""));
|
|
}
|
|
else
|
|
{
|
|
read_omp_preg ();
|
|
read_omp_task ();
|
|
}
|
|
if (ompavail && coll_params.profile_mode)
|
|
{
|
|
dbeSession->status_ompavail = 1;
|
|
register_metric (Metric::OMP_WORK);
|
|
register_metric (Metric::OMP_WAIT);
|
|
register_metric (Metric::OMP_OVHD);
|
|
if (coll_params.lms_magic_id == LMS_MAGIC_ID_SOLARIS)
|
|
register_metric (Metric::OMP_MASTER_THREAD);
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
Experiment::read_ifreq_file ()
|
|
{
|
|
char *fname = dbe_sprintf (NTXT ("%s/%s"), expt_name, SP_IFREQ_FILE);
|
|
FILE *f = fopen (fname, NTXT ("r"));
|
|
free (fname);
|
|
if (f == NULL)
|
|
{
|
|
ifreqavail = false;
|
|
return;
|
|
}
|
|
ifreqavail = true;
|
|
ifreqq = new Emsgqueue (NTXT ("ifreqq"));
|
|
|
|
while (1)
|
|
{
|
|
Emsg *m;
|
|
char str[MAXPATHLEN];
|
|
char *e = fgets (str, ((int) sizeof (str)) - 1, f);
|
|
if (e == NULL)
|
|
{
|
|
// end the list from the experiment
|
|
m = new Emsg (CMSG_COMMENT,
|
|
GTXT ("============================================================"));
|
|
ifreqq->append (m);
|
|
break;
|
|
}
|
|
// get the string
|
|
size_t i = strlen (str);
|
|
if (i > 0 && str[i - 1] == '\n')
|
|
// remove trailing nl
|
|
str[i - 1] = 0;
|
|
// and append it
|
|
m = new Emsg (CMSG_COMMENT, str);
|
|
ifreqq->append (m);
|
|
}
|
|
(void) fclose (f);
|
|
}
|
|
|
|
Experiment *
|
|
Experiment::getBaseFounder ()
|
|
{
|
|
if (baseFounder)
|
|
return baseFounder;
|
|
Experiment *founder = this;
|
|
Experiment *parent = founder->founder_exp;
|
|
while (parent)
|
|
{
|
|
founder = parent;
|
|
parent = founder->founder_exp;
|
|
}
|
|
baseFounder = founder;
|
|
return baseFounder;
|
|
}
|
|
|
|
hrtime_t
|
|
Experiment::getRelativeStartTime ()
|
|
{
|
|
if (exp_rel_start_time_set)
|
|
return exp_rel_start_time;
|
|
Experiment *founder = getBaseFounder ();
|
|
hrtime_t child_start = this->getStartTime ();
|
|
hrtime_t founder_start = founder->getStartTime ();
|
|
exp_rel_start_time = child_start - founder_start;
|
|
if (child_start == 0 && founder_start)
|
|
exp_rel_start_time = 0; // when descendents have incomplete log.xml
|
|
exp_rel_start_time_set = true;
|
|
return exp_rel_start_time;
|
|
}
|
|
|
|
DataDescriptor *
|
|
Experiment::get_raw_events (int data_id)
|
|
{
|
|
DataDescriptor *dDscr;
|
|
switch (data_id)
|
|
{
|
|
case DATA_CLOCK:
|
|
dDscr = get_profile_events ();
|
|
break;
|
|
case DATA_SYNCH:
|
|
dDscr = get_sync_events ();
|
|
break;
|
|
case DATA_HWC:
|
|
dDscr = get_hwc_events ();
|
|
break;
|
|
case DATA_HEAP:
|
|
dDscr = get_heap_events ();
|
|
break;
|
|
case DATA_HEAPSZ:
|
|
dDscr = get_heapsz_events ();
|
|
break;
|
|
case DATA_IOTRACE:
|
|
dDscr = get_iotrace_events ();
|
|
break;
|
|
case DATA_RACE:
|
|
dDscr = get_race_events ();
|
|
break;
|
|
case DATA_DLCK:
|
|
dDscr = get_deadlock_events ();
|
|
break;
|
|
case DATA_SAMPLE:
|
|
dDscr = get_sample_events ();
|
|
break;
|
|
case DATA_GCEVENT:
|
|
dDscr = get_gc_events ();
|
|
break;
|
|
default:
|
|
dDscr = NULL;
|
|
break;
|
|
}
|
|
return dDscr;
|
|
}
|
|
|
|
int
|
|
Experiment::base_data_id (int data_id)
|
|
{
|
|
switch (data_id)
|
|
{
|
|
case DATA_HEAPSZ:
|
|
return DATA_HEAP; // DATA_HEAPSZ DataView is based on DATA_HEAP's DataView
|
|
default:
|
|
break;
|
|
}
|
|
return data_id;
|
|
}
|
|
|
|
DataView *
|
|
Experiment::create_derived_data_view (int data_id, DataView *dview)
|
|
{
|
|
// dview contains filtered packets
|
|
switch (data_id)
|
|
{
|
|
case DATA_HEAPSZ:
|
|
return create_heapsz_data_view (dview);
|
|
default:
|
|
break;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
DataDescriptor *
|
|
Experiment::get_profile_events ()
|
|
{
|
|
DataDescriptor *dDscr = getDataDescriptor (DATA_CLOCK);
|
|
if (dDscr == NULL)
|
|
return NULL;
|
|
if (dDscr->getSize () == 0)
|
|
{
|
|
char *base_name = get_basename (expt_name);
|
|
char *msg = dbe_sprintf (GTXT ("Loading Profile Data: %s"), base_name);
|
|
read_data_file (SP_PROFILE_FILE, msg);
|
|
free (msg);
|
|
add_evt_time_to_profile_events (dDscr);
|
|
resolve_frame_info (dDscr);
|
|
}
|
|
else if (!dDscr->isResolveFrInfoDone ())
|
|
resolve_frame_info (dDscr);
|
|
return dDscr;
|
|
}
|
|
|
|
void
|
|
Experiment::add_evt_time_to_profile_events (DataDescriptor *dDscr)
|
|
{
|
|
if (coll_params.lms_magic_id != LMS_MAGIC_ID_SOLARIS)
|
|
return;
|
|
|
|
DataView *dview = dDscr->createView ();
|
|
dview->sort (PROP_THRID, PROP_TSTAMP);
|
|
|
|
// add PROP_EVT_TIME
|
|
PropDescr* tmp_propDscr = new PropDescr (PROP_EVT_TIME, "EVT_TIME");
|
|
tmp_propDscr->uname = dbe_strdup (GTXT ("Event duration"));
|
|
tmp_propDscr->vtype = TYPE_INT64;
|
|
dDscr->addProperty (tmp_propDscr);
|
|
|
|
long sz = dview->getSize ();
|
|
long long ptimer_usec = get_params ()->ptimer_usec;
|
|
for (long i = 0; i < sz; i++)
|
|
{
|
|
int next_sample;
|
|
int jj;
|
|
{
|
|
hrtime_t this_tstamp = dview->getLongValue (PROP_TSTAMP, i);
|
|
long this_thrid = dview->getLongValue (PROP_THRID, i);
|
|
for (jj = i + 1; jj < sz; jj++)
|
|
{
|
|
hrtime_t tmp_tstamp = dview->getLongValue (PROP_TSTAMP, jj);
|
|
if (tmp_tstamp != this_tstamp)
|
|
break;
|
|
long tmp_thrid = dview->getLongValue (PROP_THRID, jj);
|
|
if (tmp_thrid != this_thrid)
|
|
break;
|
|
}
|
|
next_sample = jj;
|
|
}
|
|
|
|
long nticks = 0;
|
|
for (jj = i; jj < next_sample; jj++)
|
|
nticks += dview->getLongValue (PROP_NTICK, jj);
|
|
if (nticks <= 1)
|
|
continue; // no duration
|
|
|
|
nticks--;
|
|
hrtime_t duration = ptimer_usec * 1000LL * nticks; // nanoseconds
|
|
for (jj = i; jj < next_sample; jj++)
|
|
dview->setValue (PROP_EVT_TIME, jj, duration);
|
|
i = jj - 1;
|
|
}
|
|
delete dview;
|
|
}
|
|
|
|
DataDescriptor *
|
|
Experiment::get_sync_events ()
|
|
{
|
|
DataDescriptor *dDscr = getDataDescriptor (DATA_SYNCH);
|
|
if (dDscr == NULL)
|
|
return NULL;
|
|
if (dDscr->getSize () > 0)
|
|
return dDscr;
|
|
|
|
// fetch data
|
|
{
|
|
char *base_name = get_basename (expt_name);
|
|
char *msg = dbe_sprintf (GTXT ("Loading Synctrace Data: %s"), base_name);
|
|
read_data_file (SP_SYNCTRACE_FILE, msg);
|
|
free (msg);
|
|
resolve_frame_info (dDscr);
|
|
}
|
|
|
|
// check for PROP_EVT_TIME
|
|
PropDescr *tmp_propDscr = dDscr->getProp (PROP_EVT_TIME);
|
|
if (tmp_propDscr)
|
|
return dDscr;
|
|
|
|
// add PROP_EVT_TIME
|
|
tmp_propDscr = new PropDescr (PROP_EVT_TIME, "EVT_TIME");
|
|
tmp_propDscr->uname = dbe_strdup (GTXT ("Event duration"));
|
|
tmp_propDscr->vtype = TYPE_INT64;
|
|
dDscr->addProperty (tmp_propDscr);
|
|
|
|
long sz = dDscr->getSize ();
|
|
for (long i = 0; i < sz; i++)
|
|
{
|
|
uint64_t event_duration = dDscr->getLongValue (PROP_TSTAMP, i);
|
|
event_duration -= dDscr->getLongValue (PROP_SRQST, i);
|
|
dDscr->setValue (PROP_EVT_TIME, i, event_duration);
|
|
}
|
|
return dDscr;
|
|
}
|
|
|
|
DataDescriptor *
|
|
Experiment::get_hwc_events ()
|
|
{
|
|
DataDescriptor *dDscr = getDataDescriptor (DATA_HWC);
|
|
if (dDscr == NULL)
|
|
return NULL;
|
|
if (dDscr->getSize () == 0)
|
|
{
|
|
char *base_name = get_basename (expt_name);
|
|
char *msg = dbe_sprintf (GTXT ("Loading HW Profile Data: %s"), base_name);
|
|
|
|
// clear HWC event stats
|
|
dsevents = 0;
|
|
dsnoxhwcevents = 0;
|
|
read_data_file (SP_HWCNTR_FILE, msg);
|
|
free (msg);
|
|
resolve_frame_info (dDscr);
|
|
|
|
// describe the HW counters in PropDescr
|
|
PropDescr *prop = dDscr->getProp (PROP_HWCTAG);
|
|
if (prop)
|
|
{
|
|
Collection_params *cparam = get_params ();
|
|
if (cparam->hw_mode != 0)
|
|
for (int aux = 0; aux < MAX_HWCOUNT; aux++)
|
|
if (cparam->hw_aux_name[aux])
|
|
{
|
|
const char* cmdname = cparam->hw_aux_name[aux];
|
|
const char* uname = cparam->hw_username[aux];
|
|
prop->addState (aux, cmdname, uname);
|
|
}
|
|
}
|
|
else
|
|
assert (0);
|
|
|
|
double dserrrate = 100.0 * ((double) dsnoxhwcevents) / ((double) dsevents);
|
|
if ((dsevents > 0) && (dserrrate > 10.0))
|
|
{
|
|
// warn the user that rate is high
|
|
StringBuilder sb;
|
|
if (dbeSession->check_ignore_no_xhwcprof ())
|
|
sb.sprintf (
|
|
GTXT ("Warning: experiment %s has %.1f%%%% (%lld of %lld) dataspace events that were accepted\n without verification; data may be incorrect or misleading\n recompile with -xhwcprof and rerecord to get better data\n"),
|
|
base_name, dserrrate, (long long) dsnoxhwcevents,
|
|
(long long) dsevents);
|
|
else
|
|
sb.sprintf (
|
|
GTXT ("Warning: experiment %s has %.1f%%%% (%lld of %lld) dataspace events that could not be verified\n recompile with -xhwcprof and rerecord to get better data\n"),
|
|
base_name, dserrrate, (long long) dsnoxhwcevents,
|
|
(long long) dsevents);
|
|
errorq->append (new Emsg (CMSG_WARN, sb));
|
|
}
|
|
|
|
// see if we've scanned the data
|
|
if (hwc_scanned == 0)
|
|
{
|
|
// no, scan the packets to see how many are bogus, or represent lost interrupts
|
|
long hwc_cnt = 0;
|
|
|
|
// loop over the packets, counting the bad ones
|
|
if (hwc_bogus != 0 || hwc_lost_int != 0)
|
|
{
|
|
// hwc counter data had bogus packets and/or packets reflecting lost interrupts
|
|
double bogus_rate = 100. * (double) hwc_bogus / (double) hwc_cnt;
|
|
if (bogus_rate > 5.)
|
|
{
|
|
StringBuilder sb;
|
|
sb.sprintf (
|
|
GTXT ("WARNING: Too many invalid HW counter profile events (%ld/%ld = %3.2f%%) in experiment %d (`%s'); data may be unreliable"),
|
|
(long) hwc_bogus, (long) hwc_cnt, bogus_rate,
|
|
(int) userExpId, base_name);
|
|
Emsg *m = new Emsg (CMSG_WARN, sb);
|
|
warnq->append (m);
|
|
}
|
|
hwc_scanned = 1;
|
|
}
|
|
}
|
|
}
|
|
return dDscr;
|
|
}
|
|
|
|
DataDescriptor *
|
|
Experiment::get_iotrace_events ()
|
|
{
|
|
DataDescriptor *dDscr = getDataDescriptor (DATA_IOTRACE);
|
|
if (dDscr == NULL)
|
|
return NULL;
|
|
|
|
if (dDscr->getSize () > 0)
|
|
return dDscr;
|
|
|
|
char *base_name = get_basename (expt_name);
|
|
char *msg = dbe_sprintf (GTXT ("Loading IO Trace Data: %s"), base_name);
|
|
read_data_file (SP_IOTRACE_FILE, msg);
|
|
free (msg);
|
|
|
|
if (dDscr->getSize () == 0)
|
|
return dDscr;
|
|
resolve_frame_info (dDscr);
|
|
|
|
// check for PROP_EVT_TIME
|
|
PropDescr *tmp_propDscr = dDscr->getProp (PROP_EVT_TIME);
|
|
if (tmp_propDscr)
|
|
return dDscr;
|
|
|
|
// add PROP_EVT_TIME
|
|
tmp_propDscr = new PropDescr (PROP_EVT_TIME, "EVT_TIME");
|
|
tmp_propDscr->uname = dbe_strdup (GTXT ("Event duration"));
|
|
tmp_propDscr->vtype = TYPE_INT64;
|
|
dDscr->addProperty (tmp_propDscr);
|
|
|
|
// add PROP_IOVFD
|
|
tmp_propDscr = new PropDescr (PROP_IOVFD, "IOVFD");
|
|
tmp_propDscr->uname = dbe_strdup (GTXT ("Virtual File Descriptor"));
|
|
tmp_propDscr->vtype = TYPE_INT64;
|
|
dDscr->addProperty (tmp_propDscr);
|
|
|
|
delete fDataMap;
|
|
fDataMap = new DefaultMap<int64_t, FileData*>;
|
|
|
|
delete vFdMap;
|
|
vFdMap = new DefaultMap<int, int64_t>;
|
|
|
|
static int64_t virtualFd = 0;
|
|
|
|
FileData *fData;
|
|
virtualFd += 10;
|
|
fData = fDataMap->get (VIRTUAL_FD_STDIN);
|
|
if (fData == NULL)
|
|
{
|
|
fData = new FileData (STDIN_FILENAME);
|
|
fData->setVirtualFd (VIRTUAL_FD_STDIN);
|
|
fData->id = VIRTUAL_FD_STDIN;
|
|
fData->setFileDes (STDIN_FD);
|
|
fDataMap->put (VIRTUAL_FD_STDIN, fData);
|
|
vFdMap->put (STDIN_FD, VIRTUAL_FD_STDIN);
|
|
}
|
|
|
|
fData = fDataMap->get (VIRTUAL_FD_STDOUT);
|
|
if (fData == NULL)
|
|
{
|
|
fData = new FileData (STDOUT_FILENAME);
|
|
fData->setVirtualFd (VIRTUAL_FD_STDOUT);
|
|
fData->id = VIRTUAL_FD_STDOUT;
|
|
fData->setFileDes (STDOUT_FD);
|
|
fDataMap->put (VIRTUAL_FD_STDOUT, fData);
|
|
vFdMap->put (STDOUT_FD, VIRTUAL_FD_STDOUT);
|
|
}
|
|
|
|
fData = fDataMap->get (VIRTUAL_FD_STDERR);
|
|
if (fData == NULL)
|
|
{
|
|
fData = new FileData (STDERR_FILENAME);
|
|
fData->setVirtualFd (VIRTUAL_FD_STDERR);
|
|
fData->id = VIRTUAL_FD_STDERR;
|
|
fData->setFileDes (STDERR_FD);
|
|
fDataMap->put (VIRTUAL_FD_STDERR, fData);
|
|
vFdMap->put (STDERR_FD, VIRTUAL_FD_STDERR);
|
|
}
|
|
|
|
fData = fDataMap->get (VIRTUAL_FD_OTHERIO);
|
|
if (fData == NULL)
|
|
{
|
|
fData = new FileData (OTHERIO_FILENAME);
|
|
fData->setVirtualFd (VIRTUAL_FD_OTHERIO);
|
|
fData->id = VIRTUAL_FD_OTHERIO;
|
|
fData->setFileDes (OTHERIO_FD);
|
|
fDataMap->put (VIRTUAL_FD_OTHERIO, fData);
|
|
}
|
|
|
|
DataView *dview = dDscr->createView ();
|
|
dview->sort (PROP_TSTAMP);
|
|
long sz = dview->getSize ();
|
|
for (long i = 0; i < sz; i++)
|
|
{
|
|
hrtime_t event_duration = dview->getLongValue (PROP_TSTAMP, i);
|
|
hrtime_t event_start = dview->getLongValue (PROP_IORQST, i);
|
|
if (event_start > 0)
|
|
event_duration -= event_start;
|
|
else
|
|
event_duration = 0;
|
|
dview->setValue (PROP_EVT_TIME, i, event_duration);
|
|
|
|
int32_t fd = -1;
|
|
int64_t vFd = VIRTUAL_FD_NONE;
|
|
char *fName = NULL;
|
|
int32_t origFd = -1;
|
|
StringBuilder *sb = NULL;
|
|
FileData *fDataOrig = NULL;
|
|
FileSystem_type fsType;
|
|
|
|
IOTrace_type ioType = (IOTrace_type) dview->getIntValue (PROP_IOTYPE, i);
|
|
switch (ioType)
|
|
{
|
|
case READ_TRACE:
|
|
case WRITE_TRACE:
|
|
case READ_TRACE_ERROR:
|
|
case WRITE_TRACE_ERROR:
|
|
fd = dview->getIntValue (PROP_IOFD, i);
|
|
vFd = vFdMap->get (fd);
|
|
if (vFd == 0 || vFd == VIRTUAL_FD_NONE
|
|
|| (fData = fDataMap->get (vFd)) == NULL)
|
|
{
|
|
fData = new FileData (UNKNOWNFD_FILENAME);
|
|
fData->setVirtualFd (virtualFd);
|
|
fData->setFsType ("N/A");
|
|
fData->setFileDes (fd);
|
|
fDataMap->put (virtualFd, fData);
|
|
vFdMap->put (fd, virtualFd);
|
|
vFd = virtualFd;
|
|
virtualFd++;
|
|
}
|
|
dview->setValue (PROP_IOVFD, i, vFd);
|
|
break;
|
|
case OPEN_TRACE:
|
|
fName = NULL;
|
|
sb = (StringBuilder*) dview->getObjValue (PROP_IOFNAME, i);
|
|
if (sb != NULL && sb->length () > 0)
|
|
fName = sb->toString ();
|
|
fd = dview->getIntValue (PROP_IOFD, i);
|
|
origFd = dview->getIntValue (PROP_IOOFD, i);
|
|
fsType = (FileSystem_type) dview->getIntValue (PROP_IOFSTYPE, i);
|
|
|
|
if (fName != NULL)
|
|
{
|
|
fData = new FileData (fName);
|
|
fDataMap->put (virtualFd, fData);
|
|
vFdMap->put (fd, virtualFd);
|
|
fData->setFileDes (fd);
|
|
fData->setFsType (fsType);
|
|
fData->setVirtualFd (virtualFd);
|
|
vFd = virtualFd;
|
|
virtualFd++;
|
|
}
|
|
else if (origFd > 0)
|
|
{
|
|
vFd = vFdMap->get (origFd);
|
|
if (vFd == 0 || vFd == VIRTUAL_FD_NONE)
|
|
{
|
|
Dprintf (DEBUG_IO,
|
|
"*** Error I/O tracing: (open) cannot get the virtual file descriptor, fd=%d origFd=%d\n",
|
|
fd, origFd);
|
|
continue;
|
|
}
|
|
else if ((fDataOrig = fDataMap->get (vFd)) == NULL)
|
|
{
|
|
Dprintf (DEBUG_IO,
|
|
"*** Error IO tracing: (open) cannot get original FileData object, fd=%d origFd=%d\n",
|
|
fd, origFd);
|
|
continue;
|
|
}
|
|
else
|
|
{
|
|
fName = fDataOrig->getFileName ();
|
|
fData = new FileData (fName);
|
|
fData->setFileDes (fd);
|
|
fData->setFsType (fDataOrig->getFsType ());
|
|
fData->setVirtualFd (virtualFd);
|
|
fDataMap->put (virtualFd, fData);
|
|
vFdMap->put (fd, virtualFd);
|
|
vFd = virtualFd;
|
|
virtualFd++;
|
|
}
|
|
}
|
|
else if (fd >= 0)
|
|
{
|
|
vFd = vFdMap->get (fd);
|
|
if (vFd == 0 || vFd == VIRTUAL_FD_NONE
|
|
|| (fData = fDataMap->get (vFd)) == NULL)
|
|
{
|
|
fData = new FileData (UNKNOWNFD_FILENAME);
|
|
fData->setVirtualFd (virtualFd);
|
|
fData->setFsType ("N/A");
|
|
fData->setFileDes (fd);
|
|
fDataMap->put (virtualFd, fData);
|
|
vFdMap->put (fd, virtualFd);
|
|
vFd = virtualFd;
|
|
virtualFd++;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Dprintf (DEBUG_IO,
|
|
NTXT ("*** Error IO tracing: (open) unknown open IO type, fd=%d origFd=%d\n"), fd, origFd);
|
|
continue;
|
|
}
|
|
|
|
dview->setValue (PROP_IOVFD, i, vFd);
|
|
break;
|
|
|
|
case OPEN_TRACE_ERROR:
|
|
fName = NULL;
|
|
|
|
sb = (StringBuilder*) dview->getObjValue (PROP_IOFNAME, i);
|
|
if (sb != NULL && sb->length () > 0)
|
|
fName = sb->toString ();
|
|
fd = dview->getIntValue (PROP_IOFD, i);
|
|
origFd = dview->getIntValue (PROP_IOOFD, i);
|
|
fsType = (FileSystem_type) dview->getIntValue (PROP_IOFSTYPE, i);
|
|
|
|
if (fName != NULL)
|
|
{
|
|
fData = new FileData (fName);
|
|
fDataMap->put (virtualFd, fData);
|
|
fData->setFileDes (fd);
|
|
fData->setFsType (fsType);
|
|
fData->setVirtualFd (virtualFd);
|
|
vFd = virtualFd;
|
|
virtualFd++;
|
|
}
|
|
else if (origFd > 0)
|
|
{
|
|
vFd = vFdMap->get (origFd);
|
|
if (vFd == 0 || vFd == VIRTUAL_FD_NONE)
|
|
{
|
|
Dprintf (DEBUG_IO,
|
|
"*** Error IO tracing: (open error) cannot get the virtual file descriptor, fd=%d origFd=%d\n",
|
|
fd, origFd);
|
|
continue;
|
|
}
|
|
else if ((fDataOrig = fDataMap->get (vFd)) == NULL)
|
|
{
|
|
Dprintf (DEBUG_IO,
|
|
"*** Error IO tracing: (open error) cannot get original FileData object, fd=%d origFd=%d\n",
|
|
fd, origFd);
|
|
continue;
|
|
}
|
|
else
|
|
{
|
|
fName = fDataOrig->getFileName ();
|
|
fData = new FileData (fName);
|
|
fData->setFileDes (fd);
|
|
fData->setFsType (fDataOrig->getFsType ());
|
|
fData->setVirtualFd (virtualFd);
|
|
fDataMap->put (virtualFd, fData);
|
|
vFd = virtualFd;
|
|
virtualFd++;
|
|
}
|
|
}
|
|
|
|
dview->setValue (PROP_IOVFD, i, vFd);
|
|
break;
|
|
|
|
case CLOSE_TRACE:
|
|
case CLOSE_TRACE_ERROR:
|
|
fd = dview->getIntValue (PROP_IOFD, i);
|
|
vFd = vFdMap->get (fd);
|
|
if (vFd == 0 || vFd == VIRTUAL_FD_NONE)
|
|
{
|
|
Dprintf (DEBUG_IO,
|
|
"*** Error IO tracing: (close) cannot get the virtual file descriptor, fd=%d\n",
|
|
fd);
|
|
continue;
|
|
}
|
|
fData = fDataMap->get (vFd);
|
|
if (fData == NULL)
|
|
{
|
|
Dprintf (DEBUG_IO,
|
|
"*** Error IO tracing: (close) cannot get the FileData object, fd=%d\n",
|
|
fd);
|
|
continue;
|
|
}
|
|
|
|
vFdMap->put (fd, VIRTUAL_FD_NONE);
|
|
dview->setValue (PROP_IOVFD, i, vFd);
|
|
break;
|
|
|
|
case OTHERIO_TRACE:
|
|
case OTHERIO_TRACE_ERROR:
|
|
vFd = VIRTUAL_FD_OTHERIO;
|
|
fData = fDataMap->get (vFd);
|
|
if (fData == NULL)
|
|
{
|
|
Dprintf (DEBUG_IO,
|
|
"*** Error IO tracing: (other IO) cannot get the FileData object\n");
|
|
continue;
|
|
}
|
|
|
|
dview->setValue (PROP_IOVFD, i, vFd);
|
|
break;
|
|
case IOTRACETYPE_LAST:
|
|
break;
|
|
}
|
|
}
|
|
|
|
delete dview;
|
|
|
|
return dDscr;
|
|
}
|
|
|
|
DataDescriptor *
|
|
Experiment::get_heap_events ()
|
|
{
|
|
DataDescriptor *dDscr = getDataDescriptor (DATA_HEAP);
|
|
if (dDscr == NULL)
|
|
return NULL;
|
|
if (dDscr->getSize () > 0)
|
|
return dDscr;
|
|
|
|
char *base_name = get_basename (expt_name);
|
|
char *msg = dbe_sprintf (GTXT ("Loading Heap Trace Data: %s"), base_name);
|
|
read_data_file (SP_HEAPTRACE_FILE, msg);
|
|
free (msg);
|
|
|
|
if (dDscr->getSize () == 0)
|
|
return dDscr;
|
|
resolve_frame_info (dDscr);
|
|
|
|
// Match FREE to MALLOC
|
|
PropDescr *prop = new PropDescr (PROP_HLEAKED, NTXT ("HLEAKED"));
|
|
prop->uname = dbe_strdup (GTXT ("Bytes Leaked"));
|
|
prop->vtype = TYPE_UINT64;
|
|
dDscr->addProperty (prop);
|
|
|
|
prop = new PropDescr (PROP_HMEM_USAGE, NTXT ("HMEM_USAGE"));
|
|
prop->uname = dbe_strdup (GTXT ("Heap Memory Usage"));
|
|
prop->vtype = TYPE_UINT64;
|
|
dDscr->addProperty (prop);
|
|
|
|
prop = new PropDescr (PROP_HFREED, NTXT ("HFREED"));
|
|
prop->uname = dbe_strdup (GTXT ("Bytes Freed"));
|
|
prop->vtype = TYPE_UINT64;
|
|
dDscr->addProperty (prop);
|
|
|
|
prop = new PropDescr (PROP_HCUR_ALLOCS, NTXT ("HCUR_ALLOCS"));
|
|
prop->uname = dbe_strdup (GTXT ("Net Bytes Allocated"));
|
|
prop->vtype = TYPE_INT64;
|
|
dDscr->addProperty (prop);
|
|
|
|
prop = new PropDescr (PROP_HCUR_LEAKS, NTXT ("HCUR_LEAKS"));
|
|
prop->uname = dbe_strdup (GTXT ("Net Bytes Leaked"));
|
|
prop->vtype = TYPE_UINT64;
|
|
dDscr->addProperty (prop);
|
|
|
|
prop = new PropDescr (PROP_HCUR_NET_ALLOC, NTXT ("HCUR_NET_ALLOC"));
|
|
prop->vtype = TYPE_INT64;
|
|
prop->flags = DDFLAG_NOSHOW;
|
|
dDscr->addProperty (prop);
|
|
|
|
prop = new PropDescr (PROP_DDSCR_LNK, NTXT ("DDSCR_LNK"));
|
|
prop->vtype = TYPE_UINT64;
|
|
prop->flags = DDFLAG_NOSHOW;
|
|
dDscr->addProperty (prop);
|
|
|
|
prop = new PropDescr (PROP_VOIDP_OBJ, NTXT ("VOIDP_OBJ"));
|
|
prop->vtype = TYPE_OBJ;
|
|
prop->flags = DDFLAG_NOSHOW;
|
|
dDscr->addProperty (prop);
|
|
|
|
prop = new PropDescr (PROP_TSTAMP2, NTXT ("TSTAMP2"));
|
|
prop->uname = dbe_strdup (GTXT ("End Timestamp (nanoseconds)"));
|
|
prop->vtype = TYPE_UINT64;
|
|
prop->flags = DDFLAG_NOSHOW;
|
|
dDscr->addProperty (prop);
|
|
|
|
DataView *dview = dDscr->createView ();
|
|
dview->sort (PROP_TSTAMP);
|
|
|
|
// Keep track of memory usage
|
|
Size memoryUsage = 0;
|
|
|
|
HeapMap *heapmap = new HeapMap ();
|
|
long sz = dview->getSize ();
|
|
for (long i = 0; i < sz; i++)
|
|
{
|
|
|
|
Heap_type mtype = (Heap_type) dview->getIntValue (PROP_HTYPE, i);
|
|
Vaddr vaddr = dview->getULongValue (PROP_HVADDR, i);
|
|
Vaddr ovaddr = dview->getULongValue (PROP_HOVADDR, i);
|
|
Size hsize = dview->getULongValue (PROP_HSIZE, i);
|
|
hrtime_t tstamp = dview->getLongValue (PROP_TSTAMP, i);
|
|
|
|
switch (mtype)
|
|
{
|
|
case MALLOC_TRACE:
|
|
dview->setValue (PROP_TSTAMP2, i, (uint64_t) MAX_TIME);
|
|
if (vaddr)
|
|
{
|
|
dview->setValue (PROP_HLEAKED, i, hsize);
|
|
heapmap->allocate (vaddr, i + 1);
|
|
|
|
// Increase heap size
|
|
memoryUsage += hsize;
|
|
dview->setValue (PROP_HMEM_USAGE, i, memoryUsage);
|
|
}
|
|
break;
|
|
|
|
case FREE_TRACE:
|
|
if (vaddr)
|
|
{
|
|
long idx = heapmap->deallocate (vaddr) - 1;
|
|
if (idx >= 0)
|
|
{
|
|
// Decrease heap size
|
|
Size leaked = dview->getLongValue (PROP_HLEAKED, idx);
|
|
memoryUsage -= leaked;
|
|
dview->setValue (PROP_HMEM_USAGE, i, memoryUsage);
|
|
|
|
Size alloc = dview->getLongValue (PROP_HSIZE, idx);
|
|
// update allocation
|
|
dview->setValue (PROP_HLEAKED, idx, (uint64_t) 0);
|
|
dview->setValue (PROP_TSTAMP2, idx, tstamp);
|
|
dview->setValue (PROP_DDSCR_LNK, idx, dview->getIdByIdx (i) + 1);
|
|
// update this event
|
|
dview->setValue (PROP_HFREED, i, alloc);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case REALLOC_TRACE:
|
|
dview->setValue (PROP_TSTAMP2, i, (uint64_t) MAX_TIME);
|
|
if (ovaddr)
|
|
{
|
|
long idx = heapmap->deallocate (ovaddr) - 1;
|
|
if (idx >= 0)
|
|
{
|
|
// Decrease heap size
|
|
Size leaked = dview->getLongValue (PROP_HLEAKED, idx);
|
|
memoryUsage -= leaked;
|
|
dview->setValue (PROP_HMEM_USAGE, i, memoryUsage);
|
|
|
|
Size alloc = dview->getLongValue (PROP_HSIZE, idx);
|
|
// update allocation
|
|
dview->setValue (PROP_HLEAKED, idx, (uint64_t) 0);
|
|
dview->setValue (PROP_TSTAMP2, idx, tstamp);
|
|
dview->setValue (PROP_DDSCR_LNK, idx, dview->getIdByIdx (i) + 1);
|
|
// update this event
|
|
dview->setValue (PROP_HFREED, i, alloc);
|
|
}
|
|
}
|
|
if (vaddr)
|
|
{
|
|
dview->setValue (PROP_HLEAKED, i, hsize);
|
|
heapmap->allocate (vaddr, i + 1);
|
|
|
|
// Increase heap size
|
|
memoryUsage += hsize;
|
|
dview->setValue (PROP_HMEM_USAGE, i, memoryUsage);
|
|
}
|
|
break;
|
|
case MMAP_TRACE:
|
|
case MUNMAP_TRACE:
|
|
// Adjust the size to be multiple of page_size
|
|
//hsize = (( hsize - 1 ) / page_size + 1 ) * page_size;
|
|
if (vaddr)
|
|
{
|
|
UnmapChunk *list;
|
|
if (mtype == MMAP_TRACE)
|
|
{
|
|
dview->setValue (PROP_TSTAMP2, i, (uint64_t) MAX_TIME);
|
|
dview->setValue (PROP_HLEAKED, i, hsize);
|
|
list = heapmap->mmap (vaddr, hsize, i);
|
|
|
|
// Increase heap size
|
|
memoryUsage += hsize;
|
|
dview->setValue (PROP_HMEM_USAGE, i, memoryUsage);
|
|
}
|
|
else
|
|
{ // MUNMAP_TRACE
|
|
list = heapmap->munmap (vaddr, hsize);
|
|
|
|
// Set allocation size to zero
|
|
// Note: We're currently reusing PROP_HSIZE to mean allocation size
|
|
// If we ever need to save the original HSIZE, we'll need to
|
|
// create a new PROP_* to represent event allocation size
|
|
//
|
|
// For now, tuck the original size away as HOVADDR
|
|
dview->setValue (PROP_HOVADDR, i, (uint64_t) hsize);
|
|
dview->setValue (PROP_HSIZE, i, (uint64_t) 0);
|
|
}
|
|
Size total_freed = 0;
|
|
while (list)
|
|
{
|
|
long idx = list->val;
|
|
total_freed += list->size;
|
|
Size leaked = dview->getLongValue (PROP_HLEAKED, idx);
|
|
|
|
// Decrease heap size
|
|
memoryUsage -= list->size;
|
|
dview->setValue (PROP_HMEM_USAGE, i, memoryUsage);
|
|
|
|
Size leak_update = leaked - list->size;
|
|
// update allocation
|
|
dview->setValue (PROP_HLEAKED, idx, leak_update);
|
|
// update allocation's list of frees
|
|
{
|
|
UnmapChunk *copy = new UnmapChunk;
|
|
heapUnmapEvents->append (copy);
|
|
copy->val = dview->getIdByIdx (i);
|
|
copy->size = list->size;
|
|
copy->next = (UnmapChunk *) dview->getObjValue (PROP_VOIDP_OBJ, idx);
|
|
dview->setObjValue (PROP_VOIDP_OBJ, idx, copy);
|
|
}
|
|
if (leak_update <= 0)
|
|
if (leak_update == 0)
|
|
dview->setValue (PROP_TSTAMP2, idx, tstamp);
|
|
UnmapChunk *t = list;
|
|
list = list->next;
|
|
delete t;
|
|
}
|
|
// update this event
|
|
if (total_freed)
|
|
// only need to write value if it is non-zero
|
|
dview->setValue (PROP_HFREED, i, total_freed);
|
|
}
|
|
break;
|
|
// ignoring HEAPTYPE_LAST, which will never be recorded
|
|
case HEAPTYPE_LAST:
|
|
break;
|
|
}
|
|
}
|
|
delete heapmap;
|
|
delete dview;
|
|
|
|
return dDscr;
|
|
}
|
|
|
|
DataDescriptor *
|
|
Experiment::get_heapsz_events ()
|
|
{
|
|
DataDescriptor *dDscr = getDataDescriptor (DATA_HEAPSZ);
|
|
if (dDscr)
|
|
return dDscr;
|
|
dDscr = get_heap_events (); // derived from DATA_HEAP
|
|
if (dDscr == NULL)
|
|
return NULL;
|
|
dDscr = newDataDescriptor (DATA_HEAPSZ, 0, dDscr);
|
|
return dDscr;
|
|
}
|
|
|
|
static void
|
|
update_heapsz_packet (std::set<long> &pkt_id_set, DataView *dview,
|
|
long alloc_pkt_id, int64_t net_alloc, uint64_t leaks)
|
|
{
|
|
// pkt_id_set: set is updated to include packet
|
|
// alloc_pkt_id: data descriptor id (NOT dview idx)
|
|
// net_alloc: adjustment to net allocation for this packet (note: signed value)
|
|
// leaks: leak bytes to attribute to alloc_pkt_id
|
|
std::pair < std::set<long>::iterator, bool> ret;
|
|
ret = pkt_id_set.insert (alloc_pkt_id); // add to set
|
|
bool new_to_set = ret.second; // was not in set
|
|
if (!new_to_set)
|
|
{
|
|
// Has been seen before, update values
|
|
net_alloc += dview->getDataDescriptorValue (PROP_HCUR_NET_ALLOC, alloc_pkt_id);
|
|
if (leaks)
|
|
{
|
|
uint64_t old = dview->getDataDescriptorValue (PROP_HCUR_LEAKS, alloc_pkt_id);
|
|
if (old != 0)
|
|
leaks = old;
|
|
}
|
|
}
|
|
dview->setDataDescriptorValue (PROP_HCUR_NET_ALLOC, alloc_pkt_id, net_alloc);
|
|
dview->setDataDescriptorValue (PROP_HCUR_LEAKS, alloc_pkt_id, leaks);
|
|
}
|
|
|
|
DataView *
|
|
Experiment::create_heapsz_data_view (DataView *heap_dview)
|
|
{
|
|
// heap_dview has DATA_HEAP _filtered_ packets.
|
|
// This creates, populates, and returns DATA_HEAPSZ DataView
|
|
DataDescriptor *dDscr = get_heapsz_events ();
|
|
if (dDscr == NULL)
|
|
return NULL;
|
|
std::set<long> pkt_id_set;
|
|
DataView *dview = heap_dview;
|
|
long sz = dview->getSize ();
|
|
for (long i = 0; i < sz; i++)
|
|
{
|
|
int64_t hsize = (int64_t) dview->getULongValue (PROP_HSIZE, i);
|
|
uint64_t leaks = dview->getULongValue (PROP_HLEAKED, i);
|
|
long alloc_pkt_id = dview->getIdByIdx (i);
|
|
update_heapsz_packet (pkt_id_set, dview, alloc_pkt_id, hsize, leaks);
|
|
|
|
// linked free
|
|
UnmapChunk *mmap_frees = (UnmapChunk *) dview->getObjValue (PROP_VOIDP_OBJ, i); // mmap metadata
|
|
if (mmap_frees)
|
|
{
|
|
// mmap: all frees associated with this packet
|
|
while (mmap_frees)
|
|
{
|
|
long free_pkt_id = mmap_frees->val;
|
|
int64_t free_sz = mmap_frees->size;
|
|
update_heapsz_packet (pkt_id_set, dview, free_pkt_id, -free_sz, 0);
|
|
mmap_frees = mmap_frees->next;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// malloc: check for associated free
|
|
long free_pkt_id = dview->getLongValue (PROP_DDSCR_LNK, i) - 1;
|
|
if (free_pkt_id >= 0)
|
|
update_heapsz_packet (pkt_id_set, dview, free_pkt_id, -hsize, 0);
|
|
}
|
|
}
|
|
|
|
// create a new DataView based on the filtered-in and associated free events
|
|
std::set<long>::iterator it;
|
|
DataView *heapsz_dview = dDscr->createExtManagedView ();
|
|
for (it = pkt_id_set.begin (); it != pkt_id_set.end (); ++it)
|
|
{
|
|
long ddscr_pkt_id = *it;
|
|
heapsz_dview->appendDataDescriptorId (ddscr_pkt_id);
|
|
}
|
|
compute_heapsz_data_view (heapsz_dview);
|
|
return heapsz_dview;
|
|
}
|
|
|
|
void
|
|
Experiment::compute_heapsz_data_view (DataView *heapsz_dview)
|
|
{
|
|
DataView *dview = heapsz_dview;
|
|
|
|
// Keep track of memory usage
|
|
int64_t currentAllocs = 0;
|
|
Size currentLeaks = 0;
|
|
dview->sort (PROP_TSTAMP);
|
|
long sz = dview->getSize ();
|
|
for (long i = 0; i < sz; i++)
|
|
{
|
|
int64_t net_alloc = dview->getLongValue (PROP_HCUR_NET_ALLOC, i);
|
|
currentAllocs += net_alloc;
|
|
dview->setValue (PROP_HCUR_ALLOCS, i, currentAllocs);
|
|
|
|
Size leaks = dview->getULongValue (PROP_HCUR_LEAKS, i);
|
|
currentLeaks += leaks;
|
|
dview->setValue (PROP_HCUR_LEAKS, i, currentLeaks);
|
|
}
|
|
}
|
|
|
|
void
|
|
Experiment::DBG_memuse (Sample * s)
|
|
{
|
|
DataDescriptor *dDscr = getDataDescriptor (DATA_HEAP);
|
|
if (dDscr == NULL || dDscr->getSize () == 0)
|
|
return;
|
|
|
|
DataView *dview = dDscr->createView ();
|
|
dview->sort (PROP_TSTAMP);
|
|
hrtime_t ts1 = s->get_start_time ();
|
|
hrtime_t ts2 = s->get_end_time ();
|
|
|
|
HeapMap *heapmap = new HeapMap ();
|
|
long sz = dview->getSize ();
|
|
Size maxSize = 0;
|
|
Size curSize = 0;
|
|
hrtime_t maxTime = 0;
|
|
for (long i = 0; i < sz; i++)
|
|
{
|
|
hrtime_t tstamp = dview->getLongValue (PROP_TSTAMP, i);
|
|
if (tstamp < ts1)
|
|
continue;
|
|
if (tstamp >= ts2)
|
|
break;
|
|
|
|
Heap_type mtype = (Heap_type) dview->getIntValue (PROP_HTYPE, i);
|
|
Vaddr vaddr = dview->getULongValue (PROP_HVADDR, i);
|
|
Vaddr ovaddr = dview->getULongValue (PROP_HOVADDR, i);
|
|
switch (mtype)
|
|
{
|
|
case REALLOC_TRACE:
|
|
break;
|
|
case MALLOC_TRACE:
|
|
ovaddr = 0;
|
|
break;
|
|
case FREE_TRACE:
|
|
ovaddr = vaddr;
|
|
vaddr = 0;
|
|
break;
|
|
default:
|
|
vaddr = 0;
|
|
ovaddr = 0;
|
|
break;
|
|
}
|
|
if (ovaddr)
|
|
{
|
|
long idx = heapmap->deallocate (ovaddr) - 1;
|
|
if (idx >= 0)
|
|
curSize -= dview->getULongValue (PROP_HSIZE, idx);
|
|
}
|
|
if (vaddr)
|
|
{
|
|
heapmap->allocate (vaddr, i + 1);
|
|
curSize += dview->getULongValue (PROP_HSIZE, i);
|
|
if (curSize > maxSize)
|
|
{
|
|
maxSize = curSize;
|
|
maxTime = tstamp;
|
|
}
|
|
}
|
|
}
|
|
printf ("SAMPLE=%s (id=%d) MEMUSE=%lld TSTAMP=%lld\n", s->get_start_label (),
|
|
s->get_number (), maxSize, maxTime - getStartTime ());
|
|
delete dview;
|
|
delete heapmap;
|
|
}
|
|
|
|
void
|
|
Experiment::DBG_memuse (const char *sname)
|
|
{
|
|
for (int i = 0; i < samples->size (); ++i)
|
|
{
|
|
Sample *sample = samples->fetch (i);
|
|
if (streq (sname, sample->get_start_label ()))
|
|
{
|
|
DBG_memuse (sample);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
DataDescriptor *
|
|
Experiment::get_race_events ()
|
|
{
|
|
DataDescriptor *dDscr = getDataDescriptor (DATA_RACE);
|
|
if (dDscr == NULL)
|
|
return NULL;
|
|
if (dDscr->getSize () == 0)
|
|
{
|
|
char *base_name = get_basename (expt_name);
|
|
char *msg = dbe_sprintf (GTXT ("Loading Race Data: %s"), base_name);
|
|
read_data_file (SP_RACETRACE_FILE, msg);
|
|
free (msg);
|
|
resolve_frame_info (dDscr);
|
|
}
|
|
return dDscr;
|
|
}
|
|
|
|
DataDescriptor *
|
|
Experiment::get_deadlock_events ()
|
|
{
|
|
DataDescriptor *dDscr = getDataDescriptor (DATA_DLCK);
|
|
if (dDscr == NULL)
|
|
return NULL;
|
|
if (dDscr->getSize () == 0)
|
|
{
|
|
char *base_name = get_basename (expt_name);
|
|
char *msg = dbe_sprintf (GTXT ("Loading Deadlocks Data: %s"), base_name);
|
|
read_data_file (SP_DEADLOCK_FILE, msg);
|
|
free (msg);
|
|
resolve_frame_info (dDscr);
|
|
}
|
|
return dDscr;
|
|
}
|
|
|
|
DataDescriptor *
|
|
Experiment::get_sample_events ()
|
|
{
|
|
DataDescriptor *dDscr = getDataDescriptor (DATA_SAMPLE);
|
|
if (dDscr == NULL)
|
|
return NULL;
|
|
if (dDscr->getSize () > 0)
|
|
return dDscr;
|
|
|
|
// read_overview_file(); //YXXX do this here at some point instead of:
|
|
PropDescr *tmp_propDscr;
|
|
tmp_propDscr = new PropDescr (PROP_SMPLOBJ, NTXT ("SMPLOBJ"));
|
|
tmp_propDscr->uname = NULL;
|
|
tmp_propDscr->vtype = TYPE_OBJ;
|
|
dDscr->addProperty (tmp_propDscr);
|
|
|
|
tmp_propDscr = new PropDescr (PROP_TSTAMP, NTXT ("TSTAMP"));
|
|
tmp_propDscr->uname = dbe_strdup ("High resolution timestamp");
|
|
tmp_propDscr->vtype = TYPE_UINT64;
|
|
dDscr->addProperty (tmp_propDscr);
|
|
|
|
tmp_propDscr = new PropDescr (PROP_SAMPLE, NTXT ("SAMPLE"));
|
|
tmp_propDscr->uname = dbe_strdup ("Sample number");
|
|
tmp_propDscr->vtype = TYPE_UINT64;
|
|
dDscr->addProperty (tmp_propDscr);
|
|
|
|
tmp_propDscr = new PropDescr (PROP_EVT_TIME, NTXT ("EVT_TIME"));
|
|
tmp_propDscr->uname = dbe_strdup ("Event duration");
|
|
tmp_propDscr->vtype = TYPE_UINT64;
|
|
dDscr->addProperty (tmp_propDscr);
|
|
|
|
long ssize = samples->size ();
|
|
for (long ii = 0; ii < ssize; ii++)
|
|
{
|
|
Sample * sample = samples->fetch (ii);
|
|
long recn = dDscr->addRecord ();
|
|
hrtime_t sduration = sample->get_end_time () - sample->get_start_time ();
|
|
dDscr->setObjValue (PROP_SMPLOBJ, recn, sample);
|
|
dDscr->setValue (PROP_SAMPLE, recn, sample->get_number ());
|
|
dDscr->setValue (PROP_TSTAMP, recn, sample->get_end_time ());
|
|
dDscr->setValue (PROP_EVT_TIME, recn, sduration);
|
|
}
|
|
return dDscr;
|
|
}
|
|
|
|
DataDescriptor *
|
|
Experiment::get_gc_events ()
|
|
{
|
|
DataDescriptor *dDscr = getDataDescriptor (DATA_GCEVENT);
|
|
if (dDscr == NULL)
|
|
return NULL;
|
|
if (dDscr->getSize () > 0)
|
|
return dDscr;
|
|
|
|
// read_overview_file(); //YXXX do this here at some point instead of:
|
|
PropDescr *tmp_propDscr;
|
|
tmp_propDscr = new PropDescr (PROP_GCEVENTOBJ, NTXT ("GCEVENTOBJ"));
|
|
tmp_propDscr->uname = NULL;
|
|
tmp_propDscr->vtype = TYPE_OBJ;
|
|
dDscr->addProperty (tmp_propDscr);
|
|
|
|
tmp_propDscr = new PropDescr (PROP_TSTAMP, NTXT ("TSTAMP"));
|
|
tmp_propDscr->uname = dbe_strdup ("High resolution timestamp");
|
|
tmp_propDscr->vtype = TYPE_UINT64;
|
|
dDscr->addProperty (tmp_propDscr);
|
|
|
|
tmp_propDscr = new PropDescr (PROP_GCEVENT, NTXT ("GCEVENT"));
|
|
tmp_propDscr->uname = dbe_strdup ("GCEvent number");
|
|
tmp_propDscr->vtype = TYPE_UINT64;
|
|
dDscr->addProperty (tmp_propDscr);
|
|
|
|
tmp_propDscr = new PropDescr (PROP_EVT_TIME, NTXT ("EVT_TIME"));
|
|
tmp_propDscr->uname = dbe_strdup ("Event duration");
|
|
tmp_propDscr->vtype = TYPE_UINT64;
|
|
dDscr->addProperty (tmp_propDscr);
|
|
|
|
long ssize = gcevents->size ();
|
|
for (long ii = 0; ii < ssize; ii++)
|
|
{
|
|
GCEvent * gcevent = gcevents->fetch (ii);
|
|
long recn = dDscr->addRecord ();
|
|
hrtime_t sduration = gcevent->end - gcevent->start;
|
|
dDscr->setObjValue (PROP_GCEVENTOBJ, recn, gcevent);
|
|
dDscr->setValue (PROP_GCEVENT, recn, gcevent->id);
|
|
dDscr->setValue (PROP_TSTAMP, recn, gcevent->end);
|
|
dDscr->setValue (PROP_EVT_TIME, recn, sduration);
|
|
}
|
|
return dDscr;
|
|
}
|
|
|
|
void
|
|
Experiment::update_last_event (hrtime_t ts/*wall_ts*/)
|
|
{
|
|
if (last_event == ZERO_TIME)
|
|
{
|
|
// not yet initialized
|
|
last_event = ts;
|
|
}
|
|
if (last_event - exp_start_time < ts - exp_start_time)
|
|
// compare deltas to avoid hrtime_t wrap
|
|
last_event = ts;
|
|
}
|
|
|
|
void
|
|
Experiment::write_header ()
|
|
{
|
|
StringBuilder sb;
|
|
|
|
// write commentary to the experiment, describing the parameters
|
|
if (dbeSession->ipc_mode || dbeSession->rdt_mode)
|
|
{
|
|
// In GUI: print start time at the beginning
|
|
time_t t = (time_t) start_sec;
|
|
char *start_time = ctime (&t);
|
|
if (start_time != NULL)
|
|
{
|
|
sb.setLength (0);
|
|
sb.sprintf (GTXT ("Experiment started %s"), start_time);
|
|
commentq->append (new Emsg (CMSG_COMMENT, sb));
|
|
}
|
|
}
|
|
// write message with target arglist
|
|
if (uarglist != NULL)
|
|
{
|
|
sb.setLength (0);
|
|
sb.sprintf (GTXT ("\nTarget command (%s): '%s'"),
|
|
(wsize == W32 ? "32-bit" : "64-bit"), uarglist);
|
|
commentq->append (new Emsg (CMSG_COMMENT, sb));
|
|
}
|
|
|
|
sb.setLength (0);
|
|
sb.sprintf (GTXT ("Process pid %d, ppid %d, pgrp %d, sid %d"),
|
|
pid, ppid, pgrp, sid);
|
|
commentq->append (new Emsg (CMSG_COMMENT, sb));
|
|
|
|
// add comment for user name, if set
|
|
if (username != NULL)
|
|
{
|
|
sb.setLength (0);
|
|
sb.sprintf (GTXT ("User: `%s'"), username);
|
|
commentq->append (new Emsg (CMSG_COMMENT, sb));
|
|
}
|
|
|
|
// add comment for current working directory
|
|
if (ucwd != NULL)
|
|
{
|
|
sb.setLength (0);
|
|
sb.sprintf (GTXT ("Current working directory: %s"), ucwd);
|
|
commentq->append (new Emsg (CMSG_COMMENT, sb));
|
|
}
|
|
|
|
// add comment for collector version string
|
|
if (cversion != NULL)
|
|
{
|
|
char *wstring;
|
|
switch (wsize)
|
|
{
|
|
case Wnone:
|
|
wstring = NTXT ("?");
|
|
break;
|
|
case W32:
|
|
wstring = GTXT ("32-bit");
|
|
break;
|
|
case W64:
|
|
wstring = GTXT ("64-bit");
|
|
break;
|
|
default:
|
|
wstring = NTXT ("??");
|
|
break;
|
|
}
|
|
sb.setLength (0);
|
|
sb.sprintf (GTXT ("Collector version: `%s'; experiment version %d.%d (%s)"),
|
|
cversion, exp_maj_version, exp_min_version, wstring);
|
|
commentq->append (new Emsg (CMSG_COMMENT, sb));
|
|
}
|
|
|
|
// add comment for driver version string (er_kernel)
|
|
if (dversion != NULL)
|
|
{
|
|
sb.setLength (0);
|
|
sb.sprintf (GTXT ("Kernel driver version: `%s'"), dversion);
|
|
commentq->append (new Emsg (CMSG_COMMENT, sb));
|
|
}
|
|
|
|
if (jversion != NULL)
|
|
{
|
|
sb.setLength (0);
|
|
sb.sprintf (GTXT ("JVM version: `%s'"), jversion);
|
|
commentq->append (new Emsg (CMSG_COMMENT, sb));
|
|
}
|
|
|
|
// add comment for hostname, parameters
|
|
if (hostname == NULL)
|
|
hostname = dbe_strdup (GTXT ("unknown"));
|
|
if (os_version == NULL)
|
|
os_version = dbe_strdup (GTXT ("unknown"));
|
|
if (architecture == NULL)
|
|
architecture = dbe_strdup (GTXT ("unknown"));
|
|
sb.setLength (0);
|
|
sb.sprintf (GTXT ("Host `%s', OS `%s', page size %d, architecture `%s'"),
|
|
hostname, os_version, page_size, architecture);
|
|
commentq->append (new Emsg (CMSG_COMMENT, sb));
|
|
|
|
sb.setLength (0);
|
|
if (maxclock != minclock)
|
|
{
|
|
clock = maxclock;
|
|
sb.sprintf (
|
|
GTXT (" %d CPUs, with clocks ranging from %d to %d MHz.; max of %d MHz. assumed"),
|
|
ncpus, minclock, maxclock, clock);
|
|
}
|
|
else
|
|
sb.sprintf (GTXT (" %d CPU%s, clock speed %d MHz."),
|
|
ncpus, (ncpus == 1 ? NTXT ("") : "s"), clock);
|
|
commentq->append (new Emsg (CMSG_COMMENT, sb));
|
|
|
|
// add comment for machine memory size
|
|
if (page_size > 0 && npages > 0)
|
|
{
|
|
long long memsize = ((long long) npages * page_size) / (1024 * 1024);
|
|
sb.setLength (0);
|
|
sb.sprintf (GTXT (" Memory: %d pages @ %d = %lld MB."),
|
|
npages, page_size, memsize);
|
|
commentq->append (new Emsg (CMSG_COMMENT, sb));
|
|
}
|
|
|
|
// add comment for machine memory size
|
|
if (machinemodel != NULL)
|
|
{
|
|
sb.setLength (0);
|
|
sb.sprintf (GTXT (" Machine model: %s"), machinemodel);
|
|
commentq->append (new Emsg (CMSG_COMMENT, sb));
|
|
}
|
|
|
|
// add comment for start time
|
|
time_t t = (time_t) start_sec;
|
|
char *p = ctime (&t);
|
|
sb.setLength (0);
|
|
if (p != NULL)
|
|
sb.sprintf (GTXT ("Experiment started %s"), p);
|
|
else
|
|
sb.sprintf (GTXT ("\nExperiment start not recorded"));
|
|
write_coll_params ();
|
|
commentq->append (new Emsg (CMSG_COMMENT, sb));
|
|
commentq->appendqueue (runlogq);
|
|
runlogq->mark_clear ();
|
|
}
|
|
|
|
void
|
|
Experiment::write_coll_params ()
|
|
{
|
|
StringBuilder sb;
|
|
|
|
// now write the various collection parameters as comments
|
|
sb.setLength (0);
|
|
sb.append (GTXT ("Data collection parameters:"));
|
|
commentq->append (new Emsg (CMSG_COMMENT, sb));
|
|
if (coll_params.profile_mode == 1)
|
|
{
|
|
sb.setLength (0);
|
|
sb.sprintf (GTXT (" Clock-profiling, interval = %d microsecs."),
|
|
(int) (coll_params.ptimer_usec));
|
|
commentq->append (new Emsg (CMSG_COMMENT, sb));
|
|
}
|
|
if (coll_params.sync_mode == 1)
|
|
{
|
|
sb.setLength (0);
|
|
char *scope_str = NTXT ("");
|
|
switch (coll_params.sync_scope)
|
|
{
|
|
case 0:
|
|
scope_str = GTXT ("Native- and Java-APIs");
|
|
break;
|
|
case SYNCSCOPE_JAVA:
|
|
scope_str = GTXT ("JAVA-APIs");
|
|
break;
|
|
case SYNCSCOPE_NATIVE:
|
|
scope_str = GTXT ("Native-APIs");
|
|
break;
|
|
case SYNCSCOPE_JAVA | SYNCSCOPE_NATIVE:
|
|
scope_str = GTXT ("Native- and Java-APIs");
|
|
break;
|
|
}
|
|
if (coll_params.sync_threshold < 0)
|
|
sb.sprintf (GTXT (" Synchronization tracing, threshold = %d microsecs. (calibrated); %s"),
|
|
-coll_params.sync_threshold, scope_str);
|
|
else
|
|
sb.sprintf (GTXT (" Synchronization tracing, threshold = %d microsecs.; %s"),
|
|
coll_params.sync_threshold, scope_str);
|
|
commentq->append (new Emsg (CMSG_COMMENT, sb));
|
|
}
|
|
if (coll_params.heap_mode == 1)
|
|
{
|
|
sb.setLength (0);
|
|
sb.append (GTXT (" Heap tracing"));
|
|
commentq->append (new Emsg (CMSG_COMMENT, sb));
|
|
}
|
|
if (coll_params.io_mode == 1)
|
|
{
|
|
sb.setLength (0);
|
|
sb.append (GTXT (" IO tracing"));
|
|
commentq->append (new Emsg (CMSG_COMMENT, sb));
|
|
}
|
|
if (coll_params.race_mode == 1)
|
|
{
|
|
sb.setLength (0);
|
|
char *race_stack_name;
|
|
switch (coll_params.race_stack)
|
|
{
|
|
case 0:
|
|
race_stack_name = GTXT ("dual-stack");
|
|
break;
|
|
case 1:
|
|
race_stack_name = GTXT ("single-stack");
|
|
break;
|
|
case 2:
|
|
race_stack_name = GTXT ("leaf");
|
|
break;
|
|
default:
|
|
abort ();
|
|
}
|
|
sb.sprintf (GTXT (" Datarace detection, %s"), race_stack_name);
|
|
commentq->append (new Emsg (CMSG_COMMENT, sb));
|
|
}
|
|
if (coll_params.deadlock_mode == 1)
|
|
{
|
|
sb.setLength (0);
|
|
sb.append (GTXT (" Deadlock detection"));
|
|
commentq->append (new Emsg (CMSG_COMMENT, sb));
|
|
}
|
|
if (coll_params.hw_mode == 1)
|
|
{
|
|
sb.setLength (0);
|
|
if (hwc_default == true)
|
|
sb.append (GTXT (" HW counter-profiling (default); counters:"));
|
|
else
|
|
sb.append (GTXT (" HW counter-profiling; counters:"));
|
|
commentq->append (new Emsg (CMSG_COMMENT, sb));
|
|
for (int i = 0; i < MAX_HWCOUNT; i++)
|
|
{
|
|
if (!coll_params.hw_aux_name[i])
|
|
continue;
|
|
sb.setLength (0);
|
|
sb.sprintf (GTXT (" %s, tag %d, interval %d, memop %d"),
|
|
coll_params.hw_aux_name[i], i,
|
|
coll_params.hw_interval[i], coll_params.hw_tpc[i]);
|
|
commentq->append (new Emsg (CMSG_COMMENT, sb));
|
|
}
|
|
}
|
|
if (coll_params.sample_periodic == 1)
|
|
{
|
|
sb.setLength (0);
|
|
sb.sprintf (GTXT (" Periodic sampling, %d secs."),
|
|
coll_params.sample_timer);
|
|
commentq->append (new Emsg (CMSG_COMMENT, sb));
|
|
}
|
|
if (coll_params.limit != 0)
|
|
{
|
|
sb.setLength (0);
|
|
sb.sprintf (GTXT (" Experiment size limit, %d"),
|
|
coll_params.limit);
|
|
commentq->append (new Emsg (CMSG_COMMENT, sb));
|
|
}
|
|
if (coll_params.linetrace != NULL)
|
|
{
|
|
sb.setLength (0);
|
|
sb.sprintf (GTXT (" Follow descendant processes from: %s"),
|
|
coll_params.linetrace);
|
|
commentq->append (new Emsg (CMSG_COMMENT, sb));
|
|
}
|
|
if (coll_params.pause_sig != NULL)
|
|
{
|
|
sb.setLength (0);
|
|
sb.sprintf (GTXT (" Pause signal %s"), coll_params.pause_sig);
|
|
commentq->append (new Emsg (CMSG_COMMENT, sb));
|
|
}
|
|
if (coll_params.sample_sig != NULL)
|
|
{
|
|
sb.setLength (0);
|
|
sb.sprintf (GTXT (" Sample signal %s"), coll_params.sample_sig);
|
|
commentq->append (new Emsg (CMSG_COMMENT, sb));
|
|
}
|
|
if (coll_params.start_delay != NULL)
|
|
{
|
|
sb.setLength (0);
|
|
sb.sprintf (GTXT (" Data collection delay start %s seconds"), coll_params.start_delay);
|
|
commentq->append (new Emsg (CMSG_COMMENT, sb));
|
|
}
|
|
if (coll_params.terminate != NULL)
|
|
{
|
|
sb.setLength (0);
|
|
sb.sprintf (GTXT (" Data collection termination after %s seconds"), coll_params.terminate);
|
|
commentq->append (new Emsg (CMSG_COMMENT, sb));
|
|
}
|
|
// add a blank line after data description
|
|
commentq->append (new Emsg (CMSG_COMMENT, NTXT ("")));
|
|
}
|
|
|
|
|
|
/*
|
|
* Raw packet processing
|
|
*/
|
|
static int
|
|
check_mstate (char *ptr, PacketDescriptor *pDscr, int arg)
|
|
{
|
|
switch (arg)
|
|
{
|
|
case PROP_UCPU:
|
|
case PROP_SCPU:
|
|
case PROP_TRAP:
|
|
case PROP_TFLT:
|
|
case PROP_DFLT:
|
|
case PROP_KFLT:
|
|
case PROP_ULCK:
|
|
case PROP_TSLP:
|
|
case PROP_WCPU:
|
|
case PROP_TSTP:
|
|
break;
|
|
default:
|
|
return 0;
|
|
}
|
|
Vector<FieldDescr*> *fields = pDscr->getFields ();
|
|
for (int i = 0, sz = fields->size (); i < sz; i++)
|
|
{
|
|
FieldDescr *fDscr = fields->fetch (i);
|
|
if (fDscr->propID == arg)
|
|
return *((int*) (ptr + fDscr->offset));
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
#define PACKET_ALIGNMENT 4
|
|
|
|
uint64_t
|
|
Experiment::readPacket (Data_window *dwin, Data_window::Span *span)
|
|
{
|
|
Common_packet *rcp = (Common_packet *) dwin->bind (span,
|
|
sizeof (CommonHead_packet));
|
|
uint16_t v16;
|
|
uint64_t size = 0;
|
|
if (rcp)
|
|
{
|
|
if ((((long) rcp) % PACKET_ALIGNMENT) != 0)
|
|
{
|
|
invalid_packet++;
|
|
size = PROFILE_BUFFER_CHUNK - span->offset % PROFILE_BUFFER_CHUNK;
|
|
return size;
|
|
}
|
|
v16 = (uint16_t) rcp->tsize;
|
|
size = dwin->decode (v16);
|
|
if (size == 0)
|
|
{
|
|
size = PROFILE_BUFFER_CHUNK - span->offset % PROFILE_BUFFER_CHUNK;
|
|
return size;
|
|
}
|
|
rcp = (Common_packet *) dwin->bind (span, size);
|
|
}
|
|
if (rcp == NULL)
|
|
return 0;
|
|
|
|
if ((((long) rcp) % PACKET_ALIGNMENT) != 0)
|
|
{
|
|
invalid_packet++;
|
|
size = PROFILE_BUFFER_CHUNK - span->offset % PROFILE_BUFFER_CHUNK;
|
|
return size;
|
|
}
|
|
v16 = (uint16_t) rcp->type;
|
|
uint32_t rcptype = dwin->decode (v16);
|
|
if (rcptype == EMPTY_PCKT)
|
|
return size;
|
|
if (rcptype == FRAME_PCKT)
|
|
{
|
|
RawFramePacket *fp = new RawFramePacket;
|
|
fp->uid = dwin->decode (((Frame_packet*) rcp)->uid);
|
|
fp->uidn = NULL;
|
|
fp->uidj = NULL;
|
|
fp->omp_uid = NULL;
|
|
fp->omp_state = 0;
|
|
char *ptr = (char*) rcp + dwin->decode (((Frame_packet*) rcp)->hsize);
|
|
if ((((long) ptr) % PACKET_ALIGNMENT) != 0)
|
|
{
|
|
invalid_packet++;
|
|
delete fp;
|
|
return size;
|
|
}
|
|
v16 = (uint16_t) ((Frame_packet*) rcp)->tsize;
|
|
char *end = (char*) rcp + dwin->decode (v16);
|
|
for (; ptr < end;)
|
|
{
|
|
Common_info *cinfo = (Common_info*) ptr;
|
|
uint32_t hsize = dwin->decode (cinfo->hsize);
|
|
if (hsize == 0 || ptr + hsize > end)
|
|
break;
|
|
int kind = dwin->decode (cinfo->kind);
|
|
bool compressed = false;
|
|
if (kind & COMPRESSED_INFO)
|
|
{
|
|
compressed = true;
|
|
kind &= ~COMPRESSED_INFO;
|
|
}
|
|
switch (kind)
|
|
{
|
|
case STACK_INFO:
|
|
{
|
|
char *stack = ptr + sizeof (Stack_info);
|
|
size_t stack_size = hsize - sizeof (Stack_info);
|
|
uint64_t uidn = dwin->decode (((Stack_info*) cinfo)->uid);
|
|
if (stack_size <= 0)
|
|
{
|
|
fp->uidn = get_uid_node (uidn);
|
|
break;
|
|
}
|
|
uint64_t link_uid = (uint64_t) 0;
|
|
if (compressed)
|
|
{
|
|
stack_size -= sizeof (uint64_t);
|
|
unsigned char *s = (unsigned char*) (stack + stack_size);
|
|
int shift = 0;
|
|
for (size_t i = 0; i<sizeof (link_uid); i++)
|
|
{
|
|
link_uid |= (uint64_t) * s++ << shift;
|
|
shift += 8;
|
|
}
|
|
}
|
|
if (wsize == W32)
|
|
fp->uidn = add_uid (dwin, uidn,
|
|
(int) (stack_size / sizeof (uint32_t)),
|
|
(uint32_t*) stack, link_uid);
|
|
else
|
|
fp->uidn = add_uid (dwin, uidn,
|
|
(int) (stack_size / sizeof (uint64_t)),
|
|
(uint64_t*) stack, link_uid);
|
|
break;
|
|
}
|
|
case JAVA_INFO:
|
|
{
|
|
char *stack = ptr + sizeof (Java_info);
|
|
size_t stack_size = hsize - sizeof (Java_info);
|
|
uint64_t uidj = dwin->decode (((Java_info*) cinfo)->uid);
|
|
if (stack_size <= 0)
|
|
{
|
|
fp->uidj = get_uid_node (uidj);
|
|
break;
|
|
}
|
|
|
|
uint64_t link_uid = (uint64_t) 0;
|
|
if (compressed)
|
|
{
|
|
stack_size -= sizeof (uint64_t);
|
|
unsigned char *s = (unsigned char*) (stack + stack_size);
|
|
int shift = 0;
|
|
for (size_t i = 0; i<sizeof (link_uid); i++)
|
|
{
|
|
link_uid |= (uint64_t) * s++ << shift;
|
|
shift += 8;
|
|
}
|
|
}
|
|
if (wsize == W32)
|
|
fp->uidj = add_uid (dwin, uidj,
|
|
(int) (stack_size / sizeof (uint32_t)),
|
|
(uint32_t*) stack, link_uid);
|
|
else
|
|
{
|
|
// bug 6909545: garbage in 64-bit JAVA_INFO
|
|
char *nstack = (char*) malloc (stack_size);
|
|
char *dst = nstack;
|
|
char *srcmax = stack + stack_size - sizeof (uint64_t);
|
|
for (char *src = stack; src <= srcmax;)
|
|
{
|
|
int64_t val = dwin->decode (*(int32_t*) src);
|
|
*(uint64_t*) dst = dwin->decode (val);
|
|
src += sizeof (uint64_t);
|
|
dst += sizeof (uint64_t);
|
|
if (src > srcmax)
|
|
{
|
|
fprintf (stderr, "er_print: Experiment::readPacket: Error in data: src=%llx greater than %llx\n",
|
|
(long long) src, (long long) srcmax);
|
|
break;
|
|
}
|
|
*(uint64_t*) dst = *(uint64_t*) src;
|
|
src += sizeof (uint64_t);
|
|
dst += sizeof (uint64_t);
|
|
}
|
|
fp->uidj = add_uid (dwin, uidj,
|
|
(int) (stack_size / sizeof (uint64_t)),
|
|
(uint64_t*) nstack, link_uid);
|
|
free (nstack);
|
|
}
|
|
break;
|
|
}
|
|
case OMP_INFO:
|
|
fp->omp_state = dwin->decode (((OMP_info*) ptr)->omp_state);
|
|
break;
|
|
case OMP2_INFO:
|
|
{
|
|
uint64_t omp_uid = dwin->decode (((OMP2_info*) ptr)->uid);
|
|
fp->omp_uid = get_uid_node (omp_uid);
|
|
fp->omp_state = dwin->decode (((OMP2_info*) ptr)->omp_state);
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
ptr += hsize;
|
|
}
|
|
frmpckts->append (fp);
|
|
return size;
|
|
}
|
|
else if (rcptype == UID_PCKT)
|
|
{
|
|
Uid_packet *uidp = (Uid_packet*) rcp;
|
|
uint64_t uid = dwin->decode (uidp->uid);
|
|
char *arr_bytes = (char*) (uidp + 1);
|
|
v16 = (uint16_t) rcp->tsize;
|
|
size_t arr_length = dwin->decode (v16) - sizeof (Uid_packet);
|
|
if (arr_length <= 0)
|
|
return size;
|
|
uint64_t link_uid = (uint64_t) 0;
|
|
if (dwin->decode (uidp->flags) & COMPRESSED_INFO)
|
|
{
|
|
arr_length -= sizeof (uint64_t);
|
|
unsigned char *s = (unsigned char*) (arr_bytes + arr_length);
|
|
int shift = 0;
|
|
for (size_t i = 0; i<sizeof (link_uid); i++)
|
|
{
|
|
link_uid |= (uint64_t) * s++ << shift;
|
|
shift += 8;
|
|
}
|
|
}
|
|
if (wsize == W32)
|
|
add_uid (dwin, uid, (int) (arr_length / sizeof (uint32_t)),
|
|
(uint32_t*) arr_bytes, link_uid);
|
|
else
|
|
add_uid (dwin, uid, (int) (arr_length / sizeof (uint64_t)),
|
|
(uint64_t*) arr_bytes, link_uid);
|
|
return size;
|
|
}
|
|
|
|
PacketDescriptor *pcktDescr = getPacketDescriptor (rcptype);
|
|
if (pcktDescr == NULL)
|
|
return size;
|
|
DataDescriptor *dataDescr = pcktDescr->getDataDescriptor ();
|
|
if (dataDescr == NULL)
|
|
return size;
|
|
|
|
/* omazur: TBR START -- old experiment */
|
|
if (rcptype == PROF_PCKT)
|
|
{
|
|
// For backward compatibility with older SS12 experiments
|
|
int numstates = get_params ()->lms_magic_id; // ugly, for old experiments
|
|
if (numstates > LMS_NUM_SOLARIS_MSTATES)
|
|
numstates = LMS_NUM_SOLARIS_MSTATES;
|
|
for (int i = 0; i < numstates; i++)
|
|
if (check_mstate ((char*) rcp, pcktDescr, PROP_UCPU + i))
|
|
readPacket (dwin, (char*) rcp, pcktDescr, dataDescr, PROP_UCPU + i,
|
|
size);
|
|
}
|
|
else
|
|
readPacket (dwin, (char*) rcp, pcktDescr, dataDescr, 0, size);
|
|
return size;
|
|
}
|
|
|
|
void
|
|
Experiment::readPacket (Data_window *dwin, char *ptr, PacketDescriptor *pDscr,
|
|
DataDescriptor *dDscr, int arg, uint64_t pktsz)
|
|
{
|
|
union Value
|
|
{
|
|
uint32_t val32;
|
|
uint64_t val64;
|
|
} *v;
|
|
|
|
long recn = dDscr->addRecord ();
|
|
Vector<FieldDescr*> *fields = pDscr->getFields ();
|
|
int sz = fields->size ();
|
|
for (int i = 0; i < sz; i++)
|
|
{
|
|
FieldDescr *field = fields->fetch (i);
|
|
v = (Value*) (ptr + field->offset);
|
|
if (field->propID == arg)
|
|
{
|
|
dDscr->setValue (PROP_NTICK, recn, dwin->decode (v->val32));
|
|
dDscr->setValue (PROP_MSTATE, recn, (uint32_t) (field->propID - PROP_UCPU));
|
|
}
|
|
if (field->propID == PROP_THRID || field->propID == PROP_LWPID
|
|
|| field->propID == PROP_CPUID)
|
|
{
|
|
uint64_t tmp64 = 0;
|
|
switch (field->vtype)
|
|
{
|
|
case TYPE_INT32:
|
|
case TYPE_UINT32:
|
|
tmp64 = dwin->decode (v->val32);
|
|
break;
|
|
case TYPE_INT64:
|
|
case TYPE_UINT64:
|
|
tmp64 = dwin->decode (v->val64);
|
|
break;
|
|
case TYPE_STRING:
|
|
case TYPE_DOUBLE:
|
|
case TYPE_OBJ:
|
|
case TYPE_DATE:
|
|
case TYPE_BOOL:
|
|
case TYPE_ENUM:
|
|
case TYPE_LAST:
|
|
case TYPE_NONE:
|
|
break;
|
|
}
|
|
uint32_t tag = mapTagValue ((Prop_type) field->propID, tmp64);
|
|
dDscr->setValue (field->propID, recn, tag);
|
|
}
|
|
else
|
|
{
|
|
switch (field->vtype)
|
|
{
|
|
case TYPE_INT32:
|
|
case TYPE_UINT32:
|
|
dDscr->setValue (field->propID, recn, dwin->decode (v->val32));
|
|
break;
|
|
case TYPE_INT64:
|
|
case TYPE_UINT64:
|
|
dDscr->setValue (field->propID, recn, dwin->decode (v->val64));
|
|
break;
|
|
case TYPE_STRING:
|
|
{
|
|
int len = (int) (pktsz - field->offset);
|
|
if ((len > 0) && (ptr[field->offset] != 0))
|
|
{
|
|
StringBuilder *sb = new StringBuilder ();
|
|
sb->append (ptr + field->offset, 0, len);
|
|
dDscr->setObjValue (field->propID, recn, sb);
|
|
}
|
|
break;
|
|
}
|
|
// ignoring the following cases (why?)
|
|
case TYPE_DOUBLE:
|
|
case TYPE_OBJ:
|
|
case TYPE_DATE:
|
|
case TYPE_BOOL:
|
|
case TYPE_ENUM:
|
|
case TYPE_LAST:
|
|
case TYPE_NONE:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#define PROG_BYTE 102400 // update progress bar every PROG_BYTE bytes
|
|
|
|
void
|
|
Experiment::read_data_file (const char *fname, const char *msg)
|
|
{
|
|
Data_window::Span span;
|
|
off64_t total_len, remain_len;
|
|
char *progress_bar_msg;
|
|
int progress_bar_percent = -1;
|
|
|
|
char *data_file_name = dbe_sprintf (NTXT ("%s/%s"), expt_name, fname);
|
|
Data_window *dwin = new Data_window (data_file_name);
|
|
// Here we can call stat(data_file_name) to get file size,
|
|
// and call a function to reallocate vectors for clock profiling data
|
|
free (data_file_name);
|
|
if (dwin->not_opened ())
|
|
{
|
|
delete dwin;
|
|
return;
|
|
}
|
|
dwin->need_swap_endian = need_swap_endian;
|
|
|
|
span.offset = 0;
|
|
span.length = dwin->get_fsize ();
|
|
total_len = remain_len = span.length;
|
|
progress_bar_msg = dbe_sprintf (NTXT ("%s %s"), NTXT (" "), msg);
|
|
invalid_packet = 0;
|
|
for (;;)
|
|
{
|
|
uint64_t pcktsz = readPacket (dwin, &span);
|
|
if (pcktsz == 0)
|
|
break;
|
|
// Update progress bar
|
|
if ((span.length <= remain_len) && (remain_len > 0))
|
|
{
|
|
int percent = (int) (100 * (total_len - remain_len) / total_len);
|
|
if (percent > progress_bar_percent)
|
|
{
|
|
progress_bar_percent += 10;
|
|
theApplication->set_progress (percent, progress_bar_msg);
|
|
}
|
|
remain_len -= PROG_BYTE;
|
|
}
|
|
span.length -= pcktsz;
|
|
span.offset += pcktsz;
|
|
}
|
|
delete dwin;
|
|
|
|
if (invalid_packet)
|
|
{
|
|
StringBuilder sb;
|
|
sb.sprintf (GTXT ("WARNING: There are %d invalid packet(s) in the %s file"),
|
|
invalid_packet, fname);
|
|
Emsg *m = new Emsg (CMSG_WARN, sb);
|
|
warnq->append (m);
|
|
}
|
|
|
|
theApplication->set_progress (0, NTXT (""));
|
|
free (progress_bar_msg);
|
|
}
|
|
|
|
int
|
|
Experiment::read_overview_file ()
|
|
{
|
|
char *data_file_name = dbe_sprintf ("%s/%s", expt_name, SP_OVERVIEW_FILE);
|
|
Data_window *dwin = new Data_window (data_file_name);
|
|
free (data_file_name);
|
|
if (dwin->not_opened ())
|
|
{
|
|
delete dwin;
|
|
return 0;
|
|
}
|
|
dwin->need_swap_endian = need_swap_endian;
|
|
newDataDescriptor (DATA_SAMPLE);
|
|
|
|
Data_window::Span span;
|
|
span.offset = 0;
|
|
span.length = dwin->get_fsize ();
|
|
|
|
PrUsage *data = NULL, *data_prev = NULL;
|
|
Sample *sample;
|
|
int sample_number = 1;
|
|
|
|
int64_t prDataSize;
|
|
if (wsize == W32)
|
|
prDataSize = PrUsage::bind32Size ();
|
|
else
|
|
prDataSize = PrUsage::bind64Size ();
|
|
|
|
while (span.length > 0)
|
|
{
|
|
data_prev = data;
|
|
data = new PrUsage ();
|
|
|
|
void *dw = dwin->bind (&span, prDataSize);
|
|
if ((dw == NULL) || (prDataSize > span.length))
|
|
{
|
|
Emsg *m = new Emsg (CMSG_ERROR, GTXT ("Warning: overview data file can't be read"));
|
|
warnq->append (m);
|
|
status = FAILURE;
|
|
delete dwin;
|
|
return status;
|
|
}
|
|
|
|
if (wsize == W32)
|
|
data->bind32 (dw, need_swap_endian);
|
|
else
|
|
data->bind64 (dw, need_swap_endian);
|
|
span.length -= prDataSize;
|
|
span.offset += prDataSize;
|
|
|
|
// Skip the first packet
|
|
if (data_prev == NULL)
|
|
continue;
|
|
if (sample_number > samples->size ())
|
|
{ // inconsistent log/overview
|
|
sample = new Sample (sample_number);
|
|
char * label = GTXT ("<unknown>");
|
|
sample->start_label = dbe_strdup (label);
|
|
sample->end_label = dbe_strdup (label);
|
|
samples->append (sample);
|
|
}
|
|
else
|
|
sample = samples->fetch (sample_number - 1);
|
|
sample_number++;
|
|
sample->start_time = data_prev->pr_tstamp + 1;
|
|
sample->end_time = data->pr_tstamp;
|
|
sample->prusage = data_prev;
|
|
|
|
data_prev->pr_rtime = data->pr_rtime - data_prev->pr_rtime;
|
|
data_prev->pr_utime = data->pr_utime - data_prev->pr_utime;
|
|
data_prev->pr_stime = data->pr_stime - data_prev->pr_stime;
|
|
data_prev->pr_ttime = data->pr_ttime - data_prev->pr_ttime;
|
|
data_prev->pr_tftime = data->pr_tftime - data_prev->pr_tftime;
|
|
data_prev->pr_dftime = data->pr_dftime - data_prev->pr_dftime;
|
|
data_prev->pr_kftime = data->pr_kftime - data_prev->pr_kftime;
|
|
data_prev->pr_ltime = data->pr_ltime - data_prev->pr_ltime;
|
|
data_prev->pr_slptime = data->pr_slptime - data_prev->pr_slptime;
|
|
data_prev->pr_wtime = data->pr_wtime - data_prev->pr_wtime;
|
|
data_prev->pr_stoptime = data->pr_stoptime - data_prev->pr_stoptime;
|
|
data_prev->pr_minf = data->pr_minf - data_prev->pr_minf;
|
|
data_prev->pr_majf = data->pr_majf - data_prev->pr_majf;
|
|
data_prev->pr_nswap = data->pr_nswap - data_prev->pr_nswap;
|
|
data_prev->pr_inblk = data->pr_inblk - data_prev->pr_inblk;
|
|
data_prev->pr_oublk = data->pr_oublk - data_prev->pr_oublk;
|
|
data_prev->pr_msnd = data->pr_msnd - data_prev->pr_msnd;
|
|
data_prev->pr_mrcv = data->pr_mrcv - data_prev->pr_mrcv;
|
|
data_prev->pr_sigs = data->pr_sigs - data_prev->pr_sigs;
|
|
data_prev->pr_vctx = data->pr_vctx - data_prev->pr_vctx;
|
|
data_prev->pr_ictx = data->pr_ictx - data_prev->pr_ictx;
|
|
data_prev->pr_sysc = data->pr_sysc - data_prev->pr_sysc;
|
|
data_prev->pr_ioch = data->pr_ioch - data_prev->pr_ioch;
|
|
sample->get_usage (); // force validation
|
|
}
|
|
|
|
for (long smpNum = samples->size (); smpNum >= sample_number; smpNum--)
|
|
{
|
|
// overview file was truncated
|
|
sample = samples->remove (smpNum - 1);
|
|
delete sample;
|
|
}
|
|
|
|
if (data)
|
|
{
|
|
// Update last_event so that getEndTime() covers
|
|
// all loadobjects, too.
|
|
update_last_event (data->pr_tstamp);
|
|
delete data;
|
|
}
|
|
delete dwin;
|
|
return SUCCESS;
|
|
}
|
|
|
|
int
|
|
Experiment::uidNodeCmp (const void *a, const void *b)
|
|
{
|
|
UIDnode *nd1 = *(UIDnode**) a;
|
|
UIDnode *nd2 = *(UIDnode**) b;
|
|
if (nd1->uid == nd2->uid)
|
|
return 0;
|
|
return nd1->uid < nd2->uid ? -1 : 1;
|
|
}
|
|
|
|
static uint64_t
|
|
funcAddr (uint32_t val)
|
|
{
|
|
if (val == (uint32_t) SP_LEAF_CHECK_MARKER)
|
|
return (uint64_t) SP_LEAF_CHECK_MARKER;
|
|
if (val == (uint32_t) SP_TRUNC_STACK_MARKER)
|
|
return (uint64_t) SP_TRUNC_STACK_MARKER;
|
|
if (val == (uint32_t) SP_FAILED_UNWIND_MARKER)
|
|
return (uint64_t) SP_FAILED_UNWIND_MARKER;
|
|
return val;
|
|
}
|
|
|
|
Experiment::UIDnode *
|
|
Experiment::add_uid (Data_window *dwin, uint64_t uid, int size,
|
|
uint32_t *array, uint64_t link_uid)
|
|
{
|
|
if (uid == (uint64_t) 0)
|
|
return NULL;
|
|
uint64_t val = funcAddr (dwin->decode (array[0]));
|
|
UIDnode *node = NULL;
|
|
UIDnode *res = get_uid_node (uid, val);
|
|
UIDnode *next = res;
|
|
for (int i = 0; i < size; i++)
|
|
{
|
|
val = funcAddr (dwin->decode (array[i]));
|
|
if (next == NULL)
|
|
{
|
|
next = get_uid_node ((uint64_t) 0, val);
|
|
if (node != NULL)
|
|
node->next = next;
|
|
}
|
|
node = next;
|
|
next = node->next;
|
|
if (node->val == 0)
|
|
node->val = val;
|
|
else if (node->val != val) // Algorithmic error (should never happen)
|
|
node->val = (uint64_t) SP_LEAF_CHECK_MARKER;
|
|
}
|
|
if (next == NULL && link_uid != (uint64_t) 0 && node != NULL)
|
|
node->next = get_uid_node (link_uid);
|
|
return res;
|
|
}
|
|
|
|
Experiment::UIDnode *
|
|
Experiment::add_uid (Data_window *dwin, uint64_t uid, int size, uint64_t *array, uint64_t link_uid)
|
|
{
|
|
if (uid == (uint64_t) 0)
|
|
return NULL;
|
|
UIDnode *node = NULL;
|
|
uint64_t val = dwin->decode (array[0]);
|
|
UIDnode *res = get_uid_node (uid, val);
|
|
UIDnode *next = res;
|
|
for (int i = 0; i < size; i++)
|
|
{
|
|
val = dwin->decode (array[i]);
|
|
if (next == NULL)
|
|
{
|
|
next = get_uid_node ((uint64_t) 0, val);
|
|
if (node != NULL)
|
|
node->next = next;
|
|
}
|
|
node = next;
|
|
next = node->next;
|
|
if (node->val == (uint64_t) 0)
|
|
node->val = val;
|
|
else if (node->val != val) // Algorithmic error (should never happen)
|
|
node->val = (uint64_t) - 1;
|
|
}
|
|
if (next == NULL && link_uid != (uint64_t) 0 && node != NULL)
|
|
node->next = get_uid_node (link_uid);
|
|
return res;
|
|
}
|
|
|
|
Experiment::UIDnode *
|
|
Experiment::new_uid_node (uint64_t uid, uint64_t val)
|
|
{
|
|
#define NCHUNKSTEP 1024
|
|
if (nnodes >= nchunks * CHUNKSZ)
|
|
{
|
|
// Reallocate Node chunk array
|
|
UIDnode** old_chunks = chunks;
|
|
chunks = new UIDnode*[nchunks + NCHUNKSTEP];
|
|
memcpy (chunks, old_chunks, nchunks * sizeof (UIDnode*));
|
|
nchunks += NCHUNKSTEP;
|
|
delete[] old_chunks;
|
|
// Clean future pointers
|
|
memset (&chunks[nchunks - NCHUNKSTEP], 0, NCHUNKSTEP * sizeof (UIDnode*));
|
|
}
|
|
|
|
if (NULL == chunks[nnodes / CHUNKSZ]) // Allocate new chunk for nodes.
|
|
chunks[nnodes / CHUNKSZ] = new UIDnode[CHUNKSZ];
|
|
UIDnode *node = &chunks[nnodes / CHUNKSZ][nnodes % CHUNKSZ];
|
|
node->uid = uid;
|
|
node->val = val;
|
|
node->next = NULL;
|
|
nnodes++;
|
|
return node;
|
|
}
|
|
|
|
Experiment::UIDnode *
|
|
Experiment::get_uid_node (uint64_t uid, uint64_t val)
|
|
{
|
|
int hash = (((int) uid) >> 4) & (HTableSize - 1);
|
|
if (uid != (uint64_t) 0)
|
|
{
|
|
UIDnode *node = uidHTable[hash];
|
|
if (node && node->uid == uid)
|
|
return node;
|
|
}
|
|
UIDnode *node = new_uid_node (uid, val);
|
|
if (uid != (uint64_t) 0)
|
|
{
|
|
uidHTable[hash] = node;
|
|
uidnodes->append (node);
|
|
}
|
|
return node;
|
|
}
|
|
|
|
Experiment::UIDnode *
|
|
Experiment::get_uid_node (uint64_t uid)
|
|
{
|
|
if (uid == (uint64_t) 0)
|
|
return NULL;
|
|
int hash = (((int) uid) >> 4) & (HTableSize - 1);
|
|
UIDnode *node = uidHTable[hash];
|
|
if (node && node->uid == uid)
|
|
return node;
|
|
node = new_uid_node (uid, (uint64_t) 0);
|
|
node->next = node;
|
|
return node;
|
|
}
|
|
|
|
Experiment::UIDnode *
|
|
Experiment::find_uid_node (uint64_t uid)
|
|
{
|
|
int hash = (((int) uid) >> 4) & (HTableSize - 1);
|
|
UIDnode *node = uidHTable[hash];
|
|
if (node && node->uid == uid)
|
|
return node;
|
|
int lt = 0;
|
|
int rt = uidnodes->size () - 1;
|
|
while (lt <= rt)
|
|
{
|
|
int md = (lt + rt) / 2;
|
|
node = uidnodes->fetch (md);
|
|
if (node->uid < uid)
|
|
lt = md + 1;
|
|
else if (node->uid > uid)
|
|
rt = md - 1;
|
|
else
|
|
{
|
|
uidHTable[hash] = node;
|
|
return node;
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
int
|
|
Experiment::frUidCmp (const void *a, const void *b)
|
|
{
|
|
RawFramePacket *fp1 = *(RawFramePacket**) a;
|
|
RawFramePacket *fp2 = *(RawFramePacket**) b;
|
|
if (fp1->uid == fp2->uid)
|
|
return 0;
|
|
return fp1->uid < fp2->uid ? -1 : 1;
|
|
}
|
|
|
|
Experiment::RawFramePacket *
|
|
Experiment::find_frame_packet (uint64_t uid)
|
|
{
|
|
int lt = 0;
|
|
int rt = frmpckts->size () - 1;
|
|
while (lt <= rt)
|
|
{
|
|
int md = (lt + rt) / 2;
|
|
RawFramePacket *fp = frmpckts->fetch (md);
|
|
if (fp->uid < uid)
|
|
lt = md + 1;
|
|
else if (fp->uid > uid)
|
|
rt = md - 1;
|
|
else
|
|
return fp;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
#define FRINFO_CACHEOPT_SIZE_LIMIT 4000000
|
|
#define FRINFO_PIPELINE_SIZE_LIMIT 500000
|
|
#define FRINFO_PIPELINE_NUM_STAGES 3
|
|
|
|
// Pipelined execution of resolve_frame_info() and add_stack().
|
|
// Since this is the largest time consuming part of loading an experiment (especially
|
|
// so for large java experiments) - executing this part as a 3 stage pipeline can
|
|
// give significant performance gain - and this concept can be aggressively applied
|
|
// to enhance the gain further in future. The three stages are:
|
|
// Phase 1: resolve_frame_info()
|
|
// Phase 2: first part of add_stack() where the native stack is built
|
|
// Phase 3: second part og add_stack() where the java stack is built
|
|
// Phase 4: insert the native and java stacks into the stack map
|
|
// The main thread operates in the first Phase and the other stages are
|
|
// operated by a ssplib sequential queue - The threads working on the queues run concurrently
|
|
// with each other and with the main thread. But within a particular queue, jobs are
|
|
// executed sequentially
|
|
|
|
|
|
// This is the second phase of the pipeline of resolve_frame_info and add_stack
|
|
// It works on a chunk of iterations (size CSTCTX_CHUNK_SZ) and invokes add_stack()
|
|
// for each one of them
|
|
|
|
void
|
|
Experiment::resolve_frame_info (DataDescriptor *dDscr)
|
|
{
|
|
if (!resolveFrameInfo)
|
|
return;
|
|
if (NULL == cstack)
|
|
return;
|
|
dDscr->setResolveFrInfoDone ();
|
|
|
|
// Check for TSTAMP
|
|
int propID = dbeSession->getPropIdByName (NTXT ("TSTAMP"));
|
|
Data *dataTStamp = dDscr->getData (propID);
|
|
if (dataTStamp == NULL)
|
|
return;
|
|
|
|
propID = dbeSession->getPropIdByName (NTXT ("FRINFO"));
|
|
Data *dataFrinfo = dDscr->getData (propID);
|
|
|
|
propID = dbeSession->getPropIdByName (NTXT ("THRID"));
|
|
Data *dataThrId = dDscr->getData (propID);
|
|
|
|
// We can get frame info either by FRINFO or by [THRID,STKIDX]
|
|
if (dataFrinfo == NULL)
|
|
return;
|
|
|
|
char *propName = NTXT ("MSTACK");
|
|
propID = dbeSession->getPropIdByName (propName);
|
|
PropDescr *prMStack = new PropDescr (propID, propName);
|
|
prMStack->uname = dbe_strdup (GTXT ("Machine Call Stack"));
|
|
prMStack->vtype = TYPE_OBJ;
|
|
dDscr->addProperty (prMStack);
|
|
|
|
propName = NTXT ("USTACK");
|
|
propID = dbeSession->getPropIdByName (propName);
|
|
PropDescr *prUStack = new PropDescr (propID, propName);
|
|
prUStack->uname = dbe_strdup (GTXT ("User Call Stack"));
|
|
prUStack->vtype = TYPE_OBJ;
|
|
dDscr->addProperty (prUStack);
|
|
|
|
propName = NTXT ("XSTACK");
|
|
propID = dbeSession->getPropIdByName (propName);
|
|
PropDescr *prXStack = new PropDescr (propID, propName);
|
|
prXStack->uname = dbe_strdup (GTXT ("Expert Call Stack"));
|
|
prXStack->vtype = TYPE_OBJ;
|
|
dDscr->addProperty (prXStack);
|
|
|
|
propName = NTXT ("HSTACK");
|
|
propID = dbeSession->getPropIdByName (propName);
|
|
PropDescr *prHStack = new PropDescr (propID, propName);
|
|
prHStack->uname = dbe_strdup (GTXT ("ShowHide Call Stack"));
|
|
prHStack->vtype = TYPE_OBJ;
|
|
dDscr->addProperty (prHStack);
|
|
|
|
if (has_java)
|
|
{
|
|
propName = NTXT ("JTHREAD");
|
|
propID = dbeSession->getPropIdByName (propName);
|
|
PropDescr *prJThread = new PropDescr (propID, propName);
|
|
prJThread->uname = dbe_strdup (GTXT ("Java Thread"));
|
|
prJThread->vtype = TYPE_OBJ;
|
|
dDscr->addProperty (prJThread);
|
|
}
|
|
|
|
if (ompavail)
|
|
{
|
|
PropDescr *prop = new PropDescr (PROP_OMPSTATE, NTXT ("OMPSTATE"));
|
|
prop->uname = dbe_strdup (GTXT ("OpenMP state"));
|
|
prop->vtype = TYPE_UINT32;
|
|
char * stateNames [OMP_LAST_STATE] = OMP_THR_STATE_STRINGS;
|
|
char * stateUNames[OMP_LAST_STATE] = OMP_THR_STATE_USTRINGS;
|
|
for (int ii = 0; ii < OMP_LAST_STATE; ii++)
|
|
prop->addState (ii, stateNames[ii], stateUNames[ii]);
|
|
dDscr->addProperty (prop);
|
|
|
|
// add PROP_CPRID to profiling data (not same as omptrace's PROP_CPRID)
|
|
prop = dDscr->getProp (PROP_CPRID);
|
|
if (prop)
|
|
{
|
|
VType_type type = prop->vtype;
|
|
assert (type == TYPE_OBJ); //see 7040526
|
|
}
|
|
prop = new PropDescr (PROP_CPRID, NTXT ("CPRID")); //profiling PROP_CPRID
|
|
prop->uname = dbe_strdup (GTXT ("OpenMP parallel region"));
|
|
prop->vtype = TYPE_OBJ;
|
|
dDscr->addProperty (prop);
|
|
|
|
// add PROP_TSKID to profiling data (not same as omptrace's PROP_TSKID)
|
|
prop = dDscr->getProp (PROP_TSKID);
|
|
if (prop)
|
|
{
|
|
VType_type type = prop->vtype;
|
|
assert (type == TYPE_OBJ); //see 7040526
|
|
}
|
|
prop = new PropDescr (PROP_TSKID, NTXT ("TSKID")); //profiling PROP_TSKID
|
|
prop->uname = dbe_strdup (GTXT ("OpenMP task"));
|
|
prop->vtype = TYPE_OBJ;
|
|
dDscr->addProperty (prop);
|
|
}
|
|
char *progress_bar_msg = dbe_sprintf (NTXT ("%s %s: %s"), NTXT (" "),
|
|
GTXT ("Processing CallStack Data"),
|
|
get_basename (expt_name));
|
|
int progress_bar_percent = -1;
|
|
long deltaReport = 5000;
|
|
long nextReport = 0;
|
|
|
|
long size = dDscr->getSize ();
|
|
// bool resolve_frinfo_pipelined = size > FRINFO_PIPELINE_SIZE_LIMIT && !ompavail;
|
|
bool resolve_frinfo_pipelined = false;
|
|
|
|
Map<uint64_t, uint64_t> *nodeCache = NULL;
|
|
Map<uint64_t, uint64_t> *frameInfoCache = NULL;
|
|
if (size > FRINFO_CACHEOPT_SIZE_LIMIT && dversion == NULL)
|
|
{
|
|
frameInfoCache = new CacheMap<uint64_t, uint64_t>;
|
|
nodeCache = new CacheMap<uint64_t, uint64_t>;
|
|
}
|
|
|
|
pushCnt = popCnt = pushCnt3 = popCnt3 = 0;
|
|
nPush = nPop = 0;
|
|
|
|
FramePacket *fp = NULL;
|
|
// DbeThreadPool * threadPool = new DbeThreadPool(5);
|
|
fp = new FramePacket;
|
|
fp->stack = new Vector<Vaddr>;
|
|
fp->jstack = new Vector<Vaddr>;
|
|
fp->ompstack = new Vector<Vaddr>;
|
|
fp->omp_state = 0;
|
|
fp->mpi_state = 0;
|
|
|
|
// piggyback on post-processing to calculate exp->last_event
|
|
const hrtime_t _exp_start_time = getStartTime (); // wall clock time
|
|
hrtime_t exp_duration = getLastEvent () == ZERO_TIME ? 0
|
|
: getLastEvent () - _exp_start_time; // zero-based
|
|
|
|
int missed_fi = 0;
|
|
int total_fi = 0;
|
|
|
|
for (long i = 0; i < size; i++)
|
|
{
|
|
if (i == nextReport)
|
|
{
|
|
int percent = (int) (i * 100 / size);
|
|
if (percent > progress_bar_percent)
|
|
{
|
|
progress_bar_percent += 10;
|
|
theApplication->set_progress (percent, progress_bar_msg);
|
|
}
|
|
nextReport += deltaReport;
|
|
}
|
|
|
|
uint32_t thrid = (uint32_t) dataThrId->fetchInt (i);
|
|
hrtime_t tstamp = (hrtime_t) dataTStamp->fetchLong (i);
|
|
|
|
// piggyback on post-processing to calculate exp->last_event
|
|
{
|
|
hrtime_t relative_timestamp = tstamp - _exp_start_time;
|
|
if (exp_duration < relative_timestamp)
|
|
exp_duration = relative_timestamp;
|
|
}
|
|
uint64_t frinfo = (uint64_t) dataFrinfo->fetchLong (i);
|
|
|
|
RawFramePacket *rfp = NULL;
|
|
if (frinfo)
|
|
{
|
|
// CacheMap does not work with NULL key
|
|
if (frameInfoCache != NULL)
|
|
rfp = (RawFramePacket *) frameInfoCache->get (frinfo);
|
|
}
|
|
if (rfp == 0)
|
|
{
|
|
rfp = find_frame_packet (frinfo);
|
|
if (rfp != 0)
|
|
{
|
|
if (frameInfoCache != NULL)
|
|
frameInfoCache->put (frinfo, (uint64_t) rfp);
|
|
}
|
|
else
|
|
missed_fi++;
|
|
total_fi++;
|
|
}
|
|
|
|
// Process OpenMP properties
|
|
if (ompavail)
|
|
{
|
|
fp->omp_state = rfp ? rfp->omp_state : 0;
|
|
dDscr->setValue (PROP_OMPSTATE, i, fp->omp_state);
|
|
|
|
fp->omp_cprid = mapPRid->get (thrid, tstamp, mapPRid->REL_EQLE);
|
|
void *omp_preg = mapPReg->get (thrid, tstamp, mapPReg->REL_EQLE);
|
|
if (!omp_preg)
|
|
{
|
|
char *idxname = NTXT ("OMP_preg");
|
|
int idxtype = dbeSession->findIndexSpaceByName (idxname);
|
|
if (idxtype != -1)
|
|
{
|
|
Histable *preg0 = dbeSession->findObjectById (Histable::INDEXOBJ, idxtype, (int64_t) 0);
|
|
if (preg0)
|
|
{
|
|
Vector<Histable*> pregs;
|
|
pregs.append (preg0);
|
|
omp_preg = cstack->add_stack (&pregs);
|
|
mapPReg->put (thrid, tstamp, omp_preg);
|
|
}
|
|
}
|
|
}
|
|
dDscr->setObjValue (PROP_CPRID, i, omp_preg); //profiling PROP_CPRID
|
|
void *omp_task = mapTask->get (thrid, tstamp, mapTask->REL_EQLE);
|
|
if (!omp_task)
|
|
{
|
|
char *idxname = NTXT ("OMP_task");
|
|
int idxtype = dbeSession->findIndexSpaceByName (idxname);
|
|
if (idxtype != -1)
|
|
{
|
|
Histable *task0 = dbeSession->findObjectById (Histable::INDEXOBJ, idxtype, (int64_t) 0);
|
|
if (task0)
|
|
{
|
|
Vector<Histable*> tasks;
|
|
tasks.append (task0);
|
|
omp_task = cstack->add_stack (&tasks);
|
|
mapTask->put (thrid, tstamp, omp_task);
|
|
}
|
|
}
|
|
}
|
|
dDscr->setObjValue (PROP_TSKID, i, omp_task); //profiling PROP_TSKID
|
|
}
|
|
else
|
|
{
|
|
fp->omp_state = 0;
|
|
fp->omp_cprid = 0;
|
|
}
|
|
|
|
// Construct the native stack
|
|
fp->stack->reset ();
|
|
Vaddr leafpc = dDscr->getULongValue (PROP_LEAFPC, i);
|
|
if (leafpc)
|
|
fp->stack->append (leafpc);
|
|
UIDnode *node = rfp ? rfp->uidn : NULL;
|
|
while (node)
|
|
{
|
|
if (node->next == node)
|
|
// this node contains link_uid
|
|
node = find_uid_node (node->uid);
|
|
else
|
|
{
|
|
fp->stack->append (node->val);
|
|
node = node->next;
|
|
}
|
|
}
|
|
fp->truncated = 0;
|
|
int last = fp->stack->size () - 1;
|
|
if (last >= 0)
|
|
{
|
|
switch (fp->stack->fetch (last))
|
|
{
|
|
case SP_TRUNC_STACK_MARKER:
|
|
fp->truncated = (Vaddr) SP_TRUNC_STACK_MARKER;
|
|
fp->stack->remove (last);
|
|
break;
|
|
case SP_FAILED_UNWIND_MARKER:
|
|
fp->truncated = (Vaddr) SP_FAILED_UNWIND_MARKER;
|
|
fp->stack->remove (last);
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Construct the Java stack
|
|
fp->jstack->reset ();
|
|
node = rfp ? rfp->uidj : NULL;
|
|
while (node)
|
|
{
|
|
if (node->next == node)
|
|
{
|
|
// this node contains link_uid
|
|
UIDnode *n = NULL;
|
|
if (node->uid)
|
|
{
|
|
// CacheMap does not work with NULL key
|
|
if (nodeCache != NULL)
|
|
n = (UIDnode *) nodeCache->get (node->uid);
|
|
}
|
|
if (n == NULL)
|
|
{
|
|
n = find_uid_node (node->uid);
|
|
if (n != NULL)
|
|
{
|
|
if (nodeCache != NULL)
|
|
nodeCache->put (node->uid, (uint64_t) n);
|
|
}
|
|
}
|
|
node = n;
|
|
}
|
|
else
|
|
{
|
|
fp->jstack->append (node->val);
|
|
node = node->next;
|
|
}
|
|
}
|
|
fp->jtruncated = false;
|
|
last = fp->jstack->size () - 1;
|
|
if (last >= 1 && fp->jstack->fetch (last) == SP_TRUNC_STACK_MARKER)
|
|
{
|
|
fp->jtruncated = true;
|
|
fp->jstack->remove (last);
|
|
fp->jstack->remove (last - 1);
|
|
}
|
|
|
|
// Construct the OpenMP stack
|
|
if (ompavail)
|
|
{
|
|
fp->ompstack->reset ();
|
|
if (rfp && rfp->omp_uid)
|
|
{
|
|
if (leafpc)
|
|
fp->ompstack->append (leafpc);
|
|
node = rfp->omp_uid;
|
|
while (node)
|
|
{
|
|
if (node->next == node)
|
|
// this node contains link_uid
|
|
node = find_uid_node (node->uid);
|
|
else
|
|
{
|
|
fp->ompstack->append (node->val);
|
|
node = node->next;
|
|
}
|
|
}
|
|
fp->omptruncated = false;
|
|
last = fp->ompstack->size () - 1;
|
|
if (last >= 0)
|
|
{
|
|
switch (fp->ompstack->fetch (last))
|
|
{
|
|
case SP_TRUNC_STACK_MARKER:
|
|
fp->omptruncated = (Vaddr) SP_TRUNC_STACK_MARKER;
|
|
fp->ompstack->remove (last);
|
|
break;
|
|
case SP_FAILED_UNWIND_MARKER:
|
|
fp->omptruncated = (Vaddr) SP_FAILED_UNWIND_MARKER;
|
|
fp->ompstack->remove (last);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
cstack->add_stack (dDscr, i, fp, NULL);
|
|
}
|
|
|
|
// piggyback on post-processing to calculate exp->last_event
|
|
{
|
|
hrtime_t exp_end_time = _exp_start_time + exp_duration;
|
|
update_last_event (exp_end_time);
|
|
}
|
|
|
|
if (missed_fi > 0)
|
|
{
|
|
StringBuilder sb;
|
|
sb.sprintf (
|
|
GTXT ("*** Warning: %d frameinfo packets are missing from total of %d when resolving %s."),
|
|
missed_fi, total_fi, dDscr->getName ());
|
|
warnq->append (new Emsg (CMSG_WARN, sb));
|
|
}
|
|
|
|
// threadPool->wait_group();
|
|
// delete threadPool;
|
|
theApplication->set_progress (0, NTXT (""));
|
|
free (progress_bar_msg);
|
|
if (!resolve_frinfo_pipelined && fp != NULL)
|
|
{
|
|
delete fp->ompstack;
|
|
delete fp->jstack;
|
|
delete fp->stack;
|
|
delete fp;
|
|
}
|
|
delete frameInfoCache;
|
|
frameInfoCache = NULL;
|
|
delete nodeCache;
|
|
nodeCache = NULL;
|
|
}
|
|
|
|
void
|
|
Experiment::post_process ()
|
|
{
|
|
// update non_paused_time after final update to "last_event"
|
|
if (resume_ts != MAX_TIME && last_event)
|
|
{
|
|
hrtime_t ts = last_event - exp_start_time;
|
|
hrtime_t delta = ts - resume_ts;
|
|
non_paused_time += delta;
|
|
resume_ts = MAX_TIME; // collection is paused
|
|
}
|
|
|
|
// GC: prune events outside of experiment duration, calculate GC duration, update indices
|
|
int index;
|
|
GCEvent * gcevent;
|
|
gc_duration = ZERO_TIME;
|
|
if (gcevents != NULL)
|
|
{
|
|
// delete events that finish before exp_start_time or start after last_event
|
|
for (int ii = 0; ii < gcevents->size ();)
|
|
{
|
|
gcevent = gcevents->fetch (ii);
|
|
if (gcevent->end - exp_start_time < 0
|
|
|| last_event - gcevent->start < 0)
|
|
delete gcevents->remove (ii);
|
|
else
|
|
ii++;
|
|
}
|
|
}
|
|
Vec_loop (GCEvent*, gcevents, index, gcevent)
|
|
{
|
|
gcevent->id = index + 1; // renumber to account for any deleted events
|
|
if (gcevent->start - exp_start_time < 0 || gcevent->start == ZERO_TIME)
|
|
// truncate events that start before experiment start
|
|
gcevent->start = exp_start_time;
|
|
if (last_event - gcevent->end < 0)
|
|
// truncate events that end after experiment end
|
|
gcevent->end = last_event;
|
|
gc_duration += gcevent->end - gcevent->start;
|
|
}
|
|
}
|
|
|
|
Experiment::Exp_status
|
|
Experiment::find_expdir (char *path)
|
|
{
|
|
// This function checks that the experiment directory
|
|
// is of the proper form, and accessible
|
|
struct stat64 sbuf;
|
|
|
|
// Save the name
|
|
expt_name = dbe_strdup (path);
|
|
|
|
// Check that the name ends in .er
|
|
size_t i = strlen (path);
|
|
if (i > 0 && path[i - 1] == '/')
|
|
path[--i] = '\0';
|
|
|
|
if (i < 4 || strcmp (&path[i - 3], NTXT (".er")) != 0)
|
|
{
|
|
Emsg *m = new Emsg (CMSG_FATAL,
|
|
GTXT ("*** Error: not a valid experiment name"));
|
|
errorq->append (m);
|
|
status = FAILURE;
|
|
return FAILURE;
|
|
}
|
|
|
|
// Check if new directory structure (i.e., no pointer file)
|
|
if (dbe_stat (path, &sbuf))
|
|
{
|
|
Emsg *m = new Emsg (CMSG_FATAL, GTXT ("*** Error: experiment not found"));
|
|
errorq->append (m);
|
|
status = FAILURE;
|
|
return FAILURE;
|
|
}
|
|
if (S_ISDIR (sbuf.st_mode) == 0)
|
|
{
|
|
// ignore pointer-file experiments
|
|
Emsg *m = new Emsg (CMSG_FATAL,
|
|
GTXT ("*** Error: experiment was recorded with an earlier version, and can not be read"));
|
|
errorq->append (m);
|
|
obsolete = 1;
|
|
status = FAILURE;
|
|
return FAILURE;
|
|
}
|
|
return SUCCESS;
|
|
}
|
|
|
|
void
|
|
Experiment::purge ()
|
|
{
|
|
// This routine will purge all of the caches of releasable storage.
|
|
for (int i = 0; i < dataDscrs->size (); ++i)
|
|
{
|
|
DataDescriptor *dataDscr = dataDscrs->fetch (i);
|
|
if (dataDscr == NULL)
|
|
continue;
|
|
dataDscr->reset ();
|
|
}
|
|
delete cstack;
|
|
delete cstackShowHide;
|
|
cstack = CallStack::getInstance (this);
|
|
cstackShowHide = CallStack::getInstance (this);
|
|
}
|
|
|
|
void
|
|
Experiment::resetShowHideStack ()
|
|
{
|
|
delete cstackShowHide;
|
|
cstackShowHide = CallStack::getInstance (this);
|
|
}
|
|
|
|
#define GET_INT_VAL(v, s, len) \
|
|
for (v = len = 0; isdigit(*s); s++, len++) { v = v * 10 + (*s -'0'); }
|
|
|
|
static int
|
|
dir_name_cmp (const void *a, const void *b)
|
|
{
|
|
char *s1 = *((char **) a);
|
|
char *s2 = *((char **) b);
|
|
while (*s1)
|
|
{
|
|
if (isdigit (*s1) && isdigit (*s2))
|
|
{
|
|
int v1, v2, len1, len2;
|
|
GET_INT_VAL (v1, s1, len1);
|
|
GET_INT_VAL (v2, s2, len2);
|
|
if (v1 != v2)
|
|
return v1 - v2;
|
|
if (len1 != len2)
|
|
return len2 - len1;
|
|
continue;
|
|
}
|
|
if (*s1 != *s2)
|
|
break;
|
|
s1++;
|
|
s2++;
|
|
}
|
|
return *s1 - *s2;
|
|
}
|
|
|
|
Vector<char*> *
|
|
Experiment::get_descendants_names ()
|
|
{
|
|
char *dir_name = get_expt_name ();
|
|
if (dir_name == NULL)
|
|
return NULL;
|
|
DIR *exp_dir = opendir (dir_name);
|
|
if (exp_dir == NULL)
|
|
return NULL;
|
|
Vector<char*> *exp_names = new Vector<char*>();
|
|
for (struct dirent *entry = readdir (exp_dir); entry;
|
|
entry = readdir (exp_dir))
|
|
{
|
|
if (entry->d_name[0] == '_' || strncmp (entry->d_name, "M_r", 3) == 0)
|
|
{
|
|
char *dpath = dbe_sprintf (NTXT ("%s/%s"), dir_name, entry->d_name);
|
|
struct stat64 sbuf;
|
|
if (dbe_stat (dpath, &sbuf) == 0 && S_ISDIR (sbuf.st_mode))
|
|
exp_names->append (dpath);
|
|
else
|
|
free (dpath);
|
|
}
|
|
}
|
|
closedir (exp_dir);
|
|
if (exp_names->size () == 0)
|
|
{
|
|
delete exp_names;
|
|
return NULL;
|
|
}
|
|
exp_names->sort (dir_name_cmp);
|
|
return exp_names;
|
|
}
|
|
|
|
bool
|
|
Experiment::create_dir (char *dname)
|
|
{
|
|
if (mkdir (dname, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) == 0)
|
|
{
|
|
return true;
|
|
}
|
|
struct stat64 sbuf;
|
|
if (dbe_stat (dname, &sbuf) != 0 || S_ISDIR (sbuf.st_mode) == 0)
|
|
{
|
|
char *buf = dbe_sprintf (GTXT ("Unable to create directory `%s'\n"),
|
|
dname);
|
|
errorq->append (new Emsg (CMSG_ERROR, buf));
|
|
free (buf);
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
char *
|
|
Experiment::get_arch_name ()
|
|
{
|
|
if (arch_name == NULL)
|
|
{
|
|
// Determine the master experiment directory.
|
|
// omazur: should do it in a less hacky way. XXXX
|
|
char *ptr = strstr_r (expt_name, DESCENDANT_EXPT_KEY);
|
|
ptr = ptr ? ptr + 3 : expt_name + strlen (expt_name);
|
|
arch_name = dbe_sprintf (NTXT ("%.*s/%s"), (int) (ptr - expt_name),
|
|
expt_name, SP_ARCHIVES_DIR);
|
|
}
|
|
return arch_name;
|
|
}
|
|
|
|
char *
|
|
Experiment::get_fndr_arch_name ()
|
|
{
|
|
if (fndr_arch_name == NULL)
|
|
// Determine the founder experiment directory.
|
|
fndr_arch_name = dbe_strdup (get_arch_name ());
|
|
return fndr_arch_name;
|
|
}
|
|
|
|
enum
|
|
{
|
|
HASH_NAME_LEN = 11 // (64 / 6 + 1) = 11
|
|
};
|
|
|
|
static char *
|
|
get_hash_string (char buf[HASH_NAME_LEN + 1], uint64_t hash)
|
|
{
|
|
static const char *har =
|
|
"0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-_";
|
|
for (int i = 0; i < HASH_NAME_LEN; i++)
|
|
{
|
|
buf[i] = har[hash & 0x3f];
|
|
hash = hash >> 6;
|
|
}
|
|
buf[HASH_NAME_LEN] = 0;
|
|
return buf;
|
|
}
|
|
|
|
char *
|
|
Experiment::getNameInArchive (const char *fname, bool archiveFile)
|
|
{
|
|
char *aname = get_archived_name (fname, archiveFile);
|
|
char *ret = dbe_sprintf (NTXT ("%s/%s"), get_arch_name (), aname);
|
|
free (aname);
|
|
return ret;
|
|
}
|
|
|
|
#define MAX_ARCHIVE_FILENAME_LEN (256 - HASH_NAME_LEN - 2)
|
|
|
|
char *
|
|
Experiment::get_archived_name (const char *fname, bool archiveFile)
|
|
{
|
|
char *bname = get_basename (fname);
|
|
|
|
// dirname_hash:
|
|
char dirnameHash[HASH_NAME_LEN + 1];
|
|
// Treat "a.out" and "./a.out" equally
|
|
uint64_t hash = bname != fname ? crc64 (fname, bname - fname)
|
|
: crc64 (NTXT ("./"), 2);
|
|
get_hash_string (dirnameHash, hash);
|
|
|
|
char *ret;
|
|
long bname_len = dbe_sstrlen (bname);
|
|
if (bname_len > MAX_ARCHIVE_FILENAME_LEN)
|
|
{
|
|
char basenameHash[HASH_NAME_LEN + 1];
|
|
hash = crc64 (bname, bname_len);
|
|
get_hash_string (basenameHash, hash);
|
|
ret = dbe_sprintf ("%.*s%c%s_%s",
|
|
MAX_ARCHIVE_FILENAME_LEN - HASH_NAME_LEN - 1,
|
|
bname, archiveFile ? '.' : '_',
|
|
dirnameHash, basenameHash);
|
|
}
|
|
else
|
|
ret = dbe_sprintf ("%s%c%s", bname, archiveFile ? '.' : '_', dirnameHash);
|
|
return ret;
|
|
}
|
|
|
|
char *
|
|
Experiment::checkFileInArchive (const char *fname, bool archiveFile)
|
|
{
|
|
if (archiveMap)
|
|
{
|
|
char *aname = get_archived_name (fname, archiveFile);
|
|
DbeFile *df = archiveMap->get (aname);
|
|
free (aname);
|
|
if (df)
|
|
return strdup (df->get_location ());
|
|
return NULL;
|
|
}
|
|
if (founder_exp)
|
|
return founder_exp->checkFileInArchive (fname, archiveFile);
|
|
return NULL;
|
|
}
|
|
|
|
|
|
// Comparing SegMem
|
|
|
|
static int
|
|
SegMemCmp (const void *a, const void *b)
|
|
{
|
|
SegMem *item1 = *((SegMem **) a);
|
|
SegMem *item2 = *((SegMem **) b);
|
|
return item1->unload_time > item2->unload_time ? 1 :
|
|
item1->unload_time == item2->unload_time ? 0 : -1;
|
|
}
|
|
|
|
SegMem*
|
|
Experiment::update_ts_in_maps (Vaddr addr, hrtime_t ts)
|
|
{
|
|
Vector<SegMem *> *segMems = (Vector<SegMem *> *) maps->values ();
|
|
if (!segMems->is_sorted ())
|
|
{
|
|
Dprintf (DEBUG_MAPS, NTXT ("update_ts_in_maps: segMems.size=%lld\n"), (long long) segMems->size ());
|
|
segMems->sort (SegMemCmp);
|
|
}
|
|
for (int i = 0, sz = segMems ? segMems->size () : 0; i < sz; i++)
|
|
{
|
|
SegMem *sm = segMems->fetch (i);
|
|
if (ts < sm->unload_time)
|
|
{
|
|
for (; i < sz; i++)
|
|
{
|
|
sm = segMems->fetch (i);
|
|
if ((addr >= sm->base) && (addr < sm->base + sm->size))
|
|
{
|
|
Dprintf (DEBUG_MAPS,
|
|
"update_ts_in_maps: old:%u.%09u -> %u.%09u addr=0x%08llx size=%lld\n",
|
|
(unsigned) (sm->load_time / NANOSEC),
|
|
(unsigned) (sm->load_time % NANOSEC),
|
|
(unsigned) (ts / NANOSEC), (unsigned) (ts % NANOSEC),
|
|
(unsigned long long) sm->base, (long long) sm->size);
|
|
maps->remove (sm->base, sm->load_time);
|
|
sm->load_time = ts;
|
|
maps->insert (sm->base, ts, sm);
|
|
return sm;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
Dprintf (DEBUG_MAPS, "update_ts_in_maps: NOT FOUND %u.%09u addr=0x%08llx\n",
|
|
(unsigned) (ts / NANOSEC), (unsigned) (ts % NANOSEC),
|
|
(unsigned long long) addr);
|
|
return NULL;
|
|
}
|
|
|
|
DbeInstr*
|
|
Experiment::map_Vaddr_to_PC (Vaddr addr, hrtime_t ts)
|
|
{
|
|
// Look up in the hash table first
|
|
int hash = (((int) addr) >> 8) & (HTableSize - 1);
|
|
SegMem *si = smemHTable[hash];
|
|
if (si == NULL || addr < si->base || addr >= si->base + si->size
|
|
|| ts < si->load_time || ts >= si->unload_time)
|
|
{
|
|
// Not in the hash table
|
|
si = (SegMem*) maps->locate (addr, ts);
|
|
if (si == NULL || addr < si->base || addr >= si->base + si->size
|
|
|| ts < si->load_time || ts >= si->unload_time)
|
|
{
|
|
si = update_ts_in_maps (addr, ts);
|
|
if (si == NULL)
|
|
return dbeSession->get_Unknown_Function ()->find_dbeinstr (PCInvlFlag, addr);
|
|
}
|
|
smemHTable[hash] = si;
|
|
}
|
|
|
|
// Calculate the file offset of 'addr'
|
|
uint64_t f_offset = si->get_file_offset () + (addr - si->base);
|
|
|
|
DbeInstr *instr;
|
|
if (si->obj->get_type () == Histable::LOADOBJECT)
|
|
{
|
|
LoadObject *lo = (LoadObject*) si->obj;
|
|
lo->sync_read_stabs ();
|
|
instr = lo->find_dbeinstr (f_offset);
|
|
}
|
|
else
|
|
{
|
|
int hash2 = ((((int) addr) & 0xFFFC00) | (((int) f_offset) >> 2))
|
|
& (HTableSize - 1);
|
|
instr = instHTable[hash2];
|
|
if (instr == NULL || instr->func != si->obj || instr->addr != f_offset)
|
|
{
|
|
// Not in the hash table
|
|
Function *fp = (Function *) si->obj;
|
|
instr = fp->find_dbeinstr (0, f_offset);
|
|
instHTable[hash2] = instr;
|
|
}
|
|
}
|
|
if (!instr->func->isUsed)
|
|
{
|
|
instr->func->isUsed = true;
|
|
instr->func->module->isUsed = true;
|
|
instr->func->module->loadobject->isUsed = true;
|
|
}
|
|
return instr;
|
|
}
|
|
|
|
Sample *
|
|
Experiment::map_event_to_Sample (hrtime_t ts)
|
|
{
|
|
Sample *sample;
|
|
int index;
|
|
|
|
// Check if the last used sample is the right one,
|
|
// if not then find it.
|
|
if (sample_last_used && ts >= sample_last_used->start_time
|
|
&& ts <= sample_last_used->end_time)
|
|
return sample_last_used;
|
|
|
|
Vec_loop (Sample*, samples, index, sample)
|
|
{
|
|
if ((ts >= sample->start_time) &&
|
|
(ts <= sample->end_time))
|
|
{
|
|
sample_last_used = sample;
|
|
return sample;
|
|
}
|
|
}
|
|
return (Sample*) NULL;
|
|
}
|
|
|
|
GCEvent *
|
|
Experiment::map_event_to_GCEvent (hrtime_t ts)
|
|
{
|
|
GCEvent *gcevent;
|
|
int index;
|
|
|
|
// Check if the last used sample is the right one,
|
|
// if not then find it.
|
|
if (gcevent_last_used && ts >= gcevent_last_used->start
|
|
&& ts <= gcevent_last_used->end)
|
|
return gcevent_last_used;
|
|
Vec_loop (GCEvent*, gcevents, index, gcevent)
|
|
{
|
|
if ((ts >= gcevent->start) &&
|
|
(ts <= gcevent->end))
|
|
{
|
|
gcevent_last_used = gcevent;
|
|
return gcevent;
|
|
}
|
|
}
|
|
return (GCEvent*) NULL;
|
|
}
|
|
|
|
DbeInstr*
|
|
Experiment::map_jmid_to_PC (Vaddr mid, int bci, hrtime_t ts)
|
|
{
|
|
if (mid == 0 || jmaps == NULL)
|
|
// special case: no Java stack was recorded, bci - error code
|
|
return dbeSession->get_JUnknown_Function ()->find_dbeinstr (0, bci);
|
|
|
|
JMethod *jmthd = jmidHTable->get (mid);
|
|
if (jmthd == NULL)
|
|
{
|
|
jmthd = (JMethod *) jmaps->locate_exact_match (mid, ts);
|
|
if (jmthd)
|
|
jmidHTable->put (mid, jmthd);
|
|
}
|
|
if (jmthd == NULL || jmthd->get_type () != Histable::FUNCTION)
|
|
return dbeSession->get_JUnknown_Function ()->find_dbeinstr (0, (uint64_t) mid);
|
|
return jmthd->find_dbeinstr (0, bci);
|
|
}
|
|
|
|
Emsg *
|
|
Experiment::fetch_comments ()
|
|
{
|
|
return commentq->fetch ();
|
|
}
|
|
|
|
Emsg *
|
|
Experiment::fetch_runlogq ()
|
|
{
|
|
return runlogq->fetch ();
|
|
}
|
|
|
|
Emsg *
|
|
Experiment::fetch_errors ()
|
|
{
|
|
return errorq->fetch ();
|
|
}
|
|
|
|
Emsg *
|
|
Experiment::fetch_warnings ()
|
|
{
|
|
return warnq->fetch ();
|
|
}
|
|
|
|
Emsg *
|
|
Experiment::fetch_notes ()
|
|
{
|
|
return notesq->fetch ();
|
|
}
|
|
|
|
Emsg *
|
|
Experiment::fetch_ifreq ()
|
|
{
|
|
return ifreqq->fetch ();
|
|
}
|
|
|
|
Emsg *
|
|
Experiment::fetch_pprocq ()
|
|
{
|
|
return pprocq->fetch ();
|
|
}
|
|
|
|
int
|
|
Experiment::read_dyntext_file ()
|
|
{
|
|
char *data_file_name = dbe_sprintf ("%s/%s", expt_name, SP_DYNTEXT_FILE);
|
|
Data_window *dwin = new Data_window (data_file_name);
|
|
if (dwin->not_opened ())
|
|
{
|
|
free (data_file_name);
|
|
delete dwin;
|
|
return 1;
|
|
}
|
|
dwin->need_swap_endian = need_swap_endian;
|
|
|
|
Function *fp = NULL;
|
|
char *progress_msg = NULL; // Message for the progress bar
|
|
for (int64_t offset = 0;;)
|
|
{
|
|
DT_common *cpckt = (DT_common *) dwin->bind (offset, sizeof (DT_common));
|
|
if (cpckt == NULL)
|
|
break;
|
|
size_t cpcktsize = dwin->decode (cpckt->size);
|
|
cpckt = (DT_common *) dwin->bind (offset, cpcktsize);
|
|
if (cpckt == NULL)
|
|
break;
|
|
switch (dwin->decode (cpckt->type))
|
|
{
|
|
case DT_HEADER:
|
|
{
|
|
DT_header *hdr = (DT_header*) cpckt;
|
|
hrtime_t ts = dwin->decode (hdr->time) + exp_start_time;
|
|
SegMem *si = (SegMem*) maps->locate (dwin->decode (hdr->vaddr), ts);
|
|
fp = si ? (Function *) si->obj : NULL;
|
|
if (fp && (fp->get_type () != Histable::FUNCTION
|
|
|| !(fp->flags & FUNC_FLAG_DYNAMIC)))
|
|
fp = NULL;
|
|
break;
|
|
}
|
|
case DT_CODE:
|
|
if (fp)
|
|
{
|
|
fp->img_fname = data_file_name;
|
|
fp->img_offset = offset + sizeof (DT_common);
|
|
if ((platform != Intel) && (platform != Amd64))
|
|
{ //ARCH(SPARC)
|
|
// Find out 'save' instruction address for SPARC
|
|
char *ptr = ((char*) cpckt) + sizeof (DT_common);
|
|
size_t img_size = cpcktsize - sizeof (DT_common);
|
|
for (size_t i = 0; i < img_size; i += 4)
|
|
if (ptr[i] == (char) 0x9d && ptr[i + 1] == (char) 0xe3)
|
|
{
|
|
fp->save_addr = i;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case DT_SRCFILE:
|
|
if (fp)
|
|
{
|
|
char *srcname = dbe_strndup (((char*) cpckt) + sizeof (DT_common),
|
|
cpcktsize - sizeof (DT_common));
|
|
LoadObject *ds = fp->module ? fp->module->loadobject : NULL;
|
|
assert (ds != NULL);
|
|
Module *mod = dbeSession->createModule (ds, NULL);
|
|
mod->set_file_name (srcname);
|
|
//}
|
|
if (fp->module)
|
|
{
|
|
// It's most likely (unknown). Remove fp from it.
|
|
long idx = fp->module->functions->find (fp);
|
|
if (idx >= 0)
|
|
fp->module->functions->remove (idx);
|
|
}
|
|
fp->module = mod;
|
|
mod->functions->append (fp);
|
|
}
|
|
break;
|
|
case DT_LTABLE:
|
|
if (fp)
|
|
{
|
|
DT_lineno *ltab = (DT_lineno*) ((char*) cpckt + sizeof (DT_common));
|
|
size_t sz = (cpcktsize - sizeof (DT_common)) / sizeof (DT_lineno);
|
|
if (sz <= 0)
|
|
break;
|
|
// Take care of the progress bar
|
|
static int percent = 0;
|
|
static long deltaReport = sz / 100; // 1000;
|
|
static long nextReport = 0;
|
|
static long progress_count = 0;
|
|
fp->pushSrcFile (fp->getDefSrc (), 0);
|
|
for (size_t i = 0; i < sz; i++)
|
|
{
|
|
int lineno = dwin->decode (ltab[i].lineno);
|
|
if (fp->usrfunc != NULL)
|
|
{
|
|
// Update progress bar
|
|
if (dbeSession->is_interactive ())
|
|
{
|
|
if (progress_count == nextReport)
|
|
{
|
|
if (percent < 99)
|
|
{
|
|
percent++;
|
|
if (NULL == progress_msg)
|
|
{
|
|
progress_msg = dbe_sprintf (GTXT ("Processing Dynamic Text: %s"),
|
|
get_basename (expt_name));
|
|
}
|
|
theApplication->set_progress (percent, progress_msg);
|
|
nextReport += deltaReport;
|
|
}
|
|
}
|
|
progress_count++;
|
|
}
|
|
DbeLine *dbeline = fp->usrfunc->mapPCtoLine (lineno, NULL);
|
|
lineno = dbeline != NULL ? dbeline->lineno : -1;
|
|
}
|
|
fp->add_PC_info (dwin->decode (ltab[i].offset), lineno);
|
|
}
|
|
fp->popSrcFile ();
|
|
}
|
|
break;
|
|
default:
|
|
// skip unknown records
|
|
break;
|
|
}
|
|
offset += cpcktsize;
|
|
}
|
|
free (progress_msg);
|
|
free (data_file_name);
|
|
delete dwin;
|
|
return 0;
|
|
}
|
|
|
|
uint32_t
|
|
Experiment::mapTagValue (Prop_type prop, uint64_t value)
|
|
{
|
|
Vector<Histable*> *objs = tagObjs->fetch (prop);
|
|
int lt = 0;
|
|
int rt = objs->size () - 1;
|
|
while (lt <= rt)
|
|
{
|
|
int md = (lt + rt) / 2;
|
|
Other *obj = (Other*) objs->fetch (md);
|
|
if (obj->value64 < value)
|
|
lt = md + 1;
|
|
else if (obj->value64 > value)
|
|
rt = md - 1;
|
|
else
|
|
return obj->tag;
|
|
}
|
|
|
|
uint32_t tag;
|
|
if (sparse_threads && (prop == PROP_THRID || prop == PROP_LWPID))
|
|
tag = objs->size () + 1; // "+ 1" related to 7038295
|
|
else
|
|
tag = (int) value; // truncation; See 6788767
|
|
|
|
Other *obj = new Other ();
|
|
obj->value64 = value;
|
|
obj->tag = tag;
|
|
if (lt == objs->size ())
|
|
objs->append (obj);
|
|
else
|
|
objs->insert (lt, obj);
|
|
|
|
// Update min and max tags
|
|
if (prop == PROP_LWPID)
|
|
{
|
|
if ((uint64_t) tag < min_lwp)
|
|
min_lwp = (uint64_t) tag;
|
|
if ((uint64_t) tag > max_lwp)
|
|
max_lwp = (uint64_t) tag;
|
|
lwp_cnt++;
|
|
}
|
|
else if (prop == PROP_THRID)
|
|
{
|
|
if ((uint64_t) tag < min_thread)
|
|
min_thread = (uint64_t) tag;
|
|
if ((uint64_t) tag > max_thread)
|
|
max_thread = (uint64_t) tag;
|
|
thread_cnt++;
|
|
}
|
|
else if (prop == PROP_CPUID)
|
|
{
|
|
// On Solaris 8, we don't get CPU id -- don't change
|
|
if (value != (uint64_t) - 1)
|
|
{//YXXX is this related only to solaris 8?
|
|
if ((uint64_t) tag < min_cpu)
|
|
min_cpu = (uint64_t) tag;
|
|
if ((uint64_t) tag > max_cpu)
|
|
max_cpu = (uint64_t) tag;
|
|
}
|
|
cpu_cnt++;
|
|
}
|
|
return obj->tag;
|
|
}
|
|
|
|
Vector<Histable*> *
|
|
Experiment::getTagObjs (Prop_type prop)
|
|
{
|
|
return tagObjs->fetch (prop);
|
|
}
|
|
|
|
Histable *
|
|
Experiment::getTagObj (Prop_type prop, uint32_t tag)
|
|
{
|
|
Vector<Histable*> *objs = tagObjs->fetch (prop);
|
|
if (objs == NULL)
|
|
return NULL;
|
|
for (int i = 0; i < objs->size (); i++)
|
|
{
|
|
Other *obj = (Other*) objs->fetch (i);
|
|
if (obj->tag == tag)
|
|
return obj;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
JThread *
|
|
Experiment::map_pckt_to_Jthread (uint32_t tid, hrtime_t tstamp)
|
|
{
|
|
if (!has_java)
|
|
return JTHREAD_DEFAULT;
|
|
int lt = 0;
|
|
int rt = jthreads_idx->size () - 1;
|
|
while (lt <= rt)
|
|
{
|
|
int md = (lt + rt) / 2;
|
|
JThread *jthread = jthreads_idx->fetch (md);
|
|
if (jthread->tid < tid)
|
|
lt = md + 1;
|
|
else if (jthread->tid > tid)
|
|
rt = md - 1;
|
|
else
|
|
{
|
|
for (; jthread; jthread = jthread->next)
|
|
if (tstamp >= jthread->start && tstamp < jthread->end)
|
|
return jthread;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return JTHREAD_NONE;
|
|
}
|
|
|
|
JThread*
|
|
Experiment::get_jthread (uint32_t tid)
|
|
{
|
|
if (!has_java)
|
|
return JTHREAD_DEFAULT;
|
|
int lt = 0;
|
|
int rt = jthreads_idx->size () - 1;
|
|
while (lt <= rt)
|
|
{
|
|
int md = (lt + rt) / 2;
|
|
JThread *jthread = jthreads_idx->fetch (md);
|
|
if (jthread->tid < tid)
|
|
lt = md + 1;
|
|
else if (jthread->tid > tid)
|
|
rt = md - 1;
|
|
else
|
|
{
|
|
JThread *jthread_first = jthread;
|
|
while ((jthread = jthread->next) != NULL)
|
|
if (!jthread->is_system () &&
|
|
jthread->jthr_id < jthread_first->jthr_id)
|
|
jthread_first = jthread;
|
|
return jthread_first;
|
|
}
|
|
}
|
|
|
|
return JTHREAD_NONE;
|
|
}
|
|
|
|
// SS12 experiment
|
|
DataDescriptor *
|
|
Experiment::newDataDescriptor (int data_id, int flags,
|
|
DataDescriptor *master_dDscr)
|
|
{
|
|
DataDescriptor *dataDscr = NULL;
|
|
if (data_id >= 0 && data_id < dataDscrs->size ())
|
|
{
|
|
dataDscr = dataDscrs->fetch (data_id);
|
|
if (dataDscr != NULL)
|
|
return dataDscr;
|
|
}
|
|
|
|
assert (data_id >= 0 && data_id < DATA_LAST);
|
|
const char *nm = get_prof_data_type_name (data_id);
|
|
const char *uname = get_prof_data_type_uname (data_id);
|
|
|
|
if (master_dDscr)
|
|
dataDscr = new DataDescriptor (data_id, nm, uname, master_dDscr);
|
|
else
|
|
dataDscr = new DataDescriptor (data_id, nm, uname, flags);
|
|
dataDscrs->store (data_id, dataDscr);
|
|
return dataDscr;
|
|
}
|
|
|
|
Vector<DataDescriptor*> *
|
|
Experiment::getDataDescriptors ()
|
|
{
|
|
Vector<DataDescriptor*> *result = new Vector<DataDescriptor*>;
|
|
for (int i = 0; i < dataDscrs->size (); ++i)
|
|
{
|
|
DataDescriptor *dd;
|
|
dd = get_raw_events (i); // force data fetch
|
|
if (dd != NULL)
|
|
result->append (dd);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
DataDescriptor *
|
|
Experiment::getDataDescriptor (int data_id)
|
|
{
|
|
if (data_id < 0 || data_id >= dataDscrs->size ())
|
|
return NULL;
|
|
return dataDscrs->fetch (data_id);
|
|
}
|
|
|
|
PacketDescriptor *
|
|
Experiment::newPacketDescriptor (int kind, DataDescriptor *dDscr)
|
|
{
|
|
PacketDescriptor *pDscr = new PacketDescriptor (dDscr);
|
|
pcktDscrs->store (kind, pDscr);
|
|
return pDscr;
|
|
}
|
|
|
|
PacketDescriptor *
|
|
Experiment::getPacketDescriptor (int kind)
|
|
{
|
|
if (kind < 0 || kind >= pcktDscrs->size ())
|
|
return NULL;
|
|
return pcktDscrs->fetch (kind);
|
|
}
|
|
|
|
void
|
|
Experiment::set_clock (int clk)
|
|
{
|
|
if (clk > 0)
|
|
{
|
|
if (maxclock < clk)
|
|
{
|
|
maxclock = clk;
|
|
clock = maxclock;
|
|
}
|
|
if (minclock == 0 || minclock > clk)
|
|
minclock = clk;
|
|
}
|
|
}
|
|
|
|
bool
|
|
JThread::is_system ()
|
|
{
|
|
if (group_name == NULL)
|
|
return false;
|
|
return strcmp (group_name, NTXT ("system")) == 0;
|
|
}
|
|
|
|
void
|
|
Experiment::dump_stacks (FILE *outfile)
|
|
{
|
|
cstack->print (outfile);
|
|
}
|
|
|
|
void
|
|
Experiment::dump_map (FILE *outfile)
|
|
{
|
|
int index;
|
|
SegMem *s;
|
|
fprintf (outfile, GTXT ("Experiment %s\n"), get_expt_name ());
|
|
fprintf (outfile, GTXT ("Address Size (hex) Load time Unload time Checksum Name\n"));
|
|
Vec_loop (SegMem*, seg_items, index, s)
|
|
{
|
|
timestruc_t load;
|
|
timestruc_t unload;
|
|
hr2timestruc (&load, (s->load_time - exp_start_time));
|
|
if (load.tv_nsec < 0)
|
|
{
|
|
load.tv_sec--;
|
|
load.tv_nsec += NANOSEC;
|
|
}
|
|
if (s->unload_time == MAX_TIME)
|
|
{
|
|
unload.tv_sec = 0;
|
|
unload.tv_nsec = 0;
|
|
}
|
|
else
|
|
hr2timestruc (&unload, (s->unload_time - exp_start_time));
|
|
if (load.tv_nsec < 0)
|
|
{
|
|
load.tv_sec--;
|
|
load.tv_nsec += NANOSEC;
|
|
}
|
|
fprintf (outfile,
|
|
"0x%08llx %8lld (0x%08llx) %5lld.%09lld %5lld.%09lld \"%s\"\n",
|
|
(long long) s->base, (long long) s->size, (long long) s->size,
|
|
(long long) load.tv_sec, (long long) load.tv_nsec,
|
|
(long long) unload.tv_sec, (long long) unload.tv_nsec,
|
|
s->obj->get_name ());
|
|
}
|
|
fprintf (outfile, NTXT ("\n"));
|
|
}
|
|
|
|
/**
|
|
* Copy file to archive
|
|
* @param name
|
|
* @param aname
|
|
* @param hide_msg
|
|
* @return 0 - success, 1 - error
|
|
*/
|
|
int
|
|
Experiment::copy_file_to_archive (const char *name, const char *aname, int hide_msg)
|
|
{
|
|
errno = 0;
|
|
int fd_w = open64 (aname, O_WRONLY | O_CREAT | O_EXCL, 0644);
|
|
if (fd_w == -1)
|
|
{
|
|
if (errno == EEXIST)
|
|
return 0;
|
|
fprintf (stderr, GTXT ("er_archive: unable to copy `%s': %s\n"),
|
|
name, STR (strerror (errno)));
|
|
return 1;
|
|
}
|
|
|
|
if (dbe_stat_file (name, NULL) != 0)
|
|
{
|
|
fprintf (stderr, GTXT ("er_archive: cannot access file `%s': %s\n"),
|
|
name, STR (strerror (errno)));
|
|
close (fd_w);
|
|
return 1;
|
|
}
|
|
|
|
int fd_r = open64 (name, O_RDONLY);
|
|
if (fd_r == -1)
|
|
{
|
|
fprintf (stderr, GTXT ("er_archive: unable to open `%s': %s\n"),
|
|
name, strerror (errno));
|
|
close (fd_w);
|
|
unlink (aname);
|
|
return 1;
|
|
}
|
|
|
|
if (!hide_msg)
|
|
fprintf (stderr, GTXT ("Copying `%s' to `%s'\n"), name, aname);
|
|
bool do_unlink = false;
|
|
for (;;)
|
|
{
|
|
unsigned char buf[65536];
|
|
int n, n1;
|
|
n = (int) read (fd_r, (void *) buf, sizeof (buf));
|
|
if (n <= 0)
|
|
break;
|
|
n1 = (int) write (fd_w, buf, n);
|
|
if (n != n1)
|
|
{
|
|
fprintf (stderr, GTXT ("er_archive: unable to write %d bytes to `%s': %s\n"),
|
|
n, aname, STR (strerror (errno)));
|
|
do_unlink = true;
|
|
break;
|
|
}
|
|
}
|
|
close (fd_w);
|
|
|
|
struct stat64 s_buf;
|
|
if (fstat64 (fd_r, &s_buf) == 0)
|
|
{
|
|
struct utimbuf u_buf;
|
|
u_buf.actime = s_buf.st_atime;
|
|
u_buf.modtime = s_buf.st_mtime;
|
|
utime (aname, &u_buf);
|
|
}
|
|
close (fd_r);
|
|
if (do_unlink)
|
|
{
|
|
if (!hide_msg)
|
|
fprintf (stderr, GTXT ("er_archive: remove %s\n"), aname);
|
|
unlink (aname);
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* Copy file to common archive
|
|
* Algorithm:
|
|
* Calculate checksum
|
|
* Generate file name to be created in common archive
|
|
* Check if it is not in common archive yet
|
|
* Copy file to the common archive directory if it is not there yet
|
|
* Create symbolic link: "aname" -> "caname", where "caname" is the name in common archive
|
|
* @param name - original file name
|
|
* @param aname - file name in experiment archive
|
|
* @param common_archive - common archive directory
|
|
* @return 0 - success, 1 - error
|
|
*/
|
|
int
|
|
Experiment::copy_file_to_common_archive (const char *name, const char *aname,
|
|
int hide_msg,
|
|
const char *common_archive,
|
|
int relative_path)
|
|
{
|
|
if (!name || !aname || !common_archive)
|
|
{
|
|
if (!name)
|
|
fprintf (stderr, GTXT ("er_archive: Internal error: file name is NULL\n"));
|
|
if (!aname)
|
|
fprintf (stderr, GTXT ("er_archive: Internal error: file name in archive is NULL\n"));
|
|
if (!common_archive)
|
|
fprintf (stderr, GTXT ("er_archive: Internal error: path to common archive is NULL\n"));
|
|
return 1;
|
|
}
|
|
// Check if file is already archived
|
|
if (dbe_stat (aname, NULL) == 0)
|
|
return 0; // File is already archived
|
|
// Generate full path to common archive directory
|
|
char *cad = NULL;
|
|
char *abs_aname = NULL;
|
|
if ((common_archive[0] != '/') || (aname[0] != '/'))
|
|
{
|
|
long size = pathconf (NTXT ("."), _PC_PATH_MAX);
|
|
if (size < 0)
|
|
{
|
|
fprintf (stderr, GTXT ("er_archive: Fatal error: pathconf(\".\", _PC_PATH_MAX) failed\n"));
|
|
return 1;
|
|
}
|
|
char *buf = (char *) malloc ((size_t) size);
|
|
if (buf == NULL)
|
|
{
|
|
fprintf (stderr, GTXT ("er_archive: Fatal error: unable to allocate memory\n"));
|
|
return 1;
|
|
}
|
|
char *ptr = getcwd (buf, (size_t) size);
|
|
if (ptr == NULL)
|
|
{
|
|
fprintf (stderr, GTXT ("er_archive: Fatal error: cannot determine current directory\n"));
|
|
free (buf);
|
|
return 1;
|
|
}
|
|
if (common_archive[0] != '/')
|
|
cad = dbe_sprintf (NTXT ("%s/%s"), ptr, common_archive);
|
|
else
|
|
cad = dbe_strdup (common_archive);
|
|
if (aname[0] != '/')
|
|
abs_aname = dbe_sprintf (NTXT ("%s/%s"), ptr, aname);
|
|
else
|
|
abs_aname = dbe_strdup (aname);
|
|
free (buf);
|
|
}
|
|
else
|
|
{
|
|
cad = dbe_strdup (common_archive);
|
|
abs_aname = dbe_strdup (aname);
|
|
}
|
|
// Calculate checksum
|
|
char * errmsg = NULL;
|
|
uint32_t crcval = get_cksum (name, &errmsg);
|
|
if (0 == crcval)
|
|
{ // error
|
|
free (cad);
|
|
free (abs_aname);
|
|
if (NULL != errmsg)
|
|
{
|
|
fprintf (stderr, GTXT ("er_archive: Fatal error: %s\n"), errmsg);
|
|
free (errmsg);
|
|
return 1;
|
|
}
|
|
fprintf (stderr,
|
|
GTXT ("er_archive: Fatal error: get_cksum(%s) returned %d\n"),
|
|
name, crcval);
|
|
return 1;
|
|
}
|
|
// Generate file name to be created in common archive
|
|
char *fname = get_basename (name);
|
|
char *abs_caname = dbe_sprintf (NTXT ("%s/%u_%s"), cad, crcval, fname);
|
|
if (abs_caname == NULL)
|
|
{
|
|
free (cad);
|
|
free (abs_aname);
|
|
fprintf (stderr,
|
|
GTXT ("er_archive: Fatal error: unable to allocate memory\n"));
|
|
return 1;
|
|
}
|
|
// Check if full name is not too long
|
|
long len = dbe_sstrlen (abs_caname);
|
|
long max = pathconf (cad, _PC_PATH_MAX);
|
|
if ((max < 0) || (len <= 0))
|
|
{ // unknown error
|
|
fprintf (stderr, GTXT ("er_archive: Fatal error: pathconf(%s, _PC_PATH_MAX) failed\n"),
|
|
cad);
|
|
free (abs_caname);
|
|
free (cad);
|
|
free (abs_aname);
|
|
return 1;
|
|
}
|
|
if (len >= max)
|
|
{
|
|
// Try to truncate the name
|
|
if ((len - max) <= dbe_sstrlen (fname))
|
|
{
|
|
// Yes, we can do it
|
|
abs_caname[max - 1] = 0;
|
|
if (!hide_msg)
|
|
fprintf (stderr, GTXT ("er_archive: file path is too long - truncated:%s\n"),
|
|
abs_caname);
|
|
}
|
|
}
|
|
// Check if file name is not too long
|
|
char *cafname = get_basename (abs_caname);
|
|
len = dbe_sstrlen (cafname);
|
|
max = pathconf (cad, _PC_NAME_MAX);
|
|
if ((max < 0) || (len <= 0))
|
|
{ // unknown error
|
|
fprintf (stderr, GTXT ("er_archive: Fatal error: pathconf(%s, _PC_NAME_MAX) failed\n"),
|
|
cad);
|
|
free (abs_caname);
|
|
free (cad);
|
|
free (abs_aname);
|
|
return 1;
|
|
}
|
|
if (len >= max)
|
|
{
|
|
// Try to truncate the name
|
|
if ((len - max) <= dbe_sstrlen (fname))
|
|
{
|
|
// Yes, we can do it
|
|
cafname[max - 1] = 0;
|
|
if (!hide_msg)
|
|
fprintf (stderr, GTXT ("er_archive: file name is too long - truncated:%s\n"),
|
|
abs_caname);
|
|
}
|
|
}
|
|
// Copy file to the common archive directory if it is not there yet
|
|
int res = 0;
|
|
if (dbe_stat_file (abs_caname, NULL) != 0)
|
|
{
|
|
// Use temporary file to avoid synchronization problems
|
|
char *t = dbe_sprintf ("%s/archive_%llx", cad, (unsigned long long) gethrtime());
|
|
free (cad);
|
|
// Copy file to temporary file
|
|
res = copy_file_to_archive (name, t, hide_msg); // hide messages
|
|
if (res != 0)
|
|
{
|
|
fprintf (stderr, GTXT ("er_archive: Fatal error: cannot copy file %s to temporary file: %s\n"),
|
|
name, t);
|
|
unlink (t);
|
|
free (t);
|
|
free (abs_caname);
|
|
free (abs_aname);
|
|
return 1;
|
|
}
|
|
// Set read-only permissions
|
|
struct stat64 statbuf;
|
|
if (0 == dbe_stat_file (name, &statbuf))
|
|
{
|
|
mode_t mask = S_IRUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH;
|
|
mode_t mode = statbuf.st_mode & mask;
|
|
chmod (t, mode);
|
|
}
|
|
// Try to rename temporary file "t" to "abs_caname"
|
|
// res = link(t, abs_caname); // link() fails on some f/s - use rename()
|
|
res = rename (t, abs_caname);
|
|
if (res != 0)
|
|
{
|
|
if (errno != EEXIST)
|
|
{
|
|
fprintf (stderr, GTXT ("er_archive: Fatal error: rename(%s, %s) returned error: %d\n"),
|
|
t, abs_caname, res);
|
|
unlink (t);
|
|
free (t);
|
|
free (abs_caname);
|
|
free (abs_aname);
|
|
return 1;
|
|
}
|
|
// File "abs_caname" is already there - continue
|
|
}
|
|
unlink (t);
|
|
free (t);
|
|
}
|
|
else
|
|
free (cad);
|
|
char *lname = NULL;
|
|
if (relative_path)
|
|
{
|
|
if (common_archive[0] != '/' && aname[0] != '/')
|
|
{
|
|
// compare one relative path to another and find common beginning
|
|
char *rel_caname = dbe_sprintf ("%s/%s", common_archive, cafname);
|
|
if (rel_caname == NULL)
|
|
{
|
|
fprintf (stderr, GTXT ("er_archive: Fatal error: unable to allocate memory\n"));
|
|
return 1;
|
|
}
|
|
lname = get_relative_link (rel_caname, aname);
|
|
free (rel_caname);
|
|
}
|
|
else
|
|
{
|
|
if (abs_aname == NULL)
|
|
{
|
|
fprintf (stderr, GTXT ("er_archive: Fatal error: unable to allocate memory\n"));
|
|
return 1;
|
|
}
|
|
lname = get_relative_link (abs_caname, abs_aname);
|
|
}
|
|
}
|
|
else // absolute path
|
|
lname = dbe_strdup (abs_caname);
|
|
free (abs_aname);
|
|
if (lname == NULL)
|
|
{
|
|
fprintf (stderr, GTXT ("er_archive: Fatal error: unable to allocate memory\n"));
|
|
return 1;
|
|
}
|
|
// Create symbolic link: aname -> lname
|
|
if (dbe_stat_file (abs_caname, NULL) == 0)
|
|
{
|
|
res = symlink (lname, aname);
|
|
if (res != 0)
|
|
{
|
|
fprintf (stderr, GTXT ("er_archive: Fatal error: symlink(%s, %s) returned error: %d (errno=%s)\n"),
|
|
lname, aname, res, strerror (errno));
|
|
free (abs_caname);
|
|
free (lname);
|
|
return 1;
|
|
}
|
|
if (!hide_msg)
|
|
fprintf (stderr, GTXT ("Created symbolic link %s to file in common archive: %s\n"),
|
|
aname, lname);
|
|
}
|
|
else
|
|
{
|
|
fprintf (stderr, GTXT ("er_archive: Internal error: file does not exist in common archive: %s\n"),
|
|
abs_caname);
|
|
res = 1;
|
|
}
|
|
free (abs_caname);
|
|
free (lname);
|
|
return res;
|
|
}
|
|
|
|
/**
|
|
* Copy file to archive
|
|
* @param name
|
|
* @param aname
|
|
* @param hide_msg
|
|
* @param common_archive
|
|
* @return 0 - success
|
|
*/
|
|
int
|
|
Experiment::copy_file (char *name, char *aname, int hide_msg, char *common_archive, int relative_path)
|
|
{
|
|
if (common_archive)
|
|
{
|
|
if (0 == copy_file_to_common_archive (name, aname, hide_msg,
|
|
common_archive, relative_path))
|
|
return 0;
|
|
// Error. For now - fatal error. Message is already printed.
|
|
fprintf (stderr, GTXT ("er_archive: Fatal error: cannot copy file %s to common archive %s\n"),
|
|
name, common_archive);
|
|
return 1;
|
|
}
|
|
return (copy_file_to_archive (name, aname, hide_msg));
|
|
}
|
|
|
|
LoadObject *
|
|
Experiment::createLoadObject (const char *path, uint64_t chksum)
|
|
{
|
|
LoadObject *lo = dbeSession->createLoadObject (path, chksum);
|
|
if (lo->firstExp == NULL)
|
|
lo->firstExp = this;
|
|
return lo;
|
|
}
|
|
|
|
LoadObject *
|
|
Experiment::createLoadObject (const char *path, const char *runTimePath)
|
|
{
|
|
DbeFile *df = findFileInArchive (path, runTimePath);
|
|
if (df && (df->get_stat () == NULL))
|
|
df = NULL; // No access to file
|
|
LoadObject *lo = dbeSession->createLoadObject (path, runTimePath, df);
|
|
if (df && (lo->dbeFile->get_location (false) == NULL))
|
|
{
|
|
lo->dbeFile->set_location (df->get_location ());
|
|
lo->dbeFile->inArchive = df->inArchive;
|
|
lo->dbeFile->sbuf = df->sbuf;
|
|
lo->dbeFile->experiment = df->experiment;
|
|
lo->firstExp = df->experiment;
|
|
}
|
|
if (lo->firstExp == NULL)
|
|
{
|
|
lo->firstExp = this;
|
|
lo->dbeFile->experiment = this;
|
|
}
|
|
return lo;
|
|
}
|
|
|
|
SourceFile *
|
|
Experiment::get_source (const char *path)
|
|
{
|
|
if (founder_exp && (founder_exp != this))
|
|
return founder_exp->get_source (path);
|
|
if (sourcesMap == NULL)
|
|
sourcesMap = new StringMap<SourceFile*>(1024, 1024);
|
|
if (strncmp (path, NTXT ("./"), 2) == 0)
|
|
path += 2;
|
|
SourceFile *sf = sourcesMap->get (path);
|
|
if (sf)
|
|
return sf;
|
|
char *fnm = checkFileInArchive (path, false);
|
|
if (fnm)
|
|
{
|
|
sf = new SourceFile (path);
|
|
dbeSession->append (sf);
|
|
DbeFile *df = sf->dbeFile;
|
|
df->set_location (fnm);
|
|
df->inArchive = true;
|
|
df->check_access (fnm); // init 'sbuf'
|
|
df->sbuf.st_mtime = 0; // Don't check timestamps
|
|
free (fnm);
|
|
}
|
|
else
|
|
sf = dbeSession->createSourceFile (path);
|
|
sourcesMap->put (path, sf);
|
|
return sf;
|
|
}
|
|
|
|
Vector<Histable*> *
|
|
Experiment::get_comparable_objs ()
|
|
{
|
|
update_comparable_objs ();
|
|
if (comparable_objs || dbeSession->expGroups->size () <= 1)
|
|
return comparable_objs;
|
|
comparable_objs = new Vector<Histable*>(dbeSession->expGroups->size ());
|
|
for (long i = 0, sz = dbeSession->expGroups->size (); i < sz; i++)
|
|
{
|
|
ExpGroup *gr = dbeSession->expGroups->get (i);
|
|
if (groupId == gr->groupId)
|
|
{
|
|
comparable_objs->append (this);
|
|
continue;
|
|
}
|
|
Histable *h = NULL;
|
|
for (long i1 = 0, sz1 = gr->exps ? gr->exps->size () : 0; i1 < sz1; i1++)
|
|
{
|
|
Experiment *exp = gr->exps->get (i1);
|
|
if ((exp->comparable_objs == NULL) && (dbe_strcmp (utargname, exp->utargname) == 0))
|
|
{
|
|
exp->phaseCompareIdx = phaseCompareIdx;
|
|
h = exp;
|
|
h->comparable_objs = comparable_objs;
|
|
break;
|
|
}
|
|
}
|
|
comparable_objs->append (h);
|
|
}
|
|
dump_comparable_objs ();
|
|
return comparable_objs;
|
|
}
|
|
|
|
DbeFile *
|
|
Experiment::findFileInArchive (const char *fname)
|
|
{
|
|
if (archiveMap)
|
|
{
|
|
char *aname = get_archived_name (fname);
|
|
DbeFile *df = archiveMap->get (aname);
|
|
free (aname);
|
|
return df;
|
|
}
|
|
if (founder_exp)
|
|
return founder_exp->findFileInArchive (fname);
|
|
return NULL;
|
|
}
|
|
|
|
DbeFile *
|
|
Experiment::findFileInArchive (const char *className, const char *runTimePath)
|
|
{
|
|
DbeFile *df = NULL;
|
|
if (runTimePath)
|
|
{
|
|
const char *fnm = NULL;
|
|
if (strncmp (runTimePath, NTXT ("zip:"), 4) == 0)
|
|
fnm = runTimePath + 4;
|
|
else if (strncmp (runTimePath, NTXT ("jar:file:"), 9) == 0)
|
|
fnm = runTimePath + 9;
|
|
if (fnm)
|
|
{
|
|
const char *s = strchr (fnm, '!');
|
|
if (s)
|
|
{
|
|
char *s1 = dbe_strndup (fnm, s - fnm);
|
|
df = findFileInArchive (s1);
|
|
free (s1);
|
|
}
|
|
else
|
|
df = findFileInArchive (fnm);
|
|
if (df)
|
|
df->filetype |= DbeFile::F_JAR_FILE;
|
|
}
|
|
else if (strncmp (runTimePath, NTXT ("file:"), 5) == 0)
|
|
{
|
|
fnm = runTimePath + 5;
|
|
df = findFileInArchive (fnm);
|
|
}
|
|
else
|
|
df = findFileInArchive (runTimePath);
|
|
}
|
|
if (df == NULL)
|
|
df = findFileInArchive (className);
|
|
return df;
|
|
}
|