mirror of
https://github.com/vlang/v.git
synced 2025-09-13 14:32:26 +03:00
cgen: move closure C code to V code under vlib/builtin/closure/ (#24912)
This commit is contained in:
parent
a08ea74167
commit
2d87ac4837
17 changed files with 719 additions and 311 deletions
278
bench/bench_closure.v
Normal file
278
bench/bench_closure.v
Normal file
|
@ -0,0 +1,278 @@
|
|||
module main
|
||||
|
||||
import time
|
||||
import sync
|
||||
import os
|
||||
import runtime
|
||||
import v.util.version
|
||||
|
||||
// Define closure type alias
|
||||
type ClosureFN = fn () int
|
||||
|
||||
// Test closures with different capture sizes
|
||||
fn create_closure_small() ClosureFN {
|
||||
a := 0
|
||||
return fn [a] () int {
|
||||
return a
|
||||
}
|
||||
}
|
||||
|
||||
fn create_closure_medium() ClosureFN {
|
||||
a, b, c, d := 1, 2, 3, 4
|
||||
return fn [a, b, c, d] () int {
|
||||
return a + b - c * d
|
||||
}
|
||||
}
|
||||
|
||||
struct LargeData {
|
||||
array [10]int
|
||||
}
|
||||
|
||||
fn create_closure_large() ClosureFN {
|
||||
data := LargeData{
|
||||
array: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]!
|
||||
}
|
||||
return fn [data] () int {
|
||||
mut sum := 0
|
||||
for i in 0 .. 10 {
|
||||
sum += data.array[i]
|
||||
}
|
||||
return sum
|
||||
}
|
||||
}
|
||||
|
||||
// Result structs
|
||||
struct TestResult {
|
||||
test_name string
|
||||
iterations int
|
||||
time_ms i64
|
||||
ops_per_sec f64 // Operations per second
|
||||
notes string
|
||||
}
|
||||
|
||||
struct MemoryResult {
|
||||
test_name string
|
||||
count int
|
||||
start_mem_kb int
|
||||
end_mem_kb int
|
||||
delta_kb int
|
||||
bytes_per_closure int
|
||||
check_sum int
|
||||
}
|
||||
|
||||
// Benchmark group - returns result structs
|
||||
fn benchmark_closure_creation(iterations int) []TestResult {
|
||||
mut results := []TestResult{}
|
||||
|
||||
// Test small closure creation
|
||||
mut start := time.ticks()
|
||||
for _ in 0 .. iterations {
|
||||
_ = create_closure_small()
|
||||
}
|
||||
small_time := time.ticks() - start
|
||||
mut ops_per_sec := f64(iterations) * 1000.0 / f64(small_time)
|
||||
results << TestResult{'Small Closure Creation', iterations, small_time, ops_per_sec, ''}
|
||||
|
||||
// Test medium closure creation
|
||||
start = time.ticks()
|
||||
for _ in 0 .. iterations {
|
||||
_ = create_closure_medium()
|
||||
}
|
||||
medium_time := time.ticks() - start
|
||||
ops_per_sec = f64(iterations) * 1000.0 / f64(medium_time)
|
||||
results << TestResult{'Medium Closure Creation', iterations, medium_time, ops_per_sec, ''}
|
||||
|
||||
// Test large closure creation
|
||||
large_iter := iterations / 10
|
||||
start = time.ticks()
|
||||
for _ in 0 .. large_iter {
|
||||
_ = create_closure_large()
|
||||
}
|
||||
large_time := time.ticks() - start
|
||||
ops_per_sec = f64(large_iter) * 1000.0 / f64(large_time)
|
||||
results << TestResult{'Large Closure Creation', large_iter, large_time, ops_per_sec, ''} //, "Equivalent iterations: ${iterations/10}"}
|
||||
return results
|
||||
}
|
||||
|
||||
fn benchmark_closure_call(iterations int) []TestResult {
|
||||
mut results := []TestResult{}
|
||||
|
||||
closure_small := create_closure_small()
|
||||
closure_medium := create_closure_medium()
|
||||
closure_large := create_closure_large()
|
||||
|
||||
// Test small closure call
|
||||
mut start := time.ticks()
|
||||
for _ in 0 .. iterations {
|
||||
_ = closure_small()
|
||||
}
|
||||
small_time := time.ticks() - start
|
||||
mut ops_per_sec := f64(iterations) * 1000.0 / f64(small_time)
|
||||
results << TestResult{'Small Closure Call', iterations, small_time, ops_per_sec, ''}
|
||||
|
||||
// Test medium closure call
|
||||
start = time.ticks()
|
||||
for _ in 0 .. iterations {
|
||||
_ = closure_medium()
|
||||
}
|
||||
medium_time := time.ticks() - start
|
||||
ops_per_sec = f64(iterations) * 1000.0 / f64(medium_time)
|
||||
results << TestResult{'Medium Closure Call', iterations, medium_time, ops_per_sec, ''}
|
||||
|
||||
// Test large closure call
|
||||
large_iter := iterations / 10
|
||||
start = time.ticks()
|
||||
for _ in 0 .. large_iter {
|
||||
_ = closure_large()
|
||||
}
|
||||
large_time := time.ticks() - start
|
||||
ops_per_sec = f64(large_iter) * 1000.0 / f64(large_time)
|
||||
results << TestResult{'Large Closure Call', large_iter, large_time, ops_per_sec, ''}
|
||||
|
||||
return results
|
||||
}
|
||||
|
||||
fn benchmark_threaded_creation(threads int, iterations_per_thread int) TestResult {
|
||||
total_iterations := threads * iterations_per_thread
|
||||
|
||||
mut wg := sync.new_waitgroup()
|
||||
wg.add(threads)
|
||||
|
||||
start := time.ticks()
|
||||
|
||||
for _ in 0 .. threads {
|
||||
go fn [mut wg, iterations_per_thread] () {
|
||||
defer { wg.done() }
|
||||
for _ in 0 .. iterations_per_thread {
|
||||
_ = create_closure_medium()
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
wg.wait()
|
||||
elapsed := time.ticks() - start
|
||||
ops_per_sec := f64(total_iterations) * 1000.0 / f64(elapsed)
|
||||
|
||||
return TestResult{
|
||||
test_name: 'Multi-threaded Creation'
|
||||
iterations: total_iterations
|
||||
time_ms: elapsed
|
||||
ops_per_sec: ops_per_sec
|
||||
notes: 'Threads: ${threads} Iterations per thread: ${iterations_per_thread}'
|
||||
}
|
||||
}
|
||||
|
||||
fn baseline_call_performance(iterations int) TestResult {
|
||||
start := time.ticks()
|
||||
for _ in 0 .. iterations {
|
||||
_ = normal_function()
|
||||
}
|
||||
elapsed := time.ticks() - start
|
||||
ops_per_sec := f64(iterations) * 1000.0 / f64(elapsed)
|
||||
|
||||
return TestResult{
|
||||
test_name: 'Normal Function Call'
|
||||
iterations: iterations
|
||||
time_ms: elapsed
|
||||
ops_per_sec: ops_per_sec
|
||||
notes: 'Baseline'
|
||||
}
|
||||
}
|
||||
|
||||
fn benchmark_memory_usage(count int) MemoryResult {
|
||||
mut closures := []ClosureFN{}
|
||||
start_mem := runtime.used_memory() or { panic(err) }
|
||||
|
||||
for i in 0 .. count {
|
||||
the_closure := create_closure_medium()
|
||||
closures << the_closure
|
||||
|
||||
if i % 1000 == 0 {
|
||||
_ = the_closure()
|
||||
}
|
||||
}
|
||||
|
||||
end_mem := runtime.used_memory() or { panic(err) }
|
||||
delta := int(end_mem) - int(start_mem)
|
||||
bytes_per_closure := delta / count
|
||||
|
||||
// Calculate verification sum
|
||||
mut check_sum := 0
|
||||
n := if closures.len < 100 { closures.len } else { 100 }
|
||||
for idx in 0 .. n {
|
||||
check_sum += closures[idx]()
|
||||
}
|
||||
|
||||
return MemoryResult{
|
||||
test_name: 'Closure Memory Overhead'
|
||||
count: count
|
||||
start_mem_kb: int(start_mem / 1024)
|
||||
end_mem_kb: int(end_mem / 1024)
|
||||
delta_kb: delta / 1024
|
||||
bytes_per_closure: bytes_per_closure
|
||||
check_sum: check_sum
|
||||
}
|
||||
}
|
||||
|
||||
fn normal_function() int {
|
||||
return 42
|
||||
}
|
||||
|
||||
// Format performance data for readability
|
||||
fn format_perf(ops_per_sec f64) string {
|
||||
if ops_per_sec >= 1_000_000 {
|
||||
return '${ops_per_sec / 1_000_000:5.2f} Mop/s'
|
||||
} else if ops_per_sec >= 1_000 {
|
||||
return '${ops_per_sec / 1_000:5.2f} Kop/s'
|
||||
} else {
|
||||
return '${ops_per_sec:5.2f} op/s'
|
||||
}
|
||||
}
|
||||
|
||||
fn print_results_table(results []TestResult, title string) {
|
||||
println('|---------------------------|------------|----------|--------------|--------------|')
|
||||
for res in results {
|
||||
perf_str := format_perf(res.ops_per_sec)
|
||||
println('| ${res.test_name:-25} | ${res.iterations:10} | ${res.time_ms:8} | ${perf_str:-12} | ${res.notes:-12} |')
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
println('# V Language Closure Performance Benchmark Report')
|
||||
|
||||
// Configurable test parameters
|
||||
base_iter := 100_000_000 // 100 million iterations
|
||||
creation_iter := 10_000_000 // 1 million iterations
|
||||
mem_count := 100_000
|
||||
threads := 8
|
||||
thread_iter := 125_000
|
||||
|
||||
// Execute tests
|
||||
baseline_result := baseline_call_performance(base_iter)
|
||||
creation_results := benchmark_closure_creation(creation_iter)
|
||||
call_results := benchmark_closure_call(base_iter)
|
||||
thread_result := benchmark_threaded_creation(threads, thread_iter)
|
||||
mem_result := benchmark_memory_usage(mem_count)
|
||||
|
||||
// Print result tables
|
||||
println('\n## 1. Closure Performance Analysis')
|
||||
println('| Test Name | Iterations | Time(ms) | Ops/sec | Notes |')
|
||||
print_results_table([baseline_result], '1. Performance Baseline')
|
||||
print_results_table(creation_results, '2. Closure Creation Performance')
|
||||
print_results_table(call_results, '3. Closure Call Performance')
|
||||
print_results_table([thread_result], '4. Multi-threaded Performance')
|
||||
|
||||
// Print memory results
|
||||
println('\n## 2. Memory Overhead Analysis')
|
||||
println('| Test Name | Closure Count | Start Mem(KB) | End Mem(KB) | Delta(KB) | Bytes/Closure |')
|
||||
println('|-------------------------|---------------|---------------|------------|-----------|---------------|')
|
||||
println('| ${mem_result.test_name:-20} | ${mem_result.count:13} | ${mem_result.start_mem_kb:13} | ${mem_result.end_mem_kb:10} | ${mem_result.delta_kb:9} | ${mem_result.bytes_per_closure:13} |')
|
||||
println('\n**Verification Sum: ${mem_result.check_sum}** (Calculated from random sample of 100 closures)')
|
||||
|
||||
println('\n## Test Environment')
|
||||
println('- V Language Version: ${version.full_v_version(false)}')
|
||||
println('- CPU Cores: ${runtime.nr_cpus()}')
|
||||
println('- System Memory: ${runtime.total_memory()! / 1024 / 1024} MB')
|
||||
println('- Operating System: ${os.user_os()}')
|
||||
println('\n> Test Time: ${time.now().format_ss_micro()}')
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue