As a comparison, Java threads have a platform agnostic “priority”. On some platforms, you can map this priority to an OS priority via config. Without that, JNI code is used to call pthread_setschedparam()In these cases Java has one native thread per Java thread (original Java used green threads like Go).I think for go to support this, as I stated before, you need to be able to assign goroutines to “groups”, and then set the cpu mask, and thread priority for the group.
This could be done with stdlib functions, and nothing changed in the language syntax,runtime.AssignCurrentGo(group string)runtime.AssignCpuMark(group string,mask []int)
runtime.AssignCpuPriority(group string,priority int)most likely priority should be logical, with a mapping performed by the runtime. For Go’s simplicity you might be able to get away with LOW,NORMAL,HIGH,REALTIME
To unsubscribe from this group and stop receiving emails from it, send an email to golang-dev+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-dev+...@googlegroups.com.
I would expect that you could set up the following structure fairly easily:
- From a privileged C thread, invoke a cgo-exported Go function. The Go function can loop (without returning) to perform whatever real-time work is needed, using buffered channels to communicate with the rest of the program (and thereby avoid blocking the privileged thread).
- In other goroutines, perform any background work that does not need real-time scheduling (such as pre-rendering or decoding chunks of audio).
FWIW, I have done a couple of experiments with real-time audio in Go in the past. In 2013 it was possible to get acceptable latency characteristics for interactive performance on a Linux desktop machine (using the ALSA C API) without any special scheduling, provided that the main loop did not allocate. Given the GC latency improvements since then, I would be surprised if the “do not allocate” proviso is even still needed.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-dev+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-dev+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
--
You received this message because you are subscribed to the Google Groups "golang-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-dev+unsubscribe@googlegroups.com.
On 13 September 2018 at 14:53, Bryan C. Mills <bcm...@google.com> wrote:I would expect that you could set up the following structure fairly easily:
- From a privileged C thread, invoke a cgo-exported Go function. The Go function can loop (without returning) to perform whatever real-time work is needed, using buffered channels to communicate with the rest of the program (and thereby avoid blocking the privileged thread).
Yes I think that could work in the context of an OS privileged go program providing audio. However, the buffering of channels to avoid non-realtime scheduling timing of the program seems less flexible and less reliable than the group idea to me.
- In other goroutines, perform any background work that does not need real-time scheduling (such as pre-rendering or decoding chunks of audio).
FWIW, I have done a couple of experiments with real-time audio in Go in the past. In 2013 it was possible to get acceptable latency characteristics for interactive performance on a Linux desktop machine (using the ALSA C API) without any special scheduling, provided that the main loop did not allocate. Given the GC latency improvements since then, I would be surprised if the “do not allocate” proviso is even still needed.Cool! did you do duplex with ALSA? Duplex latency is much more demanding than say latency of user interface interaction. The former, such as in VoIP, is related to what we hear, which has much for fine grained timing requirements than say 30-60fps game interaction.
Scott
To unsubscribe from this group and stop receiving emails from it, send an email to golang-dev+...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
Scott
To unsubscribe from this group and stop receiving emails from it, send an email to golang-dev+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
On Thu, Sep 13, 2018 at 9:04 AM Scott Cotton <w...@iri-labs.com> wrote:On 13 September 2018 at 14:53, Bryan C. Mills <bcm...@google.com> wrote:I would expect that you could set up the following structure fairly easily:
- From a privileged C thread, invoke a cgo-exported Go function. The Go function can loop (without returning) to perform whatever real-time work is needed, using buffered channels to communicate with the rest of the program (and thereby avoid blocking the privileged thread).
Yes I think that could work in the context of an OS privileged go program providing audio. However, the buffering of channels to avoid non-realtime scheduling timing of the program seems less flexible and less reliable than the group idea to me.Buffered channels are already in the language, and already useful independent of realtime scheduling. It would be nice to see how far we can get with existing features before we propose to add new ones. 🙂
On 13 September 2018 at 15:22, Bryan C. Mills <bcm...@google.com> wrote:On Thu, Sep 13, 2018 at 9:04 AM Scott Cotton <w...@iri-labs.com> wrote:On 13 September 2018 at 14:53, Bryan C. Mills <bcm...@google.com> wrote:I would expect that you could set up the following structure fairly easily:
- From a privileged C thread, invoke a cgo-exported Go function. The Go function can loop (without returning) to perform whatever real-time work is needed, using buffered channels to communicate with the rest of the program (and thereby avoid blocking the privileged thread).
Yes I think that could work in the context of an OS privileged go program providing audio. However, the buffering of channels to avoid non-realtime scheduling timing of the program seems less flexible and less reliable than the group idea to me.Buffered channels are already in the language, and already useful independent of realtime scheduling. It would be nice to see how far we can get with existing features before we propose to add new ones. 🙂
I would be surprised it would be needed for audio as well, given the GC pause times, and also that the OS drivers are buffered.I was referring more to HPC systems and cache locality. Hard to achieve with thousands of Goroutines if you can’t group and isolate them.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-dev+unsubscribe@googlegroups.com.
One other note, if you use a Go thread/routine - it is still going to be subject to GC pauses - which can vary greatly. even with OS scheduling support.This is a completely different problem, but if it can’t be solved, the OS priority changes won’t matter.
I think for very low-latency audio, you need native threads, with no dynamic memory allocation, that communicate with the Go threads via shared memory/queue.
Or Go needs a lower pause GC, like Azul Zing, but that is proprietary.
I’m sorry but none of what you stated is true.
Unless you do no dynamic memory allocation in ANY thread, all goroutines are going to be subject to the GC pause. You can delicately share memory between Go and a native thread.
Just use an unsafe off heap allocation so the memory is not subject to GC. Go pause times are great but no where near state of the art.
I don’t think your numbers are correct. The minimum is 1 ms but the default is closer to 100 ms, but there are a lot of settings to control it.
On Sep 15, 2018, at 6:52 AM, Scott Cotton <w...@iri-labs.com> wrote:
Hi Robert,
On 15 September 2018 at 13:41, Robert Engels <ren...@ix.netcom.com> wrote:I’m sorry but none of what you stated is true.I don't find that statement constructive.
Unless you do no dynamic memory allocation in ANY thread, all goroutines are going to be subject to the GC pause. You can delicately share memory between Go and a native thread.Thus one option is to avoid dynamic memory allocation, and GC pauses are also a function of the amount of memory in the heap and the size of the pointer graph, which something the programmer can work with.
Just use an unsafe off heap allocation so the memory is not subject to GC. Go pause times are great but no where near state of the art.I'll take the recent keynote at ISSM as authoritative on this question for now.
On Sep 15, 2018, at 6:52 AM, Scott Cotton <w...@iri-labs.com> wrote:Hi Robert,On 15 September 2018 at 13:41, Robert Engels <ren...@ix.netcom.com> wrote:I’m sorry but none of what you stated is true.I don't find that statement constructive.I am not sure why. I was simply stating the statement you made were not true. Honestly, your statement is more offensive if you think about it.
i was only trying to be helpful, and I don’t appreciate being called out for stating something is untrue, and I don’t think that is productive.
On Sep 15, 2018, at 6:52 AM, Scott Cotton <w...@iri-labs.com> wrote:Hi Robert,
Unless you do no dynamic memory allocation in ANY thread, all goroutines are going to be subject to the GC pause. You can delicately share memory between Go and a native thread.Thus one option is to avoid dynamic memory allocation, and GC pauses are also a function of the amount of memory in the heap and the size of the pointer graph, which something the programmer can work with.GC pauses in Go are not based on the the heap size. The “pause” time is based on number of active threads and stack depth (coupled with the root object set). Still, if the GC is running a lot, it will starve (compete with) the CPU from the application threads making them “slower” due to scheduling, but this is not a pause.
And I said, you can allocate off heap memory to be shared with the native thread that is not subject to GC pauses, and run these threads in real time priority. This is a common technique in many Java libraries and it works in Go as well. I personally don’t use the technique because the pause time is no longer based on heap size (it was previously). It does avoid the overhead of converting “memory layout (e.g. strings)” between the sides.
Just use an unsafe off heap allocation so the memory is not subject to GC. Go pause times are great but no where near state of the art.I'll take the recent keynote at ISSM as authoritative on this question for now.I read the presentation. Go currently claims pauses times in the presentation for 2018, are 2 less than 500 us sec pauses per second. The pauses times in Azul Zing are under the 100 us for more than 1 TB of heap, and typically under 10 usec. The Azul GC often requires large heaps/head-room, 20+ GB is not uncommon, to be efficient, which is not the typically Go environment. Even the OpenJDK Shenandoah with 100+ Gb heaps have pauses less than 500 usec.So I will state it again, Go GC is very, very good, but it is not state of the art. It is close.
Most importantly though, this really has nothing to do with the requirements for real-time audio. I was attempting to explain how you could do it.
If you review https://making.pusher.com/golangs-real-time-gc-in-theory-and-practice/ you will see Go has 7 ms allocation pauses. probably too much based on what you’ve stated. I’ve run those tests on my machine using Go 1.11 and I see similar 7 ms pauses times (my Java times using standard G1 are in the 28 ms range). This is a direct link to the relevant code main.go
Yes, if you have an isolated program/service that is possible. In the context of a complex ‘midi’ player, with a GUI and lots of services - it is very hard to write GC free code - people try that in Java too and it usually leads to very subtle hard to find bugs especially in concurrent systems. The basic technique is object pool/re-use - very difficult to do error free in a concurrent environment. This is why platforms like LMAX disrupter exists, but even then, as soon as you use a char[] and incorrectly retain a reference, it will get stomped on.I believe the best solution, and it would probably work well enough is the ‘group/real-time’ enhancements I presented before, but I wouldn’t count on the timeline - thus I offered the solution you could do now.
Even if Go adopted my simple API, it is not that simple... When the goroutines/threads have varying priorities it can lead to starvation, and threads/routines not able to reach a safe point (for stack recording). So often implementations try to run all of the internal threads at a higher-priority than all user threads, but then the GC work blocks the application mutators instead of running concurrently… So there needs to be a way to temporarily boost their priority when needed… Sounds simple but there can be lots of race conditions.
I was using real-time threads in Java without JRTS (Java real-time system) very early on, maybe one of the earliest to do so, and needed to work with the Azul staff A LOT tracking down very subtle, but devastating bugs/crashes.
On Sep 15, 2018, at 4:57 PM, Scott Cotton <w...@iri-labs.com> wrote:On 15 September 2018 at 22:12, robert engels <ren...@ix.netcom.com> wrote:On Sep 15, 2018, at 6:52 AM, Scott Cotton <w...@iri-labs.com> wrote:Hi Robert,[...]Unless you do no dynamic memory allocation in ANY thread, all goroutines are going to be subject to the GC pause. You can delicately share memory between Go and a native thread.Thus one option is to avoid dynamic memory allocation, and GC pauses are also a function of the amount of memory in the heap and the size of the pointer graph, which something the programmer can work with.GC pauses in Go are not based on the the heap size. The “pause” time is based on number of active threads and stack depth (coupled with the root object set). Still, if the GC is running a lot, it will starve (compete with) the CPU from the application threads making them “slower” due to scheduling, but this is not a pause.I am not a GC expert, but my point is only the programmer has a pretty reasonable amount of control overthe work presented to the GC, especially in contexts where memory can be pre-allocated and the program has a dedicated task.And I said, you can allocate off heap memory to be shared with the native thread that is not subject to GC pauses, and run these threads in real time priority. This is a common technique in many Java libraries and it works in Go as well. I personally don’t use the technique because the pause time is no longer based on heap size (it was previously). It does avoid the overhead of converting “memory layout (e.g. strings)” between the sides.This may be worth looking at. My impression is still that the relationship between Go runtime and OS priveleged special thread scheduling is the main thing that needs to be considered. It is not clear to me that any communication between an OS priveleged special thread and a user goroutine, by sharing memory as above or otherwise addresses the scheduling problem.Just use an unsafe off heap allocation so the memory is not subject to GC. Go pause times are great but no where near state of the art.I'll take the recent keynote at ISSM as authoritative on this question for now.I read the presentation. Go currently claims pauses times in the presentation for 2018, are 2 less than 500 us sec pauses per second. The pauses times in Azul Zing are under the 100 us for more than 1 TB of heap, and typically under 10 usec. The Azul GC often requires large heaps/head-room, 20+ GB is not uncommon, to be efficient, which is not the typically Go environment. Even the OpenJDK Shenandoah with 100+ Gb heaps have pauses less than 500 usec.So I will state it again, Go GC is very, very good, but it is not state of the art. It is close.Close enough for me.Most importantly though, this really has nothing to do with the requirements for real-time audio. I was attempting to explain how you could do it.Just curious, have you done it?If you review https://making.pusher.com/golangs-real-time-gc-in-theory-and-practice/ you will see Go has 7 ms allocation pauses. probably too much based on what you’ve stated. I’ve run those tests on my machine using Go 1.11 and I see similar 7 ms pauses times (my Java times using standard G1 are in the 28 ms range). This is a direct link to the relevant code main.goI have read that some time ago, it is interesting. Thanks for bringing it up.Scott
I would think you could do that now, just start the program, on linux at least, usingchrt.The problem there are quite a few internal threads, they should inherit the priority as well since that is the default.
As at glibc 2.8, if a thread attributes object is initialized using pthread_attr_init(3), then the scheduling policy of the attributes object is set to SCHED_OTHER and the scheduling priority is set to 0. However, if the inherit-scheduler attribute is then set to PTHREAD_EXPLICIT_SCHED, then a thread created using the attribute object wrongly inherits its scheduling attributes from the creating thread. This bug does not occur if either the scheduling policy or scheduling priority attribute is explicitly set in the thread attributes object before calling pthread_create(3).
"""
I think the only way to actually do it correctly and ensure the behaviour was as desired would be to introduce calls that would make the result independent of bugs like above.
The problem is that if the internal runtime is already using priorities for the scheduler all sorts of bad things might happen.
It doesn't look to me like pthread scheduling is currently manipulated in runtime. It is however opaque because of the optimisations and trampolining around pthread function calls. my assessment is only from perusing and grepping for where it would seem such things would occur. But with all the assembly related to pthreads in runtime, I could have missed something.
If OS scheduling inheritance were under an option or environmental variable or build tag then it wouldn't in principle prevent future or other efforts to introduce OS scheduling into the runtime.
Scott
ScottSent from my iPhone
Hi Robert,
Scott Cotton
Just wanted to include the related go-nuts message from Ian for potential follow up:On Mon, Sep 17, 2018 at 10:39 AM, Scott Cotton <w...@iri-labs.com> wrote:
>
> Wanted to ask about the Go runtime use of threads. Specifically, suppose
> I've got an app in mind that would run OS-priveleged and use specially
> scheduled threads, like SCHED_RR in linux for example.
>
> One could do this with chrt or calling from a process/thread at the desired
> scheduling priority/type (as pointed out on a related thread in golang-dev)
>
> The question is: does this as of go1.11 interfere with Go runtime internal
> prioritising of threads?
> The other question is: may it one day interfere with Go runtime internal
> prioritising of threads?
Using specially scheduled threads should not be a problem if the Go
code that runs on those threads reliably calls runtime.LockOSThread.
If not, then it's hard to say.
Scott Cotton
Using specially scheduled threads should not be a problem if the Go
code that runs on those threads reliably calls runtime.LockOSThread.
If not, then it's hard to say.
I would also search “android real-time audio issues”. I know that there were problems reported there - people that created “effects software” always complained especially when compared to iOS.
As far as I know, they solved these issues - most likely by a native driver layer in the linux kernel ? - but still, Android is Java, and it didn’t even have some of the lower level bridges to C/native that Go has, so I would expect the same techniques could be applied to Go, but you probably lose cross-platform doing real-time audio anyway.I would review those problems and solutions.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-dev+unsubscribe@googlegroups.com.