diff options
-rw-r--r-- | pagecache/pagecache.py | 50 | ||||
-rw-r--r-- | profcollectd/README.md | 11 | ||||
-rw-r--r-- | profcollectd/libprofcollectd/config.rs | 19 | ||||
-rw-r--r-- | profcollectd/libprofcollectd/lib.rs | 2 | ||||
-rw-r--r-- | profcollectd/profcollectd.rc | 4 | ||||
-rw-r--r-- | simpleperf/cmd_inject.cpp | 76 | ||||
-rw-r--r-- | simpleperf/cmd_record.cpp | 2 | ||||
-rwxr-xr-x | tools/check_elf_alignment.sh | 18 |
8 files changed, 104 insertions, 78 deletions
diff --git a/pagecache/pagecache.py b/pagecache/pagecache.py index 3f96a5d1..808812c5 100644 --- a/pagecache/pagecache.py +++ b/pagecache/pagecache.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 import curses import operator @@ -8,7 +8,7 @@ import re import subprocess import sys import threading -import Queue +import queue STATS_UPDATE_INTERVAL = 0.2 PAGE_SIZE = 4096 @@ -68,21 +68,21 @@ class PagecacheStats(): def print_stats(self): # Create new merged dict - sorted_added = sorted(self._file_pages.items(), key=operator.itemgetter(1), reverse=True) + sorted_added = sorted(list(self._file_pages.items()), key=operator.itemgetter(1), reverse=True) row_format = "{:<70}{:<12}{:<14}{:<9}" - print row_format.format('NAME', 'ADDED (MB)', 'REMOVED (MB)', 'SIZE (MB)') + print(row_format.format('NAME', 'ADDED (MB)', 'REMOVED (MB)', 'SIZE (MB)')) for filename, added in sorted_added: filesize = self._file_size[filename] added = self._file_pages[filename][0] removed = self._file_pages[filename][1] - if (filename > 64): + if (len(filename) > 64): filename = filename[-64:] - print row_format.format(filename, self.pages_to_mb(added), self.pages_to_mb(removed), self.bytes_to_mb(filesize)) + print(row_format.format(filename, self.pages_to_mb(added), self.pages_to_mb(removed), self.bytes_to_mb(filesize))) - print row_format.format('TOTAL', self.pages_to_mb(self._total_pages_added), self.pages_to_mb(self._total_pages_removed), '') + print(row_format.format('TOTAL', self.pages_to_mb(self._total_pages_added), self.pages_to_mb(self._total_pages_removed), '')) def print_stats_curses(self, pad): - sorted_added = sorted(self._file_pages.items(), key=operator.itemgetter(1), reverse=True) + sorted_added = sorted(list(self._file_pages.items()), key=operator.itemgetter(1), reverse=True) height, width = pad.getmaxyx() pad.clear() pad.addstr(0, 2, 'NAME'.ljust(68), curses.A_REVERSE) @@ -94,7 +94,7 @@ class PagecacheStats(): filesize = self._file_size[filename] added = self._file_pages[filename][0] removed = self._file_pages[filename][1] - if (filename > 64): + if (len(filename) > 64): filename = filename[-64:] pad.addstr(y, 2, filename) pad.addstr(y, 70, self.pages_to_mb(added).rjust(10)) @@ -122,7 +122,7 @@ class FileReaderThread(threading.Thread): Args: file_object: The file or pipe to read from. - output_queue: A Queue.Queue object that will receive the data + output_queue: A queue.Queue object that will receive the data text_file: If True, the file will be read one line at a time, and chunk_size will be ignored. If False, line breaks are ignored and chunk_size must be set to a positive integer. @@ -204,10 +204,10 @@ class AdbUtils(): shell=False, universal_newlines=True) except OSError as error: # This usually means that the adb executable was not found in the path. - print >> sys.stderr, ('\nThe command "%s" failed with the following error:' - % ' '.join(adb_command)) - print >> sys.stderr, ' %s' % str(error) - print >> sys.stderr, 'Is adb in your path?' + print('\nThe command "%s" failed with the following error:' + % ' '.join(adb_command), file=sys.stderr) + print(' %s' % str(error), file=sys.stderr) + print('Is adb in your path?', file=sys.stderr) adb_return_code = error.errno adb_output = error except subprocess.CalledProcessError as error: @@ -265,11 +265,11 @@ def get_inode_data(datafile, dumpfile, adb_serial): 'find /apex /system /system_ext /product /data /vendor ' + '-exec stat -c "%d %i %s %n" {} \;', adb_serial) if stat_dump is None: - print 'Could not retrieve inode data from device.' + print('Could not retrieve inode data from device.') sys.exit(1) if dumpfile is not None: - print 'Storing inode data in ' + dumpfile + print('Storing inode data in ' + dumpfile) f = open(dumpfile, 'w') f.write(stat_dump) f.close() @@ -285,8 +285,8 @@ def read_and_parse_trace_file(trace_file, pagecache_stats, app_name): def read_and_parse_trace_data_live(stdout, stderr, pagecache_stats, app_name): # Start reading trace data - stdout_queue = Queue.Queue(maxsize=128) - stderr_queue = Queue.Queue() + stdout_queue = queue.Queue(maxsize=128) + stderr_queue = queue.Queue() stdout_thread = FileReaderThread(stdout, stdout_queue, text_file=True, chunk_size=64) @@ -316,13 +316,13 @@ def read_and_parse_trace_data_live(stdout, stderr, pagecache_stats, app_name): not stdout_queue.empty() or not stderr_queue.empty()): while not stderr_queue.empty(): # Pass along errors from adb. - line = stderr_queue.get() + line = stderr_queue.get().decode("utf-8") sys.stderr.write(line) while True: try: - line = stdout_queue.get(True, STATS_UPDATE_INTERVAL) + line = stdout_queue.get(True, STATS_UPDATE_INTERVAL).decode("utf-8") parse_atrace_line(line, pagecache_stats, app_name) - except Queue.Empty: + except (queue.Empty, KeyboardInterrupt): break key = '' @@ -335,9 +335,9 @@ def read_and_parse_trace_data_live(stdout, stderr, pagecache_stats, app_name): pagecache_stats.reset_stats() pagecache_stats.print_stats_curses(pagecache_pad) - except Exception, e: + except Exception as e: curses.endwin() - print e + print(e) finally: curses.endwin() # The threads should already have stopped, so this is just for cleanup. @@ -383,7 +383,7 @@ def main(): if options.trace_file is not None: if not os.path.isfile(options.trace_file): - print >> sys.stderr, ('Couldn\'t load trace file.') + print('Couldn\'t load trace file.', file=sys.stderr) sys.exit(1) trace_file = open(options.trace_file, 'r') read_and_parse_trace_file(trace_file, pagecache_stats, options.app_name) @@ -396,7 +396,7 @@ def main(): atrace = subprocess.Popen(trace_cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) except OSError as error: - print >> sys.stderr, ('The command failed') + print('The command failed', file=sys.stderr) sys.exit(1) read_and_parse_trace_data_live(atrace.stdout, atrace.stderr, pagecache_stats, options.app_name) diff --git a/profcollectd/README.md b/profcollectd/README.md index e9066000..1017e7e4 100644 --- a/profcollectd/README.md +++ b/profcollectd/README.md @@ -39,21 +39,18 @@ Setting the frequency value to `0` disables collection for the corresponding eve #### Custom configuration -In adb root: +Under adb root: ``` # Record every 60s (By default, record every 10m). The actual interval will be longer than the # set value if the device goes to hibernation. -oriole:/ # setprop persist.device_config.profcollect_native_boot.collection_interval 60 +oriole:/ # device_config put profcollect_native_boot collection_interval 60 # Each time recording, record ETM data for 1s (By default, it's 0.5s). -oriole:/ # setprop persist.device_config.profcollect_native_boot.sampling_period 1000 +oriole:/ # device_config put profcollect_native_boot sampling_period 1000 # Set ETM data storage limit to 50G (By default, it is 512M). -oriole:/ # setprop persist.device_config.profcollect_native_boot.max_trace_limit 53687091200 - -# Enable ETM data collection (By default, it's decided by the server). -oriole:/ # setprop persist.device_config.profcollect_native_boot.enabled true +oriole:/ # device_config put profcollect_native_boot max_trace_limit 53687091200 # After adjusting configuration, need to restart profcollectd oriole:/ # setprop ctl.stop profcollectd diff --git a/profcollectd/libprofcollectd/config.rs b/profcollectd/libprofcollectd/config.rs index 8a6c9e4f..0a1a9ad9 100644 --- a/profcollectd/libprofcollectd/config.rs +++ b/profcollectd/libprofcollectd/config.rs @@ -24,6 +24,7 @@ use serde::{Deserialize, Serialize}; use std::error::Error; use std::fs::{read_dir, remove_file}; use std::path::Path; +use std::process::Command; use std::str::FromStr; use std::time::Duration; @@ -61,6 +62,8 @@ pub struct Config { pub binary_filter: String, /// Maximum size of the trace directory. pub max_trace_limit: u64, + /// The kernel release version + pub kernel_release: String, } impl Config { @@ -78,13 +81,14 @@ impl Config { "max_trace_limit", /* 512MB */ 512 * 1024 * 1024, )?, + kernel_release: get_kernel_release(), }) } } -impl ToString for Config { - fn to_string(&self) -> String { - serde_json::to_string(self).expect("Failed to deserialise configuration.") +impl std::fmt::Display for Config { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", serde_json::to_string(self).expect("Failed to deserialise configuration.")) } } @@ -151,6 +155,15 @@ fn generate_random_node_id() -> MacAddr6 { MacAddr6::from(node_id) } +fn get_kernel_release() -> String { + match Command::new("uname").args(["-r"]).output() { + Ok(output) if output.status.success() => { + String::from_utf8_lossy(&output.stdout).trim().to_string() + } + _ => String::new(), + } +} + pub fn clear_data() -> Result<()> { fn remove_files(path: &Path) -> Result<()> { read_dir(path)? diff --git a/profcollectd/libprofcollectd/lib.rs b/profcollectd/libprofcollectd/lib.rs index c8e39753..f0d32a8b 100644 --- a/profcollectd/libprofcollectd/lib.rs +++ b/profcollectd/libprofcollectd/lib.rs @@ -85,7 +85,7 @@ pub fn init_service(schedule_now: bool) -> Result<()> { } fn get_profcollectd_service() -> Result<binder::Strong<dyn IProfCollectd::IProfCollectd>> { - binder::get_interface(PROFCOLLECTD_SERVICE_NAME) + binder::wait_for_interface(PROFCOLLECTD_SERVICE_NAME) .context("Failed to get profcollectd binder service, is profcollectd running?") } diff --git a/profcollectd/profcollectd.rc b/profcollectd/profcollectd.rc index 312c7003..faeb4124 100644 --- a/profcollectd/profcollectd.rc +++ b/profcollectd/profcollectd.rc @@ -13,8 +13,8 @@ on post-fs-data mkdir /data/misc/profcollectd/output 0770 shell shell mkdir /data/misc/profcollectd/report 0770 shell shell -on boot && property:persist.device_config.profcollect_native_boot.enabled=true +on boot && property:persist.device_config.aconfig_flags.profcollect_native_boot.enabled=true start profcollectd -on boot && property:persist.device_config.profcollect_native_boot.enabled= +on boot && property:persist.device_config.aconfig_flags.profcollect_native_boot.enabled= exec_background - root shell -- /system/bin/profcollectctl reset diff --git a/simpleperf/cmd_inject.cpp b/simpleperf/cmd_inject.cpp index 182f4fd2..6798a32a 100644 --- a/simpleperf/cmd_inject.cpp +++ b/simpleperf/cmd_inject.cpp @@ -683,46 +683,52 @@ class AutoFDOWriter { const AutoFDOBinaryInfo& binary = binary_map_[key]; // AutoFDO text format needs file_offsets instead of virtual addrs in a binary. And it uses // below formula: vaddr = file_offset + GetFirstLoadSegmentVaddr(). - uint64_t first_load_segment_addr = binary.first_load_segment_addr; - - auto to_offset = [&](uint64_t vaddr) -> uint64_t { - if (vaddr == 0) { - return 0; + uint64_t base_addr = binary.first_load_segment_addr; + + // Write range_count_map. Sort the output by addrs. + std::vector<std::pair<AddrPair, uint64_t>> range_counts; + for (std::pair<AddrPair, uint64_t> p : binary.range_count_map) { + if (p.first.first >= base_addr && p.first.second >= base_addr) { + p.first.first -= base_addr; + p.first.second -= base_addr; + range_counts.emplace_back(p); } - CHECK_GE(vaddr, first_load_segment_addr); - return vaddr - first_load_segment_addr; - }; - - // Write range_count_map. - std::map<AddrPair, uint64_t> range_count_map(binary.range_count_map.begin(), - binary.range_count_map.end()); - fprintf(output_fp.get(), "%zu\n", range_count_map.size()); - for (const auto& pair2 : range_count_map) { - const AddrPair& addr_range = pair2.first; - uint64_t count = pair2.second; - - fprintf(output_fp.get(), "%" PRIx64 "-%" PRIx64 ":%" PRIu64 "\n", - to_offset(addr_range.first), to_offset(addr_range.second), count); } - - // Write addr_count_map. - std::map<uint64_t, uint64_t> address_count_map(binary.address_count_map.begin(), - binary.address_count_map.end()); - fprintf(output_fp.get(), "%zu\n", address_count_map.size()); - for (const auto& [addr, count] : address_count_map) { - fprintf(output_fp.get(), "%" PRIx64 ":%" PRIu64 "\n", to_offset(addr), count); + std::sort(range_counts.begin(), range_counts.end()); + fprintf(output_fp.get(), "%zu\n", range_counts.size()); + for (const auto& p : range_counts) { + fprintf(output_fp.get(), "%" PRIx64 "-%" PRIx64 ":%" PRIu64 "\n", p.first.first, + p.first.second, p.second); } - // Write branch_count_map. - std::map<AddrPair, uint64_t> branch_count_map(binary.branch_count_map.begin(), - binary.branch_count_map.end()); - fprintf(output_fp.get(), "%zu\n", branch_count_map.size()); - for (const auto& pair2 : branch_count_map) { - const AddrPair& branch = pair2.first; - uint64_t count = pair2.second; + // Write addr_count_map. Sort the output by addrs. + std::vector<std::pair<uint64_t, uint64_t>> address_counts; + for (std::pair<uint64_t, uint64_t> p : binary.address_count_map) { + if (p.first >= base_addr) { + p.first -= base_addr; + address_counts.emplace_back(p); + } + } + std::sort(address_counts.begin(), address_counts.end()); + fprintf(output_fp.get(), "%zu\n", address_counts.size()); + for (const auto& p : address_counts) { + fprintf(output_fp.get(), "%" PRIx64 ":%" PRIu64 "\n", p.first, p.second); + } - fprintf(output_fp.get(), "%" PRIx64 "->%" PRIx64 ":%" PRIu64 "\n", to_offset(branch.first), - to_offset(branch.second), count); + // Write branch_count_map. Sort the output by addrs. + std::vector<std::pair<AddrPair, uint64_t>> branch_counts; + for (std::pair<AddrPair, uint64_t> p : binary.branch_count_map) { + if (p.first.first >= base_addr) { + p.first.first -= base_addr; + p.first.second = (p.first.second >= base_addr) ? (p.first.second - base_addr) : 0; + branch_counts.emplace_back(p); + } + } + std::sort(branch_counts.begin(), branch_counts.end()); + fprintf(output_fp.get(), "%zu\n", branch_counts.size()); + for (const auto& p : branch_counts) { + fprintf(output_fp.get(), "%" PRIx64 "->%" PRIx64 ":%" PRIu64 "\n", p.first.first, + p.first.second, p.second); } // Write the binary path in comment. diff --git a/simpleperf/cmd_record.cpp b/simpleperf/cmd_record.cpp index e08b153b..cb9ad884 100644 --- a/simpleperf/cmd_record.cpp +++ b/simpleperf/cmd_record.cpp @@ -1057,7 +1057,7 @@ bool RecordCommand::ParseOptions(const std::vector<std::string>& args, etm_branch_list_generator_ = ETMBranchListGenerator::Create(system_wide_collection_); } uint32_t interval = 0; - if (options.PullUintValue("--etm-flush-interval", &interval)) { + if (options.PullUintValue("--etm-flush-interval", &interval) && interval != 0) { etm_flush_interval_ = std::chrono::milliseconds(interval); } diff --git a/tools/check_elf_alignment.sh b/tools/check_elf_alignment.sh index b74f34ae..6cf9f92b 100755 --- a/tools/check_elf_alignment.sh +++ b/tools/check_elf_alignment.sh @@ -16,7 +16,7 @@ usage() { echo "Shared libraries are reported ALIGNED when their ELF regions are" echo "16 KB or 64 KB aligned. Otherwise they are reported as UNALIGNED." echo - echo "Usage: ${progname} [input-path|input-APK]" + echo "Usage: ${progname} [input-path|input-APK|input-APEX]" } if [ ${#} -ne 1 ]; then @@ -61,6 +61,15 @@ if [[ "${dir}" == *.apk ]]; then dir="${tmp}" fi +if [[ "${dir}" == *.apex ]]; then + trap 'cleanup_trap' EXIT + + dir_filename=$(basename "${dir}") + tmp=$(mktemp -d -t "${dir_filename%.apex}_out_XXXXX") + deapexer extract "${dir}" "${tmp}" >/dev/null 2>&1 + dir="${tmp}" +fi + RED="\e[31m" GREEN="\e[32m" ENDCOLOR="\e[0m" @@ -70,11 +79,12 @@ unaligned_libs=() echo echo "=== ELF alignment ===" -matches="$(find "${dir}" -name "*.so" -type f)" +matches="$(find "${dir}" -type f \( -name "*.so" -or -executable \))" IFS=$'\n' for match in $matches; do - res="$(objdump -p ${match} | grep LOAD | awk '{ print $NF }' | head -1)" - if [[ $res =~ "2**14" ]] || [[ $res =~ "2**16" ]]; then + [[ $(file "${match}") == *"ELF"* ]] || continue + res="$(objdump -p "${match}" | grep LOAD | awk '{ print $NF }' | head -1)" + if [[ $res =~ 2**(1[4-9]|[2-9][0-9]|[1-9][0-9]{2,}) ]]; then echo -e "${match}: ${GREEN}ALIGNED${ENDCOLOR} ($res)" else echo -e "${match}: ${RED}UNALIGNED${ENDCOLOR} ($res)" |