| <!doctype html>
|
| <html lang="en-us">
|
| <link rel="shortcut icon" href="data:image/x-icon;," type="image/x-icon" />
|
|
|
| <body>
|
| <style>
|
| pre {
|
| border: 1px solid #eee;
|
| margin: 10px 0;
|
| font-family: monospace;
|
| font-size: 10px;
|
| min-height: 100px;
|
| }
|
|
|
| body > * {
|
| margin: 20px;
|
| }
|
|
|
| #btn_fetch {
|
| font-size: 14px;
|
| }
|
| </style>
|
|
|
| <select id="source" size="4">
|
| <option selected>/trace.json</option>
|
| </select>
|
|
|
| <br />
|
|
|
| <button type="button" id="btn_fetch">Open Perfetto</button>
|
|
|
| <br />
|
|
|
| <pre id="logs" cols="80" rows="20"></pre>
|
|
|
| <script type="text/javascript">
|
|
|
| const ORIGIN = "https://ui.perfetto.dev";
|
|
|
| const logs = document.getElementById("logs");
|
| const btnFetch = document.getElementById("btn_fetch");
|
|
|
| async function getMtime() {
|
| const mtime_resp = await fetch("/mtime");
|
| const mtime = await mtime_resp.text();
|
| return mtime;
|
| }
|
|
|
| async function fetchAndOpen(traceUrl) {
|
| logs.innerText += `Fetching trace from ${traceUrl}...\n`;
|
| const mtime = await getMtime();
|
| const resp = await fetch(traceUrl);
|
|
|
| const blob = await resp.blob();
|
| const arrayBuffer = await blob.arrayBuffer();
|
| logs.innerText += `fetch() complete, now passing to ui.perfetto.dev\n`;
|
| openTrace(arrayBuffer, traceUrl, mtime);
|
| }
|
|
|
| async function repoll(win, traceUrl, mtime) {
|
| const newMtime = await getMtime();
|
| console.log(newMtime, mtime);
|
| if (newMtime !== mtime) {
|
| logs.innerText += `Trace updated, fetching new version...\n`;
|
| const resp = await fetch(traceUrl);
|
| const blob = await resp.blob();
|
| const arrayBuffer = await blob.arrayBuffer();
|
| logs.innerText += `New trace fetched, opening...\n`;
|
| sendTrace(win, arrayBuffer, traceUrl);
|
| }
|
|
|
| setTimeout(() => repoll(win, traceUrl, newMtime), 500);
|
| }
|
|
|
| function sendTrace(win, arrayBuffer, traceUrl) {
|
| const reopenUrl = new URL(location.href);
|
| reopenUrl.hash = `#reopen=${traceUrl}`;
|
| logs.innerText += `Sending trace to UI\n`;
|
| win.postMessage(
|
| {
|
| perfetto: {
|
| buffer: arrayBuffer,
|
| title: "trace.json",
|
| url: reopenUrl.toString(),
|
| keepApiOpen: true,
|
| },
|
| },
|
| ORIGIN,
|
| );
|
| }
|
|
|
| function openTrace(arrayBuffer, traceUrl, mtime) {
|
| const win = window.open(ORIGIN);
|
| if (!win) {
|
| btnFetch.style.background = "#f3ca63";
|
| btnFetch.onclick = () => openTrace(arrayBuffer);
|
| logs.innerText += `Popups blocked, you need to manually click the button`;
|
| btnFetch.innerText =
|
| "Popups blocked, click here to open the trace file";
|
| return;
|
| }
|
|
|
| const timer = setInterval(
|
| () => win.postMessage("PING", ORIGIN),
|
| 50,
|
| );
|
|
|
| const onMessageHandler = (evt) => {
|
| if (evt.data !== "PONG") return;
|
|
|
|
|
| window.clearInterval(timer);
|
| window.removeEventListener("message", onMessageHandler);
|
|
|
| sendTrace(win, arrayBuffer, traceUrl);
|
| setTimeout(() => repoll(win, traceUrl, mtime), 500);
|
| };
|
|
|
| window.addEventListener("message", onMessageHandler);
|
| }
|
|
|
|
|
| if (location.hash.startsWith("#reopen=")) {
|
| const traceUrl = location.hash.substr(8);
|
| fetchAndOpen(traceUrl);
|
| }
|
|
|
| btnFetch.onclick = () =>
|
| fetchAndOpen(document.getElementById("source").value);
|
| </script>
|
| </body>
|
| </html>
|
|
|