mirror of
https://github.com/overleaf/overleaf.git
synced 2024-11-07 20:31:06 -05:00
158 lines
4.2 KiB
JavaScript
158 lines
4.2 KiB
JavaScript
|
import { parser } from '../../frontend/js/features/source-editor/lezer-latex/latex.mjs'
|
||
|
|
||
|
import * as fs from 'fs'
|
||
|
import * as path from 'path'
|
||
|
import { fileURLToPath } from 'url'
|
||
|
import { TreeFragment } from '@lezer/common'
|
||
|
import minimist from 'minimist'
|
||
|
|
||
|
const argv = minimist(process.argv.slice(2))
|
||
|
const NUMBER_OF_OPS = argv.ops || 1000
|
||
|
const CSV_OUTPUT = argv.csv || false
|
||
|
|
||
|
const __dirname = path.dirname(fileURLToPath(import.meta.url))
|
||
|
|
||
|
const examplesDir = path.join(
|
||
|
__dirname,
|
||
|
'../../test/unit/src/lezer-latex/examples'
|
||
|
)
|
||
|
|
||
|
const folder = examplesDir
|
||
|
for (const file of fs.readdirSync(folder).sort()) {
|
||
|
if (!/\.tex$/.test(file)) continue
|
||
|
const name = /^[^.]*/.exec(file)[0]
|
||
|
const content = fs.readFileSync(path.join(folder, file), 'utf8')
|
||
|
runPerformanceTests(name, content)
|
||
|
}
|
||
|
|
||
|
function runPerformanceTests(name, content) {
|
||
|
const insertEnd = writeTextAt(
|
||
|
content,
|
||
|
content.length,
|
||
|
content.substring(0, NUMBER_OF_OPS)
|
||
|
)
|
||
|
const insertBeginning = writeTextAt(
|
||
|
content,
|
||
|
0,
|
||
|
content.substring(0, NUMBER_OF_OPS)
|
||
|
)
|
||
|
const insertMiddle = writeTextAt(
|
||
|
content,
|
||
|
Math.floor(content.length / 2),
|
||
|
content.substring(0, NUMBER_OF_OPS)
|
||
|
)
|
||
|
const randomDelete = randomDeletions(content, NUMBER_OF_OPS)
|
||
|
const middleDelete = deletionsFromMiddle(content, NUMBER_OF_OPS)
|
||
|
const randomInsert = randomInsertions(content, NUMBER_OF_OPS)
|
||
|
|
||
|
if (CSV_OUTPUT) {
|
||
|
console.log(
|
||
|
[
|
||
|
name,
|
||
|
insertBeginning.average,
|
||
|
insertMiddle.average,
|
||
|
insertEnd.average,
|
||
|
randomInsert.average,
|
||
|
randomDelete.average,
|
||
|
middleDelete.average,
|
||
|
content.length,
|
||
|
].join(',')
|
||
|
)
|
||
|
} else {
|
||
|
console.log({
|
||
|
name,
|
||
|
insertAtEnd: insertEnd.average,
|
||
|
insertAtBeginning: insertBeginning.average,
|
||
|
insertAtMiddle: insertMiddle.average,
|
||
|
randomDelete: randomDelete.average,
|
||
|
middleDelete: middleDelete.average,
|
||
|
randomInsert: randomInsert.average,
|
||
|
docLength: content.length,
|
||
|
})
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function timedChanges(document, changes, changeFn) {
|
||
|
let totalParseTime = 0
|
||
|
|
||
|
// Do a fresh parse to get TreeFragments
|
||
|
const initialTree = parser.parse(document)
|
||
|
let fragments = TreeFragment.addTree(initialTree)
|
||
|
let currentDoc = document
|
||
|
|
||
|
for (let i = 0; i < changes; ++i) {
|
||
|
const change = changeFn(currentDoc, i)
|
||
|
currentDoc = change.text
|
||
|
// Do a timed parse
|
||
|
const start = performance.now()
|
||
|
fragments = TreeFragment.applyChanges(fragments, [change.range])
|
||
|
const tree = parser.parse(currentDoc, fragments)
|
||
|
fragments = TreeFragment.addTree(tree, fragments)
|
||
|
const end = performance.now()
|
||
|
totalParseTime += end - start
|
||
|
}
|
||
|
return {
|
||
|
total: totalParseTime,
|
||
|
average: totalParseTime / changes,
|
||
|
ops: changes,
|
||
|
fragments: fragments.length,
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Write and parse after every character insertion
|
||
|
function writeTextAt(document, position, text) {
|
||
|
return timedChanges(document, text.length, (currentDoc, index) =>
|
||
|
insertAt(currentDoc, position + index, text[index])
|
||
|
)
|
||
|
}
|
||
|
|
||
|
function randomInsertions(document, num) {
|
||
|
return timedChanges(document, num, currentDoc =>
|
||
|
insertAt(currentDoc, Math.floor(Math.random() * currentDoc.length), 'a')
|
||
|
)
|
||
|
}
|
||
|
|
||
|
function randomDeletions(document, num) {
|
||
|
return timedChanges(document, num, currentDoc =>
|
||
|
deleteAt(currentDoc, Math.floor(Math.random() * currentDoc.length), 1)
|
||
|
)
|
||
|
}
|
||
|
|
||
|
function deletionsFromMiddle(document, num) {
|
||
|
const deletionPoint = Math.floor(document.length / 2)
|
||
|
const deletions = Math.min(num, deletionPoint - 1)
|
||
|
return timedChanges(document, deletions, (currentDoc, index) =>
|
||
|
deleteAt(currentDoc, deletionPoint - index, 1)
|
||
|
)
|
||
|
}
|
||
|
|
||
|
function insertAt(document, position, text) {
|
||
|
const start = document.substring(0, position)
|
||
|
const end = document.substring(position)
|
||
|
|
||
|
return {
|
||
|
text: start + text + end,
|
||
|
range: {
|
||
|
fromA: position,
|
||
|
toA: position,
|
||
|
fromB: position,
|
||
|
toB: position + text.length,
|
||
|
},
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function deleteAt(document, position, length = 1) {
|
||
|
const start = document.substring(0, position)
|
||
|
const end = document.substring(position + length)
|
||
|
|
||
|
return {
|
||
|
text: start + end,
|
||
|
range: {
|
||
|
fromA: position,
|
||
|
toA: position + length,
|
||
|
fromB: position,
|
||
|
toB: position,
|
||
|
},
|
||
|
}
|
||
|
}
|