| /* Copyright (C) 2021-2023 Free Software Foundation, Inc. |
| Contributed by Oracle. |
| |
| This file is part of GNU Binutils. |
| |
| This program is free software; you can redistribute it and/or modify |
| it under the terms of the GNU General Public License as published by |
| the Free Software Foundation; either version 3, or (at your option) |
| any later version. |
| |
| This program is distributed in the hope that it will be useful, |
| but WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| GNU General Public License for more details. |
| |
| You should have received a copy of the GNU General Public License |
| along with this program; if not, write to the Free Software |
| Foundation, 51 Franklin Street - Fifth Floor, Boston, |
| MA 02110-1301, USA. */ |
| |
| #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 |
| char *dyntext_name; // <experiment>/dyntext |
| |
| 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 */ |