xref: /aosp_15_r20/test/dittosuite/dittotrace.cpp (revision 6fa2df46f119dce7527f5beb2814eca0e6f886ac)
1*6fa2df46SAndroid Build Coastguard Worker // Copyright (C) 2021 The Android Open Source Project
2*6fa2df46SAndroid Build Coastguard Worker //
3*6fa2df46SAndroid Build Coastguard Worker // Licensed under the Apache License, Version 2.0 (the "License");
4*6fa2df46SAndroid Build Coastguard Worker // you may not use this file except in compliance with the License.
5*6fa2df46SAndroid Build Coastguard Worker // You may obtain a copy of the License at
6*6fa2df46SAndroid Build Coastguard Worker //
7*6fa2df46SAndroid Build Coastguard Worker //      http://www.apache.org/licenses/LICENSE-2.0
8*6fa2df46SAndroid Build Coastguard Worker //
9*6fa2df46SAndroid Build Coastguard Worker // Unless required by applicable law or agreed to in writing, software
10*6fa2df46SAndroid Build Coastguard Worker // distributed under the License is distributed on an "AS IS" BASIS,
11*6fa2df46SAndroid Build Coastguard Worker // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*6fa2df46SAndroid Build Coastguard Worker // See the License for the specific language governing permissions and
13*6fa2df46SAndroid Build Coastguard Worker // limitations under the License.
14*6fa2df46SAndroid Build Coastguard Worker 
15*6fa2df46SAndroid Build Coastguard Worker #include <fstream>
16*6fa2df46SAndroid Build Coastguard Worker #include <iostream>
17*6fa2df46SAndroid Build Coastguard Worker #include <map>
18*6fa2df46SAndroid Build Coastguard Worker #include <string>
19*6fa2df46SAndroid Build Coastguard Worker #include <vector>
20*6fa2df46SAndroid Build Coastguard Worker 
21*6fa2df46SAndroid Build Coastguard Worker #include <benchmark.pb.h>
22*6fa2df46SAndroid Build Coastguard Worker 
23*6fa2df46SAndroid Build Coastguard Worker #include <google/protobuf/io/zero_copy_stream_impl.h>
24*6fa2df46SAndroid Build Coastguard Worker #include <google/protobuf/text_format.h>
25*6fa2df46SAndroid Build Coastguard Worker 
26*6fa2df46SAndroid Build Coastguard Worker struct Syscall {
27*6fa2df46SAndroid Build Coastguard Worker   std::string name;
28*6fa2df46SAndroid Build Coastguard Worker   std::vector<std::string> arguments;
29*6fa2df46SAndroid Build Coastguard Worker   std::string return_value;
30*6fa2df46SAndroid Build Coastguard Worker };
31*6fa2df46SAndroid Build Coastguard Worker 
32*6fa2df46SAndroid Build Coastguard Worker // Reads lines from the provided file with strace output. Returns a list of lines
ReadLines(const std::string & file_path)33*6fa2df46SAndroid Build Coastguard Worker std::vector<std::string> ReadLines(const std::string& file_path) {
34*6fa2df46SAndroid Build Coastguard Worker   std::vector<std::string> lines;
35*6fa2df46SAndroid Build Coastguard Worker 
36*6fa2df46SAndroid Build Coastguard Worker   std::string line;
37*6fa2df46SAndroid Build Coastguard Worker   std::ifstream input(file_path);
38*6fa2df46SAndroid Build Coastguard Worker   while (std::getline(input, line)) {
39*6fa2df46SAndroid Build Coastguard Worker     lines.push_back(line);
40*6fa2df46SAndroid Build Coastguard Worker   }
41*6fa2df46SAndroid Build Coastguard Worker   input.close();
42*6fa2df46SAndroid Build Coastguard Worker 
43*6fa2df46SAndroid Build Coastguard Worker   return lines;
44*6fa2df46SAndroid Build Coastguard Worker }
45*6fa2df46SAndroid Build Coastguard Worker 
46*6fa2df46SAndroid Build Coastguard Worker // Processes the given line into syscall name, arguments and return value
ProcessLine(const std::string & line)47*6fa2df46SAndroid Build Coastguard Worker Syscall ProcessLine(const std::string& line) {
48*6fa2df46SAndroid Build Coastguard Worker   Syscall syscall;
49*6fa2df46SAndroid Build Coastguard Worker 
50*6fa2df46SAndroid Build Coastguard Worker   syscall.name = line.substr(0, line.find('('));
51*6fa2df46SAndroid Build Coastguard Worker   std::string raw_arguments = line.substr(line.find('(') + 1, line.find(')') - line.find('(') - 1);
52*6fa2df46SAndroid Build Coastguard Worker   syscall.return_value = line.substr(line.find(')'));
53*6fa2df46SAndroid Build Coastguard Worker   syscall.return_value = syscall.return_value.substr(syscall.return_value.find("= ") + 2);
54*6fa2df46SAndroid Build Coastguard Worker 
55*6fa2df46SAndroid Build Coastguard Worker   size_t next = 0;
56*6fa2df46SAndroid Build Coastguard Worker   size_t last = 0;
57*6fa2df46SAndroid Build Coastguard Worker   while ((next = raw_arguments.find(", ", last)) != std::string::npos) {
58*6fa2df46SAndroid Build Coastguard Worker     std::string part = raw_arguments.substr(last, next - last);
59*6fa2df46SAndroid Build Coastguard Worker     last = next + 2;
60*6fa2df46SAndroid Build Coastguard Worker     if (part.size() != 0) syscall.arguments.push_back(part);
61*6fa2df46SAndroid Build Coastguard Worker   }
62*6fa2df46SAndroid Build Coastguard Worker   std::string part = raw_arguments.substr(last);
63*6fa2df46SAndroid Build Coastguard Worker   if (part.size() != 0) syscall.arguments.push_back(part);
64*6fa2df46SAndroid Build Coastguard Worker 
65*6fa2df46SAndroid Build Coastguard Worker   return syscall;
66*6fa2df46SAndroid Build Coastguard Worker }
67*6fa2df46SAndroid Build Coastguard Worker 
68*6fa2df46SAndroid Build Coastguard Worker // Splits lines by pid. Returns a map where pid maps to a list of lines
SplitByPid(const std::vector<std::string> & lines)69*6fa2df46SAndroid Build Coastguard Worker std::map<int, std::vector<std::string>> SplitByPid(const std::vector<std::string>& lines) {
70*6fa2df46SAndroid Build Coastguard Worker   std::map<int, std::vector<std::string>> lines_by_pid;
71*6fa2df46SAndroid Build Coastguard Worker 
72*6fa2df46SAndroid Build Coastguard Worker   for (const auto& line : lines) {
73*6fa2df46SAndroid Build Coastguard Worker     int pid = strtoll(line.substr(0, line.find(' ')).c_str(), nullptr, 10);
74*6fa2df46SAndroid Build Coastguard Worker     lines_by_pid[pid].push_back(line);
75*6fa2df46SAndroid Build Coastguard Worker   }
76*6fa2df46SAndroid Build Coastguard Worker 
77*6fa2df46SAndroid Build Coastguard Worker   return lines_by_pid;
78*6fa2df46SAndroid Build Coastguard Worker }
79*6fa2df46SAndroid Build Coastguard Worker 
80*6fa2df46SAndroid Build Coastguard Worker // Goes through all the lines for each pid, merges lines with unfinished and resumed tags, then
81*6fa2df46SAndroid Build Coastguard Worker // calls ProcessLine on each of those merged lines. Returns a map where pid maps to a list of
82*6fa2df46SAndroid Build Coastguard Worker // processed lines/syscalls
ProcessLines(const std::map<int,std::vector<std::string>> & lines_by_pid)83*6fa2df46SAndroid Build Coastguard Worker std::map<int, std::vector<Syscall>> ProcessLines(
84*6fa2df46SAndroid Build Coastguard Worker     const std::map<int, std::vector<std::string>>& lines_by_pid) {
85*6fa2df46SAndroid Build Coastguard Worker   std::map<int, std::vector<Syscall>> processed_syscalls_by_pid;
86*6fa2df46SAndroid Build Coastguard Worker 
87*6fa2df46SAndroid Build Coastguard Worker   for (const auto& [pid, lines] : lines_by_pid) {
88*6fa2df46SAndroid Build Coastguard Worker     for (std::size_t i = 0; i < lines.size(); ++i) {
89*6fa2df46SAndroid Build Coastguard Worker       auto line = lines[i];
90*6fa2df46SAndroid Build Coastguard Worker 
91*6fa2df46SAndroid Build Coastguard Worker       // If only the resumed part of the syscall was found, ignore it
92*6fa2df46SAndroid Build Coastguard Worker       if (line.find("resumed>") != std::string::npos) continue;
93*6fa2df46SAndroid Build Coastguard Worker 
94*6fa2df46SAndroid Build Coastguard Worker       // If the syscall is detached, ignore it
95*6fa2df46SAndroid Build Coastguard Worker       if (line.find("<detached ...>") != std::string::npos) continue;
96*6fa2df46SAndroid Build Coastguard Worker 
97*6fa2df46SAndroid Build Coastguard Worker       // If the line contains "unfinished", concatenate it with the next line, which should contain
98*6fa2df46SAndroid Build Coastguard Worker       // "resumed"
99*6fa2df46SAndroid Build Coastguard Worker       if (line.find("<unfinished ...>") != std::string::npos) {
100*6fa2df46SAndroid Build Coastguard Worker         // Remove the "unfinished" tag
101*6fa2df46SAndroid Build Coastguard Worker         line = line.substr(0, line.find("<unfinished ...>"));
102*6fa2df46SAndroid Build Coastguard Worker 
103*6fa2df46SAndroid Build Coastguard Worker         // If the next line does not exist, ignore the syscall altogether
104*6fa2df46SAndroid Build Coastguard Worker         if (i + 1 >= lines.size()) continue;
105*6fa2df46SAndroid Build Coastguard Worker 
106*6fa2df46SAndroid Build Coastguard Worker         auto second_line = lines[++i];
107*6fa2df46SAndroid Build Coastguard Worker 
108*6fa2df46SAndroid Build Coastguard Worker         // Remove the "resumed" tag
109*6fa2df46SAndroid Build Coastguard Worker         second_line = second_line.substr(second_line.find("resumed>") + std::strlen("resumed>"));
110*6fa2df46SAndroid Build Coastguard Worker         // Concatenate both lines
111*6fa2df46SAndroid Build Coastguard Worker         line += second_line;
112*6fa2df46SAndroid Build Coastguard Worker       }
113*6fa2df46SAndroid Build Coastguard Worker 
114*6fa2df46SAndroid Build Coastguard Worker       // Remove the pid
115*6fa2df46SAndroid Build Coastguard Worker       line = line.substr(line.find("  ") + 2);
116*6fa2df46SAndroid Build Coastguard Worker 
117*6fa2df46SAndroid Build Coastguard Worker       // If the line starts with "---" or "+++", ignore it
118*6fa2df46SAndroid Build Coastguard Worker       if (line.length() >= 3 && (line.substr(0, 3) == "---" || line.substr(0, 3) == "+++"))
119*6fa2df46SAndroid Build Coastguard Worker         continue;
120*6fa2df46SAndroid Build Coastguard Worker 
121*6fa2df46SAndroid Build Coastguard Worker       auto processed_syscall = ProcessLine(line);
122*6fa2df46SAndroid Build Coastguard Worker       processed_syscalls_by_pid[pid].push_back(processed_syscall);
123*6fa2df46SAndroid Build Coastguard Worker     }
124*6fa2df46SAndroid Build Coastguard Worker   }
125*6fa2df46SAndroid Build Coastguard Worker 
126*6fa2df46SAndroid Build Coastguard Worker   return processed_syscalls_by_pid;
127*6fa2df46SAndroid Build Coastguard Worker }
128*6fa2df46SAndroid Build Coastguard Worker 
main(int argc,char ** argv)129*6fa2df46SAndroid Build Coastguard Worker int main(int argc, char** argv) {
130*6fa2df46SAndroid Build Coastguard Worker   if (argc != 3) {
131*6fa2df46SAndroid Build Coastguard Worker     std::cerr << "Invalid number of arguments.\n";
132*6fa2df46SAndroid Build Coastguard Worker     exit(EXIT_FAILURE);
133*6fa2df46SAndroid Build Coastguard Worker   }
134*6fa2df46SAndroid Build Coastguard Worker 
135*6fa2df46SAndroid Build Coastguard Worker   auto raw_lines = ReadLines(argv[1]);
136*6fa2df46SAndroid Build Coastguard Worker   auto raw_lines_by_pid = SplitByPid(raw_lines);
137*6fa2df46SAndroid Build Coastguard Worker   auto processed_syscalls_by_pid = ProcessLines(raw_lines_by_pid);
138*6fa2df46SAndroid Build Coastguard Worker 
139*6fa2df46SAndroid Build Coastguard Worker   std::string absolute_path = argv[2];
140*6fa2df46SAndroid Build Coastguard Worker 
141*6fa2df46SAndroid Build Coastguard Worker   // Initialize .ditto file
142*6fa2df46SAndroid Build Coastguard Worker   auto benchmark = std::make_unique<dittosuiteproto::Benchmark>();
143*6fa2df46SAndroid Build Coastguard Worker   auto main_instruction_set = benchmark->mutable_main()->mutable_instruction_set();
144*6fa2df46SAndroid Build Coastguard Worker   benchmark->mutable_global()->set_absolute_path(absolute_path);
145*6fa2df46SAndroid Build Coastguard Worker 
146*6fa2df46SAndroid Build Coastguard Worker   // Iterate over each pid and its processed lines. Start creating instructions after first openat()
147*6fa2df46SAndroid Build Coastguard Worker   // syscall, whose file name includes the provided absolute path, is found
148*6fa2df46SAndroid Build Coastguard Worker   for (const auto& [pid, syscalls] : processed_syscalls_by_pid) {
149*6fa2df46SAndroid Build Coastguard Worker     std::map<int, std::unique_ptr<dittosuiteproto::InstructionSet>> instruction_set_by_fd;
150*6fa2df46SAndroid Build Coastguard Worker     for (const auto& syscall : syscalls) {
151*6fa2df46SAndroid Build Coastguard Worker       if (syscall.name == "openat" &&
152*6fa2df46SAndroid Build Coastguard Worker           syscall.arguments[1].find(absolute_path) != std::string::npos) {
153*6fa2df46SAndroid Build Coastguard Worker         // Remove absolute_path
154*6fa2df46SAndroid Build Coastguard Worker         std::string path_name = syscall.arguments[1].substr(absolute_path.size() + 2);
155*6fa2df46SAndroid Build Coastguard Worker         // Remove quotes at the end
156*6fa2df46SAndroid Build Coastguard Worker         path_name.pop_back();
157*6fa2df46SAndroid Build Coastguard Worker 
158*6fa2df46SAndroid Build Coastguard Worker         // If the return value is -1, ignore it
159*6fa2df46SAndroid Build Coastguard Worker         if (syscall.return_value.find("-1") != std::string::npos) continue;
160*6fa2df46SAndroid Build Coastguard Worker 
161*6fa2df46SAndroid Build Coastguard Worker         int fd = strtoll(syscall.return_value.c_str(), nullptr, 10);
162*6fa2df46SAndroid Build Coastguard Worker 
163*6fa2df46SAndroid Build Coastguard Worker         // Create .ditto instruction set for this fd with open file instruction
164*6fa2df46SAndroid Build Coastguard Worker         instruction_set_by_fd[fd] = std::make_unique<dittosuiteproto::InstructionSet>();
165*6fa2df46SAndroid Build Coastguard Worker         auto instruction = instruction_set_by_fd[fd]->add_instructions()->mutable_open_file();
166*6fa2df46SAndroid Build Coastguard Worker         instruction->set_path_name(path_name);
167*6fa2df46SAndroid Build Coastguard Worker         instruction->set_output_fd("fd");
168*6fa2df46SAndroid Build Coastguard Worker       } else if (syscall.name == "pread64") {
169*6fa2df46SAndroid Build Coastguard Worker         int fd = strtoll(syscall.arguments[0].c_str(), nullptr, 10);
170*6fa2df46SAndroid Build Coastguard Worker 
171*6fa2df46SAndroid Build Coastguard Worker         if (syscall.arguments.size() != 4) continue;
172*6fa2df46SAndroid Build Coastguard Worker         if (instruction_set_by_fd.find(fd) == instruction_set_by_fd.end()) continue;
173*6fa2df46SAndroid Build Coastguard Worker 
174*6fa2df46SAndroid Build Coastguard Worker         int64_t size = strtoll(syscall.arguments[2].c_str(), nullptr, 10);
175*6fa2df46SAndroid Build Coastguard Worker         int64_t offset = strtoll(syscall.arguments[3].c_str(), nullptr, 10);
176*6fa2df46SAndroid Build Coastguard Worker 
177*6fa2df46SAndroid Build Coastguard Worker         // Create .ditto read file instruction
178*6fa2df46SAndroid Build Coastguard Worker         auto instruction = instruction_set_by_fd[fd]->add_instructions()->mutable_read_file();
179*6fa2df46SAndroid Build Coastguard Worker         instruction->set_input_fd("fd");
180*6fa2df46SAndroid Build Coastguard Worker         instruction->set_size(size);
181*6fa2df46SAndroid Build Coastguard Worker         instruction->set_block_size(size);
182*6fa2df46SAndroid Build Coastguard Worker         instruction->set_starting_offset(offset);
183*6fa2df46SAndroid Build Coastguard Worker       } else if (syscall.name == "pwrite64") {
184*6fa2df46SAndroid Build Coastguard Worker         int fd = strtoll(syscall.arguments[0].c_str(), nullptr, 10);
185*6fa2df46SAndroid Build Coastguard Worker 
186*6fa2df46SAndroid Build Coastguard Worker         if (syscall.arguments.size() != 4) continue;
187*6fa2df46SAndroid Build Coastguard Worker         if (instruction_set_by_fd.find(fd) == instruction_set_by_fd.end()) continue;
188*6fa2df46SAndroid Build Coastguard Worker 
189*6fa2df46SAndroid Build Coastguard Worker         int64_t size = strtoll(syscall.arguments[2].c_str(), nullptr, 10);
190*6fa2df46SAndroid Build Coastguard Worker         int64_t offset = strtoll(syscall.arguments[3].c_str(), nullptr, 10);
191*6fa2df46SAndroid Build Coastguard Worker 
192*6fa2df46SAndroid Build Coastguard Worker         // Create .ditto write file instruction
193*6fa2df46SAndroid Build Coastguard Worker         auto instruction = instruction_set_by_fd[fd]->add_instructions()->mutable_write_file();
194*6fa2df46SAndroid Build Coastguard Worker         instruction->set_input_fd("fd");
195*6fa2df46SAndroid Build Coastguard Worker         instruction->set_size(size);
196*6fa2df46SAndroid Build Coastguard Worker         instruction->set_block_size(size);
197*6fa2df46SAndroid Build Coastguard Worker         instruction->set_starting_offset(offset);
198*6fa2df46SAndroid Build Coastguard Worker       } else if (syscall.name == "close") {
199*6fa2df46SAndroid Build Coastguard Worker         int fd = strtoll(syscall.arguments[0].c_str(), nullptr, 10);
200*6fa2df46SAndroid Build Coastguard Worker 
201*6fa2df46SAndroid Build Coastguard Worker         if (instruction_set_by_fd.find(fd) == instruction_set_by_fd.end()) continue;
202*6fa2df46SAndroid Build Coastguard Worker 
203*6fa2df46SAndroid Build Coastguard Worker         // Create .ditto close file instruction
204*6fa2df46SAndroid Build Coastguard Worker         auto instruction = instruction_set_by_fd[fd]->add_instructions()->mutable_close_file();
205*6fa2df46SAndroid Build Coastguard Worker         instruction->set_input_fd("fd");
206*6fa2df46SAndroid Build Coastguard Worker 
207*6fa2df46SAndroid Build Coastguard Worker         // Add the instruction set for this fd to the main instruction set
208*6fa2df46SAndroid Build Coastguard Worker         main_instruction_set->add_instructions()->set_allocated_instruction_set(
209*6fa2df46SAndroid Build Coastguard Worker             instruction_set_by_fd[fd].release());
210*6fa2df46SAndroid Build Coastguard Worker         instruction_set_by_fd.erase(instruction_set_by_fd.find(fd));
211*6fa2df46SAndroid Build Coastguard Worker       }
212*6fa2df46SAndroid Build Coastguard Worker     }
213*6fa2df46SAndroid Build Coastguard Worker   }
214*6fa2df46SAndroid Build Coastguard Worker 
215*6fa2df46SAndroid Build Coastguard Worker   auto output = std::make_unique<google::protobuf::io::OstreamOutputStream>(&std::cout);
216*6fa2df46SAndroid Build Coastguard Worker   google::protobuf::TextFormat::Print(*benchmark, output.get());
217*6fa2df46SAndroid Build Coastguard Worker   return 0;
218*6fa2df46SAndroid Build Coastguard Worker }
219