Thank you so much. 2024年5月13日月曜日 12:58:09 UTC+9 Kurtis Rader:
> On my Apple Studio system the difference in speed is barely measurable and > sometimes the bitmask implementation is faster: > > macpro ~/experiment > go run ring.go > 1000000000 ops in 5092 ms > 1000000000 ops in 5140 ms > macpro ~/experiment > go run ring.go > 1000000000 ops in 5080 ms > 1000000000 ops in 5122 ms > macpro ~/experiment > go run ring.go > 1000000000 ops in 5166 ms > 1000000000 ops in 5133 ms > > > Micro-benchmarks of this nature are notoriously sensitive to noise and > unexpected factors such as the location of code and variables in memory. > Those examples show a +0.94%, +0.83%, and -0,64% change in execution time > respectively. I would not be surprised if a huge number of runs showed the > modulo variant is consistently faster on the order of 0.5% to 1.0%. > Figuring out why will likely require examining the actual instruction > sequences being executed and a very detailed understanding of the CPU > architecture. > > P.S., the code in the Go Playground can't be run as-is and was very > different from the code in your email. If you want people to help you > should make it easier for people to test the behavior of your code. > > On Sat, May 11, 2024 at 9:58 PM leon <leonca...@gmail.com> wrote: > >> I'm trying to prove an optimization technique for ring buffer is >> effective. One of the technique is using bitmask instead of modulo to >> calculate a wrap around. However, in my environment, modulo is slightly >> faster in a test where 1 billion items are enqueued /dequeued by a single >> goroutine. What do you think could be the cause? >> >> Full code: >> https://go.dev/play/p/H933oqrhPI- >> >> Environment: >> * go version go1.21.4 darwin/arm64 >> * Apple M1 Pro >> >> RingBuffer with modulo: >> ``` >> type RingBuffer0 struct { >> writeIdx uint64 >> readIdx uint64 >> buffers []any >> size uint64 >> } >> >> func NewRingBuffer0(size uint64) *RingBuffer0 { >> rb := &RingBuffer0{} >> rb.init(size) >> return rb >> } >> >> func (rb *RingBuffer0) init(size uint64) { >> rb.buffers = make([]any, size) >> rb.size = size >> } >> >> func (rb *RingBuffer0) Enqueue(item any) error { >> if rb.writeIdx-rb.readIdx == rb.size { >> return ErrBufferFull >> } >> rb.buffers[rb.writeIdx%rb.size] = item >> rb.writeIdx++ >> return nil >> } >> >> func (rb *RingBuffer0) Dequeue() (any, error) { >> if rb.writeIdx == rb.readIdx { >> return nil, ErrBufferEmpty >> } >> item := rb.buffers[rb.readIdx%rb.size] >> rb.readIdx++ >> return item, nil >> } >> ``` >> >> RingBuffer with bitmask: >> change each module calculation to the code below >> * rb.buffers[rb.writeIdx&(rb.size-1)] = item >> * item := rb.buffers[rb.readIdx&(rb.size-1)] >> >> Test: >> func TestSingle(rb RingBuffer) { >> start := time.Now() >> total := 500000 >> for i := 0; i < total; i++ { >> for j := 0; j < 1000; j++ { >> rb.Enqueue(j) >> } >> for j := 0; j < 1000; j++ { >> rb.Dequeue() >> } >> } >> end := time.Now() >> count := total * 2000 >> duration := end.Sub(start).Milliseconds() >> fmt.Printf("%d ops in %d ms\n", count, duration) >> } >> >> -- >> You received this message because you are subscribed to the Google Groups >> "golang-nuts" group. >> To unsubscribe from this group and stop receiving emails from it, send an >> email to golang-nuts...@googlegroups.com. >> To view this discussion on the web visit >> https://groups.google.com/d/msgid/golang-nuts/b9c4d2e0-4ab4-4d27-9359-abd8c090ae33n%40googlegroups.com >> >> <https://groups.google.com/d/msgid/golang-nuts/b9c4d2e0-4ab4-4d27-9359-abd8c090ae33n%40googlegroups.com?utm_medium=email&utm_source=footer> >> . >> > > > -- > Kurtis Rader > Caretaker of the exceptional canines Junior and Hank > -- You received this message because you are subscribed to the Google Groups "golang-nuts" group. To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscr...@googlegroups.com. To view this discussion on the web visit https://groups.google.com/d/msgid/golang-nuts/4c543c1f-46eb-433e-9058-1504bf5a44een%40googlegroups.com.