• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (C) 2019 The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //      http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #ifndef IORAP_SRC_PERFETTO_RX_PRODUCER_H_
16 #define IORAP_SRC_PERFETTO_RX_PRODUCER_H_
17 
18 #include "perfetto/perfetto_consumer.h"       // libiorap
19 
20 #include <perfetto/config/trace_config.pb.h>  // libperfetto
21 #include <rxcpp/rx.hpp>
22 
23 #include <iosfwd>
24 #include <functional>
25 #include <optional>
26 #include <vector>
27 
28 namespace iorap::perfetto {
29 
30 struct PerfettoDependencies {
31   using Component =
32       fruit::Component<PerfettoConsumer, ::perfetto::protos::TraceConfig>;
33   using Injector =
34       fruit::Injector<PerfettoConsumer, ::perfetto::protos::TraceConfig>;
35   using NormalizedComponent =
36       fruit::NormalizedComponent<PerfettoConsumer, ::perfetto::protos::TraceConfig>;
37 
38   // Create a 'live' component that will talk to perfetto via traced.
39   static Component CreateComponent(/*TODO: config params*/);
40 
41   // Create perfetto.protos.TraceConfig , serialized as a (machine-readable) string.
42   //
43   // The following ftrace events are enabled:
44   // * mm_filemap_add_to_page_cache
45   // * mm_filemap_delete_from_page_cache
46   //
47   // If deferred starting is also enabled, no tracing will begin until
48   // ::perfetto::consumer::StartTracing is invoked.
49   static ::perfetto::protos::TraceConfig CreateConfig(uint32_t duration_ms,
50                                                       bool deferred_start = true,
51                                                       uint32_t buffer_size = 4096);
52 };
53 
54 // This acts as a lightweight type marker so that we know what data has actually
55 // encoded under the hood.
56 template <typename T>
57 struct BinaryWireProtobuf {
dataBinaryWireProtobuf58   std::vector<std::byte>& data() {
59     return data_;
60   }
61 
dataBinaryWireProtobuf62   const std::vector<std::byte>& data() const {
63     return data_;
64   }
65 
sizeBinaryWireProtobuf66   size_t size() const {
67     return data_.size();
68   }
69 
BinaryWireProtobufBinaryWireProtobuf70   explicit BinaryWireProtobuf(char* data, size_t size)
71     : BinaryWireProtobuf(reinterpret_cast<std::byte*>(data), size) {
72   }
73 
BinaryWireProtobufBinaryWireProtobuf74   explicit BinaryWireProtobuf(std::byte* data, size_t size) {
75     data_.resize(size);
76     std::copy(data,
77               data + size,
78               data_.data());
79   }
80 
81   // Important: Deserialization could fail, for example data is truncated or
82   // some minor disc corruption occurred.
83   template <typename U>
MaybeUnserializeBinaryWireProtobuf84   std::optional<U> MaybeUnserialize() {
85     U unencoded;
86 
87     if (!unencoded.ParseFromArray(data_.data(), data_.size())) {
88       return std::nullopt;
89     }
90 
91     return {std::move(unencoded)};
92   }
93 
94   bool WriteFullyToFile(const std::string& path,
95                         bool follow_symlinks = false) const;
96 
97  private:
98   static bool CleanUpAfterFailedWrite(const std::string& path);
99   bool WriteStringToFd(int fd) const;
100 
101   std::vector<std::byte> data_;
102 };
103 
104 //using PerfettoTraceProto = BinaryWireProtobuf<::perfetto::protos::Trace>;
105 using PerfettoTraceProto = BinaryWireProtobuf<::google::protobuf::MessageLite>;
106 
107 enum class PerfettoStreamCommand {
108   kStartTracing, // -> () | on_error
109   kStopTracing,  // -> on_next(PerfettoTraceProto) | on_error
110   kShutdown,     // -> on_completed | on_error
111   // XX: should shutdown be converted to use the rx suscriber#unsubscribe instead?
112 };
113 
114 std::ostream& operator<<(std::ostream& os, PerfettoStreamCommand c);
115 
116 struct RxProducerFactory {
117   // Passing anything by value leads to a lot of pain and headache.
118   // Pass in the injector by reference because nothing else seems to work.
119   explicit RxProducerFactory(PerfettoDependencies::Injector& injector);
120 
121   // Create a one-shot perfetto observable that will begin
122   // asynchronously producing a PerfettoTraceProto after the 'kStartTracing'
123   // command is observed.
124   //
125   // libperfetto is immediately primed (i.e. connected in a deferred state)
126   // upon calling this function, to reduce the latency of 'kStartTracing'.
127   //
128   // To finish the trace, push 'kStopTracing'. To cancel or tear down at any
129   // time, push 'kShutdown'.
130   //
131   // The TraceProto may come out at any time after 'kStartTracing',
132   // this is controlled by duration_ms in the TraceConfig.
133   //
134   // TODO: libperfetto should actually stop tracing when we ask it to,
135   // instead of using a hardcoded time.
136   //
137   // The observable may go into #on_error at any time, if the underlying
138   // libperfetto states transition to a failing state.
139   // This usually means the OS is not configured correctly.
140   rxcpp::observable<PerfettoTraceProto> CreateTraceStream(
141       rxcpp::observable<PerfettoStreamCommand> commands);
142 
143   // TODO: is this refactor-able into a subscriber factory that takes
144   // the commands-observable as a parameter?
145 
146   // TODO: infinite perfetto stream.
147 
148  private:
149   // XX: why doesn't this just let me pass in a regular Component?
150   PerfettoDependencies::Injector& injector_;
151 
152   friend void CollectPerfettoTraceBufferImmediately(
153       RxProducerFactory& producer_factory,
154       const std::string& arg_output_proto);
155 };
156 
157 // An rx Coordination, which will cause a new thread to spawn for each new Worker.
158 //
159 // Idle-class priority is set for the CPU and IO priorities on the new thread.
160 //
161 // TODO: move to separate file
162 rxcpp::observe_on_one_worker ObserveOnNewIoThread();
163 
164 }  // namespace iorap::perfetto
165 #endif  // IORAP_SRC_PERFETTO_RX_PRODUCER_H_
166