blob: 382738e8223af71fcdaafdf4514244b05bad3527 [file] [log] [blame]
/*
* Copyright (C) 2022 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.
*/
#define LOG_TAG "ThreadSnapshot"
#include <utils/Log.h>
#include <utils/Timers.h>
#include <mediautils/ThreadSnapshot.h>
#include <mediautils/Process.h>
namespace android::mediautils {
pid_t ThreadSnapshot::getTid() const {
std::lock_guard lg(mLock);
return mState.mTid;
}
void ThreadSnapshot::setTid(pid_t tid) {
std::lock_guard lg(mLock);
if (mState.mTid == tid) return;
mState.reset(tid);
}
void ThreadSnapshot::reset() {
std::lock_guard lg(mLock);
mState.reset(mState.mTid);
}
void ThreadSnapshot::onBegin() {
std::string sched = getThreadSchedAsString(getTid()); // tid could race here,
// accept as benign.
std::lock_guard lg(mLock);
mState.onBegin(std::move(sched));
}
void ThreadSnapshot::onEnd() {
std::lock_guard lg(mLock);
mState.onEnd();
}
std::string ThreadSnapshot::toString() const {
// Make a local copy of the stats data under lock.
State state;
{
std::lock_guard lg(mLock);
state = mState;
}
return state.toString();
}
void ThreadSnapshot::State::reset(pid_t tid) {
mTid = tid;
mBeginTimeNs = -2;
mEndTimeNs = -1;
mCumulativeTimeNs = 0;
mBeginSched.clear();
}
void ThreadSnapshot::State::onBegin(std::string sched) {
if (mBeginTimeNs < mEndTimeNs) {
mBeginTimeNs = systemTime();
mBeginSched = std::move(sched);
}
}
void ThreadSnapshot::State::onEnd() {
if (mEndTimeNs < mBeginTimeNs) {
mEndTimeNs = systemTime();
mCumulativeTimeNs += mEndTimeNs - mBeginTimeNs;
}
}
std::string ThreadSnapshot::State::toString() const {
if (mBeginTimeNs < 0) return {}; // never begun.
// compute time intervals.
const int64_t nowNs = systemTime();
int64_t cumulativeTimeNs = mCumulativeTimeNs;
int64_t diffNs = mEndTimeNs - mBeginTimeNs; // if onEnd() isn't matched, diffNs < 0.
if (diffNs < 0) {
diffNs = nowNs - mBeginTimeNs;
cumulativeTimeNs += diffNs;
}
// normalization for rate variables
const double lastRunPerSec = 1e9 / diffNs;
const double totalPerSec = 1e9 / cumulativeTimeNs;
// HANDLE THE SCHEDULER STATISTICS HERE
// current and differential statistics for the scheduler.
std::string schedNow = getThreadSchedAsString(mTid);
const auto schedMapThen = parseThreadSchedString(mBeginSched);
const auto schedMapNow = parseThreadSchedString(schedNow);
static const char * schedDiffKeyList[] = {
"se.sum_exec_runtime",
"se.nr_migrations",
"se.statistics.wait_sum",
"se.statistics.wait_count",
"se.statistics.iowait_sum",
"se.statistics.iowait_count",
"se.statistics.nr_forced_migrations",
"nr_involuntary_switches",
};
// compute differential rate statistics.
std::string diffString;
for (const auto diffKey : schedDiffKeyList) {
if (auto itThen = schedMapThen.find(diffKey);
itThen != schedMapThen.end()) {
if (auto itNow = schedMapNow.find(diffKey);
itNow != schedMapNow.end()) {
auto diff = itNow->second - itThen->second;
diff *= lastRunPerSec;
auto total = itNow->second * totalPerSec;
diffString.append(diffKey).append(" last-run:")
.append(std::to_string(diff))
.append(" cumulative:")
.append(std::to_string(total))
.append("\n");
}
}
}
if (!diffString.empty()) {
schedNow.append("*** per second stats ***\n").append(diffString);
}
// Return snapshot string.
return schedNow;
}
} // android::mediautils