From 85cce376cbeecb185ba485c69643bfabe72fe794 Mon Sep 17 00:00:00 2001 From: Mathias Agopian Date: Tue, 4 Jun 2013 21:50:31 -0700 Subject: [PATCH] Basic binary event-log helpers EventLog can be used from SurfaceFlinger to log jank statistics events to the binary event log. Change-Id: If0fbbe7d7111f10957697166d37fd0c3418109bb --- services/surfaceflinger/Android.mk | 2 + services/surfaceflinger/EventLog/EventLog.cpp | 128 ++++++++++++++++++ services/surfaceflinger/EventLog/EventLog.h | 83 ++++++++++++ .../EventLog/EventLogTags.logtags | 38 ++++++ 4 files changed, 251 insertions(+) create mode 100644 services/surfaceflinger/EventLog/EventLog.cpp create mode 100644 services/surfaceflinger/EventLog/EventLog.h create mode 100644 services/surfaceflinger/EventLog/EventLogTags.logtags diff --git a/services/surfaceflinger/Android.mk b/services/surfaceflinger/Android.mk index 71b235a1b..f2051dded 100644 --- a/services/surfaceflinger/Android.mk +++ b/services/surfaceflinger/Android.mk @@ -18,6 +18,8 @@ LOCAL_SRC_FILES:= \ DisplayHardware/HWComposer.cpp \ DisplayHardware/PowerHAL.cpp \ DisplayHardware/VirtualDisplaySurface.cpp \ + EventLog/EventLogTags.logtags \ + EventLog/EventLog.cpp LOCAL_CFLAGS:= -DLOG_TAG=\"SurfaceFlinger\" LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES diff --git a/services/surfaceflinger/EventLog/EventLog.cpp b/services/surfaceflinger/EventLog/EventLog.cpp new file mode 100644 index 000000000..815242beb --- /dev/null +++ b/services/surfaceflinger/EventLog/EventLog.cpp @@ -0,0 +1,128 @@ +/* + * Copyright 2013 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 +#include +#include +#include + +#include "EventLog.h" + +// --------------------------------------------------------------------------- +namespace android { +// --------------------------------------------------------------------------- + +ANDROID_SINGLETON_STATIC_INSTANCE(EventLog) + + +EventLog::EventLog() { +} + +void EventLog::doLogJank(const String8& window, int32_t value) { + EventLog::TagBuffer buffer(LOGTAG_SF_JANK); + buffer.startList(2); + buffer.writeString8(window); + buffer.writeInt32(value); + buffer.endList(); + buffer.log(); +} + +void EventLog::logJank(const String8& window, int32_t value) { + EventLog::getInstance().doLogJank(window, value); +} + +// --------------------------------------------------------------------------- + +EventLog::TagBuffer::TagBuffer(int32_t tag) + : mPos(0), mTag(tag), mOverflow(false) { +} + +void EventLog::TagBuffer::log() { + if (mOverflow) { + ALOGW("couldn't log to binary event log: overflow."); + } else if (android_bWriteLog(mTag, mStorage, mPos) < 0) { + ALOGE("couldn't log to EventLog: %s", strerror(errno)); + } + // purge the buffer + mPos = 0; + mOverflow = false; +} + +void EventLog::TagBuffer::startList(int8_t count) { + if (mOverflow) return; + const size_t needed = 1 + sizeof(count); + if (mPos + needed > STORAGE_MAX_SIZE) { + mOverflow = true; + return; + } + mStorage[mPos + 0] = EVENT_TYPE_LIST; + mStorage[mPos + 1] = count; + mPos += needed; +} + +void EventLog::TagBuffer::endList() { + if (mOverflow) return; + const size_t needed = 1; + if (mPos + needed > STORAGE_MAX_SIZE) { + mOverflow = true; + return; + } + mStorage[mPos + 0] = '\n'; + mPos += needed; +} + +void EventLog::TagBuffer::writeInt32(int32_t value) { + if (mOverflow) return; + const size_t needed = 1 + sizeof(value); + if (mPos + needed > STORAGE_MAX_SIZE) { + mOverflow = true; + return; + } + mStorage[mPos + 0] = EVENT_TYPE_INT; + memcpy(&mStorage[mPos + 1], &value, sizeof(value)); + mPos += needed; +} + +void EventLog::TagBuffer::writeInt64(int64_t value) { + if (mOverflow) return; + const size_t needed = 1 + sizeof(value); + if (mPos + needed > STORAGE_MAX_SIZE) { + mOverflow = true; + return; + } + mStorage[mPos + 0] = EVENT_TYPE_LONG; + memcpy(&mStorage[mPos + 1], &value, sizeof(value)); + mPos += needed; +} + +void EventLog::TagBuffer::writeString8(const String8& value) { + if (mOverflow) return; + const int32_t stringLen = value.length(); + const size_t needed = 1 + sizeof(int32_t) + stringLen; + if (mPos + needed > STORAGE_MAX_SIZE) { + mOverflow = true; + return; + } + mStorage[mPos + 0] = EVENT_TYPE_STRING; + memcpy(&mStorage[mPos + 1], &stringLen, sizeof(int32_t)); + memcpy(&mStorage[mPos + 5], value.string(), stringLen); + mPos += needed; +} + +// --------------------------------------------------------------------------- +}// namespace android + +// --------------------------------------------------------------------------- diff --git a/services/surfaceflinger/EventLog/EventLog.h b/services/surfaceflinger/EventLog/EventLog.h new file mode 100644 index 000000000..2f1cd9b3e --- /dev/null +++ b/services/surfaceflinger/EventLog/EventLog.h @@ -0,0 +1,83 @@ +/* + * Copyright 2013 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 +#include +#include + +#ifndef ANDROID_SF_EVENTLOG_H +#define ANDROID_SF_EVENTLOG_H + +// --------------------------------------------------------------------------- +namespace android { +// --------------------------------------------------------------------------- + +class String8; + +class EventLog : public Singleton { + +public: + static void logJank(const String8& window, int32_t value); + +protected: + EventLog(); + +private: + /* + * EventLogBuffer is a helper class to construct an in-memory event log + * tag. In this version the buffer is not dynamic, so write operation can + * fail if there is not enough space in the temporary buffer. + * Once constructed, the buffer can be logger by calling the log() + * method. + */ + + class TagBuffer { + enum { STORAGE_MAX_SIZE = 128 }; + int32_t mPos; + int32_t mTag; + bool mOverflow; + char mStorage[STORAGE_MAX_SIZE]; + public: + TagBuffer(int32_t tag); + + // starts list of items + void startList(int8_t count); + // terminates the list + void endList(); + // write a 32-bit integer + void writeInt32(int32_t value); + // write a 64-bit integer + void writeInt64(int64_t value); + // write a C string + void writeString8(const String8& value); + + // outputs the the buffer to the log + void log(); + }; + + friend class Singleton; + EventLog(const EventLog&); + EventLog& operator =(const EventLog&); + + enum { LOGTAG_SF_JANK = 60100 }; + void doLogJank(const String8& window, int32_t value); +}; + +// --------------------------------------------------------------------------- +}// namespace android +// --------------------------------------------------------------------------- + +#endif /* ANDROID_SF_EVENTLOG_H */ diff --git a/services/surfaceflinger/EventLog/EventLogTags.logtags b/services/surfaceflinger/EventLog/EventLogTags.logtags new file mode 100644 index 000000000..c83692f44 --- /dev/null +++ b/services/surfaceflinger/EventLog/EventLogTags.logtags @@ -0,0 +1,38 @@ +# The entries in this file map a sparse set of log tag numbers to tag names. +# This is installed on the device, in /system/etc, and parsed by logcat. +# +# Tag numbers are decimal integers, from 0 to 2^31. (Let's leave the +# negative values alone for now.) +# +# Tag names are one or more ASCII letters and numbers or underscores, i.e. +# "[A-Z][a-z][0-9]_". Do not include spaces or punctuation (the former +# impacts log readability, the latter makes regex searches more annoying). +# +# Tag numbers and names are separated by whitespace. Blank lines and lines +# starting with '#' are ignored. +# +# Optionally, after the tag names can be put a description for the value(s) +# of the tag. Description are in the format +# (|data type[|data unit]) +# Multiple values are separated by commas. +# +# The data type is a number from the following values: +# 1: int +# 2: long +# 3: string +# 4: list +# +# The data unit is a number taken from the following list: +# 1: Number of objects +# 2: Number of bytes +# 3: Number of milliseconds +# 4: Number of allocations +# 5: Id +# 6: Percent +# Default value for data of type int/long is 2 (bytes). + +# surfaceflinger +60100 sf_jank (window|3),(value|1) + +# NOTE - the range 1000000-2000000 is reserved for partners and others who +# want to define their own log tags without conflicting with the core platform.