Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[perf] tags pool experiment #1521

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion packages/@glimmer/runtime/lib/environment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import type {
} from '@glimmer/interfaces';
import { RuntimeProgramImpl } from '@glimmer/program';
import { assert, expect } from '@glimmer/util';
import { track, updateTag } from '@glimmer/validator';
import { prepareTagsIfNeeded, track, updateTag } from '@glimmer/validator';

import DebugRenderTree from './debug-render-tree';
import { DOMChangesImpl, DOMTreeConstruction } from './dom/helper';
Expand Down Expand Up @@ -137,6 +137,9 @@ export class EnvironmentImpl implements Environment {
'A glimmer transaction was begun, but one already exists. You may have a nested transaction, possibly caused by an earlier runtime exception while rendering. Please check your console for the stack trace of any prior exceptions.'
);

setTimeout(() => {
prepareTagsIfNeeded();
});
this.debugRenderTree?.begin();

this[TRANSACTION] = new TransactionImpl();
Expand Down
1 change: 1 addition & 0 deletions packages/@glimmer/validator/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ export {
DIRTY_TAG as dirtyTag,
INITIAL,
isConstTag,
prepareTagsIfNeeded,
type Revision,
UPDATE_TAG as updateTag,
validateTag,
Expand Down
21 changes: 19 additions & 2 deletions packages/@glimmer/validator/lib/tracking.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@ import { debug } from './debug';
import { unwrap } from './utils';
import { combine, CONSTANT_TAG, isConstTag, validateTag, valueForTag } from './validators';

const TRACKING_WARM_STACK_SIZE = 20000;

function getTracker() {
return trackingStack.pop() ?? new Tracker();
}
/**
* An object that that tracks @tracked properties that were consumed.
*/
Expand Down Expand Up @@ -36,8 +41,16 @@ class Tracker {
return combine(Array.from(this.tags));
}
}
recycle() {
this.tags.clear();
trackingStack.push(this);
}
}

const trackingStack: Tracker[] = new Array(TRACKING_WARM_STACK_SIZE)
.fill(null)
.map(() => new Tracker());

/**
* Whenever a tracked computed property is entered, the current tracker is
* saved off and a new tracker is replaced.
Expand All @@ -58,7 +71,7 @@ const OPEN_TRACK_FRAMES: (Tracker | null)[] = [];
export function beginTrackFrame(debuggingContext?: string | false): void {
OPEN_TRACK_FRAMES.push(CURRENT_TRACKER);

CURRENT_TRACKER = new Tracker();
CURRENT_TRACKER = getTracker();

if (import.meta.env.DEV) {
unwrap(debug.beginTrackingTransaction)(debuggingContext);
Expand All @@ -78,7 +91,11 @@ export function endTrackFrame(): Tag {

CURRENT_TRACKER = OPEN_TRACK_FRAMES.pop() || null;

return unwrap(current).combine();
try {
return unwrap(current).combine();
} finally {
current!.recycle();
}
}

export function beginUntrackFrame(): void {
Expand Down
35 changes: 31 additions & 4 deletions packages/@glimmer/validator/lib/validators.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,11 @@ export const VOLATILE: Revision = NaN;

export let $REVISION = INITIAL;

const UPDATABLE_TAG_WARM_CHUNK_SIZE = 1000;
const UPDATABLE_TAG_WARM_STACK_SIZE = UPDATABLE_TAG_WARM_CHUNK_SIZE * 20;
const DIRTYABLE_TAG_WARM_CHUNK_SIZE = 1000;
const DIRTYABLE_TAG_WARM_STACK_SIZE = DIRTYABLE_TAG_WARM_CHUNK_SIZE * 20;

export function bump(): void {
$REVISION++;
}
Expand All @@ -39,8 +44,6 @@ const UPDATABLE_TAG_ID: IUPDATABLE_TAG_ID = 1;
const COMBINATOR_TAG_ID: ICOMBINATOR_TAG_ID = 2;
const CONSTANT_TAG_ID: ICONSTANT_TAG_ID = 3;

//////////

export const COMPUTE: TagComputeSymbol = Symbol('TAG_COMPUTE') as TagComputeSymbol;

//////////
Expand Down Expand Up @@ -90,6 +93,19 @@ function allowsCycles(tag: Tag): boolean {
}
}

export function prepareTagsIfNeeded() {
if (UPDATABLE_TAGS.length < UPDATABLE_TAG_WARM_CHUNK_SIZE) {
for (let i = 0; i < UPDATABLE_TAG_WARM_CHUNK_SIZE; i++) {
UPDATABLE_TAGS.push(new MonomorphicTagImpl(UPDATABLE_TAG_ID));
}
}
if (DIRYTABLE_TAGS.length < DIRTYABLE_TAG_WARM_CHUNK_SIZE) {
for (let i = 0; i < DIRTYABLE_TAG_WARM_CHUNK_SIZE; i++) {
DIRYTABLE_TAGS.push(new MonomorphicTagImpl(DIRYTABLE_TAG_ID));
}
}
}

class MonomorphicTagImpl<T extends MonomorphicTagId = MonomorphicTagId> {
static combine(this: void, tags: Tag[]): Tag {
switch (tags.length) {
Expand Down Expand Up @@ -222,17 +238,28 @@ class MonomorphicTagImpl<T extends MonomorphicTagId = MonomorphicTagId> {
}
}

//////////

const UPDATABLE_TAGS: UpdatableTag[] = new Array(UPDATABLE_TAG_WARM_STACK_SIZE)
.fill(null)
.map(() => new MonomorphicTagImpl(1 as IUPDATABLE_TAG_ID));
const DIRYTABLE_TAGS: DirtyableTag[] = new Array(DIRTYABLE_TAG_WARM_STACK_SIZE)
.fill(null)
.map(() => new MonomorphicTagImpl(0 as IDIRTYABLE_TAG_ID));

//////////

export const DIRTY_TAG = MonomorphicTagImpl.dirtyTag;
export const UPDATE_TAG = MonomorphicTagImpl.updateTag;

//////////

export function createTag(): DirtyableTag {
return new MonomorphicTagImpl(DIRYTABLE_TAG_ID);
return DIRYTABLE_TAGS.pop() ?? new MonomorphicTagImpl(DIRYTABLE_TAG_ID);
}

export function createUpdatableTag(): UpdatableTag {
return new MonomorphicTagImpl(UPDATABLE_TAG_ID);
return UPDATABLE_TAGS.pop() ?? new MonomorphicTagImpl(UPDATABLE_TAG_ID);
}

//////////
Expand Down
Loading