Speed up screenshot by avoid a full page + asset load for each test

The slowest part of screenshotter tests is the page load, probably
because so many assets must be loaded over the slow docker
connection. On my laptop this takes ~4s per test. The new default
avoids this cost by rendering new TeX on the existing
page. For second and subsequent tests, use `executeAsyncScript`
to call KaTeX, rather than performing a full page + asset load.
(If too many errors happen in `--verify` mode, we fall back to
full loads.)  The `--reload` flag will enable the previous behavior.

On my laptop, a full verify (chrome + FF) used to take 12m20s+.
It now takes 2m23s, a speed up of 6x.
This commit is contained in:
Eddie Kohler
2017-07-04 00:13:57 -04:00
committed by Kevin Barabash
parent a019f36f8a
commit 1704d3b003
2 changed files with 63 additions and 31 deletions

View File

@@ -65,6 +65,10 @@ const opts = require("nomnom")
abbr: "x",
help: "Comma-separated list of test cases to exclude",
})
.option("reload", {
flag: true,
help: "Reload page for each test",
})
.option("verify", {
flag: true,
help: "Check whether screenshot matches current file content",
@@ -226,6 +230,7 @@ function tryConnect() {
// Build the web driver
let driver;
let driverReady = false;
function buildDriver() {
const builder = new selenium.Builder().forBrowser(opts.browser);
const ffProfile = new firefox.Profile();
@@ -372,16 +377,32 @@ function takeScreenshot(key) {
}
const url = katexURL + "test/screenshotter/test.html?" + itm.query;
driver.get(url);
if (opts.wait) {
browserSideWait(1000 * opts.wait);
driver.call(loadMath);
function loadMath() {
if (!opts.reload && driverReady) {
driver.executeAsyncScript(
"var callback = arguments[arguments.length - 1]; " +
"handle_search_string(" +
JSON.stringify("?" + itm.query) + ", callback);")
.then(waitThenScreenshot);
} else {
driver.get(url).then(waitThenScreenshot);
}
}
function waitThenScreenshot() {
driverReady = true;
if (opts.wait) {
browserSideWait(1000 * opts.wait);
}
driver.takeScreenshot().then(haveScreenshot).then(oneDone, check);
}
driver.takeScreenshot().then(haveScreenshot).then(oneDone, check);
function haveScreenshot(img) {
img = imageDimensions(img);
if (img.width !== targetW || img.height !== targetH) {
throw new Error("Excpected " + targetW + " x " + targetH +
throw new Error("Expected " + targetW + " x " + targetH +
", got " + img.width + "x" + img.height);
}
if (key === "Lap" && opts.browser === "firefox" &&
@@ -411,9 +432,11 @@ function takeScreenshot(key) {
exitStatus = 3;
} else {
console.log("error " + key);
driver.get(url);
browserSideWait(500 * retry);
return driver.takeScreenshot().then(haveScreenshot);
browserSideWait(300 * retry);
if (retry > 1) {
driverReady = false; // reload fully
}
return driver.call(loadMath);
}
} else {
console.log("* ok " + key);

View File

@@ -32,31 +32,40 @@
<span id="math"></span>
<span id="post"></span>
<script type="text/javascript">
var query = {};
var re = /(?:^\?|&)([^&=]+)(?:=([^&]+))?/g;
var match;
while (match = re.exec(window.location.search)) {
query[match[1]] = decodeURIComponent(match[2]);
}
var mathNode = document.getElementById("math");
function handle_search_string(search, callback) {
var query = {};
var re = /(?:^\?|&)([^&=]+)(?:=([^&]+))?/g;
var match;
while (match = re.exec(search)) {
query[match[1]] = decodeURIComponent(match[2]);
}
var mathNode = document.getElementById("math");
var settings = {
displayMode: !!query["display"],
throwOnError: !query["noThrow"]
};
if (query["errorColor"]) {
settings.errorColor = query["errorColor"];
}
var macros = {};
var macroRegex = /(?:^\?|&)(?:\\|%5[Cc])([A-Za-z]+)=([^&]*)/g;
while ((match = macroRegex.exec(window.location.search)) !== null) {
settings.macros = macros;
macros["\\" + match[1]] = decodeURIComponent(match[2]);
}
var settings = {
displayMode: !!query["display"],
throwOnError: !query["noThrow"]
};
if (query["errorColor"]) {
settings.errorColor = query["errorColor"];
}
var macros = {};
var macroRegex = /(?:^\?|&)(?:\\|%5[Cc])([A-Za-z]+)=([^&]*)/g;
while ((match = macroRegex.exec(search)) !== null) {
settings.macros = macros;
macros["\\" + match[1]] = decodeURIComponent(match[2]);
}
katex.render(query["tex"], mathNode, settings);
document.getElementById("pre").innerHTML = query["pre"] || "";
document.getElementById("post").innerHTML = query["post"] || "";
katex.render(query["tex"], mathNode, settings);
document.getElementById("pre").innerHTML = query["pre"] || "";
document.getElementById("post").innerHTML = query["post"] || "";
if (callback && document.fonts && document.fonts.ready) {
document.fonts.ready.then(callback);
} else if (callback) {
callback();
}
}
handle_search_string(window.location.search);
</script>
</body>
</html>