Adding render stats APIs to UiAutomation (framework native).

bug:12927198

Change-Id: Ibb1c07f7d89e11281e5c1f27f412a29ac6f9c4ab
This commit is contained in:
Svetoslav 2014-03-20 10:28:31 -07:00
parent f74865eb52
commit d85084b2b6
19 changed files with 384 additions and 21 deletions

View File

@ -22,9 +22,12 @@
#include <utils/RefBase.h>
#include <utils/Errors.h>
#include <utils/Timers.h>
#include <utils/Vector.h>
#include <binder/IInterface.h>
#include <ui/FrameStats.h>
#include <ui/PixelFormat.h>
#include <gui/IGraphicBufferAlloc.h>
@ -122,6 +125,19 @@ public:
uint32_t reqWidth, uint32_t reqHeight,
uint32_t minLayerZ, uint32_t maxLayerZ,
bool useIdentityTransform) = 0;
/* Clears the frame statistics for animations.
*
* Requires the ACCESS_SURFACE_FLINGER permission.
*/
virtual status_t clearAnimationFrameStats() = 0;
/* Gets the frame statistics for animations.
*
* Requires the ACCESS_SURFACE_FLINGER permission.
*/
virtual status_t getAnimationFrameStats(FrameStats* outStats) const = 0;
};
// ----------------------------------------------------------------------------
@ -145,6 +161,8 @@ public:
GET_DISPLAY_INFO,
CONNECT_DISPLAY,
CAPTURE_SCREEN,
CLEAR_ANIMATION_FRAME_STATS,
GET_ANIMATION_FRAME_STATS
};
virtual status_t onTransact(uint32_t code, const Parcel& data,

View File

@ -25,6 +25,7 @@
#include <binder/IInterface.h>
#include <ui/FrameStats.h>
#include <ui/PixelFormat.h>
namespace android {
@ -65,6 +66,16 @@ public:
* Requires ACCESS_SURFACE_FLINGER permission
*/
virtual status_t destroySurface(const sp<IBinder>& handle) = 0;
/*
* Requires ACCESS_SURFACE_FLINGER permission
*/
virtual status_t clearLayerFrameStats(const sp<IBinder>& handle) const = 0;
/*
* Requires ACCESS_SURFACE_FLINGER permission
*/
virtual status_t getLayerFrameStats(const sp<IBinder>& handle, FrameStats* outStats) const = 0;
};
// ----------------------------------------------------------------------------

View File

@ -28,6 +28,7 @@
#include <utils/SortedVector.h>
#include <utils/threads.h>
#include <ui/FrameStats.h>
#include <ui/PixelFormat.h>
#include <gui/CpuConsumer.h>
@ -125,6 +126,12 @@ public:
status_t setLayerStack(const sp<IBinder>& id, uint32_t layerStack);
status_t destroySurface(const sp<IBinder>& id);
status_t clearLayerFrameStats(const sp<IBinder>& token) const;
status_t getLayerFrameStats(const sp<IBinder>& token, FrameStats* outStats) const;
static status_t clearAnimationFrameStats();
static status_t getAnimationFrameStats(FrameStats* outStats);
static void setDisplaySurface(const sp<IBinder>& token,
const sp<IGraphicBufferProducer>& bufferProducer);
static void setDisplayLayerStack(const sp<IBinder>& token,

View File

@ -24,6 +24,7 @@
#include <utils/RefBase.h>
#include <utils/threads.h>
#include <ui/FrameStats.h>
#include <ui/PixelFormat.h>
#include <ui/Region.h>
@ -73,6 +74,9 @@ public:
sp<Surface> getSurface() const;
status_t clearLayerFrameStats() const;
status_t getLayerFrameStats(FrameStats* outStats) const;
private:
// can't be copied
SurfaceControl& operator = (SurfaceControl& rhs);

63
include/ui/FrameStats.h Normal file
View File

@ -0,0 +1,63 @@
/*
* Copyright (C) 2014 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.
*/
#ifndef ANDROID_UI_FRAME_STATS_H
#define ANDROID_UI_FRAME_STATS_H
#include <utils/Flattenable.h>
#include <utils/Timers.h>
#include <utils/Vector.h>
namespace android {
class FrameStats : public LightFlattenable<FrameStats> {
public:
/*
* Approximate refresh time, in nanoseconds.
*/
nsecs_t refreshPeriodNano;
/*
* The times in nanoseconds for when the frame contents were posted by the producer (e.g.
* the application). They are either explicitly set or defaulted to the time when
* Surface::queueBuffer() was called.
*/
Vector<nsecs_t> desiredPresentTimesNano;
/*
* The times in milliseconds for when the frame contents were presented on the screen.
*/
Vector<nsecs_t> actualPresentTimesNano;
/*
* The times in nanoseconds for when the frame contents were ready to be presented. Note that
* a frame can be posted and still it contents being rendered asynchronously in GL. In such a
* case these are the times when the frame contents were completely rendered (i.e. their fences
* signaled).
*/
Vector<nsecs_t> frameReadyTimesNano;
// LightFlattenable
bool isFixedSize() const;
size_t getFlattenedSize() const;
status_t flatten(void* buffer, size_t size) const;
status_t unflatten(void const* buffer, size_t size);
};
}; // namespace android
#endif // ANDROID_UI_FRAME_STATS_H

View File

@ -229,6 +229,21 @@ public:
memcpy(info, reply.readInplace(sizeof(DisplayInfo)), sizeof(DisplayInfo));
return reply.readInt32();
}
virtual status_t clearAnimationFrameStats() {
Parcel data, reply;
data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
remote()->transact(BnSurfaceComposer::CLEAR_ANIMATION_FRAME_STATS, data, &reply);
return reply.readInt32();
}
virtual status_t getAnimationFrameStats(FrameStats* outStats) const {
Parcel data, reply;
data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
remote()->transact(BnSurfaceComposer::GET_ANIMATION_FRAME_STATS, data, &reply);
reply.read(*outStats);
return reply.readInt32();
}
};
IMPLEMENT_META_INTERFACE(SurfaceComposer, "android.ui.ISurfaceComposer");
@ -351,6 +366,20 @@ status_t BnSurfaceComposer::onTransact(
reply->writeInt32(result);
return NO_ERROR;
}
case CLEAR_ANIMATION_FRAME_STATS: {
CHECK_INTERFACE(ISurfaceComposer, data, reply);
status_t result = clearAnimationFrameStats();
reply->writeInt32(result);
return NO_ERROR;
}
case GET_ANIMATION_FRAME_STATS: {
CHECK_INTERFACE(ISurfaceComposer, data, reply);
FrameStats stats;
status_t result = getAnimationFrameStats(&stats);
reply->write(stats);
reply->writeInt32(result);
return NO_ERROR;
}
default: {
return BBinder::onTransact(code, data, reply, flags);
}

