If anyone's interested --
I spent a few hours this evening looking at decreasing mixxx's CPU utilization
while idle -- currently, on my machine, I have two mixxx threads hover at
around 15% cpu utilization while idle (waveform rendering on, no decks loaded,
mixxx just initialized) (this is in trunk). With the attached patch, one of
those threads drops to between 7 and 8% (~50% improvement).
What I've done:
First was to make the engine stop processing nothing. Trunk currently sends
buffers full of 0.0f's through the eq's, faders, etc. These aren't particularly
computationally expensive (as I learned in the process of all this), but they
account for a few % utilization. I solve this by giving enginebuffer a public
isPlaying method (as enginebuffer has access to the play button), and if both
buffers aren't playing I simply fill the buffers to the sound device with zeros
and jump out of the enginemaster::process method. Not filling the buffers with
zeros leads to nasty things when one pauses a deck, leaving no decks playing;
i.e. the previous samples are simply played continuously until play is clicked
again.
After this didn't do me a whole lot of good (1-2% utilization saved), I moved
on to sounddeviceportaudio::callbackProcess, which is/was a bit of a hog
according to profiling. Specifically, the QListIterator stuff seems like it
either likes allocating and copying memory, or maybe just sits and fires
NOOP... either way, according to the qt docs using qlist::at() is faster and
no more dangerous (in regards to thread safety) than using an iterator, so I
modified code to do so.
Anyway, the first bit (disabling enginemaster processing on silence) is worth
about 2% CPU utilization on idle on my machine, and the second bit is worth
about 5% CPU utilization (on idle, on my machine) -- both numbers can be +-2%.
Giant disclaimer: I don't deem this patch in any way ready or proper to go to
trunk, it may burn your house down, set your car on fire, or eat all your
vinyl. But if anyone else is interested in getting mixxx's cpu usage on idle
down (ideally to 0!), this might be something to reference in the future.
Thanks to Sean for pointing me in the right direction in regards to profiling.
Bill
=== modified file 'mixxx/src/engine/enginebuffer.cpp'
--- mixxx/src/engine/enginebuffer.cpp 2010-03-20 21:14:06 +0000
+++ mixxx/src/engine/enginebuffer.cpp 2010-05-18 06:17:41 +0000
@@ -257,6 +257,11 @@
return group;
}
+bool EngineBuffer::isPlaying() const
+{
+ return playButton->get();
+}
+
double EngineBuffer::getRate()
{
return m_pRateControl->getRawRate();
=== modified file 'mixxx/src/engine/enginebuffer.h'
--- mixxx/src/engine/enginebuffer.h 2010-01-29 05:08:12 +0000
+++ mixxx/src/engine/enginebuffer.h 2010-05-18 06:11:09 +0000
@@ -99,6 +99,7 @@
void process(const CSAMPLE *pIn, const CSAMPLE *pOut, const int iBufferSize);
const char* getGroup();
+ bool isPlaying() const;
public slots:
void slotControlPlay(double);
void slotControlStart(double);
=== modified file 'mixxx/src/engine/enginemaster.cpp'
--- mixxx/src/engine/enginemaster.cpp 2009-10-04 04:17:32 +0000
+++ mixxx/src/engine/enginemaster.cpp 2010-05-18 08:08:30 +0000
@@ -36,6 +36,7 @@
#endif
// #include "enginebuffermasterrate.h"
#include <QDebug>
+#include <cstring> // for memset
EngineMaster::EngineMaster(ConfigObject<ConfigValue> * _config,
EngineBuffer * _buffer1, EngineBuffer * _buffer2,
@@ -167,6 +168,12 @@
void EngineMaster::process(const CSAMPLE *, const CSAMPLE *pOut, const int iBufferSize)
{
CSAMPLE **pOutput = (CSAMPLE**)pOut;
+
+ if (!buffer1->isPlaying() && !buffer2->isPlaying()) {
+ memset(m_pHead, 0, sizeof(CSAMPLE) * iBufferSize);
+ memset(m_pMaster, 0, sizeof(CSAMPLE) * iBufferSize);
+ return;
+ }
//
// Process the buffer, the channels and the effects:
=== modified file 'mixxx/src/sounddeviceportaudio.cpp'
--- mixxx/src/sounddeviceportaudio.cpp 2010-03-20 20:24:27 +0000
+++ mixxx/src/sounddeviceportaudio.cpp 2010-05-18 07:34:20 +0000
@@ -361,11 +361,13 @@
//Interlace Audio data onto portaudio buffer
//We iterate through the source list to find out what goes in the buffer
//data is interlaced in the order of the list
- QListIterator<AudioSource> devItr(m_audioSources);
+ //QListIterator<AudioSource> devItr(m_audioSources);
int iChannel;
- while(devItr.hasNext())
+ //while(devItr.hasNext())
+ for (int i = 0; i < m_audioSources.length(); ++i)
{
- AudioSource src = devItr.next();
+ //const AudioSource& src = devItr.next();
+ const AudioSource& src = m_audioSources.at(i);
int iLocalFrameBase = (iFrameBase/iFrameSize) * src.channels;
for(iChannel = 0; iChannel < src.channels; iChannel++) //this will make sure a sample from each channel is copied
{
------------------------------------------------------------------------------
_______________________________________________
Mixxx-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/mixxx-devel