1 /*
2  * Copyright (C) 2018 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 "tools/trace_to_text/utils.h"
18 
19 #include <inttypes.h>
20 #include <stdio.h>
21 
22 #include <memory>
23 #include <ostream>
24 #include <utility>
25 
26 #include "perfetto/base/logging.h"
27 #include "perfetto/trace/ftrace/ftrace_stats.pb.h"
28 #include "perfetto/traced/sys_stats_counters.h"
29 
30 #include "perfetto/trace/trace.pb.h"
31 #include "perfetto/trace/trace_packet.pb.h"
32 
33 namespace perfetto {
34 namespace trace_to_text {
35 
ForEachPacketBlobInTrace(std::istream * input,const std::function<void (std::unique_ptr<char[]>,size_t)> & f)36 void ForEachPacketBlobInTrace(
37     std::istream* input,
38     const std::function<void(std::unique_ptr<char[]>, size_t)>& f) {
39   size_t bytes_processed = 0;
40   // The trace stream can be very large. We cannot just pass it in one go to
41   // libprotobuf as that will refuse to parse messages > 64MB. However we know
42   // that a trace is merely a sequence of TracePackets. Here we just manually
43   // tokenize the repeated TracePacket messages and parse them individually
44   // using libprotobuf.
45   for (uint32_t i = 0;; i++) {
46     if ((i & 0x3f) == 0) {
47       fprintf(stderr, "Processing trace: %8zu KB%c", bytes_processed / 1024,
48               kProgressChar);
49       fflush(stderr);
50     }
51     // A TracePacket consists in one byte stating its field id and type ...
52     char preamble;
53     input->get(preamble);
54     if (!input->good())
55       break;
56     bytes_processed++;
57     PERFETTO_DCHECK(preamble == 0x0a);  // Field ID:1, type:length delimited.
58 
59     // ... a varint stating its size ...
60     uint32_t field_size = 0;
61     uint32_t shift = 0;
62     for (;;) {
63       char c = 0;
64       input->get(c);
65       field_size |= static_cast<uint32_t>(c & 0x7f) << shift;
66       shift += 7;
67       bytes_processed++;
68       if (!(c & 0x80))
69         break;
70     }
71 
72     // ... and the actual TracePacket itself.
73     std::unique_ptr<char[]> buf(new char[field_size]);
74     input->read(buf.get(), static_cast<std::streamsize>(field_size));
75     bytes_processed += field_size;
76 
77     f(std::move(buf), field_size);
78   }
79 }
80 
ForEachPacketInTrace(std::istream * input,const std::function<void (const protos::TracePacket &)> & f)81 void ForEachPacketInTrace(
82     std::istream* input,
83     const std::function<void(const protos::TracePacket&)>& f) {
84   ForEachPacketBlobInTrace(
85       input, [f](std::unique_ptr<char[]> buf, size_t size) {
86         protos::TracePacket packet;
87         auto res = packet.ParseFromArray(buf.get(), static_cast<int>(size));
88         if (!res) {
89           PERFETTO_ELOG("Skipping invalid packet");
90           return;
91         }
92         f(packet);
93       });
94 }
95 
96 }  // namespace trace_to_text
97 }  // namespace perfetto
98