GpuMemoryTracker.cpp revision 38e0c32852e3b9d8ca4a9d3791577f52536419cb
138e0c32852e3b9d8ca4a9d3791577f52536419cbJohn Reck/*
238e0c32852e3b9d8ca4a9d3791577f52536419cbJohn Reck * Copyright (C) 2016 The Android Open Source Project
338e0c32852e3b9d8ca4a9d3791577f52536419cbJohn Reck *
438e0c32852e3b9d8ca4a9d3791577f52536419cbJohn Reck * Licensed under the Apache License, Version 2.0 (the "License");
538e0c32852e3b9d8ca4a9d3791577f52536419cbJohn Reck * you may not use this file except in compliance with the License.
638e0c32852e3b9d8ca4a9d3791577f52536419cbJohn Reck * You may obtain a copy of the License at
738e0c32852e3b9d8ca4a9d3791577f52536419cbJohn Reck *
838e0c32852e3b9d8ca4a9d3791577f52536419cbJohn Reck *      http://www.apache.org/licenses/LICENSE-2.0
938e0c32852e3b9d8ca4a9d3791577f52536419cbJohn Reck *
1038e0c32852e3b9d8ca4a9d3791577f52536419cbJohn Reck * Unless required by applicable law or agreed to in writing, software
1138e0c32852e3b9d8ca4a9d3791577f52536419cbJohn Reck * distributed under the License is distributed on an "AS IS" BASIS,
1238e0c32852e3b9d8ca4a9d3791577f52536419cbJohn Reck * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1338e0c32852e3b9d8ca4a9d3791577f52536419cbJohn Reck * See the License for the specific language governing permissions and
1438e0c32852e3b9d8ca4a9d3791577f52536419cbJohn Reck * limitations under the License.
1538e0c32852e3b9d8ca4a9d3791577f52536419cbJohn Reck */
1638e0c32852e3b9d8ca4a9d3791577f52536419cbJohn Reck
1738e0c32852e3b9d8ca4a9d3791577f52536419cbJohn Reck#include "utils/StringUtils.h"
1838e0c32852e3b9d8ca4a9d3791577f52536419cbJohn Reck#include "Texture.h"
1938e0c32852e3b9d8ca4a9d3791577f52536419cbJohn Reck
2038e0c32852e3b9d8ca4a9d3791577f52536419cbJohn Reck#include <cutils/compiler.h>
2138e0c32852e3b9d8ca4a9d3791577f52536419cbJohn Reck#include <GpuMemoryTracker.h>
2238e0c32852e3b9d8ca4a9d3791577f52536419cbJohn Reck#include <utils/Trace.h>
2338e0c32852e3b9d8ca4a9d3791577f52536419cbJohn Reck#include <array>
2438e0c32852e3b9d8ca4a9d3791577f52536419cbJohn Reck#include <sstream>
2538e0c32852e3b9d8ca4a9d3791577f52536419cbJohn Reck#include <unordered_set>
2638e0c32852e3b9d8ca4a9d3791577f52536419cbJohn Reck#include <vector>
2738e0c32852e3b9d8ca4a9d3791577f52536419cbJohn Reck
2838e0c32852e3b9d8ca4a9d3791577f52536419cbJohn Recknamespace android {
2938e0c32852e3b9d8ca4a9d3791577f52536419cbJohn Recknamespace uirenderer {
3038e0c32852e3b9d8ca4a9d3791577f52536419cbJohn Reck
3138e0c32852e3b9d8ca4a9d3791577f52536419cbJohn Reckpthread_t gGpuThread = 0;
3238e0c32852e3b9d8ca4a9d3791577f52536419cbJohn Reck
3338e0c32852e3b9d8ca4a9d3791577f52536419cbJohn Reck#define NUM_TYPES static_cast<int>(GpuObjectType::TypeCount)
3438e0c32852e3b9d8ca4a9d3791577f52536419cbJohn Reck
3538e0c32852e3b9d8ca4a9d3791577f52536419cbJohn Reckconst char* TYPE_NAMES[] = {
3638e0c32852e3b9d8ca4a9d3791577f52536419cbJohn Reck        "Texture",
3738e0c32852e3b9d8ca4a9d3791577f52536419cbJohn Reck        "OffscreenBuffer",
3838e0c32852e3b9d8ca4a9d3791577f52536419cbJohn Reck        "Layer",
3938e0c32852e3b9d8ca4a9d3791577f52536419cbJohn Reck};
4038e0c32852e3b9d8ca4a9d3791577f52536419cbJohn Reck
4138e0c32852e3b9d8ca4a9d3791577f52536419cbJohn Reckstruct TypeStats {
4238e0c32852e3b9d8ca4a9d3791577f52536419cbJohn Reck    int totalSize = 0;
4338e0c32852e3b9d8ca4a9d3791577f52536419cbJohn Reck    int count = 0;
4438e0c32852e3b9d8ca4a9d3791577f52536419cbJohn Reck};
4538e0c32852e3b9d8ca4a9d3791577f52536419cbJohn Reck
4638e0c32852e3b9d8ca4a9d3791577f52536419cbJohn Reckstatic std::array<TypeStats, NUM_TYPES> gObjectStats;
4738e0c32852e3b9d8ca4a9d3791577f52536419cbJohn Reckstatic std::unordered_set<GpuMemoryTracker*> gObjectSet;
4838e0c32852e3b9d8ca4a9d3791577f52536419cbJohn Reck
4938e0c32852e3b9d8ca4a9d3791577f52536419cbJohn Reckvoid GpuMemoryTracker::notifySizeChanged(int newSize) {
5038e0c32852e3b9d8ca4a9d3791577f52536419cbJohn Reck    int delta = newSize - mSize;
5138e0c32852e3b9d8ca4a9d3791577f52536419cbJohn Reck    mSize = newSize;
5238e0c32852e3b9d8ca4a9d3791577f52536419cbJohn Reck    gObjectStats[static_cast<int>(mType)].totalSize += delta;
5338e0c32852e3b9d8ca4a9d3791577f52536419cbJohn Reck}
5438e0c32852e3b9d8ca4a9d3791577f52536419cbJohn Reck
5538e0c32852e3b9d8ca4a9d3791577f52536419cbJohn Reckvoid GpuMemoryTracker::startTrackingObject() {
5638e0c32852e3b9d8ca4a9d3791577f52536419cbJohn Reck    auto result = gObjectSet.insert(this);
5738e0c32852e3b9d8ca4a9d3791577f52536419cbJohn Reck    LOG_ALWAYS_FATAL_IF(!result.second,
5838e0c32852e3b9d8ca4a9d3791577f52536419cbJohn Reck            "startTrackingObject() on %p failed, already being tracked!", this);
5938e0c32852e3b9d8ca4a9d3791577f52536419cbJohn Reck    gObjectStats[static_cast<int>(mType)].count++;
6038e0c32852e3b9d8ca4a9d3791577f52536419cbJohn Reck}
6138e0c32852e3b9d8ca4a9d3791577f52536419cbJohn Reck
6238e0c32852e3b9d8ca4a9d3791577f52536419cbJohn Reckvoid GpuMemoryTracker::stopTrackingObject() {
6338e0c32852e3b9d8ca4a9d3791577f52536419cbJohn Reck    size_t removed = gObjectSet.erase(this);
6438e0c32852e3b9d8ca4a9d3791577f52536419cbJohn Reck    LOG_ALWAYS_FATAL_IF(removed != 1,
6538e0c32852e3b9d8ca4a9d3791577f52536419cbJohn Reck            "stopTrackingObject removed %zd, is %p not being tracked?",
6638e0c32852e3b9d8ca4a9d3791577f52536419cbJohn Reck            removed, this);
6738e0c32852e3b9d8ca4a9d3791577f52536419cbJohn Reck    gObjectStats[static_cast<int>(mType)].count--;
6838e0c32852e3b9d8ca4a9d3791577f52536419cbJohn Reck}
6938e0c32852e3b9d8ca4a9d3791577f52536419cbJohn Reck
7038e0c32852e3b9d8ca4a9d3791577f52536419cbJohn Reckvoid GpuMemoryTracker::onGLContextCreated() {
7138e0c32852e3b9d8ca4a9d3791577f52536419cbJohn Reck    LOG_ALWAYS_FATAL_IF(gGpuThread != 0, "We already have a GL thread? "
7238e0c32852e3b9d8ca4a9d3791577f52536419cbJohn Reck            "current = %lu, gl thread = %lu", pthread_self(), gGpuThread);
7338e0c32852e3b9d8ca4a9d3791577f52536419cbJohn Reck    gGpuThread = pthread_self();
7438e0c32852e3b9d8ca4a9d3791577f52536419cbJohn Reck}
7538e0c32852e3b9d8ca4a9d3791577f52536419cbJohn Reck
7638e0c32852e3b9d8ca4a9d3791577f52536419cbJohn Reckvoid GpuMemoryTracker::onGLContextDestroyed() {
7738e0c32852e3b9d8ca4a9d3791577f52536419cbJohn Reck    gGpuThread = 0;
7838e0c32852e3b9d8ca4a9d3791577f52536419cbJohn Reck    if (CC_UNLIKELY(gObjectSet.size() > 0)) {
7938e0c32852e3b9d8ca4a9d3791577f52536419cbJohn Reck        std::stringstream os;
8038e0c32852e3b9d8ca4a9d3791577f52536419cbJohn Reck        dump(os);
8138e0c32852e3b9d8ca4a9d3791577f52536419cbJohn Reck        ALOGE("%s", os.str().c_str());
8238e0c32852e3b9d8ca4a9d3791577f52536419cbJohn Reck        LOG_ALWAYS_FATAL("Leaked %zd GPU objects!", gObjectSet.size());
8338e0c32852e3b9d8ca4a9d3791577f52536419cbJohn Reck    }
8438e0c32852e3b9d8ca4a9d3791577f52536419cbJohn Reck}
8538e0c32852e3b9d8ca4a9d3791577f52536419cbJohn Reck
8638e0c32852e3b9d8ca4a9d3791577f52536419cbJohn Reckvoid GpuMemoryTracker::dump() {
8738e0c32852e3b9d8ca4a9d3791577f52536419cbJohn Reck    std::stringstream strout;
8838e0c32852e3b9d8ca4a9d3791577f52536419cbJohn Reck    dump(strout);
8938e0c32852e3b9d8ca4a9d3791577f52536419cbJohn Reck    ALOGD("%s", strout.str().c_str());
9038e0c32852e3b9d8ca4a9d3791577f52536419cbJohn Reck}
9138e0c32852e3b9d8ca4a9d3791577f52536419cbJohn Reck
9238e0c32852e3b9d8ca4a9d3791577f52536419cbJohn Reckvoid GpuMemoryTracker::dump(std::ostream& stream) {
9338e0c32852e3b9d8ca4a9d3791577f52536419cbJohn Reck    for (int type = 0; type < NUM_TYPES; type++) {
9438e0c32852e3b9d8ca4a9d3791577f52536419cbJohn Reck        const TypeStats& stats = gObjectStats[type];
9538e0c32852e3b9d8ca4a9d3791577f52536419cbJohn Reck        stream << TYPE_NAMES[type];
9638e0c32852e3b9d8ca4a9d3791577f52536419cbJohn Reck        stream << " is using " << SizePrinter{stats.totalSize};
9738e0c32852e3b9d8ca4a9d3791577f52536419cbJohn Reck        stream << ", count = " << stats.count;
9838e0c32852e3b9d8ca4a9d3791577f52536419cbJohn Reck        stream << std::endl;
9938e0c32852e3b9d8ca4a9d3791577f52536419cbJohn Reck    }
10038e0c32852e3b9d8ca4a9d3791577f52536419cbJohn Reck}
10138e0c32852e3b9d8ca4a9d3791577f52536419cbJohn Reck
10238e0c32852e3b9d8ca4a9d3791577f52536419cbJohn Reckint GpuMemoryTracker::getInstanceCount(GpuObjectType type) {
10338e0c32852e3b9d8ca4a9d3791577f52536419cbJohn Reck    return gObjectStats[static_cast<int>(type)].count;
10438e0c32852e3b9d8ca4a9d3791577f52536419cbJohn Reck}
10538e0c32852e3b9d8ca4a9d3791577f52536419cbJohn Reck
10638e0c32852e3b9d8ca4a9d3791577f52536419cbJohn Reckint GpuMemoryTracker::getTotalSize(GpuObjectType type) {
10738e0c32852e3b9d8ca4a9d3791577f52536419cbJohn Reck    return gObjectStats[static_cast<int>(type)].totalSize;
10838e0c32852e3b9d8ca4a9d3791577f52536419cbJohn Reck}
10938e0c32852e3b9d8ca4a9d3791577f52536419cbJohn Reck
11038e0c32852e3b9d8ca4a9d3791577f52536419cbJohn Reckvoid GpuMemoryTracker::onFrameCompleted() {
11138e0c32852e3b9d8ca4a9d3791577f52536419cbJohn Reck    if (ATRACE_ENABLED()) {
11238e0c32852e3b9d8ca4a9d3791577f52536419cbJohn Reck        char buf[128];
11338e0c32852e3b9d8ca4a9d3791577f52536419cbJohn Reck        for (int type = 0; type < NUM_TYPES; type++) {
11438e0c32852e3b9d8ca4a9d3791577f52536419cbJohn Reck            snprintf(buf, 128, "hwui_%s", TYPE_NAMES[type]);
11538e0c32852e3b9d8ca4a9d3791577f52536419cbJohn Reck            const TypeStats& stats = gObjectStats[type];
11638e0c32852e3b9d8ca4a9d3791577f52536419cbJohn Reck            ATRACE_INT(buf, stats.totalSize);
11738e0c32852e3b9d8ca4a9d3791577f52536419cbJohn Reck            snprintf(buf, 128, "hwui_%s_count", TYPE_NAMES[type]);
11838e0c32852e3b9d8ca4a9d3791577f52536419cbJohn Reck            ATRACE_INT(buf, stats.count);
11938e0c32852e3b9d8ca4a9d3791577f52536419cbJohn Reck        }
12038e0c32852e3b9d8ca4a9d3791577f52536419cbJohn Reck    }
12138e0c32852e3b9d8ca4a9d3791577f52536419cbJohn Reck
12238e0c32852e3b9d8ca4a9d3791577f52536419cbJohn Reck    std::vector<const Texture*> freeList;
12338e0c32852e3b9d8ca4a9d3791577f52536419cbJohn Reck    for (const auto& obj : gObjectSet) {
12438e0c32852e3b9d8ca4a9d3791577f52536419cbJohn Reck        if (obj->objectType() == GpuObjectType::Texture) {
12538e0c32852e3b9d8ca4a9d3791577f52536419cbJohn Reck            const Texture* texture = static_cast<Texture*>(obj);
12638e0c32852e3b9d8ca4a9d3791577f52536419cbJohn Reck            if (texture->cleanup) {
12738e0c32852e3b9d8ca4a9d3791577f52536419cbJohn Reck                ALOGE("Leaked texture marked for cleanup! id=%u, size %ux%u",
12838e0c32852e3b9d8ca4a9d3791577f52536419cbJohn Reck                        texture->id(), texture->width(), texture->height());
12938e0c32852e3b9d8ca4a9d3791577f52536419cbJohn Reck                freeList.push_back(texture);
13038e0c32852e3b9d8ca4a9d3791577f52536419cbJohn Reck            }
13138e0c32852e3b9d8ca4a9d3791577f52536419cbJohn Reck        }
13238e0c32852e3b9d8ca4a9d3791577f52536419cbJohn Reck    }
13338e0c32852e3b9d8ca4a9d3791577f52536419cbJohn Reck    for (auto& texture : freeList) {
13438e0c32852e3b9d8ca4a9d3791577f52536419cbJohn Reck        const_cast<Texture*>(texture)->deleteTexture();
13538e0c32852e3b9d8ca4a9d3791577f52536419cbJohn Reck        delete texture;
13638e0c32852e3b9d8ca4a9d3791577f52536419cbJohn Reck    }
13738e0c32852e3b9d8ca4a9d3791577f52536419cbJohn Reck}
13838e0c32852e3b9d8ca4a9d3791577f52536419cbJohn Reck
13938e0c32852e3b9d8ca4a9d3791577f52536419cbJohn Reck} // namespace uirenderer
14038e0c32852e3b9d8ca4a9d3791577f52536419cbJohn Reck} // namespace android;
141