auto import from //depot/cupcake/@135843
diff --git a/libs/utils/TimerProbe.cpp b/libs/utils/TimerProbe.cpp
new file mode 100644
index 0000000..835480d
--- /dev/null
+++ b/libs/utils/TimerProbe.cpp
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2008 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 <utils/TimerProbe.h>
+
+#if ENABLE_TIMER_PROBE
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "time"
+
+namespace android {
+
+Vector<TimerProbe::Bucket> TimerProbe::gBuckets;
+TimerProbe* TimerProbe::gExecuteChain;
+int TimerProbe::gIndent;
+timespec TimerProbe::gRealBase;
+
+TimerProbe::TimerProbe(const char tag[], int* slot) : mTag(tag)
+{
+ mNext = gExecuteChain;
+ gExecuteChain = this;
+ mIndent = gIndent;
+ gIndent += 1;
+ if (mIndent > 0) {
+ if (*slot == 0) {
+ int count = gBuckets.add();
+ *slot = count;
+ Bucket& bucket = gBuckets.editItemAt(count);
+ memset(&bucket, 0, sizeof(Bucket));
+ bucket.mTag = tag;
+ bucket.mSlotPtr = slot;
+ bucket.mIndent = mIndent;
+ }
+ mBucket = *slot;
+ }
+ clock_gettime(CLOCK_REALTIME, &mRealStart);
+ if (gRealBase.tv_sec == 0)
+ gRealBase = mRealStart;
+ clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &mPStart);
+ clock_gettime(CLOCK_THREAD_CPUTIME_ID, &mTStart);
+}
+
+void TimerProbe::end()
+{
+ timespec realEnd, pEnd, tEnd;
+ clock_gettime(CLOCK_REALTIME, &realEnd);
+ clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &pEnd);
+ clock_gettime(CLOCK_THREAD_CPUTIME_ID, &tEnd);
+ print(realEnd, pEnd, tEnd);
+ mTag = NULL;
+}
+
+TimerProbe::~TimerProbe()
+{
+ if (mTag != NULL)
+ end();
+ gExecuteChain = mNext;
+ gIndent--;
+}
+
+
+uint32_t TimerProbe::ElapsedTime(const timespec& start, const timespec& end)
+{
+ int sec = end.tv_sec - start.tv_sec;
+ int nsec = end.tv_nsec - start.tv_nsec;
+ if (nsec < 0) {
+ sec--;
+ nsec += 1000000000;
+ }
+ return sec * 1000000 + nsec / 1000;
+}
+
+void TimerProbe::print(const timespec& r, const timespec& p,
+ const timespec& t) const
+{
+ uint32_t es = ElapsedTime(gRealBase, mRealStart);
+ uint32_t er = ElapsedTime(mRealStart, r);
+ uint32_t ep = ElapsedTime(mPStart, p);
+ uint32_t et = ElapsedTime(mTStart, t);
+ if (mIndent > 0) {
+ Bucket& bucket = gBuckets.editItemAt(mBucket);
+ if (bucket.mStart == 0)
+ bucket.mStart = es;
+ bucket.mReal += er;
+ bucket.mProcess += ep;
+ bucket.mThread += et;
+ bucket.mCount++;
+ return;
+ }
+ int index = 0;
+ int buckets = gBuckets.size();
+ int count = 1;
+ const char* tag = mTag;
+ int indent = mIndent;
+ do {
+ LOGD("%-30.30s: (%3d) %-5.*s time=%-10.3f real=%7dus process=%7dus (%3d%%) thread=%7dus (%3d%%)\n",
+ tag, count, indent > 5 ? 5 : indent, "+++++", es / 1000000.0,
+ er, ep, ep * 100 / er, et, et * 100 / er);
+ if (index >= buckets)
+ break;
+ Bucket& bucket = gBuckets.editItemAt(index);
+ count = bucket.mCount;
+ es = bucket.mStart;
+ er = bucket.mReal;
+ ep = bucket.mProcess;
+ et = bucket.mThread;
+ tag = bucket.mTag;
+ indent = bucket.mIndent;
+ *bucket.mSlotPtr = 0;
+ } while (++index); // always true
+ gBuckets.clear();
+}
+
+}; // namespace android
+
+#endif