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

Commit 7651a279 authored by Sungtak Lee's avatar Sungtak Lee
Browse files

Evict buffers from idle bufferpool

Evict cached buffers from idle bufferpool in order to reduce memory
consumption.

Bug: 146679370
Test: atest CtsMediaTestCases -- --module-arg CtsMediaTestCases:size:small
Change-Id: Ic23bd36c88e4bed2a3a8f8aa277ae4c8ca89a41c
parent fb128ba8
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -117,6 +117,10 @@ void Accessor::createInvalidator() {
    Accessor::Impl::createInvalidator();
}

void Accessor::createEvictor() {
    Accessor::Impl::createEvictor();
}

// Methods from ::android::hardware::media::bufferpool::V2_0::IAccessor follow.
Return<void> Accessor::connect(
        const sp<::android::hardware::media::bufferpool::V2_0::IObserver>& observer,
+2 −0
Original line number Diff line number Diff line
@@ -187,6 +187,8 @@ struct Accessor : public IAccessor {

    static void createInvalidator();

    static void createEvictor();

private:
    class Impl;
    std::shared_ptr<Impl> mImpl;
+90 −1
Original line number Diff line number Diff line
@@ -39,6 +39,9 @@ namespace {

    static constexpr size_t kMinAllocBytesForEviction = 1024*1024*15;
    static constexpr size_t kMinBufferCountForEviction = 25;

    static constexpr nsecs_t kEvictGranularityNs = 1000000000; // 1 sec
    static constexpr nsecs_t kEvictDurationNs = 5000000000; // 5 secs
}

// Buffer structure in bufferpool process
@@ -139,7 +142,7 @@ uint32_t Accessor::Impl::sSeqId = time(nullptr);

Accessor::Impl::Impl(
        const std::shared_ptr<BufferPoolAllocator> &allocator)
        : mAllocator(allocator) {}
        : mAllocator(allocator), mScheduleEvictTs(0) {}

Accessor::Impl::~Impl() {
}
@@ -177,6 +180,7 @@ ResultStatus Accessor::Impl::connect(
        }
        mBufferPool.processStatusMessages();
        mBufferPool.cleanUp();
        scheduleEvictIfNeeded();
    }
    return status;
}
@@ -191,6 +195,7 @@ ResultStatus Accessor::Impl::close(ConnectionId connectionId) {
    // Since close# will be called after all works are finished, it is OK to
    // evict unused buffers.
    mBufferPool.cleanUp(true);
    scheduleEvictIfNeeded();
    return ResultStatus::OK;
}

@@ -217,6 +222,7 @@ ResultStatus Accessor::Impl::allocate(
        mBufferPool.handleOwnBuffer(connectionId, *bufferId);
    }
    mBufferPool.cleanUp();
    scheduleEvictIfNeeded();
    return status;
}

@@ -242,6 +248,7 @@ ResultStatus Accessor::Impl::fetch(
        }
    }
    mBufferPool.cleanUp();
    scheduleEvictIfNeeded();
    return ResultStatus::CRITICAL_ERROR;
}

@@ -884,6 +891,88 @@ void Accessor::Impl::createInvalidator() {
    }
}

void Accessor::Impl::evictorThread(
        std::map<const std::weak_ptr<Accessor::Impl>, nsecs_t, std::owner_less<>> &accessors,
        std::mutex &mutex,
        std::condition_variable &cv) {
    std::list<const std::weak_ptr<Accessor::Impl>> evictList;
    while (true) {
        int expired = 0;
        int evicted = 0;
        {
            nsecs_t now = systemTime();
            std::unique_lock<std::mutex> lock(mutex);
            if (accessors.size() == 0) {
                cv.wait(lock);
            }
            auto it = accessors.begin();
            while (it != accessors.end()) {
                if (now > (it->second + kEvictDurationNs)) {
                    ++expired;
                    evictList.push_back(it->first);
                    it = accessors.erase(it);
                } else {
                    ++it;
                }
            }
        }
        // evict idle accessors;
        for (auto it = evictList.begin(); it != evictList.end(); ++it) {
            const std::shared_ptr<Accessor::Impl> accessor = it->lock();
            if (accessor) {
                accessor->cleanUp(true);
                ++evicted;
            }
        }
        if (expired > 0) {
            ALOGD("evictor expired: %d, evicted: %d", expired, evicted);
        }
        evictList.clear();
        ::usleep(kEvictGranularityNs / 1000);
    }
}

Accessor::Impl::AccessorEvictor::AccessorEvictor() {
    std::thread evictor(
            evictorThread,
            std::ref(mAccessors),
            std::ref(mMutex),
            std::ref(mCv));
    evictor.detach();
}

void Accessor::Impl::AccessorEvictor::addAccessor(
        const std::weak_ptr<Accessor::Impl> &impl, nsecs_t ts) {
    std::lock_guard<std::mutex> lock(mMutex);
    bool notify = mAccessors.empty();
    auto it = mAccessors.find(impl);
    if (it == mAccessors.end()) {
        mAccessors.emplace(impl, ts);
    } else {
        it->second = ts;
    }
    if (notify) {
        mCv.notify_one();
    }
}

std::unique_ptr<Accessor::Impl::AccessorEvictor> Accessor::Impl::sEvictor;

void Accessor::Impl::createEvictor() {
    if (!sEvictor) {
        sEvictor = std::make_unique<Accessor::Impl::AccessorEvictor>();
    }
}

void Accessor::Impl::scheduleEvictIfNeeded() {
    nsecs_t now = systemTime();

    if (now > (mScheduleEvictTs + kEvictGranularityNs)) {
        mScheduleEvictTs = now;
        sEvictor->addAccessor(shared_from_this(), now);
    }
}

}  // namespace implementation
}  // namespace V2_0
}  // namespace bufferpool
+24 −0
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@
#include <map>
#include <set>
#include <condition_variable>
#include <utils/Timers.h>
#include "Accessor.h"

namespace android {
@@ -71,6 +72,8 @@ public:

    static void createInvalidator();

    static void createEvictor();

private:
    // ConnectionId = pid : (timestamp_created + seqId)
    // in order to guarantee uniqueness for each connection
@@ -78,6 +81,8 @@ private:

    const std::shared_ptr<BufferPoolAllocator> mAllocator;

    nsecs_t mScheduleEvictTs;

    /**
     * Buffer pool implementation.
     *
@@ -389,6 +394,25 @@ private:
        std::mutex &mutex,
        std::condition_variable &cv,
        bool &ready);

    struct AccessorEvictor {
        std::map<const std::weak_ptr<Accessor::Impl>, nsecs_t, std::owner_less<>> mAccessors;
        std::mutex mMutex;
        std::condition_variable mCv;

        AccessorEvictor();
        void addAccessor(const std::weak_ptr<Accessor::Impl> &impl, nsecs_t ts);
    };

    static std::unique_ptr<AccessorEvictor> sEvictor;

    static void evictorThread(
        std::map<const std::weak_ptr<Accessor::Impl>, nsecs_t, std::owner_less<>> &accessors,
        std::mutex &mutex,
        std::condition_variable &cv);

    void scheduleEvictIfNeeded();

};

}  // namespace implementation
+1 −0
Original line number Diff line number Diff line
@@ -484,6 +484,7 @@ sp<ClientManager> ClientManager::getInstance() {
        sInstance = new ClientManager();
    }
    Accessor::createInvalidator();
    Accessor::createEvictor();
    return sInstance;
}