package org.andengine.entity.util;
import org.andengine.BuildConfig;
import org.andengine.engine.handler.IUpdateHandler;
import org.andengine.util.TextUtils;
import org.andengine.util.debug.Debug;
import org.andengine.util.debug.Debug.DebugLevel;
import org.andengine.util.system.SystemUtils;
import org.andengine.util.system.SystemUtils.SystemUtilsException;
/**
* (c) 2012 Zynga Inc.
*
* @author Nicolas Gramlich <ngramlich@zynga.com>
* @since 14:50:15 - 14.05.2012
*/
public class MemoryLogger implements IUpdateHandler {
// ===========================================================
// Constants
// ===========================================================
private static final float AVERAGE_DURATION_DEFAULT = 5;
// ===========================================================
// Fields
// ===========================================================
private final float mAverageDuration;
private final DebugLevel mDebugLevel;
private float mSecondsElapsed;
private boolean mLogSystemMemory;
private long mPreviousSystemMemorySize;
private long mPreviousSystemMemoryFreeSize;
private boolean mLogDalvikHeap;
private long mPreviousDalvikHeapSize;
private long mPreviousDalvikHeapFreeSize;
private long mPreviousDalvikHeapAllocatedSize;
private boolean mLogDalvikMemoryInfo;
private long mPreviousDalvikProportionalSetSize;
private long mPreviousDalvikPrivateDirtyPages;
private long mPreviousDalvikSharedDirtyPages;
private boolean mLogNativeHeap;
private long mPreviousNativeHeapSize;
private long mPreviousNativeHeapFreeSize;
private long mPreviousNativeHeapAllocatedSize;
private boolean mLogNativeMemoryInfo;
private long mPreviousNativeProportionalSetSize;
private long mPreviousNativePrivateDirtyPages;
private long mPreviousNativeSharedDirtyPages;
// ===========================================================
// Constructors
// ===========================================================
public MemoryLogger() {
this(DebugLevel.DEBUG);
}
public MemoryLogger(final DebugLevel pDebugLevel) {
this(MemoryLogger.AVERAGE_DURATION_DEFAULT, pDebugLevel);
}
public MemoryLogger(final float pAverageDuration) {
this(pAverageDuration, DebugLevel.DEBUG);
}
public MemoryLogger(final float pAverageDuration, final DebugLevel pDebugLevel) {
this(pAverageDuration, pDebugLevel, true, true, false, true, false);
}
public MemoryLogger(final float pAverageDuration, final DebugLevel pDebugLevel, final boolean pLogSystemMemory, final boolean pLogDalvikHeap, final boolean pLogDalvikMemoryInfo, final boolean pLogNativeHeap, final boolean pLogNativeMemoryInfo) {
this.mAverageDuration = pAverageDuration;
this.mDebugLevel = pDebugLevel;
this.mLogSystemMemory = pLogSystemMemory;
this.mLogDalvikHeap = pLogDalvikHeap;
this.mLogDalvikMemoryInfo = pLogDalvikMemoryInfo;
this.mLogNativeHeap = pLogNativeHeap;
this.mLogNativeMemoryInfo = pLogNativeMemoryInfo;
}
// ===========================================================
// Getter & Setter
// ===========================================================
// ===========================================================
// Methods for/from SuperClass/Interfaces
// ===========================================================
@Override
public void onUpdate(final float pSecondsElapsed) {
this.mSecondsElapsed += pSecondsElapsed;
if (this.mSecondsElapsed > this.mAverageDuration) {
this.onHandleLogDurationElapsed();
this.mSecondsElapsed -= this.mAverageDuration;
}
}
@Override
public void reset() {
this.mSecondsElapsed = 0;
}
// ===========================================================
// Methods
// ===========================================================
protected void onHandleLogDurationElapsed() {
if (BuildConfig.DEBUG) {
/* Execute GC. */
System.gc();
try {
final StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("+------------------------------+---------------+-----------------+\n");
stringBuilder.append("| Memory Stat | Current | Change |\n");
stringBuilder.append("+------------------------------+---------------+-----------------+\n");
if (this.mLogSystemMemory) {
final long systemMemorySize = SystemUtils.getSystemMemorySize();
final long systemMemoryFreeSize = SystemUtils.getSystemMemoryFreeSize();
final long systemMemorySizeDiff = systemMemorySize - this.mPreviousSystemMemorySize;
final long systemMemoryFreeSizeDiff = systemMemoryFreeSize - this.mPreviousSystemMemoryFreeSize;
this.mPreviousSystemMemorySize = systemMemorySize;
this.mPreviousSystemMemoryFreeSize = systemMemoryFreeSize;
stringBuilder.append("| System memory size | " + MemoryLogger.formatRight(systemMemorySize, ' ', 10) + " kB | (" + MemoryLogger.formatRight(systemMemorySizeDiff, ' ', 10, true) + " kB) |\n");
stringBuilder.append("| System memory free size | " + MemoryLogger.formatRight(systemMemoryFreeSize, ' ', 10) + " kB | (" + MemoryLogger.formatRight(systemMemoryFreeSizeDiff, ' ', 10, true) + " kB) |\n");
stringBuilder.append("+------------------------------+---------------+-----------------+\n");
}
if (this.mLogDalvikHeap) {
final long dalvikHeapSize = SystemUtils.getDalvikHeapSize();
final long dalvikHeapFreeSize = SystemUtils.getDalvikHeapFreeSize();
final long dalvikHeapAllocatedSize = SystemUtils.getDalvikHeapAllocatedSize();
final long dalvikHeapSizeDiff = dalvikHeapSize - this.mPreviousDalvikHeapSize;
final long dalvikHeapFreeSizeDiff = dalvikHeapFreeSize - this.mPreviousDalvikHeapFreeSize;
final long dalvikHeapAllocatedSizeDiff = dalvikHeapAllocatedSize - this.mPreviousDalvikHeapAllocatedSize;
stringBuilder.append("| Dalvik memory size | " + MemoryLogger.formatRight(dalvikHeapSize, ' ', 10) + " kB | (" + MemoryLogger.formatRight(dalvikHeapSizeDiff, ' ', 10, true) + " kB) |\n");
stringBuilder.append("| Dalvik memory free size | " + MemoryLogger.formatRight(dalvikHeapFreeSize, ' ', 10) + " kB | (" + MemoryLogger.formatRight(dalvikHeapFreeSizeDiff, ' ', 10, true) + " kB) |\n");
stringBuilder.append("| Dalvik memory allocated size | " + MemoryLogger.formatRight(dalvikHeapAllocatedSize, ' ', 10) + " kB | (" + MemoryLogger.formatRight(dalvikHeapAllocatedSizeDiff, ' ', 10, true) + " kB) |\n");
stringBuilder.append("+------------------------------+---------------+-----------------+\n");
this.mPreviousDalvikHeapSize = dalvikHeapSize;
this.mPreviousDalvikHeapFreeSize = dalvikHeapFreeSize;
this.mPreviousDalvikHeapAllocatedSize = dalvikHeapAllocatedSize;
}
if (this.mLogDalvikMemoryInfo) {
final long dalvikProportionalSetSize = SystemUtils.getDalvikProportionalSetSize();
final long dalvikPrivateDirtyPages = SystemUtils.getDalvikPrivateDirtyPages();
final long dalvikSharedDirtyPages = SystemUtils.getDalvikSharedDirtyPages();
final long dalvikProportionalSetSizeDiff = dalvikProportionalSetSize - this.mPreviousDalvikProportionalSetSize;
final long dalvikPrivateDirtyPagesDiff = dalvikPrivateDirtyPages - this.mPreviousDalvikPrivateDirtyPages;
final long dalvikSharedDirtyPagesDiff = dalvikSharedDirtyPages - this.mPreviousDalvikSharedDirtyPages;
stringBuilder.append("| Dalvik proportional set size | " + MemoryLogger.formatRight(dalvikProportionalSetSize, ' ', 10) + " | (" + MemoryLogger.formatRight(dalvikProportionalSetSizeDiff, ' ', 10, true) + " ) |\n");
stringBuilder.append("| Dalvik private dirty pages | " + MemoryLogger.formatRight(dalvikPrivateDirtyPages, ' ', 10) + " | (" + MemoryLogger.formatRight(dalvikPrivateDirtyPagesDiff, ' ', 10, true) + " ) |\n");
stringBuilder.append("| Dalvik shared dirty pages | " + MemoryLogger.formatRight(dalvikSharedDirtyPages, ' ', 10) + " | (" + MemoryLogger.formatRight(dalvikSharedDirtyPagesDiff, ' ', 10, true) + " ) |\n");
stringBuilder.append("+------------------------------+---------------+-----------------+\n");
this.mPreviousDalvikProportionalSetSize = dalvikProportionalSetSize;
this.mPreviousDalvikPrivateDirtyPages = dalvikPrivateDirtyPages;
this.mPreviousDalvikSharedDirtyPages = dalvikSharedDirtyPages;
}
if (this.mLogNativeHeap) {
final long nativeHeapSize = SystemUtils.getNativeHeapSize();
final long nativeHeapFreeSize = SystemUtils.getNativeHeapFreeSize();
final long nativeHeapAllocatedSize = SystemUtils.getNativeHeapAllocatedSize();
final long nativeHeapSizeDiff = nativeHeapSize - this.mPreviousNativeHeapSize;
final long nativeHeapFreeSizeDiff = nativeHeapFreeSize - this.mPreviousNativeHeapFreeSize;
final long nativeHeapAllocatedSizeDiff = nativeHeapAllocatedSize - this.mPreviousNativeHeapAllocatedSize;
stringBuilder.append("| Native memory size | " + MemoryLogger.formatRight(nativeHeapSize, ' ', 10) + " kB | (" + MemoryLogger.formatRight(nativeHeapSizeDiff, ' ', 10, true) + " kB) |\n");
stringBuilder.append("| Native memory free size | " + MemoryLogger.formatRight(nativeHeapFreeSize, ' ', 10) + " kB | (" + MemoryLogger.formatRight(nativeHeapFreeSizeDiff, ' ', 10, true) + " kB) |\n");
stringBuilder.append("| Native memory allocated size | " + MemoryLogger.formatRight(nativeHeapAllocatedSize, ' ', 10) + " kB | (" + MemoryLogger.formatRight(nativeHeapAllocatedSizeDiff, ' ', 10, true) + " kB) |\n");
stringBuilder.append("+------------------------------+---------------+-----------------+\n");
this.mPreviousNativeHeapSize = nativeHeapSize;
this.mPreviousNativeHeapFreeSize = nativeHeapFreeSize;
this.mPreviousNativeHeapAllocatedSize = nativeHeapAllocatedSize;
}
if (this.mLogNativeMemoryInfo) {
final long nativeProportionalSetSize = SystemUtils.getNativeProportionalSetSize();
final long nativePrivateDirtyPages = SystemUtils.getNativePrivateDirtyPages();
final long nativeSharedDirtyPages = SystemUtils.getNativeSharedDirtyPages();
final long nativeProportionalSetSizeDiff = nativeProportionalSetSize - this.mPreviousNativeProportionalSetSize;
final long nativePrivateDirtyPagesDiff = nativePrivateDirtyPages - this.mPreviousNativePrivateDirtyPages;
final long nativeSharedDirtyPagesDiff = nativeSharedDirtyPages - this.mPreviousNativeSharedDirtyPages;
stringBuilder.append("| Native proportional set size | " + MemoryLogger.formatRight(nativeProportionalSetSize, ' ', 10) + " | (" + MemoryLogger.formatRight(nativeProportionalSetSizeDiff, ' ', 10, true) + " ) |\n");
stringBuilder.append("| Native private dirty pages | " + MemoryLogger.formatRight(nativePrivateDirtyPages, ' ', 10) + " | (" + MemoryLogger.formatRight(nativePrivateDirtyPagesDiff, ' ', 10, true) + " ) |\n");
stringBuilder.append("| Native shared dirty pages | " + MemoryLogger.formatRight(nativeSharedDirtyPages, ' ', 10) + " | (" + MemoryLogger.formatRight(nativeSharedDirtyPagesDiff, ' ', 10, true) + " ) |\n");
stringBuilder.append("+------------------------------+---------------+-----------------+\n");
this.mPreviousNativeProportionalSetSize = nativeProportionalSetSize;
this.mPreviousNativePrivateDirtyPages = nativePrivateDirtyPages;
this.mPreviousNativeSharedDirtyPages = nativeSharedDirtyPages;
}
Debug.log(this.mDebugLevel, stringBuilder.toString());
} catch (final SystemUtilsException e) {
Debug.e(e);
}
System.gc();
}
}
public static final CharSequence formatRight(final long pLong, final char pPadChar, final int pLength) {
return MemoryLogger.formatRight(pLong, pPadChar, pLength, false);
}
public static final CharSequence formatRight(final long pLong, final char pPadChar, final int pLength, final boolean pAddPositiveSign) {
if ((pLong > 0) && pAddPositiveSign) {
return TextUtils.padFront("+" + String.valueOf(pLong), pPadChar, pLength);
} else {
return TextUtils.padFront(String.valueOf(pLong), pPadChar, pLength);
}
}
// ===========================================================
// Inner and Anonymous Classes
// ===========================================================
}