/
githubmirror
/
servo
Обзор
Документация
Войти
/
githubmirror
/
servo
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
components/default-resources/resources/about-memory.html
223 строки
7 KB
Jonathan Schwender
Embed default resources in Servo applications using a `servo-default-resources` crate (#43182)
01 апр 2026, 10:16
Не верифицирован
01 апр 2026, 10:16
f4877c1
Код
Авторство
О чём код?
<!DOCTYPE html> <html> <head> <title>about:memory</title> <script> document.addEventListener("DOMContentLoaded", start); function insertNode(root, report) { let currentNode = root; for (let path of report.path) { if (!currentNode[path]) { currentNode[path] = { total: 0, container: true }; } currentNode = currentNode[path]; currentNode.total += report.size; } currentNode.size = report.size; currentNode.container = false; } function formatBytes(bytes) { if (bytes < 1024) { return bytes + " B"; } else if (bytes < 1024 * 1024) { return (bytes / 1024).toFixed(2) + " KiB"; } else if (bytes < 1024 * 1024 * 1024) { return (bytes / (1024 * 1024)).toFixed(2) + " MiB"; } else { return (bytes / (1024 * 1024 * 1024)).toFixed(2) + " GiB"; } } function formattedSize(size) { // Use enough padding to take into account the "MiB" part. return formatBytes(size).padStart(10); } function convertNodeToDOM(node, name = null) { let result = document.createDocumentFragment(); if (node.container) { let details = document.createElement("details"); let summary = document.createElement("summary"); summary.textContent = `${formattedSize(node.total)} -- ${name}`; details.append(summary); result.append(details); // Add the children in descending order of total size. let entries = Object.entries(node) .filter((item) => { return !["total", "size", "container"].includes(item[0]); }) .sort((a, b) => b[1].total - a[1].total) .forEach((item) => details.append(convertNodeToDOM(item[1], item[0])) ); } else { let inner = document.createElement("div"); inner.textContent = `${formattedSize(node.size)} -- ${name}`; result.append(inner); } return result; } function reportsForProcess(processReport) { let explicitRoot = {}; let nonExplicitRoot = {}; let jemallocHeapReportedSize = 0; let systemHeapReportedSize = 0; let jemallocHeapAllocatedSize = NaN; let systemHeapAllocatedSize = NaN; // In content processes, get the list of urls. let urls = new Set(); processReport.reports.forEach((report) => { if (report.path[0].startsWith("url(")) { // This can be a list of urls. let path_urls = report.path[0].slice(4, -1).split(", "); path_urls.forEach((url) => urls.add(url)); } // Add "explicit" to the start of the path, when appropriate. if (report.kind.startsWith("Explicit")) { report.path.unshift("explicit"); } // Update the reported fractions of the heaps, when appropriate. if (report.kind == "ExplicitJemallocHeapSize") { jemallocHeapReportedSize += report.size; } else if (report.kind == "ExplicitSystemHeapSize") { systemHeapReportedSize += report.size; } // Record total size of the heaps, when we see them. if (report.path.length == 1) { if (report.path[0] == "jemalloc-heap-allocated") { jemallocHeapAllocatedSize = report.size; } else if (report.path[0] == "system-heap-allocated") { systemHeapAllocatedSize = report.size; } } // Insert this report at the proper position. insertNode( report.kind.startsWith("Explicit") ? explicitRoot : nonExplicitRoot, report ); }); // Compute and insert the heap-unclassified values. if (!isNaN(jemallocHeapAllocatedSize)) { insertNode(explicitRoot, { path: ["explicit", "jemalloc-heap-unclassified"], size: jemallocHeapAllocatedSize - jemallocHeapReportedSize, }); } if (!isNaN(systemHeapAllocatedSize)) { insertNode(explicitRoot, { path: ["explicit", "system-heap-unclassified"], size: systemHeapAllocatedSize - systemHeapReportedSize, }); } // Create the DOM structure for each process report: // <div class=process> <h4>...<h4> <pre> ...</pre> </div> let container = document.createElement("div"); container.classList.add("process"); let reportTitle = document.createElement("h4"); reportTitle.textContent = `${ processReport.isMainProcess ? "Main Process" : "Content Process" } (pid ${processReport.pid}) ${[...urls.values()].join(", ")}`; container.append(reportTitle); let reportNode = document.createElement("pre"); reportNode.classList.add("report"); container.append(reportNode); reportNode.append(convertNodeToDOM(explicitRoot.explicit, "explicit")); for (let prop in nonExplicitRoot) { reportNode.append(convertNodeToDOM(nonExplicitRoot[prop], prop)); } // Make sure we always put the main process first. if (processReport.isMainProcess) { window.reports.prepend(container); } else { window.reports.append(container); } } function start() { window.gcButton.onclick = async () => { window.gcButton.disabled = true; navigator.servo.garbageCollectAllContexts(); window.gcButton.disabled = false; }; window.startButton.onclick = async () => { let content = await navigator.servo.reportMemory(); let reports = JSON.parse(content); if (reports.error) { console.error(reports.error); return; } window.reports.innerHTML = ""; window.reports.classList.remove("hidden"); if (!Array.isArray(reports)) { console.error("Unexpected memory report format!"); return; } reports.forEach(reportsForProcess); }; } </script> <style> html { font-family: sans-serif; } details, details div { margin-left: 1em; } summary:hover { cursor: pointer; } div.process { margin: 0.5em; border: 2px solid gray; border-radius: 10px; padding: 5px; background-color: lightgray; } .report { line-height: 1.5em; } .report > details { margin-bottom: 1em; } .hidden { display: none; } </style> </head> <body> <h2>Memory Reports</h2> <button id="startButton">Measure</button> <button id="gcButton">Force GC</button> <div id="reports" class="hidden"></div> </body> </html>