Camera: Collect capture latency histograms
Add capture latency histograms to existing westworld metrics data.
Test: Camera CTS, and observe statsd output
Bug: 154159000
Change-Id: Id0ac5c29f29bdab5ac21f16fe33430f7a7456553
diff --git a/camera/CameraSessionStats.cpp b/camera/CameraSessionStats.cpp
index 818b4d0..28e037f 100644
--- a/camera/CameraSessionStats.cpp
+++ b/camera/CameraSessionStats.cpp
@@ -94,6 +94,24 @@
return err;
}
+ int histogramType = HISTOGRAM_TYPE_UNKNOWN;
+ if ((err = parcel->readInt32(&histogramType)) != OK) {
+ ALOGE("%s: Failed to read histogram type from parcel", __FUNCTION__);
+ return err;
+ }
+
+ std::vector<float> histogramBins;
+ if ((err = parcel->readFloatVector(&histogramBins)) != OK) {
+ ALOGE("%s: Failed to read histogram bins from parcel", __FUNCTION__);
+ return err;
+ }
+
+ std::vector<int64_t> histogramCounts;
+ if ((err = parcel->readInt64Vector(&histogramCounts)) != OK) {
+ ALOGE("%s: Failed to read histogram counts from parcel", __FUNCTION__);
+ return err;
+ }
+
mWidth = width;
mHeight = height;
mFormat = format;
@@ -104,6 +122,9 @@
mStartLatencyMs = startLatencyMs;
mMaxHalBuffers = maxHalBuffers;
mMaxAppBuffers = maxAppBuffers;
+ mHistogramType = histogramType;
+ mHistogramBins = std::move(histogramBins);
+ mHistogramCounts = std::move(histogramCounts);
return OK;
}
@@ -166,6 +187,21 @@
return err;
}
+ if ((err = parcel->writeInt32(mHistogramType)) != OK) {
+ ALOGE("%s: Failed to write histogram type", __FUNCTION__);
+ return err;
+ }
+
+ if ((err = parcel->writeFloatVector(mHistogramBins)) != OK) {
+ ALOGE("%s: Failed to write histogram bins!", __FUNCTION__);
+ return err;
+ }
+
+ if ((err = parcel->writeInt64Vector(mHistogramCounts)) != OK) {
+ ALOGE("%s: Failed to write histogram counts!", __FUNCTION__);
+ return err;
+ }
+
return OK;
}
diff --git a/camera/include/camera/CameraSessionStats.h b/camera/include/camera/CameraSessionStats.h
index 27a756f..c398aca 100644
--- a/camera/include/camera/CameraSessionStats.h
+++ b/camera/include/camera/CameraSessionStats.h
@@ -27,6 +27,11 @@
*/
class CameraStreamStats : public android::Parcelable {
public:
+ enum HistogramType {
+ HISTOGRAM_TYPE_UNKNOWN = 0,
+ HISTOGRAM_TYPE_CAPTURE_LATENCY = 1,
+ };
+
int mWidth;
int mHeight;
int mFormat;
@@ -45,15 +50,26 @@
int mMaxHalBuffers;
int mMaxAppBuffers;
+ // Histogram type. So far only capture latency histogram is supported.
+ int mHistogramType;
+ // The bounary values separating adjacent histogram bins.
+ // A vector of {h1, h2, h3} represents bins of [0, h1), [h1, h2), [h2, h3),
+ // and [h3, infinity)
+ std::vector<float> mHistogramBins;
+ // The counts for all histogram bins.
+ // size(mHistogramBins) + 1 = size(mHistogramCounts)
+ std::vector<int64_t> mHistogramCounts;
+
CameraStreamStats() :
mWidth(0), mHeight(0), mFormat(0), mDataSpace(0), mUsage(0),
mRequestCount(0), mErrorCount(0), mStartLatencyMs(0),
- mMaxHalBuffers(0), mMaxAppBuffers(0) {}
+ mMaxHalBuffers(0), mMaxAppBuffers(0), mHistogramType(HISTOGRAM_TYPE_UNKNOWN) {}
CameraStreamStats(int width, int height, int format, int dataSpace, int64_t usage,
int maxHalBuffers, int maxAppBuffers)
: mWidth(width), mHeight(height), mFormat(format), mDataSpace(dataSpace),
mUsage(usage), mRequestCount(0), mErrorCount(0), mStartLatencyMs(0),
- mMaxHalBuffers(maxHalBuffers), mMaxAppBuffers(maxAppBuffers) {}
+ mMaxHalBuffers(maxHalBuffers), mMaxAppBuffers(maxAppBuffers),
+ mHistogramType(HISTOGRAM_TYPE_UNKNOWN) {}
virtual status_t readFromParcel(const android::Parcel* parcel) override;
virtual status_t writeToParcel(android::Parcel* parcel) const override;
diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp
index 92c8e30..e80404b 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Device.cpp
@@ -2161,6 +2161,14 @@
streamStats[i].mRequestCount = stats->second.mRequestedFrameCount;
streamStats[i].mErrorCount = stats->second.mDroppedFrameCount;
streamStats[i].mStartLatencyMs = stats->second.mStartLatencyMs;
+ streamStats[i].mHistogramType =
+ hardware::CameraStreamStats::HISTOGRAM_TYPE_CAPTURE_LATENCY;
+ streamStats[i].mHistogramBins.assign(
+ stats->second.mCaptureLatencyBins.begin(),
+ stats->second.mCaptureLatencyBins.end());
+ streamStats[i].mHistogramCounts.assign(
+ stats->second.mCaptureLatencyHistogram.begin(),
+ stats->second.mCaptureLatencyHistogram.end());
}
}
listener->notifyIdle(requestCount, resultErrorCount, deviceError, streamStats);
diff --git a/services/camera/libcameraservice/utils/SessionStatsBuilder.cpp b/services/camera/libcameraservice/utils/SessionStatsBuilder.cpp
index 83965c4..7a7707c 100644
--- a/services/camera/libcameraservice/utils/SessionStatsBuilder.cpp
+++ b/services/camera/libcameraservice/utils/SessionStatsBuilder.cpp
@@ -18,12 +18,21 @@
#define ATRACE_TAG ATRACE_TAG_CAMERA
//#define LOG_NDEBUG 0
+#include <numeric>
+
+#include <inttypes.h>
#include <utils/Log.h>
#include "SessionStatsBuilder.h"
namespace android {
+// Bins for capture latency: [0, 100], [100, 200], [200, 300], ...
+// [1300, 2100], [2100, inf].
+// Capture latency is in the unit of millisecond.
+const std::array<int32_t, StreamStats::LATENCY_BIN_COUNT-1> StreamStats::mCaptureLatencyBins {
+ { 100, 200, 300, 400, 500, 700, 900, 1300, 2100 } };
+
status_t SessionStatsBuilder::addStream(int id) {
std::lock_guard<std::mutex> l(mLock);
StreamStats stats;
@@ -52,10 +61,14 @@
mCounterStopped = false;
mDeviceError = false;
for (auto& streamStats : mStatsMap) {
- streamStats.second.mRequestedFrameCount = 0;
- streamStats.second.mDroppedFrameCount = 0;
- streamStats.second.mCounterStopped = false;
- streamStats.second.mStartLatencyMs = 0;
+ StreamStats& streamStat = streamStats.second;
+ streamStat.mRequestedFrameCount = 0;
+ streamStat.mDroppedFrameCount = 0;
+ streamStat.mCounterStopped = false;
+ streamStat.mStartLatencyMs = 0;
+
+ std::fill(streamStat.mCaptureLatencyHistogram.begin(),
+ streamStat.mCaptureLatencyHistogram.end(), 0);
}
}
@@ -66,23 +79,28 @@
void SessionStatsBuilder::stopCounter(int id) {
std::lock_guard<std::mutex> l(mLock);
- mStatsMap[id].mCounterStopped = true;
+ StreamStats& streamStat = mStatsMap[id];
+ streamStat.mCounterStopped = true;
}
void SessionStatsBuilder::incCounter(int id, bool dropped, int32_t captureLatencyMs) {
std::lock_guard<std::mutex> l(mLock);
+
auto it = mStatsMap.find(id);
- if (it != mStatsMap.end()) {
- if (!it->second.mCounterStopped) {
- it->second.mRequestedFrameCount++;
- if (dropped) {
- it->second.mDroppedFrameCount++;
- } else if (it->second.mRequestedFrameCount == 1) {
- // The capture latency for the first request.
- it->second.mStartLatencyMs = captureLatencyMs;
- }
- }
+ if (it == mStatsMap.end()) return;
+
+ StreamStats& streamStat = it->second;
+ if (streamStat.mCounterStopped) return;
+
+ streamStat.mRequestedFrameCount++;
+ if (dropped) {
+ streamStat.mDroppedFrameCount++;
+ } else if (streamStat.mRequestedFrameCount - streamStat.mDroppedFrameCount == 1) {
+ // The capture latency for the first request.
+ streamStat.mStartLatencyMs = captureLatencyMs;
}
+
+ streamStat.updateLatencyHistogram(captureLatencyMs);
}
void SessionStatsBuilder::stopCounter() {
@@ -95,10 +113,10 @@
void SessionStatsBuilder::incResultCounter(bool dropped) {
std::lock_guard<std::mutex> l(mLock);
- if (!mCounterStopped) {
- mRequestCount ++;
- if (dropped) mErrorResultCount++;
- }
+ if (mCounterStopped) return;
+
+ mRequestCount++;
+ if (dropped) mErrorResultCount++;
}
void SessionStatsBuilder::onDeviceError() {
@@ -106,4 +124,18 @@
mDeviceError = true;
}
+void StreamStats::updateLatencyHistogram(int32_t latencyMs) {
+ size_t i;
+ for (i = 0; i < mCaptureLatencyBins.size(); i++) {
+ if (latencyMs < mCaptureLatencyBins[i]) {
+ mCaptureLatencyHistogram[i] ++;
+ break;
+ }
+ }
+
+ if (i == mCaptureLatencyBins.size()) {
+ mCaptureLatencyHistogram[i]++;
+ }
+}
+
}; // namespace android
diff --git a/services/camera/libcameraservice/utils/SessionStatsBuilder.h b/services/camera/libcameraservice/utils/SessionStatsBuilder.h
index 7943637..c23abb6 100644
--- a/services/camera/libcameraservice/utils/SessionStatsBuilder.h
+++ b/services/camera/libcameraservice/utils/SessionStatsBuilder.h
@@ -19,22 +19,38 @@
#include <utils/Errors.h>
-#include <mutex>
+#include <array>
#include <map>
+#include <mutex>
namespace android {
// Helper class to build stream stats
struct StreamStats {
+ // Fields for buffer drop
int64_t mRequestedFrameCount;
int64_t mDroppedFrameCount;
bool mCounterStopped;
+
+ // Fields for stream startup latency
int32_t mStartLatencyMs;
+ // Fields for capture latency measurement
+ const static int LATENCY_BIN_COUNT = 10;
+ // Boundary values separating between adjacent bins, excluding 0 and
+ // infinity.
+ const static std::array<int32_t, LATENCY_BIN_COUNT-1> mCaptureLatencyBins;
+ // Counter values for all histogram bins. One more entry than mCaptureLatencyBins.
+ std::array<int64_t, LATENCY_BIN_COUNT> mCaptureLatencyHistogram;
+
StreamStats() : mRequestedFrameCount(0),
mDroppedFrameCount(0),
mCounterStopped(false),
- mStartLatencyMs(0) {}
+ mStartLatencyMs(0),
+ mCaptureLatencyHistogram{}
+ {}
+
+ void updateLatencyHistogram(int32_t latencyMs);
};
// Helper class to build session stats