Retro68/binutils/gprofng/src/Experiment.h
Wolfgang Thaller f485e125c4 binutils 2.39
2022-10-27 20:45:45 +02:00

690 lines
20 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. */
#ifndef _EEXPERIMENT_H
#define _EEXPERIMENT_H
// The experiment class is responsible for managing all the data
// for an individual experiment
#include "Metric.h"
#include "Histable.h"
#include "Stats_data.h"
#include "DefaultMap.h"
#include "HeapMap.h"
class Data_window;
class DbeFile;
class CallStack;
class JMethod;
class Sample;
class SegMem;
class LoadObject;
class SourceFile;
class UserLabel;
class PRBTree;
class Emsg;
class Emsgqueue;
struct JThread;
struct GCEvent;
class FileData;
class Module;
class Experiment;
template <class ITEM> class Vector;
#define JTHREAD_DEFAULT ((JThread*)0)
#define JTHREAD_NONE ((JThread*)-1)
// When we perform the pipelined optimization on resolve_frame_info() and add_stack()
// this is the number of iterations one phase works on before passing on the work to
// the next phase
#define CSTCTX_CHUNK_SZ 10000
#define PIPELINE_QUEUE_SZ_HI 8
#define PIPELINE_QUEUE_SZ_LOW 2
// the add_stack_ctx structure contains the intermediate state (context) after
// CSTCTX_CHUNK_SZ number of iterations to pass on the work to another thread to
// operate on the next stage
typedef struct
{
Vector<DbeInstr*> *natpcs;
Vector<Histable*> *jpcs;
long idx;
FramePacket *frp;
hrtime_t tstamp;
uint32_t thrid;
bool last_ctx;
} cstk_ctx;
// To minimize threadpool overhead, the granularity of a job submitted is made larger:
// containing a chunk of iterations (of size CSTCTX_CHUNK_SZ)
typedef struct
{
cstk_ctx* cstCtxAr[CSTCTX_CHUNK_SZ];
int last_idx;
long idx_begin;
long idx_end;
DataDescriptor *dDscr;
Experiment *exp;
void *cstk;
} cstk_ctx_chunk;
class Experiment : public Histable, public DbeMessages
{
public:
enum Exp_status
{
SUCCESS,
INCOMPLETE,
FAILURE
};
Experiment ();
virtual ~Experiment ();
virtual Histable_type
get_type ()
{
return EXPERIMENT;
};
virtual Vector<Histable*> *get_comparable_objs ();
int groupId;
Experiment *founder_exp; // parent of this experiment
Vector<Experiment*> *children_exps; // children of this experiment
// Configuration Information
char *hostname; // Hosthame (e.g. mymachine)
hrtime_t start_sec; // Starting timeval secs.
char *username; // name of person performing the test
char *architecture; // Architecture name ("sun4")
Platform_t platform; // Sparc,Sparcv9,Intel
WSize_t wsize; // word size: may be w32 or w64
int clock; // CPU clock frequency, Mhz
int varclock; // Set if CPU clock frequency can change: turbo-mode
int maxclock; // max. CPU clock frequency on MP machine
int minclock; // min. CPU clock frequency on MP machine
int ncpus; // count of CPUs where expt was recorded
int hw_cpuver; // CPU version from libcpc
char *machinemodel; // machine model of machine on which experiment was recorded
char *os_version; // Operating system name
int page_size; // Page size (bytes)
int npages; // Number of page size
int exp_maj_version; // major version number of current experiment
int exp_min_version; // minor version number of current experiment
int hex_field_width; // number of digits in hex form of address
// for current experiment, i.e. 8 for 32bit addresses
int broken; // If SP_JCMD_RUN line not seen
int obsolete; // If pointer file experiment detected
bool hwc_default; // True if HW counters were enabled by default
int hwc_bogus; // Count of bogus HWC packets
int hwc_lost_int; // Count of packets reflecting lost interrupt
int hwc_scanned; // If the HWC packets have been scanned
int invalid_packet; // Count of invalid packets
bool exec_started; // True if exec was called, and exec error not yet seen
bool dataspaceavail; // True if dataspace data is in the experiment
bool leaklistavail; // True if leaklist data is in the experiment
bool heapdataavail; // True if heap data is in the experiment
bool racelistavail; // true if there are race events in the experiment
bool iodataavail; // true if there are io events in the experiment
bool deadlocklistavail; // true if there are deadlock events in the experiment
bool timelineavail; // true if there are valid timestamps in the experiment
bool ifreqavail; // True if instruction-frequency data is in the experiment
bool ompavail; // true if there is OpenMP data in the experiment
bool has_java;
char *uarglist; // argv[] array, as a string
char *utargname; // basename of argv[0] extracted from uarglist
char *ucwd; // working directory
char *cversion; // collector version string
char *dversion; // driver version string (er_kernel)
char *jversion; // Java version string (java profiling)
// Open the named experiment record and process log file
Exp_status open (char *directory_name);
// Update experiment (read and process new data)
Exp_status update ();
// Returns collector parameters for the current sample selection
Collection_params *
get_params ()
{
return &coll_params;
}
Exp_status
get_status ()
{
return status;
}
// Returns the number of samples. For use by FilterNumeric
int
nsamples ()
{
return samples->size ();
}
// Release any releasable memory.
void purge ();
void resetShowHideStack ();
int save_notes (char*, bool);
int delete_notes (bool);
Experiment *getBaseFounder (); // returns topmost founder or this if no descendents
hrtime_t
getStartTime ()
{
return exp_start_time;
}
hrtime_t getRelativeStartTime (); // delta between start and founder's start
hrtime_t
getWallStartSec ()
{
return start_sec;
}
hrtime_t
getLastEvent ()
{
if (last_event != ZERO_TIME)
return last_event;
return exp_start_time;
}
hrtime_t
getGCDuration ()
{
return gc_duration;
}
int
getPID ()
{
return pid;
}
int
getUserExpId ()
{
return userExpId;
}
int
getExpIdx ()
{
return expIdx;
}
void
setExpIdx (int idx)
{
expIdx = idx;
}
void
setUserExpId (int idx)
{
userExpId = idx;
}
void
setTinyThreshold (int limit)
{
tiny_threshold = limit;
}
bool
isDiscardedTinyExperiment ()
{
return discardTiny;
}
Exp_status open_epilogue ();
void read_experiment_data (bool read_ahead);
static int copy_file_to_archive (const char *name, const char *aname, int hide_msg);
static int copy_file_to_common_archive (const char *name, const char *aname,
int hide_msg, const char *common_archive, int relative_path = 0);
static int copy_file (char *name, char *aname, int hide_msg,
char *common_archive = NULL, int relative_path = 0);
// get_raw_events()
// action: get unfiltered packets, loading them if required
// parameters: data_id (see ProfData_type)
DataDescriptor *get_raw_events (int data_id);
Vector<DataDescriptor*> *getDataDescriptors ();
// Some DATA_* types are derived from others, e.g. DATA_HEAPSZ is derived from DATA_HEAP
// The following hooks support derived DataViews
int base_data_id (int data_id); // returns base data_id type (ProfData_type DATA_*)
DataView *create_derived_data_view (int data_id, DataView *dview);
Vector<BaseMetric*>*
get_metric_list ()
{
return metrics;
}
char *
get_expt_name ()
{
return expt_name; // Return the pathname to the experiment
};
Vector<char*> *get_descendants_names ();
char *get_fndr_arch_name ();
char *get_arch_name ();
char *getNameInArchive (const char *fname, bool archiveFile = false);
char *checkFileInArchive (const char *fname, bool archiveFile = false);
DbeFile *findFileInArchive (const char *className, const char *runTimePath);
DbeFile *findFileInArchive (const char *fname);
bool create_dir (char *dname);
Vaddr
ret_stack_base ()
{
return stack_base;
};
// Map a virtual address to a PC pair
DbeInstr *map_Vaddr_to_PC (Vaddr addr, hrtime_t ts);
DbeInstr *map_jmid_to_PC (Vaddr mid, int lineno, hrtime_t ts);
Sample *map_event_to_Sample (hrtime_t ts);
GCEvent *map_event_to_GCEvent (hrtime_t ts);
DataView *
getOpenMPdata ()
{
return openMPdata;
}
time_t
get_mtime ()
{
return mtime;
}
Emsg *fetch_comments (void); // fetch the queue of comment messages
Emsg *fetch_runlogq (void); // fetch the queue of run log messages
Emsg *fetch_errors (void); // fetch the queue of error messages
Emsg *fetch_warnings (void); // fetch the queue of warning messages
Emsg *fetch_notes (void); // fetch the queue of notes messages
Emsg *fetch_ifreq (void); // fetch the queue of ifreq messages
Emsg *fetch_pprocq (void); // fetch the queue of post-processing messages
// message queues
Emsgqueue *commentq; // comments for the experiment header
Emsgqueue *runlogq; // used temporarily; after log file processing,
// messages are appended to the commentq
Emsgqueue *errorq; // error messages
Emsgqueue *warnq; // warning messages
Emsgqueue *notesq; // user-written notes messages
Emsgqueue *pprocq; // postprocessing messages
Emsgqueue *ifreqq; // Instruction frequency data, from count experiment
Map<const char*, LoadObject*> *loadObjMap;
Vector<LoadObject*> *loadObjs;
void append (LoadObject *lo);
LoadObject *createLoadObject (const char *path, uint64_t chksum = 0);
LoadObject *createLoadObject (const char *path, const char *runTimePath);
SourceFile *get_source (const char *path);
void set_clock (int clk);
CallStack *
callTree ()
{
return cstack;
}
CallStack *
callTreeShowHide ()
{
return cstackShowHide;
}
uint32_t mapTagValue (Prop_type, uint64_t value);
Histable *getTagObj (Prop_type, uint32_t idx);
Vector<Histable*> *getTagObjs (Prop_type);
JThread *map_pckt_to_Jthread (uint32_t tid, hrtime_t tstamp);
JThread *get_jthread (uint32_t tid);
Vector<JThread*> *
get_jthreads ()
{
return jthreads;
}
Vector<GCEvent*> *
get_gcevents ()
{
return gcevents;
}
bool need_swap_endian;
Collection_params coll_params; // Collection params
// Ranges for threads, lwps, cpu
uint64_t min_thread;
uint64_t max_thread;
uint64_t thread_cnt;
uint64_t min_lwp;
uint64_t max_lwp;
uint64_t lwp_cnt;
uint64_t min_cpu;
uint64_t max_cpu;
uint64_t cpu_cnt;
uint64_t dsevents; // count of dataspace events
uint64_t dsnoxhwcevents; /* count of ds events that could be be validated
* because of no branch target info */
PacketDescriptor *newPacketDescriptor (int kind, DataDescriptor *dDscr);
PacketDescriptor *getPacketDescriptor (int kind);
// debugging aids -- dump_stacks, dump_map
void dump_stacks (FILE *);
void dump_map (FILE *);
// These methods are used in nightly performance regression testing
void DBG_memuse (Sample *);
void DBG_memuse (const char *sname);
void init_cache ();
DefaultMap<int64_t, FileData*> *
getFDataMap ()
{
return fDataMap;
}
CallStack *cstack;
protected:
Exp_status status; // Error status
Vector<SegMem*> *seg_items; // Master list of seg_items
CallStack *cstackShowHide;
PRBTree *maps; // All maps in (Vaddr,time)
hrtime_t gc_duration; // wall-clock hrtime of total GC intervals
hrtime_t exp_start_time; // wall-clock hrtime at exp start
hrtime_t last_event; // wall-clock hrtime of last known sample or log.xml entry
hrtime_t non_paused_time; // sum of periods where data collection is active (not paused)
hrtime_t resume_ts; // tracks log.xml start/resume times
void update_last_event (hrtime_t ts /*wall time (not 0-based)*/);
char *expt_name; // name of experiment
char *arch_name; // <experiment>/archive
char *fndr_arch_name; // <founder_experiment>/archive
//TBR? hrtime_t sample_time; // total of sample durations
int yyparse (); // Allow yyparse actions to access
Vaddr stack_base; // Stack base
// Write experiment header to comment queue
void write_header ();
void write_coll_params ();
Exp_status find_expdir (char *directory_name);
// Invoke the parser to process a file.
void read_data_file (const char*, const char*);
int read_log_file ();
void read_labels_file ();
void read_notes_file ();
void read_archives ();
int read_java_classes_file ();
void read_map_file ();
int read_overview_file ();
int read_dyntext_file ();
void read_omp_file ();
void read_omp_preg ();
void read_omp_task ();
void read_ifreq_file ();
void read_frameinfo_file ();
// Functions to process the log and loadobjects file entries
// They are deliberately made virtual to overload them
// in er_export.
virtual int process_arglist_cmd (char *, char *);
virtual int process_desc_start_cmd (char *, hrtime_t, char *, char *, int, char *);
virtual int process_desc_started_cmd (char *, hrtime_t, char *, char *, int, char *);
virtual int process_fn_load_cmd (Module *mod, char *fname, Vaddr vaddr, int fsize, hrtime_t ts);
virtual int process_fn_unload_cmd (char *, Vaddr, hrtime_t);
virtual int process_hwcounter_cmd (char *, int, char *, char *, int, int, int, char *);
virtual int process_hwsimctr_cmd (char *, int, char *, char *, char*, int, int, int, int, int);
virtual int process_jcm_load_cmd (char*, Vaddr, Vaddr, int, hrtime_t);
virtual int process_jcm_unload_cmd (char*, Vaddr, hrtime_t);
virtual int process_Linux_kernel_cmd (hrtime_t);
virtual int process_jthr_end_cmd (char *, uint64_t, Vaddr, Vaddr, hrtime_t);
virtual int process_jthr_start_cmd (char *, char *, char *, char *, uint64_t, Vaddr, Vaddr, hrtime_t);
virtual int process_gc_end_cmd (hrtime_t);
virtual int process_gc_start_cmd (hrtime_t);
virtual int process_sample_cmd (char *, hrtime_t, int id, char *lbl);
virtual int process_sample_sig_cmd (char *, int);
virtual int process_seg_map_cmd (char *, hrtime_t, Vaddr, int, int, int64_t, int64_t, int64_t, char *);
virtual int process_seg_unmap_cmd (char *, hrtime_t, Vaddr);
// creation time for experiment
time_t mtime;
hrtime_t exp_rel_start_time; // start of exp. relative to founder
bool exp_rel_start_time_set;
Vector<UserLabel*> *userLabels; // List of er_labels
int userExpId; // user value for EXPID
int expIdx; // DbeSession exp identifier
PRBTree *jmaps; // JAVA_CLASSES: (id,time)->Histable
Experiment* baseFounder; // outermost experiment (null until lazily computed)
// Represents a file in experiment
class ExperimentFile;
// XML handler to parse various experiment files
class ExperimentHandler;
class ExperimentLabelsHandler;
uint64_t readPacket (Data_window *dwin, Data_window::Span *span);
void readPacket (Data_window *dwin, char *ptr, PacketDescriptor *pDscr,
DataDescriptor *dDscr, int arg, uint64_t pktsz);
// read data
DataDescriptor *get_profile_events ();
DataDescriptor *get_sync_events ();
DataDescriptor *get_hwc_events ();
DataDescriptor *get_heap_events ();
DataDescriptor *get_heapsz_events ();
DataDescriptor *get_iotrace_events ();
DataDescriptor *get_race_events ();
DataDescriptor *get_deadlock_events ();
DataDescriptor *get_sample_events ();
DataDescriptor *get_gc_events ();
DataDescriptor *getDataDescriptor (int data_id);
DataDescriptor *newDataDescriptor (int data_id, int flags = 0,
DataDescriptor *master_dDscr = NULL);
// Frame info data structures and methods
struct UIDnode;
struct RawFramePacket;
Vector<RawFramePacket*>*frmpckts; // frame info data
static int frUidCmp (const void*, const void*);
RawFramePacket *find_frame_packet (uint64_t uid);
static const int CHUNKSZ = 16384;
long nnodes;
long nchunks;
UIDnode **chunks;
UIDnode **uidHTable;
Vector<UIDnode*> *uidnodes;
bool resolveFrameInfo;
bool discardTiny;
int tiny_threshold; /* optimize away tiny experiments which ran
* for less than specified time (ms): default 0 */
static int uidNodeCmp (const void *a, const void *b);
UIDnode *add_uid (Data_window *dwin, uint64_t uid, int size, uint32_t *array, uint64_t link_uid);
UIDnode *add_uid (Data_window *dwin, uint64_t uid, int size, uint64_t *array, uint64_t link_uid);
UIDnode *new_uid_node (uint64_t uid, uint64_t val);
UIDnode *get_uid_node (uint64_t uid, uint64_t val);
UIDnode *get_uid_node (uint64_t uid);
UIDnode *find_uid_node (uint64_t uid);
ExperimentFile *logFile;
// Data descriptors
Vector<DataDescriptor*> *dataDscrs;
Vector<PacketDescriptor*> *pcktDscrs;
long blksz; // binary data file block size
// Processed data packets
DataView *openMPdata; // OMP fork events
// Map events to OpenMP parallel regions and tasks
Map2D<uint32_t, hrtime_t, uint64_t> *mapPRid;
Map2D<uint32_t, hrtime_t, void*> *mapPReg;
Map2D<uint32_t, hrtime_t, void*> *mapTask;
// Archive content
Map<const char*, DbeFile *> *archiveMap;
Map<const char*, SourceFile*>*sourcesMap;
void init ();
void fini ();
void post_process ();
void constructJavaStack (FramePacket *, UIDnode *, Map<uint64_t, uint64_t> *);
void resolve_frame_info (DataDescriptor*);
void cleanup_cstk_ctx_chunk ();
void register_metric (Metric::Type type);
void register_metric (Hwcentry *ctr, const char* aux, const char* username);
Sample *sample_last_used;
GCEvent *gcevent_last_used;
char *first_sample_label;
Module *get_jclass (const char *className, const char *fileName);
LoadObject *get_j_lo (const char *className, const char *fileName);
Vector<BaseMetric*> *metrics;
Vector<JThread*> *jthreads; // master list of Java threads
Vector<JThread*> *jthreads_idx; // index in the master list
Vector<GCEvent*> *gcevents;
Vector<UnmapChunk*> *heapUnmapEvents;
Vector<Sample*> *samples; // Array of Sample pointers
DefaultMap<int64_t, FileData*> *fDataMap; // list of FileData objects using the virtual File descriptor as the key
DefaultMap<int, int64_t> *vFdMap; // list of virtual file descrptors using the file descriptor as the key
Vector<Vector<Histable*>*> *tagObjs; // tag objects
bool sparse_threads;
SegMem **smemHTable; // hash table for SegMem's
DbeInstr **instHTable; // hash table for DbeInstr
Map<unsigned long long, JMethod*> *jmidHTable; // hash table for jmid
// identity of target process
int pid;
int ppid;
int pgrp;
int sid;
// Map file processing related data
struct MapRecord
{
enum
{
LOAD, UNLOAD
} kind;
Histable *obj;
Vaddr base;
Size size;
hrtime_t ts;
uint64_t foff;
};
void mrec_insert (MapRecord *mrec);
SegMem *update_ts_in_maps (Vaddr addr, hrtime_t ts);
int read_warn_file ();
LoadObject *get_dynfunc_lo (const char *loName);
Function *create_dynfunc (Module *mod, char *fname, int64_t vaddr, int64_t fsize);
char *get_archived_name (const char *fname, bool archiveFile = false);
Vector<MapRecord*> *mrecs;
private:
void add_evt_time_to_profile_events (DataDescriptor *dDscr);
DataView *create_heapsz_data_view (DataView *heap_dview);
void compute_heapsz_data_view (DataView *heapsz_dview);
};
struct JThread
{
JThread *next;
char *name;
char *group_name;
char *parent_name;
uint32_t tid; // system thread id
Vaddr jthr; // recorded Java thread id
Vaddr jenv; // recorded JNIEnv id
uint32_t jthr_id; // internal JThread object id
hrtime_t start;
hrtime_t end;
JThread ()
{
name = NULL;
group_name = NULL;
parent_name = NULL;
}
~JThread ()
{
free (name);
free (group_name);
free (parent_name);
}
bool is_system ();
};
struct GCEvent
{
GCEvent ()
{
id = -1;
}
~GCEvent () { }
hrtime_t start;
hrtime_t end;
int id;
};
class ExperimentLoadCancelException
{
public:
ExperimentLoadCancelException () { };
~ExperimentLoadCancelException () { };
};
#endif /* _EEXPERIMENT_H */