Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a0991fea authored by Glenn Kasten's avatar Glenn Kasten Committed by Android Git Automerger
Browse files

am 0c22272f: Merge "Pipe throttle based on requested frame count" into jb-dev

* commit '0c22272f':
  Pipe throttle based on requested frame count
parents c9bdf9b4 0c22272f
Loading
Loading
Loading
Loading
+20 −38
Original line number Diff line number Diff line
@@ -25,9 +25,10 @@

namespace android {

MonoPipe::MonoPipe(size_t maxFrames, NBAIO_Format format, bool writeCanBlock) :
MonoPipe::MonoPipe(size_t reqFrames, NBAIO_Format format, bool writeCanBlock) :
        NBAIO_Sink(format),
        mMaxFrames(roundup(maxFrames)),
        mReqFrames(reqFrames),
        mMaxFrames(roundup(reqFrames)),
        mBuffer(malloc(mMaxFrames * Format_frameSize(format))),
        mFront(0),
        mRear(0),
@@ -45,6 +46,7 @@ ssize_t MonoPipe::availableToWrite() const
    if (CC_UNLIKELY(!mNegotiated)) {
        return NEGOTIATE;
    }
    // uses mMaxFrames not mReqFrames, so allows "over-filling" the pipe beyond requested limit
    ssize_t ret = mMaxFrames - (mRear - android_atomic_acquire_load(&mFront));
    ALOG_ASSERT((0 <= ret) && (ret <= mMaxFrames));
    return ret;
@@ -57,6 +59,7 @@ ssize_t MonoPipe::write(const void *buffer, size_t count)
    }
    size_t totalFramesWritten = 0;
    while (count > 0) {
        // can't return a negative value, as we already checked for !mNegotiated
        size_t avail = availableToWrite();
        size_t written = avail;
        if (CC_LIKELY(written > count)) {
@@ -84,50 +87,29 @@ ssize_t MonoPipe::write(const void *buffer, size_t count)
        count -= written;
        buffer = (char *) buffer + (written << mBitShift);
        // Simulate blocking I/O by sleeping at different rates, depending on a throttle.
        // The throttle tries to keep the pipe about 5/8 full on average, with a slight jitter.
        uint64_t ns;
        enum {
            THROTTLE_VERY_FAST, // pipe is (nearly) empty, fill quickly
            THROTTLE_FAST,      // pipe is normal, fill at slightly faster rate
            THROTTLE_NOMINAL,   // pipe is normal, fill at nominal rate
            THROTTLE_SLOW,      // pipe is normal, fill at slightly slower rate
            THROTTLE_VERY_SLOW, // pipe is (nearly) full, fill slowly
        } throttle;
        avail -= written;
        // FIXME cache these values to avoid re-computation
        if (avail >= (mMaxFrames * 3) / 4) {
            throttle = THROTTLE_VERY_FAST;
        } else if (avail >= mMaxFrames / 2) {
            throttle = THROTTLE_FAST;
        } else if (avail >= (mMaxFrames * 3) / 8) {
            throttle = THROTTLE_NOMINAL;
        } else if (avail >= mMaxFrames / 4) {
            throttle = THROTTLE_SLOW;
        } else {
            throttle = THROTTLE_VERY_SLOW;
        }
        // The throttle tries to keep the pipe about 11/16 full on average, with a slight jitter.
        uint32_t ns;
        if (written > 0) {
            // FIXME cache these values also
            switch (throttle) {
            case THROTTLE_VERY_FAST:
            default:
            size_t filled = (mMaxFrames - avail) + written;
            // FIXME cache these values to avoid re-computation
            if (filled <= mReqFrames / 4) {
                // pipe is (nearly) empty, fill quickly
                ns = written * ( 500000000 / Format_sampleRate(mFormat));
                break;
            case THROTTLE_FAST:
            } else if (filled <= mReqFrames / 2) {
                // pipe is normal, fill at slightly faster rate
                ns = written * ( 750000000 / Format_sampleRate(mFormat));
                break;
            case THROTTLE_NOMINAL:
            } else if (filled <= (mReqFrames * 5) / 8) {
                // pipe is normal, fill at nominal rate
                ns = written * (1000000000 / Format_sampleRate(mFormat));
                break;
            case THROTTLE_SLOW:
            } else if (filled <= (mReqFrames * 3) / 4) {
                // pipe is normal, fill at slightly slower rate
                ns = written * (1100000000 / Format_sampleRate(mFormat));
                break;
            case THROTTLE_VERY_SLOW:
            } else {
                // pipe is (nearly) full, fill slowly
                ns = written * (1250000000 / Format_sampleRate(mFormat));
                break;
            }
        } else {
            ns = mMaxFrames * (250000000 / Format_sampleRate(mFormat));
            ns = mReqFrames * (250000000 / Format_sampleRate(mFormat));
        }
        if (ns > 999999999) {
            ns = 999999999;
+4 −3
Original line number Diff line number Diff line
@@ -33,11 +33,11 @@ class MonoPipe : public NBAIO_Sink {
    friend class MonoPipeReader;

public:
    // maxFrames will be rounded up to a power of 2, and all slots are available. Must be >= 2.
    // reqFrames will be rounded up to a power of 2, and all slots are available. Must be >= 2.
    // Note: whatever shares this object with another thread needs to do so in an SMP-safe way (like
    // creating it the object before creating the other thread, or storing the object with a
    // release_store). Otherwise the other thread could see a partially-constructed object.
    MonoPipe(size_t maxFrames, NBAIO_Format format, bool writeCanBlock = false);
    MonoPipe(size_t reqFrames, NBAIO_Format format, bool writeCanBlock = false);
    virtual ~MonoPipe();

    // NBAIO_Port interface
@@ -58,9 +58,10 @@ public:

            // average number of frames present in the pipe under normal conditions.
            // See throttling mechanism in MonoPipe::write()
            size_t  getAvgFrames() const { return (mMaxFrames * 11) / 16; }
            size_t  getAvgFrames() const { return (mReqFrames * 11) / 16; }

private:
    const size_t    mReqFrames;     // as requested in constructor, unrounded
    const size_t    mMaxFrames;     // always a power of 2
    void * const    mBuffer;
    // mFront and mRear will never be separated by more than mMaxFrames.