因为perf原生的用户态工具(kerneldir/tools/perf)交叉编译出错较多,用户态源码分析改用android 7.0简化版simpleperf来分析。simpleperf支持完整perf命令中的一些常见子命令。
1、命令框架
源码入口在system/extras/simpleperf/main.cpp:
1 | int main(int argc, char** argv) { |
command map是通过RegisterCommand()来进行注册的,在CommandRegister对象的构造函数中统一注册:
1 |
|
2、list子命令
我们使用“simple list”来查看当前系统支持event的种类:
1 | # simpleperf list | more |
list子命令的实现主体在ListCommand的Run方法中,system/extras/simpleperf/cmd_list.cpp:
1 | bool ListCommand::Run(const std::vector<std::string>& args) { |
“type + config”的全集在GetAllEventTypes()函数中获取:
1 | const std::vector<EventType>& GetAllEventTypes() { |
逐个尝试“type + config”组合在当前系统中是否支持,PrintEventTypesOfType():
1 | static void PrintEventTypesOfType(uint32_t type, const std::string& type_name, |
3、stat子命令
我们经常使用“simpleperf stat xxx”命令在查看,在执行“xxx”命令的过程中,各个event的count的统计情况:
1 | # simpleperf stat sleep 10 |
系统默认创建了6种event来跟踪统计“sleep 10”命令的执行情况,这里只会使用read()调用来读取perf_event的count数据,没有使用mmap创建ringbuffer所有没有sample数据。
我们也可以自定义选项来使用命令:
1 | # simpleperf help stat |
stat子命令的实现主体在StatCommand的Run方法中,system/extras/simpleperf/cmd_stat.cpp:
1 | bool StatCommand::Run(const std::vector<std::string>& args) { |
如果不使用”-e xxx”指定event,系统会默认指定event,并且判断当前系统能支持哪些event。合法event加入到measured_event_types_中:
1 | bool StatCommand::AddDefaultMeasuredEventTypes() { |
把measured_event_types_中的event和其他选项进行组合,合法的加入到selections_中:
1 | bool StatCommand::SetEventSelection() { |
我们在给workload创建子进程时使用了pipe机制用来同步:
1 | std::unique_ptr<Workload> Workload::CreateWorkload(const std::vector<std::string>& args) { |
为了perf_event和workload之间的同步,我们设置perf_event的EnableOnExec属性:
1 | void EventSelectionSet::SetEnableOnExec(bool enable) { |
一条命令可能会创建多个perf_event。因为cpu、pid、event的组合,需要多个perf_event才能满足:
1 | bool EventSelectionSet::OpenEventFilesForThreadsOnCpus(const std::vector<pid_t>& threads, |
perf_event创建完成以后,通知workload开始exec:
1 | bool Workload::Start() { |
workload执行完成后,根据event逐个perf_event读出其count值:
1 | bool EventSelectionSet::ReadCounters(std::vector<CountersInfo>* counters) { |
再统计这些count,以报告的形式呈现出来:
1 | bool StatCommand::ShowCounters(const std::vector<CountersInfo>& counters, double duration_in_sec) { |
4、record子命令
我们可以使用“simpleperf record xxx”命令记录一个命令的详细trace数据,在执行“xxx”命令的过程中把count数据和trace数据保存到perf.data中,随后可以使用 report子命令进行分析。
1 | /sdcard # simpleperf record sleep 10 |
系统默认创建了6种event来跟踪统计“sleep 10”命令的执行情况,这里会使mmap创建ringbuffer来保存sample数据,并记录到文件中。
我们也可以自定义选项来使用命令:
1 | # simpleperf help record |
record子命令的实现主体在RecordCommand的Run方法中,基本流程和stat子命令类似多了mmap操作,system/extras/simpleperf/cmd_record.cpp:
1 | bool RecordCommand::Run(const std::vector<std::string>& args) { |
mmap操作的具体实现:
1 | bool EventSelectionSet::MmapEventFiles(size_t mmap_pages) { |
在创建perf.data文件时,还保存了不少系统信息:
1 | bool RecordCommand::CreateAndInitRecordFile() { |
通过ReadMmapEventData()函数读取ringbuffer数据,并且通过回调CollectRecordsFromKernel()函数记录到cache中:
1 | bool EventSelectionSet::ReadMmapEventData(std::function<bool(const char*, size_t)> callback) { |
5、report子命令
暂不分析。