Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright 2017 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "chrome/browser/chromeos/arc/trace/arc_trace_reader.h" | |
| 6 | |
| 7 #include <errno.h> | |
| 8 #include <string.h> | |
| 9 #include <sys/select.h> | |
| 10 | |
| 11 #include <memory> | |
| 12 #include <sstream> | |
| 13 #include <utility> | |
| 14 #include <vector> | |
| 15 | |
| 16 #include "base/json/json_writer.h" | |
| 17 #include "base/logging.h" | |
| 18 #include "base/strings/string_number_conversions.h" | |
| 19 #include "base/strings/string_split.h" | |
| 20 #include "base/values.h" | |
| 21 #include "content/public/browser/browser_thread.h" | |
| 22 | |
| 23 namespace arc { | |
| 24 | |
| 25 namespace { | |
| 26 | |
| 27 #define ARC_TRACE_MESSAGE_LENGTH (1024 + 512) | |
|
Luis Héctor Chávez
2017/02/10 17:43:54
constexpr size_t kArcTraceMessageLength = 1024 + 5
Earl Ou
2017/03/22 11:38:26
Done in Android side.
| |
| 28 | |
| 29 // Maximum data to be stored in the buffer. | |
| 30 constexpr int kTraceBufferByteSize = 16 * 1024 * 1024; // 16MB | |
| 31 | |
| 32 } // namespace | |
| 33 | |
| 34 ArcTraceReader::ArcTraceReader() | |
| 35 : is_recording_(false), input_fd_(-1), recording_thread_(nullptr) {} | |
|
Luis Héctor Chávez
2017/02/10 17:43:55
these three can be set in the .h, that way you can
Earl Ou
2017/03/22 11:38:26
Done in Android side.
| |
| 36 | |
| 37 void ArcTraceReader::Run() { | |
| 38 if (input_fd_.get() == -1) { | |
| 39 LOG(WARNING) << "No input FD is set before starting recording."; | |
| 40 return; | |
| 41 } | |
| 42 | |
| 43 int ret; | |
| 44 fd_set fds; | |
| 45 timeval tv; | |
| 46 char buf[ARC_TRACE_MESSAGE_LENGTH]; | |
| 47 | |
| 48 while (is_recording_) { | |
| 49 FD_ZERO(&fds); | |
| 50 FD_SET(input_fd_.get(), &fds); | |
| 51 | |
| 52 // Wait up to 1 second. | |
| 53 tv.tv_sec = 1; | |
| 54 tv.tv_usec = 0; | |
| 55 | |
| 56 ret = TEMP_FAILURE_RETRY( | |
| 57 select(input_fd_.get() + 1, &fds, nullptr, nullptr, &tv)); | |
| 58 if (ret < 0) { | |
| 59 LOG(ERROR) << "Unexpected error while recording ARC trace: " | |
| 60 << strerror(errno); | |
| 61 break; | |
| 62 } | |
| 63 if (!ret) // No data available. | |
| 64 continue; | |
| 65 | |
| 66 ret = TEMP_FAILURE_RETRY(read(input_fd_.get(), buf, sizeof(buf) - 1)); | |
|
Luis Héctor Chávez
2017/02/10 23:16:51
in any case, you should try to limit the amount of
Earl Ou
2017/03/22 11:38:26
This is moved to the Android side.
| |
| 67 if (ret < 0) { | |
| 68 LOG(ERROR) << "Unexpected error while reading ARC trace: " | |
| 69 << strerror(errno); | |
| 70 break; | |
| 71 } | |
| 72 if (ret == 0) { // EOF | |
| 73 LOG(WARNING) << "EOF while recording ARC trace."; | |
| 74 break; | |
| 75 } | |
| 76 buf[ret] = 0; // Make sure the string is null terminated. | |
| 77 ParseAndSaveData(buf); | |
| 78 } | |
| 79 } | |
| 80 | |
| 81 void ArcTraceReader::SetInputFD(base::ScopedFD fd) { | |
| 82 input_fd_ = std::move(fd); | |
| 83 } | |
| 84 | |
| 85 void ArcTraceReader::StartRecord() { | |
| 86 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); | |
| 87 | |
| 88 if (is_recording_) { | |
| 89 LOG(WARNING) << "ARC trace reader already started."; | |
| 90 return; | |
| 91 } | |
| 92 is_recording_ = true; | |
| 93 current_data_size_ = 0; | |
| 94 trace_buffer_ = std::queue<std::string>(); // clean the queue. | |
| 95 | |
| 96 recording_thread_.reset( | |
|
Luis Héctor Chávez
2017/02/10 17:43:54
How about using base::FileDescriptorWatcher::Watch
Luis Héctor Chávez
2017/02/10 23:16:51
You can also use something similar to https://cs.c
Earl Ou
2017/03/22 11:38:26
Done in arc_tracing_agent.cc
| |
| 97 new base::DelegateSimpleThread(this, "ArcTraceReader")); | |
| 98 recording_thread_->Start(); | |
| 99 } | |
| 100 | |
| 101 void ArcTraceReader::StopRecord(const StopTracingCallback& callback) { | |
| 102 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); | |
| 103 | |
| 104 if (!is_recording_) { | |
| 105 LOG(WARNING) << "ARC trace reader was not started."; | |
| 106 callback.Run(""); | |
| 107 return; | |
| 108 } | |
| 109 is_recording_ = false; | |
| 110 recording_thread_->Join(); | |
| 111 recording_thread_.reset(nullptr); | |
|
Luis Héctor Chávez
2017/02/10 17:43:54
nit: recording_thread_.reset();
Earl Ou
2017/03/22 11:38:26
No reading thread now as suggested.
| |
| 112 | |
| 113 // TODO(shunshingou): run the following in a separated thread to avoid long | |
|
Luis Héctor Chávez
2017/02/10 17:43:55
This must be done in this CL, unfortunately. Worst
Luis Héctor Chávez
2017/02/10 17:48:03
D'Oh, this is a socket, not a pipe. Ignore the SIG
Earl Ou
2017/02/16 09:56:45
The comment here is for the processing of stringst
Earl Ou
2017/03/22 11:38:26
Now this is running in IO thread with WatchReadabl
| |
| 114 // processing in UI thread. | |
| 115 std::stringstream ss; | |
| 116 bool is_first = true; | |
| 117 while (!trace_buffer_.empty()) { | |
| 118 if (!is_first) | |
| 119 ss << ","; | |
| 120 is_first = false; | |
| 121 ss << trace_buffer_.front(); | |
| 122 trace_buffer_.pop(); | |
| 123 } | |
| 124 callback.Run(ss.str()); | |
| 125 } | |
| 126 | |
| 127 void ArcTraceReader::WriteTraceEvent(char ph, | |
| 128 int pid, | |
| 129 int tid, | |
| 130 uint64_t ts, | |
| 131 uint64_t tts, | |
| 132 const std::string* name, | |
| 133 const int* count, | |
| 134 const int* id) { | |
| 135 base::DictionaryValue event; | |
| 136 event.SetString("cat", "android"); | |
| 137 event.SetString("ph", std::string(1, ph)); | |
| 138 event.SetInteger("pid", pid); | |
| 139 event.SetInteger("tid", tid); | |
| 140 event.SetDouble("ts", ts); | |
| 141 event.SetDouble("tts", tts); | |
| 142 if (name) | |
| 143 event.SetString("name", *name); | |
| 144 | |
| 145 if (count) | |
| 146 event.SetInteger("args.count", *count); | |
| 147 | |
| 148 if (id) | |
| 149 event.SetInteger("id", *id); | |
| 150 | |
| 151 std::string json; | |
| 152 if (!base::JSONWriter::Write(event, &json)) { | |
| 153 // Bad data, shouldn't happen as the data is prepared by ourself. | |
|
Luis Héctor Chávez
2017/02/10 17:43:54
nit: ourselves.
Earl Ou
2017/03/22 11:38:26
Done on the Android side.
| |
| 154 // Skip and return. | |
| 155 return; | |
| 156 } | |
| 157 | |
| 158 current_data_size_ += json.size(); | |
|
Luis Héctor Chávez
2017/02/10 17:43:54
Why do you still need this? Why can't you just sen
Luis Héctor Chávez
2017/02/10 23:16:51
Ignore the above comment, since it's the way the A
Earl Ou
2017/02/16 09:56:45
trace_buffer seems to be designed for Chrome traci
Earl Ou
2017/03/22 11:38:26
I'm using TraceBuffer in the new patch now.
| |
| 159 trace_buffer_.emplace(std::move(json)); | |
| 160 | |
| 161 while (current_data_size_ > kTraceBufferByteSize) { | |
| 162 current_data_size_ -= trace_buffer_.front().size(); | |
| 163 trace_buffer_.pop(); | |
| 164 } | |
| 165 } | |
| 166 | |
| 167 void ArcTraceReader::ParseAndSaveData(std::string data) { | |
|
Luis Héctor Chávez
2017/02/10 17:43:54
This might fail since |data| might contain multipl
Earl Ou
2017/02/16 09:56:46
The data would only have one trace event since we'
| |
| 168 const std::vector<std::string> tokens = | |
| 169 base::SplitString(data, "|", base::KEEP_WHITESPACE, base::SPLIT_WANT_ALL); | |
| 170 | |
| 171 // ph|pid|tid|ts|tts | |
| 172 if (tokens.size() < 5 || tokens[0].size() != 1) // bad data, skip. | |
| 173 return; | |
| 174 | |
| 175 char ph = tokens[0][0]; | |
| 176 int pid, tid; | |
| 177 uint64_t ts, tts; | |
| 178 | |
| 179 if (!base::StringToInt(tokens[1], &pid) || | |
| 180 !base::StringToInt(tokens[2], &tid) || | |
| 181 !base::StringToUint64(tokens[3], &ts) || | |
| 182 !base::StringToUint64(tokens[4], &tts)) { | |
| 183 return; // bad data, skip. | |
| 184 } | |
| 185 | |
| 186 switch (ph) { | |
| 187 case 'B': | |
| 188 // B|pid|tid|ts|tts|name | |
| 189 if (tokens.size() != 6) | |
| 190 return; // bad data, skip. | |
| 191 WriteTraceEvent(ph, pid, tid, ts, tts, &tokens[5]); | |
| 192 break; | |
| 193 case 'E': | |
| 194 // E|pid|tid|ts|tts | |
| 195 WriteTraceEvent(ph, pid, tid, ts, tts); | |
| 196 break; | |
| 197 case 'F': | |
| 198 case 'S': | |
| 199 // F|pid|tid|ts|tts|name|value | |
| 200 int id; | |
| 201 if (tokens.size() != 7 || !base::StringToInt(tokens[6], &id)) | |
| 202 return; // bad data, skip. | |
| 203 WriteTraceEvent(ph, pid, tid, ts, tts, &tokens[5], nullptr, &id); | |
| 204 break; | |
| 205 case 'C': | |
| 206 // C|pid|tid|ts|tts|name|value | |
| 207 int count; | |
| 208 if (tokens.size() != 7 || !base::StringToInt(tokens[6], &count)) | |
| 209 return; // bad data, skip. | |
| 210 WriteTraceEvent(ph, pid, tid, ts, tts, &tokens[5], &count); | |
| 211 break; | |
| 212 } | |
| 213 } | |
| 214 | |
| 215 } // namespace arc | |
| OLD | NEW |