blob: 835480d36647c4f73eba74cd43a9216a69e2e077 [file] [log] [blame]
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -07001/*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <utils/TimerProbe.h>
18
19#if ENABLE_TIMER_PROBE
20
21#ifdef LOG_TAG
22#undef LOG_TAG
23#endif
24#define LOG_TAG "time"
25
26namespace android {
27
28Vector<TimerProbe::Bucket> TimerProbe::gBuckets;
29TimerProbe* TimerProbe::gExecuteChain;
30int TimerProbe::gIndent;
31timespec TimerProbe::gRealBase;
32
33TimerProbe::TimerProbe(const char tag[], int* slot) : mTag(tag)
34{
35 mNext = gExecuteChain;
36 gExecuteChain = this;
37 mIndent = gIndent;
38 gIndent += 1;
39 if (mIndent > 0) {
40 if (*slot == 0) {
41 int count = gBuckets.add();
42 *slot = count;
43 Bucket& bucket = gBuckets.editItemAt(count);
44 memset(&bucket, 0, sizeof(Bucket));
45 bucket.mTag = tag;
46 bucket.mSlotPtr = slot;
47 bucket.mIndent = mIndent;
48 }
49 mBucket = *slot;
50 }
51 clock_gettime(CLOCK_REALTIME, &mRealStart);
52 if (gRealBase.tv_sec == 0)
53 gRealBase = mRealStart;
54 clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &mPStart);
55 clock_gettime(CLOCK_THREAD_CPUTIME_ID, &mTStart);
56}
57
58void TimerProbe::end()
59{
60 timespec realEnd, pEnd, tEnd;
61 clock_gettime(CLOCK_REALTIME, &realEnd);
62 clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &pEnd);
63 clock_gettime(CLOCK_THREAD_CPUTIME_ID, &tEnd);
64 print(realEnd, pEnd, tEnd);
65 mTag = NULL;
66}
67
68TimerProbe::~TimerProbe()
69{
70 if (mTag != NULL)
71 end();
72 gExecuteChain = mNext;
73 gIndent--;
74}
75
76
77uint32_t TimerProbe::ElapsedTime(const timespec& start, const timespec& end)
78{
79 int sec = end.tv_sec - start.tv_sec;
80 int nsec = end.tv_nsec - start.tv_nsec;
81 if (nsec < 0) {
82 sec--;
83 nsec += 1000000000;
84 }
85 return sec * 1000000 + nsec / 1000;
86}
87
88void TimerProbe::print(const timespec& r, const timespec& p,
89 const timespec& t) const
90{
91 uint32_t es = ElapsedTime(gRealBase, mRealStart);
92 uint32_t er = ElapsedTime(mRealStart, r);
93 uint32_t ep = ElapsedTime(mPStart, p);
94 uint32_t et = ElapsedTime(mTStart, t);
95 if (mIndent > 0) {
96 Bucket& bucket = gBuckets.editItemAt(mBucket);
97 if (bucket.mStart == 0)
98 bucket.mStart = es;
99 bucket.mReal += er;
100 bucket.mProcess += ep;
101 bucket.mThread += et;
102 bucket.mCount++;
103 return;
104 }
105 int index = 0;
106 int buckets = gBuckets.size();
107 int count = 1;
108 const char* tag = mTag;
109 int indent = mIndent;
110 do {
111 LOGD("%-30.30s: (%3d) %-5.*s time=%-10.3f real=%7dus process=%7dus (%3d%%) thread=%7dus (%3d%%)\n",
112 tag, count, indent > 5 ? 5 : indent, "+++++", es / 1000000.0,
113 er, ep, ep * 100 / er, et, et * 100 / er);
114 if (index >= buckets)
115 break;
116 Bucket& bucket = gBuckets.editItemAt(index);
117 count = bucket.mCount;
118 es = bucket.mStart;
119 er = bucket.mReal;
120 ep = bucket.mProcess;
121 et = bucket.mThread;
122 tag = bucket.mTag;
123 indent = bucket.mIndent;
124 *bucket.mSlotPtr = 0;
125 } while (++index); // always true
126 gBuckets.clear();
127}
128
129}; // namespace android
130
131#endif