Skip to content

Commit

Permalink
Added performance test for select previous scope (#2717)
Browse files Browse the repository at this point in the history
With our latest performance updates there is a clear difference in
performance between containing and relative scopes. To keep track of
this I have added relative scopes to the performance tests. I also added
a few tests for every scope.

## Checklist

- [x] I have added
[tests](https://www.cursorless.org/docs/contributing/test-case-recorder/)
- [/] I have updated the
[docs](https://github.com/cursorless-dev/cursorless/tree/main/docs) and
[cheatsheet](https://github.com/cursorless-dev/cursorless/tree/main/cursorless-talon/src/cheatsheet)
- [/] I have not broken the cheatsheet
  • Loading branch information
AndreasArvidsson authored Jan 11, 2025
1 parent d8287e6 commit 6c4c02a
Showing 1 changed file with 70 additions and 30 deletions.
100 changes: 70 additions & 30 deletions packages/cursorless-vscode-e2e/src/suite/performance.vscode.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import {
asyncSafety,
type ActionDescriptor,
type Modifier,
type ScopeType,
type SimpleScopeTypeType,
} from "@cursorless/common";
Expand All @@ -11,9 +12,10 @@ import { endToEndTestSetup } from "../endToEndTestSetup";

const testData = generateTestData(100);

const textBasedThresholdMs = 100;
const parseTreeThresholdMs = 500;
const surroundingPairThresholdMs = 500;
const smallThresholdMs = 100;
const largeThresholdMs = 500;

type ModifierType = "containing" | "previous" | "every";

suite("Performance", async function () {
endToEndTestSetup(this);
Expand All @@ -32,42 +34,56 @@ suite("Performance", async function () {

test(
"Remove token",
asyncSafety(() => removeToken(textBasedThresholdMs)),
asyncSafety(() => removeToken(smallThresholdMs)),
);

const fixtures: [SimpleScopeTypeType | ScopeType, number][] = [
const fixtures: (
| [SimpleScopeTypeType | ScopeType, number]
| [SimpleScopeTypeType | ScopeType, number, ModifierType]
)[] = [
// Text based
["character", textBasedThresholdMs],
["word", textBasedThresholdMs],
["token", textBasedThresholdMs],
["identifier", textBasedThresholdMs],
["line", textBasedThresholdMs],
["sentence", textBasedThresholdMs],
["paragraph", textBasedThresholdMs],
["document", textBasedThresholdMs],
["nonWhitespaceSequence", textBasedThresholdMs],
// Parse tree based
["string", parseTreeThresholdMs],
["map", parseTreeThresholdMs],
["collectionKey", parseTreeThresholdMs],
["value", parseTreeThresholdMs],
["character", smallThresholdMs],
["word", smallThresholdMs],
["token", smallThresholdMs],
["identifier", smallThresholdMs],
["line", smallThresholdMs],
["sentence", smallThresholdMs],
["paragraph", smallThresholdMs],
["document", smallThresholdMs],
["nonWhitespaceSequence", smallThresholdMs],
// Parse tree based, containing/every scope
["string", smallThresholdMs],
["map", smallThresholdMs],
["collectionKey", smallThresholdMs],
["value", smallThresholdMs],
["collectionKey", smallThresholdMs, "every"],
["value", smallThresholdMs, "every"],
// Parse tree based, relative scope
["collectionKey", largeThresholdMs, "previous"],
["value", largeThresholdMs, "previous"],
// Text based, but utilizes surrounding pair
["boundedParagraph", surroundingPairThresholdMs],
["boundedNonWhitespaceSequence", surroundingPairThresholdMs],
["collectionItem", surroundingPairThresholdMs],
["boundedParagraph", largeThresholdMs],
["boundedNonWhitespaceSequence", largeThresholdMs],
["collectionItem", largeThresholdMs],
// Surrounding pair
[{ type: "surroundingPair", delimiter: "any" }, surroundingPairThresholdMs],
[{ type: "surroundingPair", delimiter: "any" }, largeThresholdMs],
[{ type: "surroundingPair", delimiter: "curlyBrackets" }, largeThresholdMs],
[{ type: "surroundingPair", delimiter: "any" }, largeThresholdMs, "every"],
[
{ type: "surroundingPair", delimiter: "curlyBrackets" },
surroundingPairThresholdMs,
{ type: "surroundingPair", delimiter: "any" },
largeThresholdMs,
"previous",
],
];

for (const [scope, threshold] of fixtures) {
const [scopeType, title] = getScopeTypeAndTitle(scope);
for (const [scope, threshold, modifierType] of fixtures) {
const [scopeType, scopeTitle] = getScopeTypeAndTitle(scope);
const title = modifierType
? `${modifierType} ${scopeTitle}`
: `${scopeTitle}`;
test(
`Select ${title}`,
asyncSafety(() => selectScopeType(scopeType, threshold)),
asyncSafety(() => selectScopeType(scopeType, threshold, modifierType)),
);
}
});
Expand All @@ -82,16 +98,40 @@ async function removeToken(thresholdMs: number) {
});
}

async function selectScopeType(scopeType: ScopeType, thresholdMs: number) {
async function selectScopeType(
scopeType: ScopeType,
thresholdMs: number,
modifierType?: ModifierType,
) {
await testPerformance(thresholdMs, {
name: "setSelection",
target: {
type: "primitive",
modifiers: [{ type: "containingScope", scopeType }],
modifiers: [getModifier(scopeType, modifierType)],
},
});
}

function getModifier(
scopeType: ScopeType,
modifierType: ModifierType = "containing",
): Modifier {
switch (modifierType) {
case "containing":
return { type: "containingScope", scopeType };
case "every":
return { type: "everyScope", scopeType };
case "previous":
return {
type: "relativeScope",
direction: "backward",
offset: 1,
length: 1,
scopeType,
};
}
}

async function testPerformance(thresholdMs: number, action: ActionDescriptor) {
const editor = await openNewEditor(testData, { languageId: "json" });
// This is the position of the last json key in the document
Expand Down

0 comments on commit 6c4c02a

Please sign in to comment.