// Benchmarks for signal module comparison with experimental_signals
// Run both benchmarks and compare results
// =============================================================================
// Basic Signal Operations
// =============================================================================
///|
test "sig: signal.get (1000 reads)" (b : @bench.T) {
let sig = signal(42)
b.bench(fn() {
for i = 0; i < 1000; i = i + 1 {
let _ = sig.get()
}
})
}
///|
test "sig: signal.peek (1000 reads)" (b : @bench.T) {
let sig = signal(42)
b.bench(fn() {
for i = 0; i < 1000; i = i + 1 {
let _ = sig.peek()
}
})
}
///|
test "sig: signal.set (1000 writes, no subs)" (b : @bench.T) {
let sig = signal(0)
b.bench(fn() {
for i = 0; i < 1000; i = i + 1 {
sig.set(i)
}
})
}
// =============================================================================
// Computed (memo) Operations
// =============================================================================
///|
test "sig: memo.get (1000 reads, cached)" (b : @bench.T) {
let a = signal(1)
let b_sig = signal(2)
let sum = memo(fn() { a.get() + b_sig.get() })
// Initialize
let _ = sum()
b.bench(fn() {
for i = 0; i < 1000; i = i + 1 {
let _ = sum()
}
})
}
///|
test "sig: memo chain (depth 3, 1000 reads)" (b : @bench.T) {
let a = signal(1)
let b_memo = memo(fn() { a.get() + 1 })
let c_memo = memo(fn() { b_memo() * 2 })
let d_memo = memo(fn() { c_memo() + 10 })
// Initialize
let _ = d_memo()
b.bench(fn() {
for i = 0; i < 1000; i = i + 1 {
let _ = d_memo()
}
})
}
///|
test "sig: memo after update (1000 cycles)" (b : @bench.T) {
let a = signal(0)
let doubled = memo(fn() { a.get() * 2 })
b.bench(fn() {
for i = 0; i < 1000; i = i + 1 {
a.set(i)
let _ = doubled()
}
})
}
// =============================================================================
// Effect Operations
// =============================================================================
///|
test "sig: render_effect creation and dispose (100 cycles)" (b : @bench.T) {
b.bench(fn() {
for i = 0; i < 100; i = i + 1 {
let count = signal(0)
let dispose = render_effect(fn() {
let _ = count.get()
})
dispose()
}
})
}
///|
test "sig: render_effect with signal update (100 cycles)" (b : @bench.T) {
let count = signal(0)
let effect_runs = Ref::new(0)
let _dispose = render_effect(fn() {
let _ = count.get()
effect_runs.val = effect_runs.val + 1
})
b.bench(fn() {
for i = 0; i < 100; i = i + 1 {
count.set(i)
}
})
}
// =============================================================================
// Batch Operations (using untracked for signal module)
// =============================================================================
///|
test "sig: untracked batch-like (100 updates)" (b : @bench.T) {
let a = signal(0)
let b_sig = signal(0)
let c_sig = signal(0)
b.bench(fn() {
for i = 0; i < 100; i = i + 1 {
// signal module doesn't have batch, but we can simulate
a.set(i)
b_sig.set(i * 2)
c_sig.set(i * 3)
}
})
}
// =============================================================================
// Dependency Fan-out (1 signal -> N memos)
// =============================================================================
///|
test "sig: fan-out 10 memos (1000 reads each)" (b : @bench.T) {
let source = signal(1)
let memos : Array[() -> Int] = []
for i = 0; i < 10; i = i + 1 {
memos.push(memo(fn() { source.get() + 1 }))
}
// Initialize all
for m in memos {
let _ = m()
}
b.bench(fn() {
for j = 0; j < 1000; j = j + 1 {
for m in memos {
let _ = m()
}
}
})
}
///|
test "sig: fan-out 10 memos, source update (100 cycles)" (b : @bench.T) {
let source = signal(0)
let memos : Array[() -> Int] = []
for i = 0; i < 10; i = i + 1 {
memos.push(memo(fn() { source.get() + 1 }))
}
// Initialize all
for m in memos {
let _ = m()
}
b.bench(fn() {
for i = 0; i < 100; i = i + 1 {
source.set(i)
for m in memos {
let _ = m()
}
}
})
}
// =============================================================================
// Dependency Fan-in (N signals -> 1 memo)
// =============================================================================
///|
test "sig: fan-in 10 signals (1000 reads)" (b : @bench.T) {
let signals : Array[Signal[Int]] = []
for i = 0; i < 10; i = i + 1 {
signals.push(signal(i))
}
let sum = memo(fn() {
let mut total = 0
for s in signals {
total = total + s.get()
}
total
})
// Initialize
let _ = sum()
b.bench(fn() {
for j = 0; j < 1000; j = j + 1 {
let _ = sum()
}
})
}
///|
test "sig: fan-in 10 signals, 1 update (100 cycles)" (b : @bench.T) {
let signals : Array[Signal[Int]] = []
for i = 0; i < 10; i = i + 1 {
signals.push(signal(i))
}
let sum = memo(fn() {
let mut total = 0
for s in signals {
total = total + s.get()
}
total
})
// Initialize
let _ = sum()
b.bench(fn() {
for i = 0; i < 100; i = i + 1 {
signals[0].set(i)
let _ = sum()
}
})
}
// =============================================================================
// Memory / Subscribe/Unsubscribe test
// =============================================================================
///|
test "sig: repeated effect create/dispose (100 cycles)" (b : @bench.T) {
let source = signal(1)
b.bench(fn() {
for i = 0; i < 100; i = i + 1 {
let dispose = render_effect(fn() {
let _ = source.get()
})
dispose()
}
})
}