Skip to content

Commit ebb97a6

Browse files
authored
perf: don't use tracing overeager during dev (#17183)
* perf: don't use tracing overeager during dev #17176 is a case where many sources are created and then written to (due to Svelte 4 prop mechanics), and our tracing kicked in eagerly. That combined with the excessive depth of the related stack traces slowed things down tremendously. The fix is simple: Don't record stack traces until we've seen this source get updated for a couple of times. Additionally we now delete the `updates` map after a flush. Previously it was just an ever-growing stack trace map. * fix * fix
1 parent 3b4b0ad commit ebb97a6

File tree

6 files changed

+48
-13
lines changed

6 files changed

+48
-13
lines changed

.changeset/salty-hounds-worry.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'svelte': patch
3+
---
4+
5+
perf: don't use tracing overeager during dev

packages/svelte/src/compiler/phases/types.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ export interface Analysis {
5353
/** @deprecated use `runes` from `state.js` instead */
5454
runes: boolean;
5555
immutable: boolean;
56+
/** True if `$inspect.trace` is used */
5657
tracing: boolean;
5758
comments: AST.JSComment[];
5859

packages/svelte/src/internal/client/dev/tracing.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,10 @@ function log_entry(signal, entry) {
5757

5858
if (dirty && signal.updated) {
5959
for (const updated of signal.updated.values()) {
60-
// eslint-disable-next-line no-console
61-
console.log(updated.error);
60+
if (updated.error) {
61+
// eslint-disable-next-line no-console
62+
console.log(updated.error);
63+
}
6264
}
6365
}
6466

packages/svelte/src/internal/client/reactivity/batch.js

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -608,6 +608,8 @@ function flush_effects() {
608608
var was_updating_effect = is_updating_effect;
609609
is_flushing = true;
610610

611+
var source_stacks = DEV ? new Set() : null;
612+
611613
try {
612614
var flush_count = 0;
613615
set_is_updating_effect(true);
@@ -633,8 +635,10 @@ function flush_effects() {
633635
}
634636

635637
for (const update of updates.values()) {
636-
// eslint-disable-next-line no-console
637-
console.error(update.error);
638+
if (update.error) {
639+
// eslint-disable-next-line no-console
640+
console.error(update.error);
641+
}
638642
}
639643
}
640644

@@ -643,12 +647,24 @@ function flush_effects() {
643647

644648
batch.process(queued_root_effects);
645649
old_values.clear();
650+
651+
if (DEV) {
652+
for (const source of batch.current.keys()) {
653+
/** @type {Set<Source>} */ (source_stacks).add(source);
654+
}
655+
}
646656
}
647657
} finally {
648658
is_flushing = false;
649659
set_is_updating_effect(was_updating_effect);
650660

651661
last_scheduled_effect = null;
662+
663+
if (DEV) {
664+
for (const source of /** @type {Set<Source>} */ (source_stacks)) {
665+
source.updated = null;
666+
}
667+
}
652668
}
653669
}
654670

packages/svelte/src/internal/client/reactivity/sources.js

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -188,18 +188,26 @@ export function internal_set(source, value) {
188188

189189
if (DEV) {
190190
if (tracing_mode_flag || active_effect !== null) {
191-
const error = get_stack('updated at');
191+
source.updated ??= new Map();
192192

193-
if (error !== null) {
194-
source.updated ??= new Map();
195-
let entry = source.updated.get(error.stack);
193+
// For performance reasons, when not using $inspect.trace, we only start collecting stack traces
194+
// after the same source has been updated more than 5 times in the same flush cycle.
195+
const count = (source.updated.get('')?.count ?? 0) + 1;
196+
source.updated.set('', { error: /** @type {any} */ (null), count });
196197

197-
if (!entry) {
198-
entry = { error, count: 0 };
199-
source.updated.set(error.stack, entry);
200-
}
198+
if (tracing_mode_flag || count > 5) {
199+
const error = get_stack('updated at');
200+
201+
if (error !== null) {
202+
let entry = source.updated.get(error.stack);
201203

202-
entry.count++;
204+
if (!entry) {
205+
entry = { error, count: 0 };
206+
source.updated.set(error.stack, entry);
207+
}
208+
209+
entry.count++;
210+
}
203211
}
204212
}
205213

packages/svelte/src/internal/flags/index.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
1+
/** True if experimental.async=true */
12
export let async_mode_flag = false;
3+
/** True if we're not certain that we only have Svelte 5 code in the compilation */
24
export let legacy_mode_flag = false;
5+
/** True if $inspect.trace is used */
36
export let tracing_mode_flag = false;
47

58
export function enable_async_mode_flag() {

0 commit comments

Comments
 (0)