1 /*
2 * Copyright (C) 2017 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <dirent.h>
18 #include <fstream>
19 #include <iostream>
20 #include <map>
21 #include <string>
22 #include <vector>
23
24 #include <google/protobuf/text_format.h>
25 #include <test/vts/proto/ComponentSpecificationMessage.pb.h>
26 #include "VtsTraceProcessor.h"
27
28 using namespace std;
29 using google::protobuf::TextFormat;
30
31 namespace android {
32 namespace vts {
33
ParseTrace(const string & trace_file,bool ignore_timestamp,bool entry_only,VtsProfilingMessage * profiling_msg)34 bool VtsTraceProcessor::ParseTrace(const string& trace_file,
35 bool ignore_timestamp, bool entry_only,
36 VtsProfilingMessage* profiling_msg) {
37 ifstream in(trace_file, std::ios::in);
38 bool new_record = true;
39 string record_str, line;
40
41 while (getline(in, line)) {
42 // Assume records are separated by '\n'.
43 if (line.empty()) {
44 new_record = false;
45 }
46 if (new_record) {
47 record_str += line + "\n";
48 } else {
49 VtsProfilingRecord record;
50 if (!TextFormat::MergeFromString(record_str, &record)) {
51 cerr << "Can't parse a given record: " << record_str << endl;
52 return false;
53 }
54 if (ignore_timestamp) {
55 record.clear_timestamp();
56 }
57 if (entry_only) {
58 if (record.event() == InstrumentationEventType::SERVER_API_ENTRY
59 || record.event() == InstrumentationEventType::CLIENT_API_ENTRY
60 || record.event() == InstrumentationEventType::PASSTHROUGH_ENTRY)
61 *profiling_msg->add_records() = record;
62 } else {
63 *profiling_msg->add_records() = record;
64 }
65 new_record = true;
66 record_str.clear();
67 }
68 }
69 return true;
70 }
71
WriteRecords(const string & output_file,const std::vector<VtsProfilingRecord> & records)72 bool VtsTraceProcessor::WriteRecords(const string& output_file,
73 const std::vector<VtsProfilingRecord>& records) {
74 ofstream output = std::ofstream(output_file, std::fstream::out);
75 for (const auto& record : records) {
76 string record_str;
77 if (!TextFormat::PrintToString(record, &record_str)) {
78 cerr << "Can't print the message" << endl;
79 return false;
80 }
81 output << record_str << "\n";
82 }
83 output.close();
84 return true;
85 }
86
CleanupTraceForReplay(const string & trace_file)87 void VtsTraceProcessor::CleanupTraceForReplay(const string& trace_file) {
88 VtsProfilingMessage profiling_msg;
89 if (!ParseTrace(trace_file, false, false, &profiling_msg)) {
90 cerr << "Failed to parse trace file: " << trace_file << endl;
91 return;
92 }
93 vector<VtsProfilingRecord> clean_records;
94 for (const auto& record : profiling_msg.records()) {
95 if (record.event() == InstrumentationEventType::SERVER_API_ENTRY
96 || record.event() == InstrumentationEventType::SERVER_API_EXIT) {
97 clean_records.push_back(record);
98 }
99 }
100 string tmp_file = trace_file + "_tmp";
101 if (!WriteRecords(tmp_file, clean_records)) {
102 cerr << "Failed to write new trace file: " << tmp_file << endl;
103 return;
104 }
105 if (rename(tmp_file.c_str(), trace_file.c_str())) {
106 cerr << "Failed to replace old trace file: " << trace_file << endl;
107 return;
108 }
109 }
110
ProcessTraceForLatencyProfiling(const string & trace_file)111 void VtsTraceProcessor::ProcessTraceForLatencyProfiling(
112 const string& trace_file) {
113 VtsProfilingMessage profiling_msg;
114 if (!ParseTrace(trace_file, false, false, &profiling_msg)) {
115 cerr << ": Failed to parse trace file: " << trace_file << endl;
116 return;
117 }
118 if (!profiling_msg.records_size()) return;
119 if (profiling_msg.records(0).event()
120 == InstrumentationEventType::PASSTHROUGH_ENTRY
121 || profiling_msg.records(0).event()
122 == InstrumentationEventType::PASSTHROUGH_EXIT) {
123 cout << "hidl_hal_mode:passthrough" << endl;
124 } else {
125 cout << "hidl_hal_mode:binder" << endl;
126 }
127
128 for (int i = 0; i < profiling_msg.records_size() - 1; i += 2) {
129 string api = profiling_msg.records(i).func_msg().name();
130 int64_t start_timestamp = profiling_msg.records(i).timestamp();
131 int64_t end_timestamp = profiling_msg.records(i + 1).timestamp();
132 int64_t latency = end_timestamp - start_timestamp;
133 cout << api << ":" << latency << endl;
134 }
135 }
136
DedupTraces(const string & trace_dir)137 void VtsTraceProcessor::DedupTraces(const string& trace_dir) {
138 DIR *dir = opendir(trace_dir.c_str());
139 if (dir == 0) {
140 cerr << trace_dir << "does not exist." << endl;
141 return;
142 }
143 vector<VtsProfilingMessage> seen_msgs;
144 vector<string> duplicate_trace_files;
145 struct dirent *file;
146 long total_trace_num = 0;
147 long duplicat_trace_num = 0;
148 while ((file = readdir(dir)) != NULL) {
149 if (file->d_type == DT_REG) {
150 total_trace_num++;
151 string trace_file = trace_dir + file->d_name;
152 VtsProfilingMessage profiling_msg;
153 if (!ParseTrace(trace_file, true, true, &profiling_msg)) {
154 cerr << "Failed to parse trace file: " << trace_file << endl;
155 return;
156 }
157 if (!profiling_msg.records_size()) { // empty trace file
158 duplicate_trace_files.push_back(trace_file);
159 duplicat_trace_num++;
160 continue;
161 }
162 auto found = find_if(
163 seen_msgs.begin(), seen_msgs.end(),
164 [&profiling_msg] (const VtsProfilingMessage& seen_msg) {
165 std::string str_profiling_msg;
166 std::string str_seen_msg;
167 profiling_msg.SerializeToString(&str_profiling_msg);
168 seen_msg.SerializeToString(&str_seen_msg);
169 return (str_profiling_msg == str_seen_msg);
170 });
171 if (found == seen_msgs.end()) {
172 seen_msgs.push_back(profiling_msg);
173 } else {
174 duplicate_trace_files.push_back(trace_file);
175 duplicat_trace_num++;
176 }
177 }
178 }
179 for (const string& duplicate_trace : duplicate_trace_files) {
180 cout << "deleting duplicate trace file: " << duplicate_trace << endl;
181 remove(duplicate_trace.c_str());
182 }
183 cout << "Num of traces processed: " << total_trace_num << endl;
184 cout << "Num of duplicate trace deleted: " << duplicat_trace_num << endl;
185 cout << "Duplicate percentage: "
186 << float(duplicat_trace_num) / total_trace_num << endl;
187 }
188
189 } // namespace vts
190 } // namespace android
191