View File

@ -39,7 +39,9 @@ namespace android {
enum {
CREATE_SURFACE = IBinder::FIRST_CALL_TRANSACTION,
DESTROY_SURFACE
DESTROY_SURFACE,
CLEAR_LAYER_FRAME_STATS,
GET_LAYER_FRAME_STATS
};
class BpSurfaceComposerClient : public BpInterface<ISurfaceComposerClient>
@ -73,6 +75,23 @@ public:
remote()->transact(DESTROY_SURFACE, data, &reply);
return reply.readInt32();
}
virtual status_t clearLayerFrameStats(const sp<IBinder>& handle) const {
Parcel data, reply;
data.writeInterfaceToken(ISurfaceComposerClient::getInterfaceDescriptor());
data.writeStrongBinder(handle);
remote()->transact(CLEAR_LAYER_FRAME_STATS, data, &reply);
return reply.readInt32();
}
virtual status_t getLayerFrameStats(const sp<IBinder>& handle, FrameStats* outStats) const {
Parcel data, reply;
data.writeInterfaceToken(ISurfaceComposerClient::getInterfaceDescriptor());
data.writeStrongBinder(handle);
remote()->transact(GET_LAYER_FRAME_STATS, data, &reply);
reply.read(*outStats);
return reply.readInt32();
}
};
IMPLEMENT_META_INTERFACE(SurfaceComposerClient, "android.ui.ISurfaceComposerClient");
@ -101,7 +120,23 @@ status_t BnSurfaceComposerClient::onTransact(
} break;
case DESTROY_SURFACE: {
CHECK_INTERFACE(ISurfaceComposerClient, data, reply);
reply->writeInt32( destroySurface( data.readStrongBinder() ) );
reply->writeInt32(destroySurface( data.readStrongBinder() ) );
return NO_ERROR;
} break;
case CLEAR_LAYER_FRAME_STATS: {
CHECK_INTERFACE(ISurfaceComposerClient, data, reply);
sp<IBinder> handle = data.readStrongBinder();
status_t result = clearLayerFrameStats(handle);
reply->writeInt32(result);
return NO_ERROR;
} break;
case GET_LAYER_FRAME_STATS: {
CHECK_INTERFACE(ISurfaceComposerClient, data, reply);
sp<IBinder> handle = data.readStrongBinder();
FrameStats stats;
status_t result = getLayerFrameStats(handle, &stats);
reply->write(stats);
reply->writeInt32(result);
return NO_ERROR;
} break;
default:

