| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163 |
- import { parser } from '../../frontend/js/features/source-editor/lezer-latex/latex.mjs'
- import * as fs from 'node:fs'
- import * as path from 'node:path'
- import { fileURLToPath } from 'node:url'
- import { TreeFragment } from '@lezer/common'
- import minimist from 'minimist'
- import { seed, random } from './random.mjs'
- const argv = minimist(process.argv.slice(2))
- const NUMBER_OF_OPS = argv.ops || 1000
- const CSV_OUTPUT = argv.csv || false
- const SEED = argv.seed
- if (SEED) {
- seed(SEED)
- }
- const __dirname = path.dirname(fileURLToPath(import.meta.url))
- const examplesDir = path.join(
- __dirname,
- '../../test/unit/src/LezerLatex/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(random() * currentDoc.length), 'a')
- )
- }
- function randomDeletions(document, num) {
- return timedChanges(document, num, currentDoc =>
- deleteAt(currentDoc, Math.floor(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,
- },
- }
- }
|