1 /*
2 * Copyright (C) 2022 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 #define LOG_TAG "ThreadSnapshot"
18 #include <utils/Log.h>
19 #include <utils/Timers.h>
20 #include <mediautils/ThreadSnapshot.h>
21
22 #include <mediautils/Process.h>
23
24 namespace android::mediautils {
25
getTid() const26 pid_t ThreadSnapshot::getTid() const {
27 std::lock_guard lg(mLock);
28 return mState.mTid;
29 }
30
setTid(pid_t tid)31 void ThreadSnapshot::setTid(pid_t tid) {
32 std::lock_guard lg(mLock);
33 if (mState.mTid == tid) return;
34 mState.reset(tid);
35 }
36
reset()37 void ThreadSnapshot::reset() {
38 std::lock_guard lg(mLock);
39 mState.reset(mState.mTid);
40 }
41
onBegin()42 void ThreadSnapshot::onBegin() {
43 std::string sched = getThreadSchedAsString(getTid()); // tid could race here,
44 // accept as benign.
45 std::lock_guard lg(mLock);
46 mState.onBegin(std::move(sched));
47 }
48
onEnd()49 void ThreadSnapshot::onEnd() {
50 std::lock_guard lg(mLock);
51 mState.onEnd();
52 }
53
toString() const54 std::string ThreadSnapshot::toString() const {
55 // Make a local copy of the stats data under lock.
56 State state;
57 {
58 std::lock_guard lg(mLock);
59 state = mState;
60 }
61 return state.toString();
62 }
63
reset(pid_t tid)64 void ThreadSnapshot::State::reset(pid_t tid) {
65 mTid = tid;
66 mBeginTimeNs = -2;
67 mEndTimeNs = -1;
68 mCumulativeTimeNs = 0;
69 mBeginSched.clear();
70 }
71
onBegin(std::string sched)72 void ThreadSnapshot::State::onBegin(std::string sched) {
73 if (mBeginTimeNs < mEndTimeNs) {
74 mBeginTimeNs = systemTime();
75 mBeginSched = std::move(sched);
76 }
77 }
78
onEnd()79 void ThreadSnapshot::State::onEnd() {
80 if (mEndTimeNs < mBeginTimeNs) {
81 mEndTimeNs = systemTime();
82 mCumulativeTimeNs += mEndTimeNs - mBeginTimeNs;
83 }
84 }
85
toString() const86 std::string ThreadSnapshot::State::toString() const {
87 if (mBeginTimeNs < 0) return {}; // never begun.
88
89 // compute time intervals.
90 const int64_t nowNs = systemTime();
91 int64_t cumulativeTimeNs = mCumulativeTimeNs;
92 int64_t diffNs = mEndTimeNs - mBeginTimeNs; // if onEnd() isn't matched, diffNs < 0.
93 if (diffNs < 0) {
94 diffNs = nowNs - mBeginTimeNs;
95 cumulativeTimeNs += diffNs;
96 }
97 // normalization for rate variables
98 const double lastRunPerSec = 1e9 / diffNs;
99 const double totalPerSec = 1e9 / cumulativeTimeNs;
100
101 // HANDLE THE SCHEDULER STATISTICS HERE
102 // current and differential statistics for the scheduler.
103 std::string schedNow = getThreadSchedAsString(mTid);
104 const auto schedMapThen = parseThreadSchedString(mBeginSched);
105 const auto schedMapNow = parseThreadSchedString(schedNow);
106 static const char * schedDiffKeyList[] = {
107 "se.sum_exec_runtime",
108 "se.nr_migrations",
109 "se.statistics.wait_sum",
110 "se.statistics.wait_count",
111 "se.statistics.iowait_sum",
112 "se.statistics.iowait_count",
113 "se.statistics.nr_forced_migrations",
114 "nr_involuntary_switches",
115 };
116
117 // compute differential rate statistics.
118 std::string diffString;
119 for (const auto diffKey : schedDiffKeyList) {
120 if (auto itThen = schedMapThen.find(diffKey);
121 itThen != schedMapThen.end()) {
122
123 if (auto itNow = schedMapNow.find(diffKey);
124 itNow != schedMapNow.end()) {
125 auto diff = itNow->second - itThen->second;
126 diff *= lastRunPerSec;
127 auto total = itNow->second * totalPerSec;
128 diffString.append(diffKey).append(" last-run:")
129 .append(std::to_string(diff))
130 .append(" cumulative:")
131 .append(std::to_string(total))
132 .append("\n");
133 }
134 }
135 }
136
137 if (!diffString.empty()) {
138 schedNow.append("*** per second stats ***\n").append(diffString);
139 }
140
141 // Return snapshot string.
142 return schedNow;
143 }
144
145 } // android::mediautils
146