我尝试根据使用TracingProfiler收集的日志数据(特别是类别“v8.cpu_profiler”)重建Javascript函数(调用图)的确切执行顺序。
不幸的是,即使我以完全相同的方式与测试Web应用程序交互,我获得的节点(函数定义)和边(函数调用)的数量在运行中也会波动。
目前,我使用Puppeteer提取跟踪并与应用程序交互:
let browser = await puppeteer.launch({
headless: true,
userDataDir: userDataFolder,
args:[
`--disable-extensions`,
`--js-flags=--jitless --no-opt --predictable --no-concurrent-recompilation `] // disable chrome's optimizations
});
// Get the tab opened by default
let [page] = await browser.pages();
// Make sure to disable the cache
await page.setCacheEnabled(false);
// create cdp session
const cdp = await page.target().createCDPSession();
await cdp.send('Tracing.start', {
traceConfig: {
recordMode: 'recordContinuously',
includedCategories: ['disabled-by-default-v8.cpu_profiler'],
excludedCategories: ['*']
},
transferMode: 'ReturnAsStream'
});
await page.waitForTimeout(1000);
// Go to the page
await Promise.race([
page.goto(this.url, { waitUntil: ["load", "networkidle2"] }),
page.waitForTimeout("body"),
]);
// Wait to make sure that the page is fully loaded
await page.waitForTimeout(1000);
// dynamically interact with the webpage
await interact(page);
正如您所看到的,我使用标志--jitless --no-opt --predictable --no-concurrent-recompilation
来禁用我所知道的任何非确定性来源,但这仍然不够。为什么会发生这种情况?理论上,执行的函数完全相同,跟踪探查器应该非常精确。
有没有可能v8仍然在做一些优化的引擎盖下,如果是的,我如何禁用他们?
是否有其他方法可以提取执行函数的确切顺序?
1条答案
按热度按时间mqkwyuun1#
V8有一个
--trace
标志,它给出了执行函数的精确顺序。警告:它会产生大量的输出,因为在典型的网站上有大量的函数调用。函数调用序列是完全确定的。内部优化与此无关,因此没有理由关闭它们。(想想看:如果优化改变了函数调用的顺序,那么应用程序就会崩溃。无论引擎内部做什么,都不能改变网站开发者想要的行为。
“Tracing Profiler”是一个基于样本的分析器,因此在设计上是不确定的(不可能有一个标志来“关闭它”)。它使用一个每毫秒(或类似的间隔,我不确定确切的值)对主线程进行采样的ticker线程。它仅在统计上有意义(例如,如果某个函数占用了总时间的X%,则它将在大约X%的采样节拍上表示)。
当然,JavaScript应用程序可以有自己的非确定性来源:
if (Math.random() < 0.5) { foo(); } else { bar(); }
将在不同的运行中创建不同的调用序列。还可以想象,JavaScript会对鼠标移动或其他用户交互做出React,这将非常难以精确复制。