1 /* 2 * Copyright (C) 2019 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 #ifndef SRC_TRACE_PROCESSOR_RPC_RPC_H_ 18 #define SRC_TRACE_PROCESSOR_RPC_RPC_H_ 19 20 #include <functional> 21 #include <memory> 22 #include <vector> 23 24 #include <stddef.h> 25 #include <stdint.h> 26 27 #include "perfetto/trace_processor/basic_types.h" 28 #include "perfetto/trace_processor/status.h" 29 #include "src/protozero/proto_ring_buffer.h" 30 31 namespace perfetto { 32 33 namespace protos { 34 namespace pbzero { 35 class ComputeMetricResult; 36 class DisableAndReadMetatraceResult; 37 } // namespace pbzero 38 } // namespace protos 39 40 namespace trace_processor { 41 42 class Iterator; 43 class TraceProcessor; 44 45 // This class handles the binary {,un}marshalling for the Trace Processor RPC 46 // API (see protos/perfetto/trace_processor/trace_processor.proto). 47 // This is to deal with cases where the client of the trace processor is not 48 // some in-process C++ code but a remote process: 49 // There are two use cases of this: 50 // 1. The JS<>WASM interop for the web-based UI. 51 // 2. The HTTP RPC mode of trace_processor_shell that allows the UI to talk 52 // to a native trace processor instead of the bundled WASM one. 53 // This class has (a subset of) the same methods of the public TraceProcessor 54 // interface, but the methods just take and return proto-encoded binary buffers. 55 // This class does NOT define how the transport works (e.g. HTTP vs WASM interop 56 // calls), it just deals with {,un}marshalling. 57 // This class internally creates and owns a TraceProcessor instance, which 58 // lifetime is tied to the lifetime of the Rpc instance. 59 class Rpc { 60 public: 61 // The unique_ptr argument is optional. If non-null it will adopt the passed 62 // instance and allow to directly query that. If null, a new instanace will be 63 // created internally by calling Parse(). 64 explicit Rpc(std::unique_ptr<TraceProcessor>); 65 Rpc(); 66 ~Rpc(); 67 68 // 1. TraceProcessor byte-pipe RPC interface. 69 // This is a bidirectional channel with a remote TraceProcessor instance. All 70 // it needs is a byte-oriented pipe (e.g., a TCP socket, a pipe(2) between two 71 // processes or a postmessage channel in the JS+Wasm case). The messages 72 // exchanged on these pipes are TraceProcessorRpc protos (defined in 73 // trace_processor.proto). This has been introduced in Perfetto v15. 74 75 // Pushes data received by the RPC channel into the parser. Inbound messages 76 // are tokenized and turned into TraceProcessor method invocations. |data| 77 // does not need to be a whole TraceProcessorRpc message. It can be a portion 78 // of it or a union of >1 messages. 79 // Responses are sent throught the RpcResponseFunction (below). 80 void OnRpcRequest(const void* data, size_t len); 81 82 // The size argument is a uint32_t and not size_t to avoid ABI mismatches 83 // with Wasm, where size_t = uint32_t. 84 // (nullptr, 0) has the semantic of "close the channel" and is issued when an 85 // unrecoverable wire-protocol framing error is detected. 86 using RpcResponseFunction = void (*)(const void* /*data*/, uint32_t /*len*/); SetRpcResponseFunction(RpcResponseFunction f)87 void SetRpcResponseFunction(RpcResponseFunction f) { rpc_response_fn_ = f; } 88 89 // 2. TraceProcessor legacy RPC endpoints. 90 // The methods below are exposed for the old RPC interfaces, where each RPC 91 // implementation deals with the method demuxing: (i) wasm_bridge.cc has one 92 // exported C function per method (going away soon); (ii) httpd.cc has one 93 // REST endpoint per method. Over time this turned out to have too much 94 // duplicated boilerplate and we moved to the byte-pipe model above. 95 // We still keep these endpoints around, because httpd.cc still exposes the 96 // individual REST endpoints to legacy clients (TP's Python API). The 97 // mainteinance cost of those is very low. Both the new byte-pipe and the 98 // old endpoints run exactly the same code. The {de,}serialization format is 99 // the same, the only difference is only who does the method demuxing. 100 // The methods of this class are mirrors (modulo {un,}marshalling of args) of 101 // the corresponding names in trace_processor.h . See that header for docs. 102 103 util::Status Parse(const uint8_t* data, size_t len); 104 void NotifyEndOfFile(); 105 void ResetTraceProcessor(const uint8_t* args, size_t len); 106 std::string GetCurrentTraceName(); 107 std::vector<uint8_t> ComputeMetric(const uint8_t* data, size_t len); 108 void EnableMetatrace(const uint8_t* data, size_t len); // EnableMetatraceArgs 109 std::vector<uint8_t> DisableAndReadMetatrace(); 110 std::vector<uint8_t> GetStatus(); 111 112 // Creates a new RPC session by deleting all tables and views that have been 113 // created (by the UI or user) after the trace was loaded; built-in 114 // tables/view created by the ingestion process are preserved. 115 void RestoreInitialTables(); 116 117 // Runs a query and returns results in batch. Each batch is a proto-encoded 118 // TraceProcessor.QueryResult message and contains a variable number of rows. 119 // The callbacks are called inline, so the whole callstack looks as follows: 120 // Query(..., callback) 121 // callback(..., has_more=true) 122 // ... 123 // callback(..., has_more=false) 124 // (Query() returns at this point). 125 // TODO(primiano): long-term this API should change and be turned into a 126 // bidirectional streaming api (see go/imperative-metrics). The problem with 127 // the current design is that it holds the callstack until the query is done 128 // and makes nested query hard as they cause re-entrancy. It's okay for now 129 // but will change soon. 130 using QueryResultBatchCallback = std::function< 131 void(const uint8_t* /*buf*/, size_t /*len*/, bool /*has_more*/)>; 132 void Query(const uint8_t* args, size_t len, QueryResultBatchCallback); 133 134 private: 135 void ParseRpcRequest(const uint8_t* data, size_t len); 136 void ResetTraceProcessorInternal(const Config& config); 137 void MaybePrintProgress(); 138 Iterator QueryInternal(const uint8_t* args, size_t len); 139 void ComputeMetricInternal(const uint8_t* args, 140 size_t len, 141 protos::pbzero::ComputeMetricResult*); 142 void DisableAndReadMetatraceInternal( 143 protos::pbzero::DisableAndReadMetatraceResult*); 144 145 Config trace_processor_config_; 146 std::unique_ptr<TraceProcessor> trace_processor_; 147 RpcResponseFunction rpc_response_fn_; 148 protozero::ProtoRingBuffer rxbuf_; 149 int64_t tx_seq_id_ = 0; 150 int64_t rx_seq_id_ = 0; 151 bool eof_ = false; 152 int64_t t_parse_started_ = 0; 153 size_t bytes_last_progress_ = 0; 154 size_t bytes_parsed_ = 0; 155 }; 156 157 } // namespace trace_processor 158 } // namespace perfetto 159 160 #endif // SRC_TRACE_PROCESSOR_RPC_RPC_H_ 161