View File

@ -515,6 +515,21 @@ status_t SurfaceComposerClient::destroySurface(const sp<IBinder>& sid) {
return err;
}
status_t SurfaceComposerClient::clearLayerFrameStats(const sp<IBinder>& token) const {
if (mStatus != NO_ERROR) {
return mStatus;
}
return mClient->clearLayerFrameStats(token);
}
status_t SurfaceComposerClient::getLayerFrameStats(const sp<IBinder>& token,
FrameStats* outStats) const {
if (mStatus != NO_ERROR) {
return mStatus;
}
return mClient->getLayerFrameStats(token, outStats);
}
inline Composer& SurfaceComposerClient::getComposer() {
return mComposer;
}
@ -622,6 +637,14 @@ void SurfaceComposerClient::unblankDisplay(const sp<IBinder>& token) {
ComposerService::getComposerService()->unblank(token);
}
status_t SurfaceComposerClient::clearAnimationFrameStats() {
return ComposerService::getComposerService()->clearAnimationFrameStats();
}
status_t SurfaceComposerClient::getAnimationFrameStats(FrameStats* outStats) {
return ComposerService::getComposerService()->getAnimationFrameStats(outStats);
}
// ----------------------------------------------------------------------------
status_t ScreenshotClient::capture(

View File

@ -156,6 +156,20 @@ status_t SurfaceControl::setCrop(const Rect& crop) {
return client->setCrop(mHandle, crop);
}
status_t SurfaceControl::clearLayerFrameStats() const {
status_t err = validate();
if (err < 0) return err;
const sp<SurfaceComposerClient>& client(mClient);
return client->clearLayerFrameStats(mHandle);
}
status_t SurfaceControl::getLayerFrameStats(FrameStats* outStats) const {
status_t err = validate();
if (err < 0) return err;
const sp<SurfaceComposerClient>& client(mClient);
return client->getLayerFrameStats(mHandle, outStats);
}
status_t SurfaceControl::validate() const
{
if (mHandle==0 || mClient==0) {

View File

@ -18,6 +18,7 @@ include $(CLEAR_VARS)
LOCAL_SRC_FILES:= \
Fence.cpp \
FramebufferNativeWindow.cpp \
FrameStats.cpp \
GraphicBuffer.cpp \
GraphicBufferAllocator.cpp \
GraphicBufferMapper.cpp \

84
libs/ui/FrameStats.cpp Normal file
View File

@ -0,0 +1,84 @@
/*
* Copyright (C) 2014 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.
*/
#include <ui/FrameStats.h>
namespace android {
bool FrameStats::isFixedSize() const {
return false;
}
size_t FrameStats::getFlattenedSize() const {
const size_t timestampSize = sizeof(nsecs_t);
size_t size = timestampSize;
size += 3 * desiredPresentTimesNano.size() * timestampSize;
return size;
}
status_t FrameStats::flatten(void* buffer, size_t size) const {
if (size < getFlattenedSize()) {
return NO_MEMORY;
}
nsecs_t* timestamps = reinterpret_cast<nsecs_t*>(buffer);
const size_t timestampSize = sizeof(nsecs_t);
size_t frameCount = desiredPresentTimesNano.size();
memcpy(timestamps, &refreshPeriodNano, timestampSize);
timestamps += 1;
memcpy(timestamps, desiredPresentTimesNano.array(), frameCount * timestampSize);
timestamps += frameCount;
memcpy(timestamps, actualPresentTimesNano.array(), frameCount * timestampSize);
timestamps += frameCount;
memcpy(timestamps, frameReadyTimesNano.array(), frameCount * timestampSize);
return NO_ERROR;
}
status_t FrameStats::unflatten(void const* buffer, size_t size) {
const size_t timestampSize = sizeof(nsecs_t);
if (size < timestampSize) {
return NO_MEMORY;
}
nsecs_t const* timestamps = reinterpret_cast<nsecs_t const*>(buffer);
size_t frameCount = (size - timestampSize) / (3 * timestampSize);
memcpy(&refreshPeriodNano, timestamps, timestampSize);
timestamps += 1;
desiredPresentTimesNano.resize(frameCount);
memcpy(desiredPresentTimesNano.editArray(), timestamps, frameCount * timestampSize);
timestamps += frameCount;
actualPresentTimesNano.resize(frameCount);
memcpy(actualPresentTimesNano.editArray(), timestamps, frameCount * timestampSize);
timestamps += frameCount;
frameReadyTimesNano.resize(frameCount);
memcpy(frameReadyTimesNano.editArray(), timestamps, frameCount * timestampSize);
return NO_ERROR;
}
} // namespace android

View File

@ -155,5 +155,23 @@ status_t Client::destroySurface(const sp<IBinder>& handle) {
return mFlinger->onLayerRemoved(this, handle);
}
status_t Client::clearLayerFrameStats(const sp<IBinder>& handle) const {
sp<Layer> layer = getLayerUser(handle);
if (layer == NULL) {
return NAME_NOT_FOUND;
}
layer->clearFrameStats();
return NO_ERROR;
}
status_t Client::getLayerFrameStats(const sp<IBinder>& handle, FrameStats* outStats) const {
sp<Layer> layer = getLayerUser(handle);
if (layer == NULL) {
return NAME_NOT_FOUND;
}
layer->getFrameStats(outStats);
return NO_ERROR;
}
// ---------------------------------------------------------------------------
}; // namespace android

View File

@ -60,6 +60,10 @@ private:
virtual status_t destroySurface(const sp<IBinder>& handle);
virtual status_t clearLayerFrameStats(const sp<IBinder>& handle) const;
virtual status_t getLayerFrameStats(const sp<IBinder>& handle, FrameStats* outStats) const;
virtual status_t onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags);

View File

@ -22,6 +22,7 @@
#include <cutils/log.h>
#include <ui/Fence.h>
#include <ui/FrameStats.h>
#include <utils/String8.h>
@ -100,7 +101,7 @@ void FrameTracker::advanceFrame() {
processFencesLocked();
}
void FrameTracker::clear() {
void FrameTracker::clearStats() {
Mutex::Autolock lock(mMutex);
for (size_t i = 0; i < NUM_FRAME_RECORDS; i++) {
mFrameRecords[i].desiredPresentTime = 0;
@ -115,6 +116,32 @@ void FrameTracker::clear() {
mFrameRecords[mOffset].actualPresentTime = INT64_MAX;
}
void FrameTracker::getStats(FrameStats* outStats) const {
Mutex::Autolock lock(mMutex);
processFencesLocked();
outStats->refreshPeriodNano = mDisplayPeriod;
const size_t offset = mOffset;
for (size_t i = 1; i < NUM_FRAME_RECORDS; i++) {
const size_t index = (offset + i) % NUM_FRAME_RECORDS;
// Skip frame records with no data (if buffer not yet full).
if (mFrameRecords[index].desiredPresentTime == 0) {
continue;
}
nsecs_t desiredPresentTimeNano = mFrameRecords[index].desiredPresentTime;
outStats->desiredPresentTimesNano.push_back(desiredPresentTimeNano);
nsecs_t actualPresentTimeNano = mFrameRecords[index].actualPresentTime;
outStats->actualPresentTimesNano.push_back(actualPresentTimeNano);
nsecs_t frameReadyTimeNano = mFrameRecords[index].frameReadyTime;
outStats->frameReadyTimesNano.push_back(frameReadyTimeNano);
}
}
void FrameTracker::logAndResetStats(const String8& name) {
Mutex::Autolock lock(mMutex);
logStatsLocked(name);
@ -206,7 +233,7 @@ bool FrameTracker::isFrameValidLocked(size_t idx) const {
mFrameRecords[idx].actualPresentTime < INT64_MAX;
}
void FrameTracker::dump(String8& result) const {
void FrameTracker::dumpStats(String8& result) const {
Mutex::Autolock lock(mMutex);
processFencesLocked();

View File

@ -78,15 +78,18 @@ public:
// advanceFrame advances the frame tracker to the next frame.
void advanceFrame();
// clear resets all the tracked frame data to zero.
void clear();
// clearStats clears the tracked frame stats.
void clearStats();
// getStats gets the tracked frame stats.
void getStats(FrameStats* outStats) const;
// logAndResetStats dumps the current statistics to the binary event log
// and then resets the accumulated statistics to their initial values.
void logAndResetStats(const String8& name);
// dump appends the current frame display time history to the result string.
void dump(String8& result) const;
// dumpStats dump appends the current frame display time history to the result string.
void dumpStats(String8& result) const;
private:
struct FrameRecord {

View File

@ -1244,18 +1244,22 @@ void Layer::dump(String8& result, Colorizer& colorizer) const
}
}
void Layer::dumpStats(String8& result) const {
mFrameTracker.dump(result);
void Layer::dumpFrameStats(String8& result) const {
mFrameTracker.dumpStats(result);
}
void Layer::clearStats() {
mFrameTracker.clear();
void Layer::clearFrameStats() {
mFrameTracker.clearStats();
}
void Layer::logFrameStats() {
mFrameTracker.logAndResetStats(mName);
}
void Layer::getFrameStats(FrameStats* outStats) const {
mFrameTracker.getStats(outStats);
}
// ---------------------------------------------------------------------------
Layer::LayerCleaner::LayerCleaner(const sp<SurfaceFlinger>& flinger,

View File

@ -27,6 +27,7 @@
#include <utils/String8.h>
#include <utils/Timers.h>
#include <ui/FrameStats.h>
#include <ui/GraphicBuffer.h>
#include <ui/PixelFormat.h>
#include <ui/Region.h>
@ -288,9 +289,10 @@ public:
/* always call base class first */
void dump(String8& result, Colorizer& colorizer) const;
void dumpStats(String8& result) const;
void clearStats();
void dumpFrameStats(String8& result) const;
void clearFrameStats();
void logFrameStats();
void getFrameStats(FrameStats* outStats) const;
protected:
// constant

View File

@ -574,6 +574,18 @@ status_t SurfaceFlinger::getDisplayInfo(const sp<IBinder>& display, DisplayInfo*
return NO_ERROR;
}
status_t SurfaceFlinger::clearAnimationFrameStats() {
Mutex::Autolock _l(mStateLock);
mAnimFrameTracker.clearStats();
return NO_ERROR;
}
status_t SurfaceFlinger::getAnimationFrameStats(FrameStats* outStats) const {
Mutex::Autolock _l(mStateLock);
mAnimFrameTracker.getStats(outStats);
return NO_ERROR;
}
// ----------------------------------------------------------------------------
sp<IDisplayEventConnection> SurfaceFlinger::createDisplayEventConnection() {
@ -2255,14 +2267,14 @@ void SurfaceFlinger::dumpStatsLocked(const Vector<String16>& args, size_t& index
result.appendFormat("%" PRId64 "\n", period);
if (name.isEmpty()) {
mAnimFrameTracker.dump(result);
mAnimFrameTracker.dumpStats(result);
} else {
const LayerVector& currentLayers = mCurrentState.layersSortedByZ;
const size_t count = currentLayers.size();
for (size_t i=0 ; i<count ; i++) {
const sp<Layer>& layer(currentLayers[i]);
if (name == layer->getName()) {
layer->dumpStats(result);
layer->dumpFrameStats(result);
}
}
}
@ -2282,11 +2294,11 @@ void SurfaceFlinger::clearStatsLocked(const Vector<String16>& args, size_t& inde
for (size_t i=0 ; i<count ; i++) {
const sp<Layer>& layer(currentLayers[i]);
if (name.isEmpty() || (name == layer->getName())) {
layer->clearStats();
layer->clearFrameStats();
}
}
mAnimFrameTracker.clear();
mAnimFrameTracker.clearStats();
}
// This should only be called from the main thread. Otherwise it would need
@ -2500,6 +2512,8 @@ status_t SurfaceFlinger::onTransact(
case BOOT_FINISHED:
case BLANK:
case UNBLANK:
case CLEAR_ANIMATION_FRAME_STATS:
case GET_ANIMATION_FRAME_STATS:
{
// codes that require permission check
IPCThreadState* ipc = IPCThreadState::self();

View File

@ -210,6 +210,8 @@ private:
// called when screen is turning back on
virtual void unblank(const sp<IBinder>& display);
virtual status_t getDisplayInfo(const sp<IBinder>& display, DisplayInfo* info);
virtual status_t clearAnimationFrameStats();
virtual status_t getAnimationFrameStats(FrameStats* outStats) const;
/* ------------------------------------------------------------------------
* DeathRecipient interface