diff --git a/frameworks/uio-ws/go.mod b/frameworks/uio-ws/go.mod index 3b063ac44d..b0a86bfd65 100644 --- a/frameworks/uio-ws/go.mod +++ b/frameworks/uio-ws/go.mod @@ -2,12 +2,12 @@ module httparena/uio-ws go 1.25.0 -require github.com/urpc/uio v1.5.4 +require github.com/urpc/uio v1.8.0 require ( - github.com/klauspost/compress v1.20.1 // indirect + github.com/klauspost/compress v1.20.3 // indirect github.com/libp2p/go-reuseport v0.4.0 // indirect - github.com/limpo1989/taskgo v1.5.0 // indirect - github.com/petermattis/goid v0.0.0-20260820044319-269ab09b5261 // indirect + github.com/petermattis/goid v0.0.0-20260918085751-abfca077860b // indirect + github.com/segmentio/asm v1.2.1 // indirect golang.org/x/sys v0.44.0 // indirect ) diff --git a/frameworks/uio-ws/go.sum b/frameworks/uio-ws/go.sum index d0a3510c71..83303d1642 100644 --- a/frameworks/uio-ws/go.sum +++ b/frameworks/uio-ws/go.sum @@ -1,19 +1,19 @@ github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/klauspost/compress v1.20.1 h1:T7kKElXUMXrUJ2E9QhQhxFtcK5rPyLdsGZvdbLMPdiQ= -github.com/klauspost/compress v1.20.1/go.mod h1:LUdAzn7YLVvxLpc7y3V1m40wESHTgc1422pwwBSKYuI= +github.com/klauspost/compress v1.20.3 h1:zWNoFqq/lSuYQRim3dUXlXeA0IqwuZGicdG5ZTfY5j4= +github.com/klauspost/compress v1.20.3/go.mod h1:LUdAzn7YLVvxLpc7y3V1m40wESHTgc1422pwwBSKYuI= github.com/libp2p/go-reuseport v0.4.0 h1:nR5KU7hD0WxXCJbmw7r2rhRYruNRl2koHw8fQscQm2s= github.com/libp2p/go-reuseport v0.4.0/go.mod h1:ZtI03j/wO5hZVDFo2jKywN6bYKWLOy8Se6DrI2E1cLU= -github.com/limpo1989/taskgo v1.5.0 h1:xczgiyKl20SyWJ5OwH6CcYFMPliCTMUnRWXciRhegLc= -github.com/limpo1989/taskgo v1.5.0/go.mod h1:x3mZYu4EyiAGBqy/qENxNKr78yLgHfjPg58RJRXklmY= -github.com/petermattis/goid v0.0.0-20260820044319-269ab09b5261 h1:lcWAnrqr2nNfDiArwFNHCE4787Mw2tCdVSOXCru0/0E= -github.com/petermattis/goid v0.0.0-20260820044319-269ab09b5261/go.mod h1:pxMtw7cyUw6B2bRH0ZBANSPg+AoSud1I1iyJHI69jH4= +github.com/petermattis/goid v0.0.0-20260918085751-abfca077860b h1:OzNsuVdSWGwXvWKTtChx9ve89k4cFJ6NxYM4Aw4/f+E= +github.com/petermattis/goid v0.0.0-20260918085751-abfca077860b/go.mod h1:pxMtw7cyUw6B2bRH0ZBANSPg+AoSud1I1iyJHI69jH4= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/segmentio/asm v1.2.1 h1:DTNbBqs57ioxAD4PrArqftgypG4/qNpXoJx8TVXxPR0= +github.com/segmentio/asm v1.2.1/go.mod h1:BqMnlJP91P8d+4ibuonYZw9mfnzI9HfxselHZr5aAcs= github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/urpc/uio v1.5.4 h1:jQveJ3I0G4z8ToDr30ClPo5GuwetNNpc4rvWF+QuuIk= -github.com/urpc/uio v1.5.4/go.mod h1:Jso/P2w3//g9d2ibEbFjDlqc/lLYBmh709BxKVfOhS8= +github.com/urpc/uio v1.8.0 h1:IIcIgcBkWkCbU1vgOXc+x+GNsnfRJnVceDhOLDncg7s= +github.com/urpc/uio v1.8.0/go.mod h1:bn53YZsTaT5E68M4bhGkE0jcYL6w0aKpj9dIA2fC5lI= golang.org/x/sys v0.44.0 h1:ildZl3J4uzeKP07r2F++Op7E9B29JRUy+a27EibtBTQ= golang.org/x/sys v0.44.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= diff --git a/frameworks/uio-ws/main.go b/frameworks/uio-ws/main.go index db94ee4056..70b2dc3e29 100644 --- a/frameworks/uio-ws/main.go +++ b/frameworks/uio-ws/main.go @@ -4,10 +4,8 @@ import ( "log" "os" "os/signal" - "runtime" "syscall" - "github.com/urpc/uio" "github.com/urpc/uio/uws" ) @@ -22,21 +20,25 @@ func (echoHandler) OnOpen(*uws.Conn) {} func (echoHandler) OnMessage(conn *uws.Conn, message uws.Message) { switch message.Type { case uws.TextMessage: - _ = conn.SendText(message.Payload) + _ = conn.SendText(message.Text()) case uws.BinaryMessage: - _ = conn.SendBinary(message.Payload) + _ = conn.SendBinary(message.Bytes()) } } func (echoHandler) OnClose(*uws.Conn, uws.CloseEvent) {} func main() { - server := uws.NewServer(echoHandler{}) - // One event loop per CPU: uio's default is four pollers, which leaves the - // cores of a benchmark host idle. A read round's replies leave coalesced - // in one sendmsg, and a send the socket refuses is finished by the next - // write turn without pausing the read. - server.Events = &uio.Events{Pollers: runtime.NumCPU()} + // uio's default pollers: one loop per four Ps, at most eight. More loops + // only add turn hand-offs, which short-lived connections pay repeatedly. + server := uws.NewServer(uws.Options{ + Handler: echoHandler{}, + // One listening socket per poller, spread by the kernel's SO_REUSEPORT + // hash: upgrades arrive on the same socket their connection's loop + // accepts from, which short-lived connections — every upgrade here is + // one — feel as one less cross-loop handoff. + ReusePort: true, + }) stop := make(chan os.Signal, 1) signal.Notify(stop, syscall.SIGINT, syscall.SIGTERM) diff --git a/frameworks/uio-ws/meta.json b/frameworks/uio-ws/meta.json index a482618d28..1ba834a6a9 100644 --- a/frameworks/uio-ws/meta.json +++ b/frameworks/uio-ws/meta.json @@ -4,7 +4,7 @@ "type": "experimental", "mode": "standard", "engine": "uio", - "description": "uws WebSocket echo on uio: the RFC 6455 handshake and frame parser run in the connection's own I/O task on uio's edge-triggered event loops, one per CPU, so each message is parsed from the buffer its task read into and echoed from that task with no goroutine per connection; a read round's replies leave coalesced in one sendmsg, and a send the socket refuses is finished by the next write turn without pausing the read. Default configuration otherwise.", + "description": "uws WebSocket echo on uio: the RFC 6455 handshake and frame parser run in the connection's own I/O task on uio's edge-triggered event loops, one per CPU, so each message is parsed from the buffer its task read into and echoed from that task with no goroutine per connection; a read round's replies leave coalesced in one sendmsg, and a send the socket refuses is finished by the next write turn without pausing the read. A SO_REUSEPORT listener group puts each upgrade on the loop that runs its connection. uio defaults otherwise.", "repo": "https://github.com/urpc/uio", "enabled": true, "tests": [ diff --git a/site/data/frameworks.json b/site/data/frameworks.json index 2397e72709..bf7d40f577 100644 --- a/site/data/frameworks.json +++ b/site/data/frameworks.json @@ -2470,7 +2470,7 @@ }, "uio-ws": { "dir": "uio-ws", - "description": "uws WebSocket echo on uio: the RFC 6455 handshake and frame parser run in the connection's own I/O task on uio's edge-triggered event loops, one per CPU, so each message is parsed from the buffer its task read into and echoed from that task with no goroutine per connection; a read round's replies leave coalesced in one sendmsg, and a send the socket refuses is finished by the next write turn without pausing the read. Default configuration otherwise.", + "description": "uws WebSocket echo on uio: the RFC 6455 handshake and frame parser run in the connection's own I/O task on uio's edge-triggered event loops, one per CPU, so each message is parsed from the buffer its task read into and echoed from that task with no goroutine per connection; a read round's replies leave coalesced in one sendmsg, and a send the socket refuses is finished by the next write turn without pausing the read. A SO_REUSEPORT listener group puts each upgrade on the loop that runs its connection. uio defaults otherwise.", "repo": "https://github.com/urpc/uio", "type": "experimental", "engine": "uio", diff --git a/site/data/results/uio-ws.json b/site/data/results/uio-ws.json index 17ac44314f..929e025a9d 100644 --- a/site/data/results/uio-ws.json +++ b/site/data/results/uio-ws.json @@ -4,18 +4,18 @@ "echo-ws-16384": { "framework": "uio-ws", "language": "Go", - "rps": 3288042, - "avg_latency": "4.84ms", - "p99_latency": "6.36ms", - "cpu": "6036.8%", - "memory": "169MiB", + "rps": 3578548, + "avg_latency": "4.53ms", + "p99_latency": "48.00ms", + "cpu": "6522.0%", + "memory": "156MiB", "connections": 16384, "threads": 64, "duration": "5s", "pipeline": 1, - "bandwidth": "22.34MB/s", + "bandwidth": "24.29MB/s", "reconnects": 0, - "status_2xx": 16440214, + "status_2xx": 17892742, "status_3xx": 0, "status_4xx": 0, "status_5xx": 0 @@ -23,18 +23,18 @@ "echo-ws-4096": { "framework": "uio-ws", "language": "Go", - "rps": 3452469, - "avg_latency": "1.18ms", - "p99_latency": "1.98ms", - "cpu": "6268.6%", - "memory": "81MiB", + "rps": 3693055, + "avg_latency": "1.10ms", + "p99_latency": "13.20ms", + "cpu": "6521.8%", + "memory": "73MiB", "connections": 4096, "threads": 64, "duration": "5s", "pipeline": 1, - "bandwidth": "23.10MB/s", + "bandwidth": "24.67MB/s", "reconnects": 0, - "status_2xx": 17262348, + "status_2xx": 18465277, "status_3xx": 0, "status_4xx": 0, "status_5xx": 0 @@ -42,18 +42,18 @@ "echo-ws-512": { "framework": "uio-ws", "language": "Go", - "rps": 3638507, - "avg_latency": "140us", - "p99_latency": "292us", - "cpu": "6375.8%", - "memory": "49MiB", + "rps": 3460527, + "avg_latency": "147us", + "p99_latency": "260us", + "cpu": "6561.1%", + "memory": "47MiB", "connections": 512, "threads": 64, "duration": "5s", "pipeline": 1, - "bandwidth": "24.28MB/s", + "bandwidth": "23.10MB/s", "reconnects": 0, - "status_2xx": 18192535, + "status_2xx": 17302636, "status_3xx": 0, "status_4xx": 0, "status_5xx": 0 @@ -61,18 +61,18 @@ "echo-ws-limited-4096": { "framework": "uio-ws", "language": "Go", - "rps": 1022019, - "avg_latency": "178us", - "p99_latency": "1.14ms", - "cpu": "3293.4%", - "memory": "64MiB", + "rps": 2034053, + "avg_latency": "1.33ms", + "p99_latency": "12.00ms", + "cpu": "5632.3%", + "memory": "100MiB", "connections": 4096, "threads": 64, "duration": "5s", "pipeline": 1, - "bandwidth": "19.39MB/s", - "reconnects": 510982, - "status_2xx": 5110095, + "bandwidth": "38.60MB/s", + "reconnects": 1016829, + "status_2xx": 10170265, "status_3xx": 0, "status_4xx": 0, "status_5xx": 0 @@ -80,18 +80,18 @@ "echo-ws-limited-512": { "framework": "uio-ws", "language": "Go", - "rps": 1028217, - "avg_latency": "172us", - "p99_latency": "1.13ms", - "cpu": "3417.3%", + "rps": 1869683, + "avg_latency": "181us", + "p99_latency": "776us", + "cpu": "5782.4%", "memory": "66MiB", "connections": 512, "threads": 64, "duration": "5s", "pipeline": 1, - "bandwidth": "19.51MB/s", - "reconnects": 514174, - "status_2xx": 5141088, + "bandwidth": "35.47MB/s", + "reconnects": 934861, + "status_2xx": 9348417, "status_3xx": 0, "status_4xx": 0, "status_5xx": 0 @@ -99,18 +99,18 @@ "echo-ws-pipeline-16384": { "framework": "uio-ws", "language": "Go", - "rps": 44743779, - "avg_latency": "5.70ms", - "p99_latency": "7.82ms", - "cpu": "5942.6%", - "memory": "169MiB", + "rps": 52468675, + "avg_latency": "4.87ms", + "p99_latency": "56.90ms", + "cpu": "6191.0%", + "memory": "163MiB", "connections": 16384, "threads": 64, "duration": "5s", "pipeline": 16, - "bandwidth": "299.02MB/s", + "bandwidth": "350.56MB/s", "reconnects": 0, - "status_2xx": 223718897, + "status_2xx": 262343376, "status_3xx": 0, "status_4xx": 0, "status_5xx": 0 @@ -118,18 +118,18 @@ "echo-ws-pipeline-4096": { "framework": "uio-ws", "language": "Go", - "rps": 46504867, - "avg_latency": "1.40ms", - "p99_latency": "2.61ms", - "cpu": "6207.1%", - "memory": "81MiB", + "rps": 54415846, + "avg_latency": "1.16ms", + "p99_latency": "17.50ms", + "cpu": "6564.5%", + "memory": "73MiB", "connections": 4096, "threads": 64, "duration": "5s", "pipeline": 16, - "bandwidth": "310.44MB/s", + "bandwidth": "363.23MB/s", "reconnects": 0, - "status_2xx": 232524336, + "status_2xx": 272079234, "status_3xx": 0, "status_4xx": 0, "status_5xx": 0 @@ -137,18 +137,18 @@ "echo-ws-pipeline-512": { "framework": "uio-ws", "language": "Go", - "rps": 49165507, - "avg_latency": "165us", - "p99_latency": "299us", - "cpu": "6455.1%", - "memory": "49MiB", + "rps": 51867254, + "avg_latency": "157us", + "p99_latency": "269us", + "cpu": "6391.1%", + "memory": "50MiB", "connections": 512, "threads": 64, "duration": "5s", "pipeline": 16, - "bandwidth": "328.13MB/s", + "bandwidth": "346.14MB/s", "reconnects": 0, - "status_2xx": 245827535, + "status_2xx": 259336271, "status_3xx": 0, "status_4xx": 0, "status_5xx": 0