summaryrefslogtreecommitdiff
path: root/simpleperf/JITDebugReader.h
diff options
context:
space:
mode:
authorYabin Cui <yabinc@google.com>2020-07-23 15:30:14 -0700
committerYabin Cui <yabinc@google.com>2020-07-28 16:13:11 -0700
commite32ed2b96ed8692f4071b36640322600d344c1e3 (patch)
treeac39a9c593acca23c9c9e5d05a7547404eaae232 /simpleperf/JITDebugReader.h
parent682156e46d861038047f382cdfe86b10abf52e07 (diff)
downloadextras-e32ed2b96ed8692f4071b36640322600d344c1e3.tar.gz
simpleperf: dump jit symfiles to a single file.
Currently, each jit symfile is dumped to a distinct temporary file. This creates many temporary files, having two drawbacks: 1. It leaves many junk files if simpleperf is killed in the middle. 2. The names of the temporary files change in different recording files, making them harder to compare. This CL fixes it by making changes below: 1. Store jit symfiles in a single file. The location of a symfile is passed via a special path format: <file_path>:<file_start>-<file_end>. So the unwinder and ElfFile class can read it correctly. 2. Add Dso::GetReportPath() to give a unified name for jit symfiles. And use it in different reporting methods. Also split JITDebugReader::ReadProcess() into smaller functions. Bug: 159155297 Test: run simpleperf_unit_test Test: run simpleperf manually Change-Id: I37cd1888b855b4b88bb83e453e39230b96fb304f
Diffstat (limited to 'simpleperf/JITDebugReader.h')
-rw-r--r--simpleperf/JITDebugReader.h67
1 files changed, 51 insertions, 16 deletions
diff --git a/simpleperf/JITDebugReader.h b/simpleperf/JITDebugReader.h
index 3be124e6..31741a54 100644
--- a/simpleperf/JITDebugReader.h
+++ b/simpleperf/JITDebugReader.h
@@ -54,6 +54,7 @@ struct JITDebugInfo {
// For JITed code, it is the path of a temporary ELF file storing its debug info.
// For dex file, it is the path of the file containing the dex file.
std::string file_path;
+ uint64_t file_offset;
// The map for dex file extracted in memory. On Android Q, ART extracts dex files in apk files
// directly into memory, and names it using prctl(). The kernel doesn't generate a new mmap
@@ -61,34 +62,56 @@ struct JITDebugInfo {
std::shared_ptr<ThreadMmap> extracted_dex_file_map;
JITDebugInfo(pid_t pid, uint64_t timestamp, uint64_t jit_code_addr, uint64_t jit_code_len,
- const std::string& file_path)
- : type(JIT_DEBUG_JIT_CODE), pid(pid), timestamp(timestamp), jit_code_addr(jit_code_addr),
- jit_code_len(jit_code_len), file_path(file_path) {}
+ const std::string& file_path, uint64_t file_offset)
+ : type(JIT_DEBUG_JIT_CODE),
+ pid(pid),
+ timestamp(timestamp),
+ jit_code_addr(jit_code_addr),
+ jit_code_len(jit_code_len),
+ file_path(file_path),
+ file_offset(file_offset) {}
JITDebugInfo(pid_t pid, uint64_t timestamp, uint64_t dex_file_offset,
const std::string& file_path,
const std::shared_ptr<ThreadMmap>& extracted_dex_file_map)
- : type(JIT_DEBUG_DEX_FILE), pid(pid), timestamp(timestamp), dex_file_offset(dex_file_offset),
- file_path(file_path), extracted_dex_file_map(extracted_dex_file_map) {}
+ : type(JIT_DEBUG_DEX_FILE),
+ pid(pid),
+ timestamp(timestamp),
+ dex_file_offset(dex_file_offset),
+ file_path(file_path),
+ file_offset(0),
+ extracted_dex_file_map(extracted_dex_file_map) {}
bool operator>(const JITDebugInfo& other) const {
return timestamp > other.timestamp;
}
};
+class TempSymFile;
+
// JITDebugReader reads debug info of JIT code and dex files of processes using ART. The
// corresponding debug interface in ART is at art/runtime/jit/debugger_interface.cc.
class JITDebugReader {
public:
- // keep_symfiles: whether to keep dumped JIT debug info files after recording. Usually they
- // are only kept for debug unwinding.
- // sync_with_records: If true, sync debug info with records based on monotonic timestamp.
- // Otherwise, save debug info whenever they are added.
- JITDebugReader(bool keep_symfiles, bool sync_with_records)
- : keep_symfiles_(keep_symfiles), sync_with_records_(sync_with_records) {}
+ enum class SymFileOption {
+ kDropSymFiles, // JIT symfiles are dropped after recording.
+ kKeepSymFiles, // JIT symfiles are kept after recording, usually for debug unwinding.
+ };
+
+ enum class SyncOption {
+ kNoSync, // Don't sync debug info with records.
+ kSyncWithRecords, // Sync debug info with records based on monotonic timestamp.
+ };
+
+ // symfile_prefix: JITDebugReader creates temporary file to store symfiles for JIT code. Add this
+ // prefix to avoid conflicts.
+ JITDebugReader(const std::string& symfile_prefix, SymFileOption symfile_option,
+ SyncOption sync_option);
+
+ ~JITDebugReader();
bool SyncWithRecords() const {
- return sync_with_records_;
+ return sync_option_ == SyncOption::kSyncWithRecords;
}
typedef std::function<bool(const std::vector<JITDebugInfo>&, bool)> debug_info_callback_t;
@@ -108,9 +131,14 @@ class JITDebugReader {
bool FlushDebugInfo(uint64_t timestamp);
private:
+ enum class DescriptorType {
+ kDEX,
+ kJIT,
+ };
// An arch-independent representation of JIT/dex debug descriptor.
struct Descriptor {
+ DescriptorType type;
int version = 0;
uint32_t action_seqlock = 0; // incremented before and after any modification
uint64_t action_timestamp = 0; // CLOCK_MONOTONIC time of last action
@@ -152,7 +180,10 @@ class JITDebugReader {
uint64_t dex_descriptor_offset = 0;
};
- void ReadProcess(Process& process, std::vector<JITDebugInfo>* debug_info);
+ bool ReadProcess(Process& process, std::vector<JITDebugInfo>* debug_info);
+ bool ReadDebugInfo(Process& process, Descriptor& new_descriptor,
+ std::vector<JITDebugInfo>* debug_info);
+ bool IsDescriptorChanged(Process& process, Descriptor& old_descriptor);
bool InitializeProcess(Process& process);
const DescriptorsLocation* GetDescriptorsLocation(const std::string& art_lib_path,
bool is_64bit);
@@ -170,14 +201,15 @@ class JITDebugReader {
uint64_t last_action_timestamp, uint32_t read_entry_limit,
std::vector<CodeEntry>* new_code_entries);
- void ReadJITCodeDebugInfo(Process& process, const std::vector<CodeEntry>& jit_entries,
+ bool ReadJITCodeDebugInfo(Process& process, const std::vector<CodeEntry>& jit_entries,
std::vector<JITDebugInfo>* debug_info);
void ReadDexFileDebugInfo(Process& process, const std::vector<CodeEntry>& dex_entries,
std::vector<JITDebugInfo>* debug_info);
bool AddDebugInfo(const std::vector<JITDebugInfo>& debug_info, bool sync_kernel_records);
- bool keep_symfiles_ = false;
- bool sync_with_records_ = false;
+ const std::string symfile_prefix_;
+ SymFileOption symfile_option_;
+ SyncOption sync_option_;
IOEventRef read_event_ = nullptr;
debug_info_callback_t debug_info_callback_;
@@ -191,6 +223,9 @@ class JITDebugReader {
std::priority_queue<JITDebugInfo, std::vector<JITDebugInfo>, std::greater<JITDebugInfo>>
debug_info_q_;
+
+ // temporary files used to store jit symfiles created by the app process and the zygote process.
+ std::unique_ptr<TempSymFile> app_symfile_;
};
} //namespace simpleperf