Skip to content

Commit

Permalink
Merge pull request mathquill#1025 from desmosinc/fix-selection-perf-m…
Browse files Browse the repository at this point in the history
…erge

Fix selection perf merge
  • Loading branch information
jwmerrill committed Oct 2, 2023
2 parents ca30110 + a337b54 commit 58e2143
Show file tree
Hide file tree
Showing 85 changed files with 14,906 additions and 9,388 deletions.
4 changes: 4 additions & 0 deletions .git-blame-ignore-revs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
52972ff01abab19a5861ac2364efc7471c336ae7
d0530dbba74c87bbeb02433a490c49c28c1deb9d
8546f1fd2784ef579ef951c6d3ec4c20b1b156c5
353fd24b7d01420d405377985dc5a43ea7b69498
2 changes: 2 additions & 0 deletions .gitconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[blame]
ignoreRevsFile = .git-blame-ignore-revs
1 change: 1 addition & 0 deletions .husky/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
_
8 changes: 8 additions & 0 deletions .husky/pre-commit
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"

# run prettier on staged files
npx lint-staged

# typecheck
make lint
6 changes: 6 additions & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
*.min.js
*.min.css
build
src/intro.js
src/outro.js
test/support/jquery-1.5.2.js
3 changes: 3 additions & 0 deletions .prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"singleQuote": true
}
76 changes: 45 additions & 31 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -24,36 +24,38 @@ SRC_DIR = ./src
INTRO = $(SRC_DIR)/intro.js
OUTRO = $(SRC_DIR)/outro.js

PJS_SRC = ./node_modules/pjs/src/p.js

BASE_SOURCES = \
$(PJS_SRC) \
$(SRC_DIR)/tree.js \
$(SRC_DIR)/cursor.js \
$(SRC_DIR)/controller.js \
$(SRC_DIR)/publicapi.js \
$(SRC_DIR)/services/parser.util.js \
$(SRC_DIR)/services/saneKeyboardEvents.util.js \
$(SRC_DIR)/services/aria.js \
$(SRC_DIR)/services/exportText.js \
$(SRC_DIR)/services/focusBlur.js \
$(SRC_DIR)/services/keystroke.js \
$(SRC_DIR)/services/latex.js \
$(SRC_DIR)/services/mouse.js \
$(SRC_DIR)/services/scrollHoriz.js \
$(SRC_DIR)/services/textarea.js
$(SRC_DIR)/utils.ts \
$(SRC_DIR)/services/aria.ts \
$(SRC_DIR)/tree.ts \
$(SRC_DIR)/cursor.ts \
$(SRC_DIR)/controller.ts \
$(SRC_DIR)/publicapi.ts \
$(SRC_DIR)/services/parser.util.ts \
$(SRC_DIR)/services/saneKeyboardEvents.util.ts \
$(SRC_DIR)/services/exportText.ts \
$(SRC_DIR)/services/focusBlur.ts \
$(SRC_DIR)/services/keystroke.ts \
$(SRC_DIR)/services/latex.ts \
$(SRC_DIR)/services/mouse.ts \
$(SRC_DIR)/services/scrollHoriz.ts \
$(SRC_DIR)/services/textarea.ts

