|  | // Copyright 2006 The Android Open Source Project | 
|  |  | 
|  | #ifndef TRACE_READER_BASE_H | 
|  | #define TRACE_READER_BASE_H | 
|  |  | 
|  | #include <inttypes.h> | 
|  | #include "trace_common.h" | 
|  | #include "hash_table.h" | 
|  |  | 
|  | class BBReader; | 
|  | class InsnReader; | 
|  | class AddrReader; | 
|  | class ExcReader; | 
|  | class PidReader; | 
|  | class MethodReader; | 
|  |  | 
|  | struct StaticRec { | 
|  | uint64_t    bb_num; | 
|  | uint32_t    bb_addr; | 
|  | uint32_t    num_insns; | 
|  | }; | 
|  |  | 
|  | struct StaticBlock { | 
|  | StaticRec   rec; | 
|  | uint32_t    *insns; | 
|  | }; | 
|  |  | 
|  | struct BBEvent { | 
|  | uint64_t    time; | 
|  | uint64_t    bb_num; | 
|  | uint32_t    bb_addr; | 
|  | uint32_t    *insns; | 
|  | int         num_insns; | 
|  | int         pid; | 
|  | int         is_thumb; | 
|  | }; | 
|  |  | 
|  | struct PidEvent { | 
|  | uint64_t    time; | 
|  | int         rec_type;       // record type: fork, context switch, exit ... | 
|  | int         tgid;           // thread group id | 
|  | int         pid;            // for fork: child pid; for switch: next pid; | 
|  | //   for exit: exit value | 
|  | uint32_t    vstart;         // virtual start address (only used with mmap) | 
|  | uint32_t    vend;           // virtual end address (only used with mmap) | 
|  | uint32_t    offset;         // virtual file offset (only used with mmap) | 
|  |  | 
|  | // Dynamically allocated path to executable (or lib). In the case of | 
|  | // an mmapped dex file, the path is modified to be more useful for | 
|  | // comparing against the output of dexlist.  For example, instead of this: | 
|  | //   /data/dalvik-cache/system@app@TestHarness.apk@classes.dex | 
|  | // We convert to this: | 
|  | //   /system/app/TestHarness.apk | 
|  | char        *path; | 
|  | char        *mmap_path;     // unmodified mmap path | 
|  | int         argc;           // number of args | 
|  | char        **argv;         // dynamically allocated array of args | 
|  | }; | 
|  |  | 
|  | struct MethodRec { | 
|  | uint64_t    time; | 
|  | uint32_t    addr; | 
|  | int         pid; | 
|  | int         flags; | 
|  | }; | 
|  |  | 
|  | struct DexSym { | 
|  | uint32_t    addr; | 
|  | int         len; | 
|  | char        *name; | 
|  | }; | 
|  |  | 
|  | struct DexFileList { | 
|  | char        *path; | 
|  | int         nsymbols; | 
|  | DexSym      *symbols; | 
|  | }; | 
|  |  | 
|  | class TraceReaderBase { | 
|  | public: | 
|  | TraceReaderBase(); | 
|  | virtual ~TraceReaderBase(); | 
|  |  | 
|  | friend class BBReader; | 
|  |  | 
|  | void                Open(const char *filename); | 
|  | void                Close(); | 
|  | void                WriteHeader(TraceHeader *header); | 
|  | inline bool         ReadBB(BBEvent *event); | 
|  | int                 ReadStatic(StaticRec *rec); | 
|  | int                 ReadStaticInsns(int num, uint32_t *insns); | 
|  | TraceHeader         *GetHeader()                { return header_; } | 
|  | inline uint64_t     ReadInsnTime(uint64_t min_time); | 
|  | void                TruncateLastBlock(uint32_t num_insns); | 
|  | inline bool         ReadAddr(uint64_t *time, uint32_t *addr, int *flags); | 
|  | inline bool         ReadExc(uint64_t *time, uint32_t *current_pc, | 
|  | uint64_t *recnum, uint32_t *target_pc, | 
|  | uint64_t *bb_num, uint64_t *bb_start_time, | 
|  | int *num_insns); | 
|  | inline bool         ReadPidEvent(PidEvent *event); | 
|  | inline bool         ReadMethod(MethodRec *method_record); | 
|  | StaticBlock         *GetStaticBlock(uint64_t bb_num) { return &blocks_[bb_num]; } | 
|  | uint32_t            *GetInsns(uint64_t bb_num) { return blocks_[bb_num].insns; } | 
|  | uint32_t            GetBBAddr(uint64_t bb_num) { | 
|  | return blocks_[bb_num].rec.bb_addr & ~1; | 
|  | } | 
|  | int                 GetIsThumb(uint64_t bb_num) { | 
|  | return blocks_[bb_num].rec.bb_addr & 1; | 
|  | } | 
|  | void                SetPostProcessing(bool val) { post_processing_ = val; } | 
|  |  | 
|  | protected: | 
|  | virtual int         FindCurrentPid(uint64_t time); | 
|  | int                 current_pid_; | 
|  | int                 next_pid_; | 
|  | uint64_t            next_pid_switch_time_; | 
|  | PidReader           *internal_pid_reader_; | 
|  | MethodReader        *internal_method_reader_; | 
|  | HashTable<DexFileList*> *dex_hash_; | 
|  |  | 
|  | private: | 
|  | int          FindNumInsns(uint64_t bb_num, uint64_t bb_start_time); | 
|  | void         ReadTraceHeader(FILE *fstream, const char *filename, | 
|  | const char *tracename, TraceHeader *header); | 
|  | PidEvent     *FindMmapDexFileEvent(); | 
|  | void         ParseDexList(const char *filename); | 
|  |  | 
|  | char         *static_filename_; | 
|  | FILE         *static_fstream_; | 
|  | TraceHeader  *header_; | 
|  | BBReader     *bb_reader_; | 
|  | InsnReader   *insn_reader_; | 
|  | AddrReader   *load_addr_reader_; | 
|  | AddrReader   *store_addr_reader_; | 
|  | ExcReader    *exc_reader_; | 
|  | PidReader    *pid_reader_; | 
|  | MethodReader *method_reader_; | 
|  | ExcReader    *internal_exc_reader_; | 
|  | StaticBlock  *blocks_; | 
|  | bool         exc_end_; | 
|  | uint64_t     bb_recnum_; | 
|  | uint64_t     exc_recnum_; | 
|  | uint64_t     exc_bb_num_; | 
|  | uint64_t     exc_time_; | 
|  | int          exc_num_insns_; | 
|  | bool         post_processing_; | 
|  |  | 
|  | bool         load_eof_; | 
|  | uint64_t     load_time_; | 
|  | uint32_t     load_addr_; | 
|  | bool         store_eof_; | 
|  | uint64_t     store_time_; | 
|  | uint32_t     store_addr_; | 
|  | }; | 
|  |  | 
|  | class Decoder; | 
|  |  | 
|  | class BBReader { | 
|  | public: | 
|  | explicit BBReader(TraceReaderBase *trace); | 
|  | ~BBReader(); | 
|  | void     Open(const char *filename); | 
|  | void     Close(); | 
|  | bool     ReadBB(BBEvent *event); | 
|  |  | 
|  | private: | 
|  | struct TimeRec { | 
|  | BBRec       bb_rec; | 
|  | uint64_t    next_time; | 
|  | }; | 
|  |  | 
|  | struct Future { | 
|  | Future      *next; | 
|  | TimeRec     bb; | 
|  | }; | 
|  |  | 
|  | inline Future   *AllocFuture(); | 
|  | inline void     FreeFuture(Future *future); | 
|  | inline void     InsertFuture(Future *future); | 
|  | inline int      DecodeNextRec(); | 
|  |  | 
|  | TimeRec         nextrec_; | 
|  | Future          futures_[kMaxNumBasicBlocks]; | 
|  | Future          *head_; | 
|  | Future          *free_; | 
|  | Decoder         *decoder_; | 
|  | bool            is_eof_; | 
|  | TraceReaderBase *trace_; | 
|  | }; | 
|  |  | 
|  | class InsnReader { | 
|  | public: | 
|  | InsnReader(); | 
|  | ~InsnReader(); | 
|  |  | 
|  | void        Open(const char *filename); | 
|  | void        Close(); | 
|  | uint64_t    ReadInsnTime(uint64_t min_time); | 
|  |  | 
|  | private: | 
|  | Decoder     *decoder_; | 
|  | uint64_t    prev_time_; | 
|  | uint64_t    time_diff_; | 
|  | int         repeat_; | 
|  | }; | 
|  |  | 
|  | class AddrReader { | 
|  | public: | 
|  | AddrReader(); | 
|  | ~AddrReader(); | 
|  |  | 
|  | bool        Open(const char *filename, const char *suffix); | 
|  | void        Close(); | 
|  | bool        ReadAddr(uint64_t *time, uint32_t *addr); | 
|  |  | 
|  | private: | 
|  | Decoder     *decoder_; | 
|  | uint32_t    prev_addr_; | 
|  | uint64_t    prev_time_; | 
|  | bool        opened_;        // true after file is opened | 
|  | }; | 
|  |  | 
|  | class ExcReader { | 
|  | public: | 
|  | ExcReader(); | 
|  | ~ExcReader(); | 
|  |  | 
|  | void        Open(const char *filename); | 
|  | void        Close(); | 
|  | bool        ReadExc(uint64_t *time, uint32_t *current_pc, | 
|  | uint64_t *recnum, uint32_t *target_pc, | 
|  | uint64_t *bb_num, uint64_t *bb_start_time, | 
|  | int *num_insns); | 
|  |  | 
|  | private: | 
|  | Decoder     *decoder_; | 
|  | uint64_t    prev_time_; | 
|  | uint64_t    prev_recnum_; | 
|  | }; | 
|  |  | 
|  | class PidReader { | 
|  | public: | 
|  | PidReader(); | 
|  | ~PidReader(); | 
|  |  | 
|  | void        Open(const char *filename); | 
|  | void        Close(); | 
|  | bool        ReadPidEvent(struct PidEvent *event); | 
|  | void        Dispose(struct PidEvent *event); | 
|  |  | 
|  | private: | 
|  | Decoder     *decoder_; | 
|  | uint64_t    prev_time_; | 
|  | }; | 
|  |  | 
|  | class MethodReader { | 
|  | public: | 
|  | MethodReader(); | 
|  | ~MethodReader(); | 
|  |  | 
|  | bool        Open(const char *filename); | 
|  | void        Close(); | 
|  | bool        ReadMethod(MethodRec *method_record); | 
|  |  | 
|  | private: | 
|  | Decoder     *decoder_; | 
|  | uint64_t    prev_time_; | 
|  | uint32_t    prev_addr_; | 
|  | int32_t     prev_pid_; | 
|  | bool        opened_;        // true after file is opened | 
|  | }; | 
|  |  | 
|  | // Reads the next dynamic basic block from the trace. | 
|  | // Returns true on end-of-file. | 
|  | inline bool TraceReaderBase::ReadBB(BBEvent *event) | 
|  | { | 
|  | bb_recnum_ += 1; | 
|  | return bb_reader_->ReadBB(event); | 
|  | } | 
|  |  | 
|  | inline uint64_t TraceReaderBase::ReadInsnTime(uint64_t min_time) | 
|  | { | 
|  | return insn_reader_->ReadInsnTime(min_time); | 
|  | } | 
|  |  | 
|  | inline bool TraceReaderBase::ReadAddr(uint64_t *time, uint32_t *addr, int *flags) | 
|  | { | 
|  | if (load_eof_ && store_eof_) | 
|  | return true; | 
|  |  | 
|  | if (store_eof_ || (!load_eof_ && load_time_ <= store_time_)) { | 
|  | *time = load_time_; | 
|  | *addr = load_addr_; | 
|  | *flags = 0; | 
|  | load_eof_ = load_addr_reader_->ReadAddr(&load_time_, &load_addr_); | 
|  | } else { | 
|  | *time = store_time_; | 
|  | *addr = store_addr_; | 
|  | *flags = 1; | 
|  | store_eof_ = store_addr_reader_->ReadAddr(&store_time_, &store_addr_); | 
|  | } | 
|  | return false; | 
|  | } | 
|  |  | 
|  | inline bool TraceReaderBase::ReadExc(uint64_t *time, uint32_t *current_pc, | 
|  | uint64_t *recnum, uint32_t *target_pc, | 
|  | uint64_t *bb_num, uint64_t *bb_start_time, | 
|  | int *num_insns) | 
|  | { | 
|  | return exc_reader_->ReadExc(time, current_pc, recnum, target_pc, bb_num, | 
|  | bb_start_time, num_insns); | 
|  | } | 
|  |  | 
|  | inline bool TraceReaderBase::ReadPidEvent(PidEvent *event) | 
|  | { | 
|  | return pid_reader_->ReadPidEvent(event); | 
|  | } | 
|  |  | 
|  | inline bool TraceReaderBase::ReadMethod(MethodRec *method_record) | 
|  | { | 
|  | return method_reader_->ReadMethod(method_record); | 
|  | } | 
|  |  | 
|  | // Duplicates a string, allocating space using new[]. | 
|  | inline char * Strdup(const char *src) { | 
|  | int len = strlen(src); | 
|  | char *copy = new char[len + 1]; | 
|  | strcpy(copy, src); | 
|  | return copy; | 
|  | } | 
|  |  | 
|  | #endif /* TRACE_READER_BASE_H */ |