/// <summary> /// Check if another instance of trace_processor_shell is running on this port /// </summary> /// <param name="port"></param> /// <returns></returns> private bool IsPortAvailable(int port) { try { TraceProcessorRpc rpc = new TraceProcessorRpc { Request = TraceProcessorRpc.Types.TraceProcessorMethod.TpmGetStatus }; // Send the request var rpcResult = SendRpcRequest(rpc); if (rpcResult.Msg.Count != 1 || rpcResult.Msg[0].Status == null) { throw new Exception("Invalid RPC stream result from trace_processor_shell"); } else { // If the response contains Perfetto, trace_processor_shell is already running on this port return(!rpcResult.Msg[0].Status.HumanReadableVersion.Contains("Perfetto")); } } catch (HttpRequestException) { // Exception here is the connection refused message, meaning the RPC server has not been initialized // Which means this port is not being used by another trace_processor_shell return(true); } }
/// <summary> /// Perform a SQL query against trace_processor_shell to gather Perfetto trace data. /// </summary> /// <param name="sqlQuery">The query to perform against the loaded trace in trace_processor_shell</param> /// <returns>List of RPC objects that contain the QueryResults</returns> public RepeatedField <TraceProcessorRpc> QueryTrace(string sqlQuery) { // Make sure ShellProcess is running if (ShellProcess == null || ShellProcess.HasExited) { throw new Exception("The trace_process_shell is not running"); } int cnt = 0; // Check if the trace is loaded // We know the shell is running, so the trace could still be in the loading process. Give it a little while to finish loading // before we error out. while (!CheckIfTraceIsLoaded()) { if (cnt++ > MaxRetryLimit) { throw new Exception("Unable to query Perfetto trace because trace_processor_shell.exe does not appear to have loaded it"); } } TraceProcessorRpc rpc = new TraceProcessorRpc { Request = TraceProcessorRpc.Types.TraceProcessorMethod.TpmQueryStreaming, QueryArgs = new QueryArgs() }; rpc.QueryArgs.SqlQuery = sqlQuery; var rpcResult = SendRpcRequest(rpc); return(rpcResult.Msg); }
/// <summary> /// Sends an RPC request to trace_processor_shell. This utilizies the bidirectional pipe that exists with the /rpc endpoint. /// TraceProcessorRpcStream objects get passed back and forth /// </summary> /// <param name="rpc">RPC stream object that contains the request</param> /// <returns>RPC stream object that contains the response</returns> private TraceProcessorRpcStream SendRpcRequest(TraceProcessorRpc rpc) { TraceProcessorRpcStream rpcStream = new TraceProcessorRpcStream(); rpcStream.Msg.Add(rpc); TraceProcessorRpcStream returnStream = null; using (var client = new HttpClient()) { client.DefaultRequestHeaders.Add("Connection", "keep-alive"); client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/x-protobuf")); //ACCEPT header HttpContent sc = new ByteArrayContent(rpcStream.ToByteArray()); var response = client.PostAsync($"http://localhost:{HttpPort}/rpc", sc).GetAwaiter().GetResult(); var byteArray = response.Content.ReadAsByteArrayAsync().Result; returnStream = TraceProcessorRpcStream.Parser.ParseFrom(byteArray); } if (returnStream == null) { throw new Exception("Problem with the RPC stream returned from trace_processor_shell.exe"); } return(returnStream); }
/// <summary> /// Check if the trace_processor_shell has a loaded trace. Assumes the shell executable is already running. Will throw otherwise. /// </summary> /// <returns></returns> private bool CheckIfTraceIsLoaded() { if (ShellProcess == null || ShellProcess.HasExited) { throw new Exception("The trace_process_shell is not running"); } try { TraceProcessorRpc rpc = new TraceProcessorRpc { Request = TraceProcessorRpc.Types.TraceProcessorMethod.TpmGetStatus }; // Send the request var rpcResult = SendRpcRequest(rpc); if (rpcResult.Msg.Count != 1 || rpcResult.Msg[0].Status == null) { throw new Exception("Invalid RPC stream result from trace_processor_shell"); } else { return(rpcResult.Msg[0].Status.HasLoadedTraceName); } } catch (HttpRequestException) { // Exception here is the connection refused message, meaning the RPC server has not been initialized return(false); } }