SOURCES_FULL = \
$(BASE_SOURCES) \
$(SRC_DIR)/commands/math.js \
$(SRC_DIR)/commands/text.js \
$(SRC_DIR)/commands/math/*.js
$(SRC_DIR)/commands/math.ts \
$(SRC_DIR)/commands/text.ts \
$(SRC_DIR)/commands/math/advancedSymbols.ts \
$(SRC_DIR)/commands/math/basicSymbols.ts \
$(SRC_DIR)/commands/math/commands.ts \
$(SRC_DIR)/commands/math/LatexCommandInput.ts


SOURCES_BASIC = \
$(BASE_SOURCES) \
$(SRC_DIR)/commands/math.js \
$(SRC_DIR)/commands/math/basicSymbols.js \
$(SRC_DIR)/commands/math/commands.js
$(SRC_DIR)/commands/math.ts \
$(SRC_DIR)/commands/math/basicSymbols.ts \
$(SRC_DIR)/commands/math/commands.ts

CSS_DIR = $(SRC_DIR)/css
CSS_MAIN = $(CSS_DIR)/main.less
Expand Down Expand Up @@ -100,7 +102,7 @@ BUILD_DIR_EXISTS = $(BUILD_DIR)/.exists--used_by_Makefile
# -*- Build tasks -*-
#

.PHONY: all basic dev js uglify css font clean
.PHONY: all basic dev js uglify css font clean setup-gitconfig prettify-all
all: font css uglify
basic: $(UGLY_BASIC_JS) $(BASIC_CSS)
unminified_basic: $(BASIC_JS) $(BASIC_CSS)
Expand All @@ -112,19 +114,25 @@ css: $(BUILD_CSS)
font: $(FONT_TARGET)
clean:
rm -rf $(BUILD_DIR)

$(PJS_SRC): $(NODE_MODULES_INSTALLED)
# This adds an entry to your local .git/config file that looks like this:
# [include]
# path = ../.gitconfig
# that tells git to include the additional configuration specified inside the .gitconfig file that's checked in here.
setup-gitconfig:
@git config --local include.path ../.gitconfig
prettify-all:
npx prettier --write '**/*.{ts,js,css,html}'

$(BUILD_JS): $(INTRO) $(SOURCES_FULL) $(OUTRO) $(BUILD_DIR_EXISTS)
cat $^ | ./script/escape-non-ascii > $@
cat $^ | ./script/escape-non-ascii | ./script/tsc-emit-only > $@
perl -pi -e s/mq-/$(MQ_CLASS_PREFIX)mq-/g $@
perl -pi -e s/{VERSION}/v$(VERSION)/ $@

$(UGLY_JS): $(BUILD_JS) $(NODE_MODULES_INSTALLED)
$(UGLIFY) $(UGLIFY_OPTS) < $< > $@

$(BASIC_JS): $(INTRO) $(SOURCES_BASIC) $(OUTRO) $(BUILD_DIR_EXISTS)
cat $^ | ./script/escape-non-ascii > $@
cat $^ | ./script/escape-non-ascii | ./script/tsc-emit-only > $@
perl -pi -e s/mq-/$(MQ_CLASS_PREFIX)mq-/g $@
perl -pi -e s/{VERSION}/v$(VERSION)/ $@

Expand All @@ -146,7 +154,7 @@ ifdef NO_INSTALL
@echo "Skipping npm install because NO_INSTALL environment variable is set."
else
test -e $(NODE_MODULES_INSTALLED) || rm -rf ./node_modules/ # robust against previous botched npm install
NODE_ENV=development npm install
NODE_ENV=development npm ci
touch $(NODE_MODULES_INSTALLED)
endif

Expand All @@ -161,14 +169,20 @@ $(FONT_TARGET): $(FONT_SOURCE) $(BUILD_DIR_EXISTS)
#
# -*- Test tasks -*-
#
.PHONY:
lint:
npx tsc --noEmit

.PHONY: test server run-server
.PHONY: test server benchmark
server:
node script/test_server.js
test: dev $(BUILD_TEST) $(BASIC_JS) $(BASIC_CSS)
@echo
@echo "** now open test/{unit,visual}.html in your browser to run the {unit,visual} tests. **"
benchmark: dev $(BUILD_TEST) $(BASIC_JS) $(BASIC_CSS)
@echo
@echo "** now open benchmark/{render,select}.html in your browser. **"

$(BUILD_TEST): $(INTRO) $(SOURCES_FULL) $(UNIT_TESTS) $(OUTRO) $(BUILD_DIR_EXISTS)
cat $^ > $@
cat $^ | ./script/tsc-emit-only > $@
perl -pi -e s/{VERSION}/v$(VERSION)/ $@
173 changes: 173 additions & 0 deletions benchmark/render.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=624" />

<title>MathQuill Performance Test Page</title>

<link rel="stylesheet" type="text/css" href="../build/mathquill.css" />

<script src="https://cdnjs.cloudflare.com/ajax/libs/seedrandom/3.0.5/seedrandom.min.js"></script>
<script
type="text/javascript"
src="../test/support/jquery-1.5.2.js"
></script>
<script type="text/javascript">
window.onerror = function (err) {
document.querySelector('html').style.background = 'red';
};
</script>
<script type="text/javascript" src="../build/mathquill.js"></script>

