Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

High CPU usage after speaker.Init() called #14

Open
duysqubix opened this issue Oct 10, 2023 · 5 comments
Open

High CPU usage after speaker.Init() called #14

duysqubix opened this issue Oct 10, 2023 · 5 comments
Labels
bug Something isn't working

Comments

@duysqubix
Copy link
Contributor

First of all, thanks for Beep and the excellent documentation.

I've written a doorbell in Go that listens to an MQTT channel and then plays a ding-dong noise when a button is pressed. I can deploy the code to multiple hosts on different platforms, which is the appeal of using Go for this.

My code runs as a systemd unit, starts up and initialises the sound streams using Beep's speaker package. However, I've noticed that the baseline CPU usages is pretty high - I have two wav files open and this is using ~15% CPU - even on a puny Celeron box this seems excessive. I've written some minimal code to reproduce this:

package main

import (
    "os"
    "github.com/faiface/beep"
    "github.com/faiface/beep/wav"
    "github.com/faiface/beep/speaker"    
    "time"
)

func main() {
    path := os.Args[1]

    f, _ := os.Open(path)

    streamer, format, _ := wav.Decode(f)    

    speaker.Init(format.SampleRate, format.SampleRate.N(time.Second/100))
    time.Sleep(30 * time.Second)
    done := make(chan bool)
    speaker.Play(beep.Seq(streamer, beep.Callback(func() {
        done <- true
    })))
    <-done

}

Save the snippet above as play.go and then run with go run play.go <wavfile>. During the time.Sleep (after init, but before the sound is actually played) you can see the usage in top.

I can reduce the CPU usage by reducing the sample rate in the Init call - with time.Second it was down to about 1% - but that still seems high since it should be completely idle. I also tried using buffering as per the wiki, but that didn't make any difference. Did I miss something here? I'm using go1.18.1.

Original issue: faiface/beep#159

@MarkKremer
Copy link
Contributor

As mentioned in the original issue, I expect the speaker.Init was called with an invalid sample rate. I added an item to the collection issue to improve error checking.

Feel free to re-open the issue if this wasn't the problem.

@MarkKremer MarkKremer added bug Something isn't working invalid This doesn't seem right labels Oct 10, 2023
@MarkKremer MarkKremer reopened this Jan 23, 2024
@MarkKremer MarkKremer removed the invalid This doesn't seem right label Jan 23, 2024
@MarkKremer
Copy link
Contributor

This got a new reply from the original author in the faiface/beep repo:

Sorry to comment on a closed issue and to take such a long time to get back to this: I tried this:

package main

import (
    "fmt"
    "os"
    "github.com/faiface/beep"
    "github.com/faiface/beep/wav"
    "github.com/faiface/beep/speaker"    
    "time"
)

func main() {
    path := os.Args[1]

    f, err := os.Open(path)
    if (err != nil) {
        fmt.Println(err)
    }

    streamer, format, err := wav.Decode(f)    
    if (err != nil) {
        fmt.Println(err)
    }

    fmt.Println(format.SampleRate)

    speaker.Init(format.SampleRate, format.SampleRate.N(time.Second/100))
    time.Sleep(300 * time.Second)
    done := make(chan bool)
    speaker.Play(beep.Seq(streamer, beep.Callback(func() {
        done <- true
    })))
    <-done

 }

Neither the os.Open() nor the wav.Decode() return an error. The SampleRate is reported as 44100, which seems about right. Is there anything else I can try?

@MarkKremer
Copy link
Contributor

Some things to try:

  • upgrade to the latest version of gopxl/beep. Some changes have been made to the speaker and it uses a newer version of Oto.
  • pick a bigger buffersize. 1/100th of a second is too small. 1/60th is stretching it and 1/30th is more reasonable on most systems.

Which OS are you running?

Related issue: #137

@psaffrey
Copy link

Thanks @MarkKremer and I'm glad to see that this project lives on in another repo :)

I tried updating to gopxl/beep/speaker@v1.3.0 and I also increased the buffer size to time.Second/10, as in the "Hello, Beep!" example. The CPU usage is still around 15% and the pulseaudio CPU usage is also high. I got this with top -b -n 2 -d 0.2 -p 1031,4650:

    PID USER      PR  NI    VIRT    RES    SHR S  %CPU  %MEM     TIME+ COMMAND
   4650 psaffrey  20   0 1495404  10136   6708 S  15.0   0.1   0:01.41 play_minimal
   1031 psaffrey   9 -11 2472696  28432  21640 S  10.0   0.4   0:46.68 pulseaudio

I'm running Ubuntu 22.04.

@MarkKremer
Copy link
Contributor

Could you profile this for me? See #137 (comment) but put the profiling code above your own example code that is giving you the high load and share both the profiler output and the code here.

I don't have time right now but I'll try to look into it within a couple weeks. Although from a quick look at the profile in the other issue it wasn't clear to me yet how it can be improved.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

3 participants