• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright (C) 2024 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
15import protos from '../../../protos';
16import {assetSrc} from '../../../base/assets';
17import {defer} from '../../../base/deferred';
18import {assertTrue} from '../../../base/logging';
19import {errResult, okResult, Result} from '../../../base/result';
20import {utf8Decode, utf8Encode} from '../../../base/string_utils';
21import WasmModuleGen from '../../../gen/trace_config_utils';
22
23/**
24 * This file is the TS-equivalent of src/trace_config_utils.
25 * It exposes two functions to conver the TraceConfig proto from txt<>protobuf.
26 * It guarrantees to have the same behaviour of perfetto_cmd and trace_processor
27 * by using precisely the same code via WebAssembly.
28 */
29interface WasmModule {
30  module: WasmModuleGen.Module;
31  buf: Uint8Array;
32}
33
34let moduleInstance: WasmModule | undefined = undefined;
35
36/**
37 * Convert a binary-encoded protos.TracConfig to pbtxt (i.e. the text format
38 * that can be passed to perfetto --txt).
39 */
40export async function traceConfigToTxt(
41  config: Uint8Array | protos.ITraceConfig,
42): Promise<string> {
43  const wasm = await initWasmOnce();
44
45  const configU8: Uint8Array =
46    config instanceof Uint8Array
47      ? config
48      : protos.TraceConfig.encode(config).finish();
49  assertTrue(configU8.length <= wasm.buf.length);
50  wasm.buf.set(configU8);
51
52  const txtSize =
53    wasm.module.ccall(
54      'trace_config_pb_to_txt',
55      'number',
56      ['number'],
57      [configU8.length],
58    ) >>> 0;
59
60  const txt = utf8Decode(wasm.buf.subarray(0, txtSize));
61  return txt;
62}
63
64/** Convert a pbtxt (text-proto) text to a proto-encoded TraceConfig. */
65export async function traceConfigToPb(
66  configTxt: string,
67): Promise<Result<Uint8Array>> {
68  const wasm = await initWasmOnce();
69
70  const configUtf8 = utf8Encode(configTxt);
71  assertTrue(configUtf8.length <= wasm.buf.length);
72  wasm.buf.set(configUtf8);
73
74  const resSize =
75    wasm.module.ccall(
76      'trace_config_txt_to_pb',
77      'number',
78      ['number'],
79      [configUtf8.length],
80    ) >>> 0;
81
82  const success = wasm.buf.at(0) === 1;
83  const payload = wasm.buf.slice(1, 1 + resSize);
84  return success ? okResult(payload) : errResult(utf8Decode(payload));
85}
86
87async function initWasmOnce(): Promise<WasmModule> {
88  if (moduleInstance === undefined) {
89    // We have to fetch the .wasm file manually because the stub generated by
90    // emscripten uses sync-loading, which works only in Workers.
91    const resp = await fetch(assetSrc('trace_config_utils.wasm'));
92    const wasmBinary = await resp.arrayBuffer();
93    const deferredRuntimeInitialized = defer<void>();
94    const instance = WasmModuleGen({
95      noInitialRun: true,
96      locateFile: (s: string) => s,
97      print: (s: string) => console.log(s),
98      printErr: (s: string) => console.error(s),
99      onRuntimeInitialized: () => deferredRuntimeInitialized.resolve(),
100      wasmBinary,
101    } as WasmModuleGen.ModuleArgs);
102    await deferredRuntimeInitialized;
103    const bufAddr =
104      instance.ccall('trace_config_utils_buf', 'number', [], []) >>> 0;
105    const bufSize =
106      instance.ccall('trace_config_utils_buf_size', 'number', [], []) >>> 0;
107    moduleInstance = {
108      module: instance,
109      buf: instance.HEAPU8.subarray(bufAddr, bufAddr + bufSize),
110    };
111  }
112  return moduleInstance;
113}
114