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