Initial project import

This commit is contained in:
Agila Forge Importer committed 2026-07-13 15:20:32 +00:00
commit 23f2d29e32
11957 files changed
+1754577

No files matched your search

@@ -0,0 +1,26 @@
// Example: Basic goroutine usage with `go` keyword.
//
// This demonstrates how V's `go` keyword launches goroutines
// using the GMP scheduler (translated from Go's runtime).
//
// `go` launches a lightweight goroutine (like Go's goroutines)
// `spawn` launches an OS thread (like V's traditional threads)
module main
import time
fn say(msg string) {
for i in 0 .. 5 {
println('${msg}: ${i}')
time.sleep(100 * time.millisecond)
}
}
fn main() {
// Launch goroutines with `go` - lightweight, Go-style concurrency
go say('goroutine 1')
go say('goroutine 2')
// Main goroutine continues running
say('main')
}
@@ -0,0 +1,119 @@
// Goroutine benchmark in Go – equivalent to goroutine_benchmark.v.
//
// Tests:
// 1. Goroutine creation + completion (fan-out/fan-in via unbuffered channel)
// 2. Channel ping-pong between two goroutines
// 3. Many goroutines contending on a single channel
//
// Run: go run goroutine_benchmark.go
package main
import (
"fmt"
"time"
)
// ---------------------------------------------------------------------------
// Benchmark 1 – fan-out / fan-in (unbuffered channel)
// ---------------------------------------------------------------------------
func benchFanOutFanIn(n int) {
c := make(chan int) // unbuffered, matching V benchmark
start := time.Now()
for i := 0; i < n; i++ {
go func() {
c <- 1
}()
}
for i := 0; i < n; i++ {
<-c
}
elapsed := time.Since(start)
fmt.Printf("fan-out/fan-in %d goroutines: %d us (%d ns/goroutine)\n",
n, elapsed.Microseconds(), elapsed.Nanoseconds()/int64(n))
}
// ---------------------------------------------------------------------------
// Benchmark 2 – channel ping-pong
// ---------------------------------------------------------------------------
func benchPingPong(n int) {
c1 := make(chan int, 1)
c2 := make(chan int, 1)
go func() {
for i := 0; i < n; i++ {
val := <-c1
c2 <- val + 1
}
}()
start := time.Now()
val := 0
for i := 0; i < n; i++ {
c1 <- val
val = <-c2
}
elapsed := time.Since(start)
fmt.Printf("ping-pong %d round-trips: %d us (%d ns/round-trip)\n",
n, elapsed.Microseconds(), elapsed.Nanoseconds()/int64(n))
}
// ---------------------------------------------------------------------------
// Benchmark 3 – contended channel (many producers, one consumer)
// ---------------------------------------------------------------------------
func benchContendedChannel(numProducers int, msgsPerProducer int) {
total := numProducers * msgsPerProducer
c := make(chan int, 64)
start := time.Now()
for p := 0; p < numProducers; p++ {
go func() {
for i := 0; i < msgsPerProducer; i++ {
c <- i
}
}()
}
for i := 0; i < total; i++ {
<-c
}
elapsed := time.Since(start)
fmt.Printf("contended chan %d producers x %d msgs: %d us (%d ns/msg)\n",
numProducers, msgsPerProducer,
elapsed.Microseconds(), elapsed.Nanoseconds()/int64(total))
}
// ---------------------------------------------------------------------------
// Main
// ---------------------------------------------------------------------------
func main() {
fmt.Println("=== Go Goroutine Benchmark ===")
fmt.Println()
benchFanOutFanIn(10)
benchFanOutFanIn(50)
benchFanOutFanIn(100)
benchFanOutFanIn(500)
fmt.Println()
benchPingPong(1000)
benchPingPong(10000)
benchPingPong(100000)
fmt.Println()
benchContendedChannel(4, 1000)
benchContendedChannel(10, 1000)
fmt.Println()
}
@@ -0,0 +1,157 @@
// Goroutine benchmark: measures scheduling and channel throughput
// of V's goroutine runtime (translated from Go's GMP scheduler).
//
// Compile: v -enable-globals -cc gcc -gc none -prod run goroutine_benchmark.v
// For comparison, see goroutine_benchmark.go.
//
// Note: Under the v1 compiler, the goroutines module uses pthreads-based
// sync.Mutex which has limitations with ucontext-based context switching.
// The v2 compiler will use a native spinlock, enabling higher scale.
module main
import goroutines
import sync
import time
__global bench_sem = sync.Semaphore{}
__global bench_n = int(0)
__global bench_chan1 = &goroutines.Chan(unsafe { nil })
__global bench_chan2 = &goroutines.Chan(unsafe { nil })
__global bench_msgs_per = int(0)
// --- fan-out/fan-in ---
fn fan_worker(arg voidptr) {
c := unsafe { &goroutines.Chan(arg) }
mut val := 1
goroutines.chan_send(c, voidptr(&val), true)
}
fn fan_collector(arg voidptr) {
c := unsafe { &goroutines.Chan(arg) }
mut recv_val := 0
for _ in 0 .. bench_n {
goroutines.chan_recv(c, voidptr(&recv_val), true)
}
bench_sem.post()
}
fn bench_fan_out_fan_in(n int) {
bench_n = n
c := goroutines.chan_make(int(sizeof(int)), 0)
sw := time.new_stopwatch()
goroutines.goroutine_create(voidptr(&fan_collector), voidptr(c), 0)
for _ in 0 .. n {
goroutines.goroutine_create(voidptr(&fan_worker), voidptr(c), 0)
}
bench_sem.wait()
elapsed := sw.elapsed()
us := elapsed.microseconds()
ns_per := elapsed.nanoseconds() / n
C.printf(c'fan-out/fan-in %d goroutines: %lld us (%lld ns/goroutine)\n', n, us, ns_per)
}
// --- ping-pong ---
fn ping_side(arg voidptr) {
mut val := 0
for _ in 0 .. bench_n {
goroutines.chan_send(bench_chan1, voidptr(&val), true)
goroutines.chan_recv(bench_chan2, voidptr(&val), true)
}
bench_sem.post()
}
fn pong_side(arg voidptr) {
mut val := 0
for _ in 0 .. bench_n {
goroutines.chan_recv(bench_chan1, voidptr(&val), true)
val++
goroutines.chan_send(bench_chan2, voidptr(&val), true)
}
}
fn bench_ping_pong(n int) {
bench_n = n
bench_chan1 = goroutines.chan_make(int(sizeof(int)), 1)
bench_chan2 = goroutines.chan_make(int(sizeof(int)), 1)
sw := time.new_stopwatch()
goroutines.goroutine_create(voidptr(&pong_side), unsafe { nil }, 0)
goroutines.goroutine_create(voidptr(&ping_side), unsafe { nil }, 0)
bench_sem.wait()
elapsed := sw.elapsed()
us := elapsed.microseconds()
ns_per := elapsed.nanoseconds() / n
C.printf(c'ping-pong %d round-trips: %lld us (%lld ns/round-trip)\n', n, us, ns_per)
}
// --- contended channel ---
fn producer(arg voidptr) {
c := unsafe { &goroutines.Chan(arg) }
mut val := 0
for _ in 0 .. bench_msgs_per {
val++
goroutines.chan_send(c, voidptr(&val), true)
}
}
fn consumer_fn(arg voidptr) {
c := unsafe { &goroutines.Chan(arg) }
mut recv_val := 0
for _ in 0 .. bench_n {
goroutines.chan_recv(c, voidptr(&recv_val), true)
}
bench_sem.post()
}
fn bench_contended_channel(num_producers int, msgs_per_producer int) {
total := num_producers * msgs_per_producer
bench_n = total
bench_msgs_per = msgs_per_producer
c := goroutines.chan_make(int(sizeof(int)), 64)
sw := time.new_stopwatch()
goroutines.goroutine_create(voidptr(&consumer_fn), voidptr(c), 0)
for _ in 0 .. num_producers {
goroutines.goroutine_create(voidptr(&producer), voidptr(c), 0)
}
bench_sem.wait()
elapsed := sw.elapsed()
us := elapsed.microseconds()
ns_per := elapsed.nanoseconds() / total
C.printf(c'contended chan %d producers x %d msgs: %lld us (%lld ns/msg)\n', num_producers,
msgs_per_producer, us, ns_per)
}
fn main() {
C.printf(c'=== V Goroutine Benchmark ===\n\n')
bench_fan_out_fan_in(10)
bench_fan_out_fan_in(50)
bench_fan_out_fan_in(100)
bench_fan_out_fan_in(500)
C.printf(c'\n')
bench_ping_pong(1000)
bench_ping_pong(10000)
bench_ping_pong(100000)
C.printf(c'\n')
bench_contended_channel(4, 1000)
bench_contended_channel(10, 1000)
C.printf(c'\n')
goroutines.shutdown()
}
@@ -0,0 +1,124 @@
// V spawn (OS threads) benchmark – for comparison with Go goroutines.
//
// Uses V's built-in `spawn` (OS threads) and `chan` (V1 channels).
// This measures V's current threading primitives vs Go's goroutines.
//
// Run: v -prod run spawn_benchmark.v
module main
import time
// ---------------------------------------------------------------------------
// Benchmark 1 – fan-out / fan-in
// ---------------------------------------------------------------------------
fn fan_worker(c chan int) {
c <- 1
}
fn bench_fan_out_fan_in(n int) {
c := chan int{cap: n}
sw := time.new_stopwatch()
for _ in 0 .. n {
spawn fan_worker(c)
}
for _ in 0 .. n {
_ = <-c
}
elapsed := sw.elapsed()
us := elapsed.microseconds()
ns_per := elapsed.nanoseconds() / n
println('fan-out/fan-in ${n} threads: ${us} us (${ns_per} ns/thread)')
}
// ---------------------------------------------------------------------------
// Benchmark 2 – channel ping-pong
// ---------------------------------------------------------------------------
fn pinger(c1 chan int, c2 chan int, n int) {
mut val := 0
for _ in 0 .. n {
val = <-c1
val++
c2 <- val
}
}
fn bench_ping_pong(n int) {
c1 := chan int{cap: 1}
c2 := chan int{cap: 1}
spawn pinger(c1, c2, n)
sw := time.new_stopwatch()
mut val := 0
for _ in 0 .. n {
c1 <- val
val = <-c2
}
elapsed := sw.elapsed()
us := elapsed.microseconds()
ns_per := elapsed.nanoseconds() / n
println('ping-pong ${n} round-trips: ${us} us (${ns_per} ns/round-trip)')
}
// ---------------------------------------------------------------------------
// Benchmark 3 – contended channel (many producers, one consumer)
// ---------------------------------------------------------------------------
fn producer(c chan int, count int) {
mut val := 0
for _ in 0 .. count {
val++
c <- val
}
}
fn bench_contended_channel(num_producers int, msgs_per_producer int) {
total := num_producers * msgs_per_producer
c := chan int{cap: 64}
sw := time.new_stopwatch()
for _ in 0 .. num_producers {
spawn producer(c, msgs_per_producer)
}
for _ in 0 .. total {
_ = <-c
}
elapsed := sw.elapsed()
us := elapsed.microseconds()
ns_per := elapsed.nanoseconds() / total
println('contended chan ${num_producers} producers x ${msgs_per_producer} msgs: ${us} us (${ns_per} ns/msg)')
}
// ---------------------------------------------------------------------------
// Main
// ---------------------------------------------------------------------------
fn main() {
println('=== V spawn (OS threads) Benchmark ===')
println('')
bench_fan_out_fan_in(1000)
bench_fan_out_fan_in(10000)
// Skip 100k - too many OS threads
println('')
bench_ping_pong(10000)
bench_ping_pong(100000)
println('')
bench_contended_channel(10, 1000)
bench_contended_channel(100, 1000)
println('')
}