<style type="text/css">
body {
font-size: 0.8em;
}
.test-case {
margin-top: 1em;
}
</style>
</head>
<body>
<div id="body">
<h1>MathQuill performance test page</h1>
<p>
This page randomly generates one or more latex expressions and times how
long it takes to mathquillify them. Query parameters:
</p>
<ul>
<li>
maxDepth: max depth of randomly generated latex expressions (default:
6)
</li>
<li>
maxLength: (approximate) max length of randomly generated latex
expressions (default: 2048)
</li>
<li>samples: the number of expressions to generate (default: 1)</li>
<li>
seed: random seed (to generate same expressions across page loads)
</li>
</ul>

<textarea></textarea>
<button id="run-button">Run with custom latex</button>
<div id="results"></div>
<h3>All MQ render times:</h3>
<input id="all-results" type="text" />
</div>

<script type="text/javascript">
const MQ = MathQuill.getInterface(MathQuill.getInterface.MAX);
const params = new URLSearchParams(window.location.search);
if (!params.has('seed')) {
params.append('seed', Math.random().toString(16).slice(2, 10));
window.location.href = window.location.href + '?' + params.toString();
}
const MAX_DEPTH = params.get('maxDepth') || 6;
const MAX_LENGTH = params.get('maxLength') || 2048;
const NUM_SAMPLES = params.has('samples')
? parseInt(params.get('samples'))
: 1;
const random = new Math.seedrandom(params.get('seed'));

window.results = [];
for (let i = 0; i < NUM_SAMPLES; i++) {
const latex = randomLatex();
run(latex);
}
printResults();

document
.querySelector('#run-button')
.addEventListener('click', async () => {
run(document.querySelector('textarea').value);
printResults();
});

function run(latex) {
const div = document.createElement('div');
div.classList.add('test-case');
div.innerHTML = `
<div class="test-case-render">
<div><span class="mathquill-math-field"></span></div>
<div><span class="html-only mq-math-mode"></span></div>
</div>
<div class="mq-result"></div>
<div class="html-result"></div>
`;
document.querySelector('#results').appendChild(div);

const mqElement = div.querySelector('.mathquill-math-field');
const htmlElement = div.querySelector('.html-only');

mqElement.innerText = latex;

let start = performance.now();
MQ.MathField(mqElement);
// Force syncronous layout
document.body.getBoundingClientRect();
const mqDuration = performance.now() - start;

const html = mqElement.innerHTML;
start = performance.now();
htmlElement.innerHTML = html;
// Force syncronous layout
document.body.getBoundingClientRect();
const htmlDuration = performance.now() - start;
results.push({ latex, mqDuration, htmlDuration });

div.querySelector('.mq-result').innerText = `MQ: ${mqDuration.toFixed(
2
)} ms`;
div.querySelector(
'.html-result'
).innerText = `HTML: ${htmlDuration.toFixed(2)} ms`;
}

function printResults() {
document.querySelector('#all-results').value = `[${results
.map((r) => r.mqDuration.toFixed(2))
.join(',')}]`;
}

function randomLatex(depth = MAX_DEPTH) {
if (depth <= 0) {
return randomInteger(randomInteger(1));
}

const randomLatexTemplates = [
[(a, b) => `\\frac{${a}}{${b}}`, 2],
[(a, b) => `${a}+${b}`, 2],
[(a) => `\\sqrt{${a}}`, 1],
[(a, b) => `${a}^{${b}}`, 2],
[(a, b) => `${a}_{${b}}`, 2],
[(...args) => `\\left[${args.join(',')}\\right]`, -1],
[(a) => `\\left(${a}\\right)`, 1],
];

let [fn, arity] =
randomLatexTemplates[
Math.floor(random() * randomLatexTemplates.length)
];
const args = [];
if (arity < 0) {
arity = randomInteger(2);
}
let length = 0;
for (let i = 0; i < arity; i++) {
const arg = randomLatex(depth - 1);
length += arg.length;
if (length + arg.length > MAX_LENGTH) break;
args.push(arg);
}
return fn(...args);
}

function randomInteger(maxDigits) {
return Math.floor(random() * Math.pow(10, maxDigits));
}
</script>
</body>
</html>
Loading

0 comments on commit 58e2143

Please sign in to comment.