1*d57664e9SAndroid Build Coastguard Worker /*
2*d57664e9SAndroid Build Coastguard Worker * Copyright (C) 2019 The Android Open Source Project
3*d57664e9SAndroid Build Coastguard Worker *
4*d57664e9SAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*d57664e9SAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*d57664e9SAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*d57664e9SAndroid Build Coastguard Worker *
8*d57664e9SAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*d57664e9SAndroid Build Coastguard Worker *
10*d57664e9SAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*d57664e9SAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*d57664e9SAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*d57664e9SAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*d57664e9SAndroid Build Coastguard Worker * limitations under the License.
15*d57664e9SAndroid Build Coastguard Worker */
16*d57664e9SAndroid Build Coastguard Worker
17*d57664e9SAndroid Build Coastguard Worker #include "TraceBuffer.h"
18*d57664e9SAndroid Build Coastguard Worker
19*d57664e9SAndroid Build Coastguard Worker #include <chrono>
20*d57664e9SAndroid Build Coastguard Worker #include <sstream>
21*d57664e9SAndroid Build Coastguard Worker #include <unistd.h>
22*d57664e9SAndroid Build Coastguard Worker #include <vector>
23*d57664e9SAndroid Build Coastguard Worker
24*d57664e9SAndroid Build Coastguard Worker #include <inttypes.h>
25*d57664e9SAndroid Build Coastguard Worker
26*d57664e9SAndroid Build Coastguard Worker #include "android-base/utf8.h"
27*d57664e9SAndroid Build Coastguard Worker
28*d57664e9SAndroid Build Coastguard Worker #include "util/Files.h"
29*d57664e9SAndroid Build Coastguard Worker
30*d57664e9SAndroid Build Coastguard Worker namespace aapt {
31*d57664e9SAndroid Build Coastguard Worker namespace tracebuffer {
32*d57664e9SAndroid Build Coastguard Worker
33*d57664e9SAndroid Build Coastguard Worker namespace {
34*d57664e9SAndroid Build Coastguard Worker
35*d57664e9SAndroid Build Coastguard Worker constexpr char kBegin = 'B';
36*d57664e9SAndroid Build Coastguard Worker constexpr char kEnd = 'E';
37*d57664e9SAndroid Build Coastguard Worker
38*d57664e9SAndroid Build Coastguard Worker struct TracePoint {
39*d57664e9SAndroid Build Coastguard Worker char type;
40*d57664e9SAndroid Build Coastguard Worker pid_t tid;
41*d57664e9SAndroid Build Coastguard Worker int64_t time;
42*d57664e9SAndroid Build Coastguard Worker std::string tag;
43*d57664e9SAndroid Build Coastguard Worker };
44*d57664e9SAndroid Build Coastguard Worker
45*d57664e9SAndroid Build Coastguard Worker std::vector<TracePoint> traces;
46*d57664e9SAndroid Build Coastguard Worker bool enabled = true;
47*d57664e9SAndroid Build Coastguard Worker constinit std::chrono::steady_clock::time_point startTime = {};
48*d57664e9SAndroid Build Coastguard Worker
GetTime()49*d57664e9SAndroid Build Coastguard Worker int64_t GetTime() noexcept {
50*d57664e9SAndroid Build Coastguard Worker auto now = std::chrono::steady_clock::now();
51*d57664e9SAndroid Build Coastguard Worker if (startTime == decltype(tracebuffer::startTime){}) {
52*d57664e9SAndroid Build Coastguard Worker startTime = now;
53*d57664e9SAndroid Build Coastguard Worker }
54*d57664e9SAndroid Build Coastguard Worker return std::chrono::duration_cast<std::chrono::microseconds>(now - startTime).count();
55*d57664e9SAndroid Build Coastguard Worker }
56*d57664e9SAndroid Build Coastguard Worker
AddWithTime(std::string tag,char type,int64_t time)57*d57664e9SAndroid Build Coastguard Worker void AddWithTime(std::string tag, char type, int64_t time) noexcept {
58*d57664e9SAndroid Build Coastguard Worker TracePoint t = {type, getpid(), time, std::move(tag)};
59*d57664e9SAndroid Build Coastguard Worker traces.emplace_back(std::move(t));
60*d57664e9SAndroid Build Coastguard Worker }
61*d57664e9SAndroid Build Coastguard Worker
Add(std::string tag,char type)62*d57664e9SAndroid Build Coastguard Worker void Add(std::string tag, char type) noexcept {
63*d57664e9SAndroid Build Coastguard Worker AddWithTime(std::move(tag), type, GetTime());
64*d57664e9SAndroid Build Coastguard Worker }
65*d57664e9SAndroid Build Coastguard Worker
Flush(const std::string & basePath)66*d57664e9SAndroid Build Coastguard Worker void Flush(const std::string& basePath) {
67*d57664e9SAndroid Build Coastguard Worker if (basePath.empty()) {
68*d57664e9SAndroid Build Coastguard Worker return;
69*d57664e9SAndroid Build Coastguard Worker }
70*d57664e9SAndroid Build Coastguard Worker BeginTrace(__func__); // We can't do much here, only record that it happened.
71*d57664e9SAndroid Build Coastguard Worker
72*d57664e9SAndroid Build Coastguard Worker std::ostringstream s;
73*d57664e9SAndroid Build Coastguard Worker s << basePath << aapt::file::sDirSep << "report_aapt2_" << getpid() << ".json";
74*d57664e9SAndroid Build Coastguard Worker FILE* f = android::base::utf8::fopen(s.str().c_str(), "a");
75*d57664e9SAndroid Build Coastguard Worker if (f == nullptr) {
76*d57664e9SAndroid Build Coastguard Worker return;
77*d57664e9SAndroid Build Coastguard Worker }
78*d57664e9SAndroid Build Coastguard Worker
79*d57664e9SAndroid Build Coastguard Worker // Wrap the trace in a JSON array [] to make Chrome/Perfetto UI handle it.
80*d57664e9SAndroid Build Coastguard Worker char delimiter = '[';
81*d57664e9SAndroid Build Coastguard Worker for (const TracePoint& trace : traces) {
82*d57664e9SAndroid Build Coastguard Worker fprintf(f,
83*d57664e9SAndroid Build Coastguard Worker "%c{\"ts\" : \"%" PRIu64
84*d57664e9SAndroid Build Coastguard Worker "\", \"ph\" : \"%c\", \"tid\" : \"%d\" , \"pid\" : \"%d\", \"name\" : \"%s\" }\n",
85*d57664e9SAndroid Build Coastguard Worker delimiter, trace.time, trace.type, 0, trace.tid, trace.tag.c_str());
86*d57664e9SAndroid Build Coastguard Worker delimiter = ',';
87*d57664e9SAndroid Build Coastguard Worker }
88*d57664e9SAndroid Build Coastguard Worker if (!traces.empty()) {
89*d57664e9SAndroid Build Coastguard Worker fprintf(f, "]");
90*d57664e9SAndroid Build Coastguard Worker }
91*d57664e9SAndroid Build Coastguard Worker fclose(f);
92*d57664e9SAndroid Build Coastguard Worker traces.clear();
93*d57664e9SAndroid Build Coastguard Worker }
94*d57664e9SAndroid Build Coastguard Worker
95*d57664e9SAndroid Build Coastguard Worker } // namespace
96*d57664e9SAndroid Build Coastguard Worker
97*d57664e9SAndroid Build Coastguard Worker } // namespace tracebuffer
98*d57664e9SAndroid Build Coastguard Worker
BeginTrace(std::string tag)99*d57664e9SAndroid Build Coastguard Worker void BeginTrace(std::string tag) {
100*d57664e9SAndroid Build Coastguard Worker if (!tracebuffer::enabled) return;
101*d57664e9SAndroid Build Coastguard Worker tracebuffer::Add(std::move(tag), tracebuffer::kBegin);
102*d57664e9SAndroid Build Coastguard Worker }
103*d57664e9SAndroid Build Coastguard Worker
EndTrace(std::string tag)104*d57664e9SAndroid Build Coastguard Worker void EndTrace(std::string tag) {
105*d57664e9SAndroid Build Coastguard Worker if (!tracebuffer::enabled) return;
106*d57664e9SAndroid Build Coastguard Worker tracebuffer::Add(std::move(tag), tracebuffer::kEnd);
107*d57664e9SAndroid Build Coastguard Worker }
108*d57664e9SAndroid Build Coastguard Worker
enable(bool value)109*d57664e9SAndroid Build Coastguard Worker bool Trace::enable(bool value) {
110*d57664e9SAndroid Build Coastguard Worker return tracebuffer::enabled = value;
111*d57664e9SAndroid Build Coastguard Worker }
112*d57664e9SAndroid Build Coastguard Worker
Trace(const char * tag)113*d57664e9SAndroid Build Coastguard Worker Trace::Trace(const char* tag) {
114*d57664e9SAndroid Build Coastguard Worker if (!tracebuffer::enabled) return;
115*d57664e9SAndroid Build Coastguard Worker tag_.assign(tag);
116*d57664e9SAndroid Build Coastguard Worker tracebuffer::Add(tag_, tracebuffer::kBegin);
117*d57664e9SAndroid Build Coastguard Worker }
118*d57664e9SAndroid Build Coastguard Worker
Trace(std::string tag)119*d57664e9SAndroid Build Coastguard Worker Trace::Trace(std::string tag) : tag_(std::move(tag)) {
120*d57664e9SAndroid Build Coastguard Worker if (!tracebuffer::enabled) return;
121*d57664e9SAndroid Build Coastguard Worker tracebuffer::Add(tag_, tracebuffer::kBegin);
122*d57664e9SAndroid Build Coastguard Worker }
123*d57664e9SAndroid Build Coastguard Worker
124*d57664e9SAndroid Build Coastguard Worker template <class SpanOfStrings>
makeTag(std::string_view tag,const SpanOfStrings & args)125*d57664e9SAndroid Build Coastguard Worker std::string makeTag(std::string_view tag, const SpanOfStrings& args) {
126*d57664e9SAndroid Build Coastguard Worker std::ostringstream s;
127*d57664e9SAndroid Build Coastguard Worker s << tag;
128*d57664e9SAndroid Build Coastguard Worker if (!args.empty()) {
129*d57664e9SAndroid Build Coastguard Worker for (const auto& arg : args) {
130*d57664e9SAndroid Build Coastguard Worker s << ' ';
131*d57664e9SAndroid Build Coastguard Worker s << arg;
132*d57664e9SAndroid Build Coastguard Worker }
133*d57664e9SAndroid Build Coastguard Worker }
134*d57664e9SAndroid Build Coastguard Worker return std::move(s).str();
135*d57664e9SAndroid Build Coastguard Worker }
136*d57664e9SAndroid Build Coastguard Worker
Trace(std::string_view tag,const std::vector<android::StringPiece> & args)137*d57664e9SAndroid Build Coastguard Worker Trace::Trace(std::string_view tag, const std::vector<android::StringPiece>& args) {
138*d57664e9SAndroid Build Coastguard Worker if (!tracebuffer::enabled) return;
139*d57664e9SAndroid Build Coastguard Worker tag_ = makeTag(tag, args);
140*d57664e9SAndroid Build Coastguard Worker tracebuffer::Add(tag_, tracebuffer::kBegin);
141*d57664e9SAndroid Build Coastguard Worker }
142*d57664e9SAndroid Build Coastguard Worker
~Trace()143*d57664e9SAndroid Build Coastguard Worker Trace::~Trace() {
144*d57664e9SAndroid Build Coastguard Worker if (!tracebuffer::enabled) return;
145*d57664e9SAndroid Build Coastguard Worker tracebuffer::Add(std::move(tag_), tracebuffer::kEnd);
146*d57664e9SAndroid Build Coastguard Worker }
147*d57664e9SAndroid Build Coastguard Worker
FlushTrace(std::string_view basepath,std::string_view tag)148*d57664e9SAndroid Build Coastguard Worker FlushTrace::FlushTrace(std::string_view basepath, std::string_view tag) {
149*d57664e9SAndroid Build Coastguard Worker if (!Trace::enable(!basepath.empty())) return;
150*d57664e9SAndroid Build Coastguard Worker basepath_.assign(basepath);
151*d57664e9SAndroid Build Coastguard Worker tag_.assign(tag);
152*d57664e9SAndroid Build Coastguard Worker tracebuffer::Add(tag_, tracebuffer::kBegin);
153*d57664e9SAndroid Build Coastguard Worker }
154*d57664e9SAndroid Build Coastguard Worker
FlushTrace(std::string_view basepath,std::string_view tag,const std::vector<android::StringPiece> & args)155*d57664e9SAndroid Build Coastguard Worker FlushTrace::FlushTrace(std::string_view basepath, std::string_view tag,
156*d57664e9SAndroid Build Coastguard Worker const std::vector<android::StringPiece>& args) {
157*d57664e9SAndroid Build Coastguard Worker if (!Trace::enable(!basepath.empty())) return;
158*d57664e9SAndroid Build Coastguard Worker basepath_.assign(basepath);
159*d57664e9SAndroid Build Coastguard Worker tag_ = makeTag(tag, args);
160*d57664e9SAndroid Build Coastguard Worker tracebuffer::Add(tag_, tracebuffer::kBegin);
161*d57664e9SAndroid Build Coastguard Worker }
162*d57664e9SAndroid Build Coastguard Worker
FlushTrace(std::string_view basepath,std::string_view tag,const std::vector<std::string> & args)163*d57664e9SAndroid Build Coastguard Worker FlushTrace::FlushTrace(std::string_view basepath, std::string_view tag,
164*d57664e9SAndroid Build Coastguard Worker const std::vector<std::string>& args) {
165*d57664e9SAndroid Build Coastguard Worker if (!Trace::enable(!basepath.empty())) return;
166*d57664e9SAndroid Build Coastguard Worker basepath_.assign(basepath);
167*d57664e9SAndroid Build Coastguard Worker tag_ = makeTag(tag, args);
168*d57664e9SAndroid Build Coastguard Worker tracebuffer::Add(tag_, tracebuffer::kBegin);
169*d57664e9SAndroid Build Coastguard Worker }
170*d57664e9SAndroid Build Coastguard Worker
~FlushTrace()171*d57664e9SAndroid Build Coastguard Worker FlushTrace::~FlushTrace() {
172*d57664e9SAndroid Build Coastguard Worker if (!tracebuffer::enabled) return;
173*d57664e9SAndroid Build Coastguard Worker tracebuffer::Add(std::move(tag_), tracebuffer::kEnd);
174*d57664e9SAndroid Build Coastguard Worker tracebuffer::Flush(basepath_);
175*d57664e9SAndroid Build Coastguard Worker }
176*d57664e9SAndroid Build Coastguard Worker
177*d57664e9SAndroid Build Coastguard Worker } // namespace aapt
178