• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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