451 lines
12 KiB
Plaintext
451 lines
12 KiB
Plaintext
|
// socket_performance_fixed.wren - Fixed socket performance test
|
||
|
import "socket" for Socket, SocketInstance
|
||
|
|
||
|
foreign class Host {
|
||
|
foreign static signalDone()
|
||
|
}
|
||
|
|
||
|
class SocketPerformance {
|
||
|
static findFreePort(startPort) {
|
||
|
for (port in startPort...(startPort + 100)) {
|
||
|
var result = SocketInstance.new()
|
||
|
if (result && !result[0]) {
|
||
|
var sock = result[1]
|
||
|
var bindResult = sock.bind("127.0.0.1", port)
|
||
|
if (bindResult && !bindResult[0]) {
|
||
|
sock.close()
|
||
|
return port
|
||
|
}
|
||
|
sock.close()
|
||
|
}
|
||
|
}
|
||
|
return 0
|
||
|
}
|
||
|
|
||
|
static runEchoTest() {
|
||
|
System.print("\n=== Echo Performance Test ===")
|
||
|
|
||
|
// Find a free port
|
||
|
var port = findFreePort(25000)
|
||
|
if (port == 0) {
|
||
|
System.print("Could not find free port")
|
||
|
return
|
||
|
}
|
||
|
System.print("Using port %(port)")
|
||
|
|
||
|
// Create server
|
||
|
var serverResult = SocketInstance.new()
|
||
|
if (!serverResult || serverResult[0]) {
|
||
|
System.print("Failed to create server")
|
||
|
return
|
||
|
}
|
||
|
var serverSock = serverResult[1]
|
||
|
|
||
|
// Bind and listen
|
||
|
var bindResult = serverSock.bind("127.0.0.1", port)
|
||
|
if (bindResult[0]) {
|
||
|
System.print("Bind failed: %(bindResult[0])")
|
||
|
serverSock.close()
|
||
|
return
|
||
|
}
|
||
|
|
||
|
var listenResult = serverSock.listen(10)
|
||
|
if (listenResult[0]) {
|
||
|
System.print("Listen failed: %(listenResult[0])")
|
||
|
serverSock.close()
|
||
|
return
|
||
|
}
|
||
|
|
||
|
var messageCount = 1000
|
||
|
var messageSize = 100
|
||
|
var message = "X" * messageSize
|
||
|
|
||
|
var serverDone = false
|
||
|
var serverMessages = 0
|
||
|
var serverBytes = 0
|
||
|
|
||
|
// Server fiber
|
||
|
var serverFiber = Fiber.new {
|
||
|
var acceptResult = serverSock.accept()
|
||
|
if (!acceptResult[0] && acceptResult[1]) {
|
||
|
var clientSock = SocketInstance.fromFd(acceptResult[1])
|
||
|
|
||
|
while (serverMessages < messageCount) {
|
||
|
var readResult = clientSock.read(4096)
|
||
|
if (!readResult[0] && readResult[1] && readResult[1].count > 0) {
|
||
|
serverBytes = serverBytes + readResult[1].count
|
||
|
serverMessages = serverMessages + 1
|
||
|
|
||
|
// Echo back
|
||
|
clientSock.write(readResult[1])
|
||
|
}
|
||
|
|
||
|
if (serverMessages % 10 == 0) {
|
||
|
Fiber.yield()
|
||
|
}
|
||
|
}
|
||
|
|
||
|
clientSock.close()
|
||
|
}
|
||
|
serverDone = true
|
||
|
}
|
||
|
|
||
|
var clientDone = false
|
||
|
var clientMessages = 0
|
||
|
var clientBytes = 0
|
||
|
|
||
|
// Client fiber
|
||
|
var clientFiber = Fiber.new {
|
||
|
// Let server start
|
||
|
for (i in 1..10) Fiber.yield()
|
||
|
|
||
|
var connectResult = SocketInstance.connect("127.0.0.1", port)
|
||
|
if (connectResult[0]) {
|
||
|
System.print("Connect failed: %(connectResult[0])")
|
||
|
clientDone = true
|
||
|
return
|
||
|
}
|
||
|
var clientSock = connectResult[1]
|
||
|
|
||
|
var startTime = System.clock
|
||
|
|
||
|
// Send messages and read echoes
|
||
|
for (i in 1..messageCount) {
|
||
|
var writeErr = clientSock.write(message)
|
||
|
if (!writeErr) {
|
||
|
clientMessages = clientMessages + 1
|
||
|
|
||
|
// Read echo (with timeout)
|
||
|
var gotEcho = false
|
||
|
for (attempt in 1..50) {
|
||
|
var readResult = clientSock.read(4096)
|
||
|
if (!readResult[0] && readResult[1] && readResult[1].count > 0) {
|
||
|
clientBytes = clientBytes + readResult[1].count
|
||
|
gotEcho = true
|
||
|
break
|
||
|
}
|
||
|
if (attempt % 10 == 0) Fiber.yield()
|
||
|
}
|
||
|
|
||
|
if (!gotEcho && i > 10) {
|
||
|
System.print("No echo received for message %(i)")
|
||
|
break
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (i % 10 == 0) Fiber.yield()
|
||
|
}
|
||
|
|
||
|
var elapsed = System.clock - startTime
|
||
|
|
||
|
System.print("\nClient Statistics:")
|
||
|
System.print(" Messages sent: %(clientMessages)")
|
||
|
System.print(" Bytes received: %(clientBytes)")
|
||
|
System.print(" Time: %(elapsed)s")
|
||
|
System.print(" Throughput: %(clientMessages/elapsed) msgs/sec")
|
||
|
System.print(" Bandwidth: %((clientBytes/elapsed/1024).floor) KB/sec")
|
||
|
|
||
|
clientSock.close()
|
||
|
clientDone = true
|
||
|
}
|
||
|
|
||
|
// Run both fibers
|
||
|
serverFiber.call()
|
||
|
clientFiber.call()
|
||
|
|
||
|
var iterations = 0
|
||
|
var maxIterations = 10000
|
||
|
while ((!serverDone || !clientDone) && iterations < maxIterations) {
|
||
|
if (!serverDone) serverFiber.call()
|
||
|
if (!clientDone) clientFiber.call()
|
||
|
iterations = iterations + 1
|
||
|
Fiber.yield()
|
||
|
}
|
||
|
|
||
|
System.print("\nServer Statistics:")
|
||
|
System.print(" Messages echoed: %(serverMessages)")
|
||
|
System.print(" Bytes processed: %(serverBytes)")
|
||
|
System.print(" Event loop iterations: %(iterations)")
|
||
|
|
||
|
serverSock.close()
|
||
|
}
|
||
|
|
||
|
static runConcurrentTest() {
|
||
|
System.print("\n=== Concurrent Connections Test ===")
|
||
|
|
||
|
var port = findFreePort(26000)
|
||
|
if (port == 0) {
|
||
|
System.print("Could not find free port")
|
||
|
return
|
||
|
}
|
||
|
System.print("Using port %(port)")
|
||
|
|
||
|
var serverResult = SocketInstance.new()
|
||
|
if (!serverResult || serverResult[0]) return
|
||
|
var serverSock = serverResult[1]
|
||
|
|
||
|
serverSock.bind("127.0.0.1", port)
|
||
|
serverSock.listen(50)
|
||
|
|
||
|
var connectionCount = 20
|
||
|
var connectionsAccepted = 0
|
||
|
var messagesSent = 0
|
||
|
|
||
|
// Server fiber - handles all connections
|
||
|
var serverDone = false
|
||
|
var serverFiber = Fiber.new {
|
||
|
var handlers = []
|
||
|
var attempts = 0
|
||
|
|
||
|
while (connectionsAccepted < connectionCount && attempts < 2000) {
|
||
|
var acceptResult = serverSock.accept()
|
||
|
if (!acceptResult[0] && acceptResult[1]) {
|
||
|
connectionsAccepted = connectionsAccepted + 1
|
||
|
var clientSock = SocketInstance.fromFd(acceptResult[1])
|
||
|
|
||
|
// Handler for this connection
|
||
|
var handler = Fiber.new {
|
||
|
var msg = "Hello from server to connection %(connectionsAccepted)!"
|
||
|
clientSock.write(msg)
|
||
|
messagesSent = messagesSent + 1
|
||
|
|
||
|
// Read client response
|
||
|
for (i in 1..20) {
|
||
|
var readResult = clientSock.read(256)
|
||
|
if (!readResult[0] && readResult[1] && readResult[1].count > 0) {
|
||
|
break
|
||
|
}
|
||
|
Fiber.yield()
|
||
|
}
|
||
|
|
||
|
clientSock.close()
|
||
|
}
|
||
|
|
||
|
handlers.add(handler)
|
||
|
handler.call()
|
||
|
}
|
||
|
|
||
|
// Process active handlers
|
||
|
var active = []
|
||
|
for (h in handlers) {
|
||
|
if (!h.isDone) {
|
||
|
h.call()
|
||
|
active.add(h)
|
||
|
}
|
||
|
}
|
||
|
handlers = active
|
||
|
|
||
|
attempts = attempts + 1
|
||
|
Fiber.yield()
|
||
|
}
|
||
|
|
||
|
serverDone = true
|
||
|
}
|
||
|
|
||
|
// Create client fibers
|
||
|
var clientFibers = []
|
||
|
var clientsConnected = 0
|
||
|
var messagesReceived = 0
|
||
|
|
||
|
var startTime = System.clock
|
||
|
|
||
|
for (i in 1..connectionCount) {
|
||
|
var clientId = i
|
||
|
var clientFiber = Fiber.new {
|
||
|
// Stagger connections slightly
|
||
|
for (j in 1..clientId) Fiber.yield()
|
||
|
|
||
|
var connectResult = SocketInstance.connect("127.0.0.1", port)
|
||
|
if (!connectResult[0]) {
|
||
|
clientsConnected = clientsConnected + 1
|
||
|
var sock = connectResult[1]
|
||
|
|
||
|
// Read server message
|
||
|
for (attempt in 1..50) {
|
||
|
var readResult = sock.read(256)
|
||
|
if (!readResult[0] && readResult[1] && readResult[1].count > 0) {
|
||
|
messagesReceived = messagesReceived + 1
|
||
|
// Send response
|
||
|
sock.write("Client %(clientId) received: %(readResult[1])")
|
||
|
break
|
||
|
}
|
||
|
Fiber.yield()
|
||
|
}
|
||
|
|
||
|
sock.close()
|
||
|
}
|
||
|
}
|
||
|
clientFibers.add(clientFiber)
|
||
|
}
|
||
|
|
||
|
// Start all fibers
|
||
|
serverFiber.call()
|
||
|
for (cf in clientFibers) cf.call()
|
||
|
|
||
|
// Run event loop
|
||
|
var iterations = 0
|
||
|
while (iterations < 5000) {
|
||
|
if (!serverDone) serverFiber.call()
|
||
|
|
||
|
var active = []
|
||
|
for (cf in clientFibers) {
|
||
|
if (!cf.isDone) {
|
||
|
cf.call()
|
||
|
active.add(cf)
|
||
|
}
|
||
|
}
|
||
|
clientFibers = active
|
||
|
|
||
|
if (serverDone && clientFibers.count == 0) break
|
||
|
|
||
|
iterations = iterations + 1
|
||
|
Fiber.yield()
|
||
|
}
|
||
|
|
||
|
var elapsed = System.clock - startTime
|
||
|
|
||
|
System.print("\nResults:")
|
||
|
System.print(" Connections attempted: %(connectionCount)")
|
||
|
System.print(" Clients connected: %(clientsConnected)")
|
||
|
System.print(" Connections accepted: %(connectionsAccepted)")
|
||
|
System.print(" Messages sent by server: %(messagesSent)")
|
||
|
System.print(" Messages received by clients: %(messagesReceived)")
|
||
|
System.print(" Time: %(elapsed)s")
|
||
|
System.print(" Connection rate: %(clientsConnected/elapsed) conn/sec")
|
||
|
System.print(" Event loop iterations: %(iterations)")
|
||
|
|
||
|
serverSock.close()
|
||
|
}
|
||
|
|
||
|
static runLatencyTest() {
|
||
|
System.print("\n=== Latency Test (ping-pong) ===")
|
||
|
|
||
|
var port = findFreePort(27000)
|
||
|
if (port == 0) return
|
||
|
|
||
|
var serverResult = SocketInstance.new()
|
||
|
if (!serverResult || serverResult[0]) return
|
||
|
var serverSock = serverResult[1]
|
||
|
|
||
|
serverSock.bind("127.0.0.1", port)
|
||
|
serverSock.listen(1)
|
||
|
|
||
|
var pingCount = 100
|
||
|
var serverDone = false
|
||
|
|
||
|
// Server: respond to pings with pongs
|
||
|
var serverFiber = Fiber.new {
|
||
|
var acceptResult = serverSock.accept()
|
||
|
if (!acceptResult[0] && acceptResult[1]) {
|
||
|
var clientSock = SocketInstance.fromFd(acceptResult[1])
|
||
|
|
||
|
for (i in 1..pingCount) {
|
||
|
// Wait for ping
|
||
|
var gotPing = false
|
||
|
for (attempt in 1..100) {
|
||
|
var readResult = clientSock.read(256)
|
||
|
if (!readResult[0] && readResult[1] && readResult[1].count > 0) {
|
||
|
// Send pong immediately
|
||
|
clientSock.write("pong")
|
||
|
gotPing = true
|
||
|
break
|
||
|
}
|
||
|
Fiber.yield()
|
||
|
}
|
||
|
if (!gotPing) break
|
||
|
}
|
||
|
|
||
|
clientSock.close()
|
||
|
}
|
||
|
serverDone = true
|
||
|
}
|
||
|
|
||
|
var clientDone = false
|
||
|
var latencies = []
|
||
|
|
||
|
// Client: send pings and measure round-trip time
|
||
|
var clientFiber = Fiber.new {
|
||
|
for (i in 1..10) Fiber.yield()
|
||
|
|
||
|
var connectResult = SocketInstance.connect("127.0.0.1", port)
|
||
|
if (connectResult[0]) {
|
||
|
clientDone = true
|
||
|
return
|
||
|
}
|
||
|
var clientSock = connectResult[1]
|
||
|
|
||
|
for (i in 1..pingCount) {
|
||
|
var pingStart = System.clock
|
||
|
|
||
|
// Send ping
|
||
|
clientSock.write("ping")
|
||
|
|
||
|
// Wait for pong
|
||
|
var gotPong = false
|
||
|
for (attempt in 1..100) {
|
||
|
var readResult = clientSock.read(256)
|
||
|
if (!readResult[0] && readResult[1] && readResult[1].count > 0) {
|
||
|
var latency = (System.clock - pingStart) * 1000 // Convert to ms
|
||
|
latencies.add(latency)
|
||
|
gotPong = true
|
||
|
break
|
||
|
}
|
||
|
Fiber.yield()
|
||
|
}
|
||
|
|
||
|
if (!gotPong) break
|
||
|
}
|
||
|
|
||
|
clientSock.close()
|
||
|
clientDone = true
|
||
|
}
|
||
|
|
||
|
// Run test
|
||
|
serverFiber.call()
|
||
|
clientFiber.call()
|
||
|
|
||
|
while (!serverDone || !clientDone) {
|
||
|
if (!serverDone) serverFiber.call()
|
||
|
if (!clientDone) clientFiber.call()
|
||
|
Fiber.yield()
|
||
|
}
|
||
|
|
||
|
// Calculate statistics
|
||
|
if (latencies.count > 0) {
|
||
|
var sum = 0
|
||
|
var min = latencies[0]
|
||
|
var max = latencies[0]
|
||
|
|
||
|
for (lat in latencies) {
|
||
|
sum = sum + lat
|
||
|
if (lat < min) min = lat
|
||
|
if (lat > max) max = lat
|
||
|
}
|
||
|
|
||
|
var avg = sum / latencies.count
|
||
|
|
||
|
System.print("\nLatency Statistics (%(latencies.count) samples):")
|
||
|
System.print(" Average: %(avg) ms")
|
||
|
System.print(" Min: %(min) ms")
|
||
|
System.print(" Max: %(max) ms")
|
||
|
System.print(" Ping rate: %(1000/avg) pings/sec possible")
|
||
|
}
|
||
|
|
||
|
serverSock.close()
|
||
|
}
|
||
|
}
|
||
|
|
||
|
var mainFiber = Fiber.new {
|
||
|
System.print("=== Socket Performance Test Suite ===")
|
||
|
System.print("With fiber performance: 2.6M yields/sec (0.38μs/yield)")
|
||
|
|
||
|
SocketPerformance.runEchoTest()
|
||
|
SocketPerformance.runConcurrentTest()
|
||
|
SocketPerformance.runLatencyTest()
|
||
|
|
||
|
System.print("\n=== All Tests Complete ===")
|
||
|
Host.signalDone()
|
||
|
|
||
|
while(true) { Fiber.yield() }
|
||
|
}
|