summaryrefslogtreecommitdiffstats
path: root/services
diff options
context:
space:
mode:
authorGlenn Kasten <gkasten@google.com>2013-07-15 14:45:07 -0700
committerGlenn Kasten <gkasten@google.com>2013-07-19 09:30:37 -0700
commit4182c4e2a07e2441fcd5c22eaff0ddfe7f826f61 (patch)
treec7ed5d9b71f919bf664dd0cb6cbdd1c3de2f9241 /services
parent0d61251648b5110bfc33ef5b3d19bbf65db0a7b5 (diff)
downloadframeworks_av-4182c4e2a07e2441fcd5c22eaff0ddfe7f826f61.zip
frameworks_av-4182c4e2a07e2441fcd5c22eaff0ddfe7f826f61.tar.gz
frameworks_av-4182c4e2a07e2441fcd5c22eaff0ddfe7f826f61.tar.bz2
Use AudioSystem::setLowRamDevice() to configure memory
Bug: 9798886 Change-Id: I9321e3f369f1ed9429ae222e3926ebdeb012b8b0
Diffstat (limited to 'services')
-rw-r--r--services/audioflinger/AudioFlinger.cpp22
-rw-r--r--services/audioflinger/AudioFlinger.h11
-rw-r--r--services/audioflinger/FastMixer.cpp42
-rw-r--r--services/audioflinger/FastMixer.h19
-rw-r--r--services/audioflinger/Threads.cpp4
5 files changed, 80 insertions, 18 deletions
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 6a3007b..99e077c 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -62,6 +62,7 @@
#include <media/nbaio/Pipe.h>
#include <media/nbaio/PipeReader.h>
#include <media/AudioParameter.h>
+#include <private/android_filesystem_config.h>
// ----------------------------------------------------------------------------
@@ -139,7 +140,9 @@ AudioFlinger::AudioFlinger()
mMasterMute(false),
mNextUniqueId(1),
mMode(AUDIO_MODE_INVALID),
- mBtNrecIsOff(false)
+ mBtNrecIsOff(false),
+ mIsLowRamDevice(true),
+ mIsDeviceTypeKnown(false)
{
getpid_cached = getpid();
char value[PROPERTY_VALUE_MAX];
@@ -1381,6 +1384,23 @@ size_t AudioFlinger::getPrimaryOutputFrameCount()
// ----------------------------------------------------------------------------
+status_t AudioFlinger::setLowRamDevice(bool isLowRamDevice)
+{
+ uid_t uid = IPCThreadState::self()->getCallingUid();
+ if (uid != AID_SYSTEM) {
+ return PERMISSION_DENIED;
+ }
+ Mutex::Autolock _l(mLock);
+ if (mIsDeviceTypeKnown) {
+ return INVALID_OPERATION;
+ }
+ mIsLowRamDevice = isLowRamDevice;
+ mIsDeviceTypeKnown = true;
+ return NO_ERROR;
+}
+
+// ----------------------------------------------------------------------------
+
audio_io_handle_t AudioFlinger::openOutput(audio_module_handle_t module,
audio_devices_t *pDevices,
uint32_t *pSamplingRate,
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index 2df9173..f31619b 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -220,6 +220,8 @@ public:
virtual uint32_t getPrimaryOutputSamplingRate();
virtual size_t getPrimaryOutputFrameCount();
+ virtual status_t setLowRamDevice(bool isLowRamDevice);
+
virtual status_t onTransact(
uint32_t code,
const Parcel& data,
@@ -623,6 +625,15 @@ public:
static const size_t kTeeSinkTrackFramesDefault = 0x1000;
#endif
+ // This method reads from a variable without mLock, but the variable is updated under mLock. So
+ // we might read a stale value, or a value that's inconsistent with respect to other variables.
+ // In this case, it's safe because the return value isn't used for making an important decision.
+ // The reason we don't want to take mLock is because it could block the caller for a long time.
+ bool isLowRamDevice() const { return mIsLowRamDevice; }
+
+private:
+ bool mIsLowRamDevice;
+ bool mIsDeviceTypeKnown;
};
#undef INCLUDING_FROM_AUDIOFLINGER_H
diff --git a/services/audioflinger/FastMixer.cpp b/services/audioflinger/FastMixer.cpp
index 819e8ec..5350e2c 100644
--- a/services/audioflinger/FastMixer.cpp
+++ b/services/audioflinger/FastMixer.cpp
@@ -83,7 +83,7 @@ bool FastMixer::threadLoop()
struct timespec oldLoad = {0, 0}; // previous value of clock_gettime(CLOCK_THREAD_CPUTIME_ID)
bool oldLoadValid = false; // whether oldLoad is valid
uint32_t bounds = 0;
- bool full = false; // whether we have collected at least kSamplingN samples
+ bool full = false; // whether we have collected at least mSamplingN samples
#ifdef CPU_FREQUENCY_STATISTICS
ThreadCpuUsage tcu; // for reading the current CPU clock frequency in kHz
#endif
@@ -534,11 +534,11 @@ bool FastMixer::threadLoop()
#ifdef FAST_MIXER_STATISTICS
if (isWarm) {
// advance the FIFO queue bounds
- size_t i = bounds & (FastMixerDumpState::kSamplingN - 1);
+ size_t i = bounds & (dumpState->mSamplingN - 1);
bounds = (bounds & 0xFFFF0000) | ((bounds + 1) & 0xFFFF);
if (full) {
bounds += 0x10000;
- } else if (!(bounds & (FastMixerDumpState::kSamplingN - 1))) {
+ } else if (!(bounds & (dumpState->mSamplingN - 1))) {
full = true;
}
// compute the delta value of clock_gettime(CLOCK_MONOTONIC)
@@ -608,27 +608,43 @@ bool FastMixer::threadLoop()
// never return 'true'; Thread::_threadLoop() locks mutex which can result in priority inversion
}
-FastMixerDumpState::FastMixerDumpState() :
+FastMixerDumpState::FastMixerDumpState(
+#ifdef FAST_MIXER_STATISTICS
+ uint32_t samplingN
+#endif
+ ) :
mCommand(FastMixerState::INITIAL), mWriteSequence(0), mFramesWritten(0),
mNumTracks(0), mWriteErrors(0), mUnderruns(0), mOverruns(0),
mSampleRate(0), mFrameCount(0), /* mMeasuredWarmupTs({0, 0}), */ mWarmupCycles(0),
mTrackMask(0)
#ifdef FAST_MIXER_STATISTICS
- , mBounds(0)
+ , mSamplingN(0), mBounds(0)
#endif
{
mMeasuredWarmupTs.tv_sec = 0;
mMeasuredWarmupTs.tv_nsec = 0;
#ifdef FAST_MIXER_STATISTICS
+ increaseSamplingN(samplingN);
+#endif
+}
+
+#ifdef FAST_MIXER_STATISTICS
+void FastMixerDumpState::increaseSamplingN(uint32_t samplingN)
+{
+ if (samplingN <= mSamplingN || samplingN > kSamplingN || roundup(samplingN) != samplingN) {
+ return;
+ }
+ uint32_t additional = samplingN - mSamplingN;
// sample arrays aren't accessed atomically with respect to the bounds,
// so clearing reduces chance for dumpsys to read random uninitialized samples
- memset(&mMonotonicNs, 0, sizeof(mMonotonicNs));
- memset(&mLoadNs, 0, sizeof(mLoadNs));
+ memset(&mMonotonicNs[mSamplingN], 0, sizeof(mMonotonicNs[0]) * additional);
+ memset(&mLoadNs[mSamplingN], 0, sizeof(mLoadNs[0]) * additional);
#ifdef CPU_FREQUENCY_STATISTICS
- memset(&mCpukHz, 0, sizeof(mCpukHz));
-#endif
+ memset(&mCpukHz[mSamplingN], 0, sizeof(mCpukHz[0]) * additional);
#endif
+ mSamplingN = samplingN;
}
+#endif
FastMixerDumpState::~FastMixerDumpState()
{
@@ -648,7 +664,7 @@ static int compare_uint32_t(const void *pa, const void *pb)
}
}
-void FastMixerDumpState::dump(int fd)
+void FastMixerDumpState::dump(int fd) const
{
if (mCommand == FastMixerState::INITIAL) {
fdprintf(fd, "FastMixer not initialized\n");
@@ -699,9 +715,9 @@ void FastMixerDumpState::dump(int fd)
uint32_t newestOpen = bounds & 0xFFFF;
uint32_t oldestClosed = bounds >> 16;
uint32_t n = (newestOpen - oldestClosed) & 0xFFFF;
- if (n > kSamplingN) {
+ if (n > mSamplingN) {
ALOGE("too many samples %u", n);
- n = kSamplingN;
+ n = mSamplingN;
}
// statistics for monotonic (wall clock) time, thread raw CPU load in time, CPU clock frequency,
// and adjusted CPU load in MHz normalized for CPU clock frequency
@@ -717,7 +733,7 @@ void FastMixerDumpState::dump(int fd)
uint32_t *tail = n >= kTailDenominator ? new uint32_t[n] : NULL;
// loop over all the samples
for (uint32_t j = 0; j < n; ++j) {
- size_t i = oldestClosed++ & (kSamplingN - 1);
+ size_t i = oldestClosed++ & (mSamplingN - 1);
uint32_t wallNs = mMonotonicNs[i];
if (tail != NULL) {
tail[j] = wallNs;
diff --git a/services/audioflinger/FastMixer.h b/services/audioflinger/FastMixer.h
index 2ab1d04..6158925 100644
--- a/services/audioflinger/FastMixer.h
+++ b/services/audioflinger/FastMixer.h
@@ -85,10 +85,14 @@ struct FastTrackDump {
// Only POD types are permitted, and the contents shouldn't be trusted (i.e. do range checks).
// It has a different lifetime than the FastMixer, and so it can't be a member of FastMixer.
struct FastMixerDumpState {
- FastMixerDumpState();
+ FastMixerDumpState(
+#ifdef FAST_MIXER_STATISTICS
+ uint32_t samplingN = kSamplingNforLowRamDevice
+#endif
+ );
/*virtual*/ ~FastMixerDumpState();
- void dump(int fd); // should only be called on a stable copy, not the original
+ void dump(int fd) const; // should only be called on a stable copy, not the original
FastMixerState::Command mCommand; // current command
uint32_t mWriteSequence; // incremented before and after each write()
@@ -106,8 +110,15 @@ struct FastMixerDumpState {
#ifdef FAST_MIXER_STATISTICS
// Recently collected samples of per-cycle monotonic time, thread CPU time, and CPU frequency.
- // kSamplingN is the size of the sampling frame, and must be a power of 2 <= 0x8000.
+ // kSamplingN is max size of sampling frame (statistics), and must be a power of 2 <= 0x8000.
+ // The sample arrays are virtually allocated based on this compile-time constant,
+ // but are only initialized and used based on the runtime parameter mSamplingN.
static const uint32_t kSamplingN = 0x8000;
+ // Compile-time constant for a "low RAM device", must be a power of 2 <= kSamplingN.
+ // This value was chosen such that each array uses 1 small page (4 Kbytes).
+ static const uint32_t kSamplingNforLowRamDevice = 0x400;
+ // Corresponding runtime maximum size of sample arrays, must be a power of 2 <= kSamplingN.
+ uint32_t mSamplingN;
// The bounds define the interval of valid samples, and are represented as follows:
// newest open (excluded) endpoint = lower 16 bits of bounds, modulo N
// oldest closed (included) endpoint = upper 16 bits of bounds, modulo N
@@ -119,6 +130,8 @@ struct FastMixerDumpState {
#ifdef CPU_FREQUENCY_STATISTICS
uint32_t mCpukHz[kSamplingN]; // absolute CPU clock frequency in kHz, bits 0-3 are CPU#
#endif
+ // Increase sampling window after construction, must be a power of 2 <= kSamplingN
+ void increaseSamplingN(uint32_t samplingN);
#endif
};
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index 97a1e43..f27d908 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -2285,6 +2285,8 @@ void AudioFlinger::MixerThread::threadLoop_write()
#endif
}
state->mCommand = FastMixerState::MIX_WRITE;
+ mFastMixerDumpState.increaseSamplingN(mAudioFlinger->isLowRamDevice() ?
+ FastMixerDumpState::kSamplingNforLowRamDevice : FastMixerDumpState::kSamplingN);
sq->end();
sq->push(FastMixerStateQueue::BLOCK_UNTIL_PUSHED);
if (kUseFastMixer == FastMixer_Dynamic) {
@@ -3085,7 +3087,7 @@ void AudioFlinger::MixerThread::dumpInternals(int fd, const Vector<String16>& ar
write(fd, result.string(), result.size());
// Make a non-atomic copy of fast mixer dump state so it won't change underneath us
- FastMixerDumpState copy = mFastMixerDumpState;
+ const FastMixerDumpState copy(mFastMixerDumpState);
copy.dump(fd);
#ifdef STATE_QUEUE_DUMP