Golang Sync Mutex: Normal and Starvation Mode
victoriametrics.com
Golang Sync Mutex: Normal and Starvation Mode
1–10 of 15 posts
Re: Golang Sync Mutex: Normal and Starvation Mode
#2Re: Golang Sync Mutex: Normal and Starvation Mode
#3I have misgivings about such long spinlocks in user space. A millisecond is over a million instructions.
Re: Golang Sync Mutex: Normal and Starvation Mode
#4I have misgivings about such long spinlocks in user space. A millisecond is over a million instructions.
Does the spinlock last a millisecond? It sounds from the article that it lasts 120 cycles.
That may mean that after 1ms, the mutex becomes more fair. That seems to be a further fallback than ending spinning.
Go tends to use only one real thread per CPU, so the problems are different than they are in, say, Rust. Go is doing some CPU dispatching in user space.
Re: Golang Sync Mutex: Normal and Starvation Mode
#5Earlier quoted context omitted.
Does the spinlock last a millisecond? It sounds from the article that it lasts 120 cycles.
"Starvation mode kicks in if a goroutine fails to acquire the lock for more than 1 millisecond." That may mean that after 1ms, the mutex becomes more fair. That seems to be a further fallback than ending spinning. Go tends to use only one real thread per CPU, so the problems are different than they are in, say, Rust. Go is doing some CPU dispatching in user space.
Re: Golang Sync Mutex: Normal and Starvation Mode
#6This is untrue right? It can only protect code, not data, right?
Re: Golang Sync Mutex: Normal and Starvation Mode
#7> Mutex, or MUTual EXclusion, in Go is basically a way to make sure that only one goroutine is messing with a shared resource at a time. This resource can be a piece of code, an integer, a map, a struct, a channel, or pretty much anything. This is untrue right? It can only protect code , not data , right?
Re: Golang Sync Mutex: Normal and Starvation Mode
#8Earlier quoted context omitted.
"Starvation mode kicks in if a goroutine fails to acquire the lock for more than 1 millisecond." That may mean that after 1ms, the mutex becomes more fair. That seems to be a further fallback than ending spinning. Go tends to use only one real thread per CPU, so the problems are different than they are in, say, Rust. Go is doing some CPU dispatching in user space.
Indeed, starvation mode is just a way to ensure fairness, at the cost of surrendering control and being woken up later. Mutexes can be costly when there is a lot of competition, it is up to us to use it correctly
I've hit something like this in Wine's storage allocator. Wine has its own "malloc", not the Microsoft one. It has three nested locks, and the innermost one is a raw spinlock. When a buffer is resized ("realloc"), and a new buffer has to be allocated, the copying is done inside a spinlock. If you have enough threads doing realloc calls (think "push") the whole thing goes into futex congestion collapse and performance drops by two orders of magnitude.
A spinlock in user space is an optimistic assumption. It's an assumption that the wait will be very short. It's important to have something tracking whether that assumption is working. At some load level, it's time to do an actual lock and give up control to another thread. "Starvation mode" may be intended to do that. But it seems more oriented towards preventing infinite overtaking.
Can you push Go's mutexes into futex congestion?
Re: Golang Sync Mutex: Normal and Starvation Mode
#9> Mutex, or MUTual EXclusion, in Go is basically a way to make sure that only one goroutine is messing with a shared resource at a time. This resource can be a piece of code, an integer, a map, a struct, a channel, or pretty much anything. This is untrue right? It can only protect code , not data , right?
Do traffic lights protect the flow of traffic, or do they protect people? It seems reductive to fixate on traffic lights stopping intersecting flows of traffic, when the intent is to ultimately protect people from slamming into (and thus injuring/killing) each other. It may be a tempting counterpoint that traffic lights don't do anything to protect someone from cancer, heart attack, etc -- but that's simply out of the scope of the protection that traffic lights are intended to provide.
Similarly, it seems odd to me to suggest that a mutex protects code -- what is it protecting that code from? How can the code be corrupted, damaged, or otherwise harmed? A mutex does prevent other non-lock-holding threads from running simultaneously, but that's all in service of protecting the data. The data is protected by imposing order on the execution of the code -- by serializing access to that data.
Controlling something isn't the same as protecting that something. A traffic light controls traffic, but it protects the people sharing the road. A mutex controls the execution of code, but it protects data.
Re: Golang Sync Mutex: Normal and Starvation Mode
#10Earlier quoted context omitted.
Indeed, starvation mode is just a way to ensure fairness, at the cost of surrendering control and being woken up later. Mutexes can be costly when there is a lot of competition, it is up to us to use it correctly
Who's "us"? In Go, the threads are a shared resource across all the code. Multiple libraries can be contending for a resource. I've hit something like this in Wine's storage allocator. Wine has its own "malloc", not the Microsoft one. It has three nested locks, and the innermost one is a raw spinlock. When a buffer is resized ("realloc"), and a new buffer has to be allocated, the copying is done inside a spinlock. If…
I think starvation mode is a pragmatic way of solving the issue: overtaking happens when the fast path assumption is wrong - but absolute fairness is not a requirement. So it’s ok. The gains of the fast path is enough to justify having that starvation mode.
I would argue that if some piece of code ends up wasting lots of time on futex calls, it suggests that this code was not designed with the right use case in mind.
Interesting comment about wine’s allocator, did not know about this