All Downloads are FREE. Search and download functionalities are using the official Maven repository.

src.android.util.imagepool.ImagePoolStatsDebugImpl Maven / Gradle / Ivy

Go to download

A library jar that provides APIs for Applications written for the Google Android Platform.

There is a newer version: 15-robolectric-12650502
Show newest version
/*
 * Copyright (C) 2018 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.util.imagepool;

import java.lang.management.GarbageCollectorMXBean;
import java.lang.management.ManagementFactory;
import java.util.HashMap;
import java.util.Map;

import com.google.common.collect.HashMultiset;
import com.google.common.collect.Multiset;

/**
 * Useful impl for debugging reproable error.
 */
public class ImagePoolStatsDebugImpl extends ImagePoolStatsProdImpl {

    private static String PACKAGE_NAME = ImagePoolStats.class.getPackage().getName();

    // Used for deugging purposes only.
    private final Map mCallStack = new HashMap<>();
    private long mRequestedTotalBytes = 0;
    private long mAllocatedOutsidePoolBytes = 0;

    // Used for gc-related stats.
    private long mPreviousGcCollection = 0;
    private long mPreviousGcTime = 0;

    /** Used for policy */
    @Override
    public void recordBucketCreation(int widthBucket, int heightBucket) {
        super.recordBucketCreation(widthBucket, heightBucket);
    }

    @Override
    public boolean fitsMaxCacheSize(int width, int height, long maxCacheSize) {
        return super.fitsMaxCacheSize(width, height, maxCacheSize);
    }

    @Override
    public void clear() {
        super.clear();

        mRequestedTotalBytes = 0;
        mAllocatedOutsidePoolBytes = 0;
        mTooBigForPoolCount = 0;
        mCallStack.clear();
    }

    @Override
    public void tooBigForCache() {
        super.tooBigForCache();
    }

    /** Used for Debugging only */
    @Override
    public void recordBucketRequest(int w, int h) {
        mRequestedTotalBytes += (w * h * ESTIMATED_PIXEL_BYTES);
    }

    @Override
    public void recordAllocOutsidePool(int width, int height) {
        mAllocatedOutsidePoolBytes += (width * height * ESTIMATED_PIXEL_BYTES);
    }

    @Override
    public void acquiredImage(Integer imageHash) {
        for (int i = 1; i < Thread.currentThread().getStackTrace().length; i++) {
            StackTraceElement element = Thread.currentThread().getStackTrace()[i];
            String str = element.toString();

            if (!str.contains(PACKAGE_NAME)) {
                mCallStack.put(imageHash, str);
                break;
            }
        }
    }

    @Override
    public void disposeImage(Integer imageHash) {
        mCallStack.remove(imageHash);
    }

    @Override
    public void start() {
        long totalGarbageCollections = 0;
        long garbageCollectionTime = 0;
        for (GarbageCollectorMXBean gc : ManagementFactory.getGarbageCollectorMXBeans()) {
            long count = gc.getCollectionCount();
            if (count >= 0) {
                totalGarbageCollections += count;
            }
            long time = gc.getCollectionTime();
            if (time >= 0) {
                garbageCollectionTime += time;
            }
        }
        mPreviousGcCollection = totalGarbageCollections;
        mPreviousGcTime = garbageCollectionTime;
    }

    private String calculateGcStatAndReturn() {
        long totalGarbageCollections = 0;
        long garbageCollectionTime = 0;
        for (GarbageCollectorMXBean gc : ManagementFactory.getGarbageCollectorMXBeans()) {
            long count = gc.getCollectionCount();
            if (count > 0) {
                totalGarbageCollections += count;
            }
            long time = gc.getCollectionTime();
            if(time > 0) {
                garbageCollectionTime += time;
            }
        }
        totalGarbageCollections -= mPreviousGcCollection;
        garbageCollectionTime -= mPreviousGcTime;

        StringBuilder builder = new StringBuilder();
        builder.append("Total Garbage Collections: ");
        builder.append(totalGarbageCollections);
        builder.append("\n");

        builder.append("Total Garbage Collection Time (ms): ");
        builder.append(garbageCollectionTime);
        builder.append("\n");

        return builder.toString();
    }

    @Override
    public String getStatistic() {
        StringBuilder builder = new StringBuilder();

        builder.append(calculateGcStatAndReturn());
        builder.append("Memory\n");
        builder.append(" requested total         : ");
        builder.append(mRequestedTotalBytes / 1_000_000);
        builder.append(" MB\n");
        builder.append(" allocated (in pool)     : ");
        builder.append(mAllocateTotalBytes / 1_000_000);
        builder.append(" MB\n");
        builder.append(" allocated (out of pool) : ");
        builder.append(mAllocatedOutsidePoolBytes / 1_000_000);
        builder.append(" MB\n");

        double percent = (1.0 - (double) mRequestedTotalBytes / (mAllocateTotalBytes +
                mAllocatedOutsidePoolBytes));
        if (percent < 0.0) {
            builder.append(" saved : ");
            builder.append(-1.0 * percent);
            builder.append("%\n");
        } else {
            builder.append(" wasting : ");
            builder.append(percent);
            builder.append("%\n");
        }

        builder.append("Undispose images\n");
        Multiset countSet = HashMultiset.create();
        for (String callsite : mCallStack.values()) {
            countSet.add(callsite);
        }

        for (Multiset.Entry entry : countSet.entrySet()) {
            builder.append(" - ");
            builder.append(entry.getElement());
            builder.append(" - missed dispose : ");
            builder.append(entry.getCount());
            builder.append(" times\n");
        }

        builder.append("Number of times requested image didn't fit the pool : ");
        builder.append(mTooBigForPoolCount);
        builder.append("\n");

        return builder.toString();
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy