Optimize some CodecCounter inefficiency.

1. Use ints rather than longs.
2. Remove some counters that dont seem hugely useful.
3. Replace use of volatile with explicit method calls that
   cause a memory barrier. This is a lot more efficient than
   using volatile because it can be invoked only once per
   doSomeWork.
This commit is contained in:
Oliver Woodman 2014-08-11 17:42:08 +01:00
parent 9a124120ff
commit 25a532656c
3 changed files with 25 additions and 44 deletions

View file

@ -17,54 +17,41 @@ package com.google.android.exoplayer;
/** /**
* Maintains codec event counts, for debugging purposes only. * Maintains codec event counts, for debugging purposes only.
* <p>
* Counters should be written from the playback thread only. Counters may be read from any thread.
* To ensure that the counter values are correctly reflected between threads, users of this class
* should invoke {@link #ensureUpdated()} prior to reading and after writing.
*/ */
public final class CodecCounters { public final class CodecCounters {
public volatile long codecInitCount; public int codecInitCount;
public volatile long codecReleaseCount; public int codecReleaseCount;
public volatile long outputFormatChangedCount; public int outputFormatChangedCount;
public volatile long outputBuffersChangedCount; public int outputBuffersChangedCount;
public volatile long queuedInputBufferCount; public int renderedOutputBufferCount;
public volatile long inputBufferWaitingForSampleCount; public int skippedOutputBufferCount;
public volatile long keyframeCount; public int droppedOutputBufferCount;
public volatile long queuedEndOfStreamCount;
public volatile long renderedOutputBufferCount;
public volatile long skippedOutputBufferCount;
public volatile long droppedOutputBufferCount;
public volatile long discardedSamplesCount;
/** /**
* Resets all counts to zero. * Should be invoked from the playback thread after the counters have been updated. Should also
* be invoked from any other thread that wishes to read the counters, before reading. These calls
* ensure that counter updates are made visible to the reading threads.
*/ */
public void zeroAllCounts() { public synchronized void ensureUpdated() {
codecInitCount = 0; // Do nothing. The use of synchronized ensures a memory barrier should another thread also
codecReleaseCount = 0; // call this method.
outputFormatChangedCount = 0;
outputBuffersChangedCount = 0;
queuedInputBufferCount = 0;
inputBufferWaitingForSampleCount = 0;
keyframeCount = 0;
queuedEndOfStreamCount = 0;
renderedOutputBufferCount = 0;
skippedOutputBufferCount = 0;
droppedOutputBufferCount = 0;
discardedSamplesCount = 0;
} }
public String getDebugString() { public String getDebugString() {
ensureUpdated();
StringBuilder builder = new StringBuilder(); StringBuilder builder = new StringBuilder();
builder.append("cic(").append(codecInitCount).append(")"); builder.append("cic(").append(codecInitCount).append(")");
builder.append("crc(").append(codecReleaseCount).append(")"); builder.append("crc(").append(codecReleaseCount).append(")");
builder.append("ofc(").append(outputFormatChangedCount).append(")"); builder.append("ofc(").append(outputFormatChangedCount).append(")");
builder.append("obc(").append(outputBuffersChangedCount).append(")"); builder.append("obc(").append(outputBuffersChangedCount).append(")");
builder.append("qib(").append(queuedInputBufferCount).append(")");
builder.append("wib(").append(inputBufferWaitingForSampleCount).append(")");
builder.append("kfc(").append(keyframeCount).append(")");
builder.append("qes(").append(queuedEndOfStreamCount).append(")");
builder.append("ren(").append(renderedOutputBufferCount).append(")"); builder.append("ren(").append(renderedOutputBufferCount).append(")");
builder.append("sob(").append(skippedOutputBufferCount).append(")"); builder.append("sob(").append(skippedOutputBufferCount).append(")");
builder.append("dob(").append(droppedOutputBufferCount).append(")"); builder.append("dob(").append(droppedOutputBufferCount).append(")");
builder.append("dsc(").append(discardedSamplesCount).append(")");
return builder.toString(); return builder.toString();
} }

View file

@ -60,7 +60,7 @@ import java.util.List;
private static final int IDLE_INTERVAL_MS = 1000; private static final int IDLE_INTERVAL_MS = 1000;
private final Handler handler; private final Handler handler;
private final HandlerThread internalPlayerThread; private final HandlerThread internalPlaybackThread;
private final Handler eventHandler; private final Handler eventHandler;
private final MediaClock mediaClock; private final MediaClock mediaClock;
private final boolean[] rendererEnabledFlags; private final boolean[] rendererEnabledFlags;
@ -100,7 +100,7 @@ import java.util.List;
mediaClock = new MediaClock(); mediaClock = new MediaClock();
enabledRenderers = new ArrayList<TrackRenderer>(rendererEnabledFlags.length); enabledRenderers = new ArrayList<TrackRenderer>(rendererEnabledFlags.length);
internalPlayerThread = new HandlerThread(getClass().getSimpleName() + ":Handler") { internalPlaybackThread = new HandlerThread(getClass().getSimpleName() + ":Handler") {
@Override @Override
public void run() { public void run() {
// Note: The documentation for Process.THREAD_PRIORITY_AUDIO that states "Applications can // Note: The documentation for Process.THREAD_PRIORITY_AUDIO that states "Applications can
@ -109,12 +109,12 @@ import java.util.List;
super.run(); super.run();
} }
}; };
internalPlayerThread.start(); internalPlaybackThread.start();
handler = new Handler(internalPlayerThread.getLooper(), this); handler = new Handler(internalPlaybackThread.getLooper(), this);
} }
public Looper getPlaybackLooper() { public Looper getPlaybackLooper() {
return internalPlayerThread.getLooper(); return internalPlaybackThread.getLooper();
} }
public int getCurrentPosition() { public int getCurrentPosition() {
@ -179,7 +179,7 @@ import java.util.List;
Thread.currentThread().interrupt(); Thread.currentThread().interrupt();
} }
} }
internalPlayerThread.quit(); internalPlaybackThread.quit();
} }
} }

View file

@ -382,6 +382,7 @@ public abstract class MediaCodecTrackRenderer extends TrackRenderer {
while (feedInputBuffer()) {} while (feedInputBuffer()) {}
} }
} }
codecCounters.ensureUpdated();
} catch (IOException e) { } catch (IOException e) {
throw new ExoPlaybackException(e); throw new ExoPlaybackException(e);
} }
@ -403,7 +404,6 @@ public abstract class MediaCodecTrackRenderer extends TrackRenderer {
if (!sampleHolder.decodeOnly) { if (!sampleHolder.decodeOnly) {
currentPositionUs = sampleHolder.timeUs; currentPositionUs = sampleHolder.timeUs;
} }
codecCounters.discardedSamplesCount++;
} else if (result == SampleSource.FORMAT_READ) { } else if (result == SampleSource.FORMAT_READ) {
onInputFormatChanged(formatHolder); onInputFormatChanged(formatHolder);
} }
@ -476,7 +476,6 @@ public abstract class MediaCodecTrackRenderer extends TrackRenderer {
} }
if (result == SampleSource.NOTHING_READ) { if (result == SampleSource.NOTHING_READ) {
codecCounters.inputBufferWaitingForSampleCount++;
return false; return false;
} }
if (result == SampleSource.DISCONTINUITY_READ) { if (result == SampleSource.DISCONTINUITY_READ) {
@ -505,7 +504,6 @@ public abstract class MediaCodecTrackRenderer extends TrackRenderer {
try { try {
codec.queueInputBuffer(inputIndex, 0, 0, 0, MediaCodec.BUFFER_FLAG_END_OF_STREAM); codec.queueInputBuffer(inputIndex, 0, 0, 0, MediaCodec.BUFFER_FLAG_END_OF_STREAM);
inputIndex = -1; inputIndex = -1;
codecCounters.queuedEndOfStreamCount++;
} catch (CryptoException e) { } catch (CryptoException e) {
notifyCryptoError(e); notifyCryptoError(e);
throw new ExoPlaybackException(e); throw new ExoPlaybackException(e);
@ -545,10 +543,6 @@ public abstract class MediaCodecTrackRenderer extends TrackRenderer {
} else { } else {
codec.queueInputBuffer(inputIndex, 0 , bufferSize, presentationTimeUs, 0); codec.queueInputBuffer(inputIndex, 0 , bufferSize, presentationTimeUs, 0);
} }
codecCounters.queuedInputBufferCount++;
if ((sampleHolder.flags & MediaExtractor.SAMPLE_FLAG_SYNC) != 0) {
codecCounters.keyframeCount++;
}
inputIndex = -1; inputIndex = -1;
codecReconfigurationState = RECONFIGURATION_STATE_NONE; codecReconfigurationState = RECONFIGURATION_STATE_NONE;
} catch (CryptoException e) { } catch (CryptoException e) {