blob: 0064de5b804838a913b58d732c7ac9788dcaf530 [file] [log] [blame]
// Copyright (C) 2019 The Android Open Source Project
// Copyright (C) 2019 Google Inc.
//
// 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 "android/base/Tracing.h"
#include "android/base/system/System.h"
#include "android/base/memory/LazyInstance.h"
#include "android/base/threads/Thread.h"
#include "android/base/threads/ThreadStore.h"
#include <string>
#include <vector>
namespace android {
namespace base {
static constexpr size_t kDefaultIndentLevels = 8;
static constexpr char kIndentString[] = " ";
class IndentPrinter {
public:
IndentPrinter() {
ensureIndentLevel(kDefaultIndentLevels);
}
void begin(const char* name) {
auto us = System::getSystemTimeUs();
mTimes[mIndentLevel] = us;
float ms = ((float)us) / 1000.0f;
mNames[mIndentLevel] = name;
printf("tid:0x%016llx:%s%s @ %f ms {\n",
(unsigned long long)getCurrentThreadId(),
mIndents[mIndentLevel].c_str(),
name,
ms);
++mIndentLevel;
ensureIndentLevel(mIndentLevel);
}
void end() {
--mIndentLevel;
auto us = System::getSystemTimeUs();
mTimes[mIndentLevel] = us - mTimes[mIndentLevel];
float ms = (float)mTimes[mIndentLevel] / 1000.0f;
printf("tid:0x%016llx:%s} %s for %f ms\n",
(unsigned long long)getCurrentThreadId(),
mIndents[mIndentLevel].c_str(),
mNames[mIndentLevel].c_str(),
ms);
}
private:
void ensureIndentLevel(size_t level) {
if (mIndents.size() < level) {
size_t prev_size = mIndents.size();
mIndents.resize(level * 2);
for (size_t i = prev_size;
i < mIndents.size(); ++i) {
std::string s;
for (size_t j = 0; j < i; ++j) {
s += kIndentString;
}
mIndents[i] = s;
}
}
if (mTimes.size() < level) {
mTimes.resize(level * 2, 0.0f);
}
if (mNames.size() < level) {
mNames.resize(level * 2);
}
}
size_t mIndentLevel = 0;
std::vector<std::string> mIndents;
std::vector<System::WallDuration> mTimes;
std::vector<std::string> mNames;
};
class ThresholdPrinter {
public:
ThresholdPrinter() {
ensureIndentLevel(kDefaultIndentLevels);
}
void begin(const char* name, uint64_t thresholdUs) {
auto us = System::getSystemTimeUs();
mTimes[mIndentLevel] = us;
mThresholds[mIndentLevel] = thresholdUs;
float ms = ((float)us) / 1000.0f;
mNames[mIndentLevel] = name;
++mIndentLevel;
ensureIndentLevel(mIndentLevel);
}
void end() {
--mIndentLevel;
auto us = System::getSystemTimeUs();
mTimes[mIndentLevel] = us - mTimes[mIndentLevel];
if (mTimes[mIndentLevel] > mThresholds[mIndentLevel]) {
float thresholdMs = mThresholds[mIndentLevel] / 1000.0f;
float ms = mTimes[mIndentLevel] / 1000.0f;
printf("tid:0x%016llx:%s [%s] over threshold %f ms: %f ms\n",
(unsigned long long)getCurrentThreadId(),
mIndents[mIndentLevel].c_str(),
mNames[mIndentLevel].c_str(),
thresholdMs, ms);
}
}
private:
void ensureIndentLevel(size_t level) {
if (mIndents.size() < level) {
size_t prev_size = mIndents.size();
mIndents.resize(level * 2);
for (size_t i = prev_size;
i < mIndents.size(); ++i) {
std::string s;
for (size_t j = 0; j < i; ++j) {
s += kIndentString;
}
mIndents[i] = s;
}
}
if (mTimes.size() < level) {
mTimes.resize(level * 2, 0);
}
if (mThresholds.size() < level) {
mThresholds.resize(level * 2, 0);
}
if (mNames.size() < level) {
mNames.resize(level * 2);
}
}
size_t mIndentLevel = 0;
std::vector<std::string> mIndents;
std::vector<System::WallDuration> mTimes;
std::vector<System::WallDuration> mThresholds;
std::vector<std::string> mNames;
};
typedef ThreadStore<IndentPrinter> IndentPrinterStore;
typedef ThreadStore<ThresholdPrinter> ThresholdPrinterStore;
static LazyInstance<IndentPrinterStore> sIndentPrinterStore =
LAZY_INSTANCE_INIT;
static LazyInstance<ThresholdPrinterStore> sThresholdPrinterStore =
LAZY_INSTANCE_INIT;
static IndentPrinter* indentPrinter_getForThread() {
auto state = sIndentPrinterStore.ptr();
auto printer = state->get();
if (!printer) {
printer = new IndentPrinter;
state->set(printer);
}
return state->get();
}
static void indentTrace_begin(const char* name) {
indentPrinter_getForThread()->begin(name);
}
static void indentTrace_end() {
indentPrinter_getForThread()->end();
}
static ThresholdPrinter* thresholdPrinter_getForThread() {
auto state = sThresholdPrinterStore.ptr();
auto printer = state->get();
if (!printer) {
printer = new ThresholdPrinter;
state->set(printer);
}
return state->get();
}
static void thresholdTrace_begin(const char* name, uint64_t thresholdUs) {
thresholdPrinter_getForThread()->begin(name, thresholdUs);
}
static void thresholdTrace_end() {
thresholdPrinter_getForThread()->end();
}
class TraceConfig {
public:
TraceConfig() {
mEnabled =
System::getEnvironmentVariable(
"ANDROID_EMU_TRACING") == "1";
}
bool enabled() const { return mEnabled; }
private:
bool mEnabled = false;
};
static LazyInstance<TraceConfig> sTraceConfig =
LAZY_INSTANCE_INIT;
bool shouldEnableTracing() {
return sTraceConfig->enabled();
}
#ifdef __cplusplus
# define CC_LIKELY( exp ) (__builtin_expect( !!(exp), true ))
# define CC_UNLIKELY( exp ) (__builtin_expect( !!(exp), false ))
#else
# define CC_LIKELY( exp ) (__builtin_expect( !!(exp), 1 ))
# define CC_UNLIKELY( exp ) (__builtin_expect( !!(exp), 0 ))
#endif
void ScopedTrace::beginTraceImpl(const char* name) {
if (CC_UNLIKELY(shouldEnableTracing())) {
indentTrace_begin(name);
}
}
void ScopedTrace::endTraceImpl(const char*) {
if (CC_UNLIKELY(shouldEnableTracing())) {
indentTrace_end();
}
}
void beginTrace(const char* name) {
if (CC_UNLIKELY(shouldEnableTracing())) {
indentTrace_begin(name);
}
}
void endTrace() {
if (CC_UNLIKELY(shouldEnableTracing())) {
indentTrace_end();
}
}
void ScopedThresholdTrace::beginTraceImpl(const char* name, uint64_t thresholdUs) {
if (CC_UNLIKELY(shouldEnableTracing())) {
thresholdTrace_begin(name, thresholdUs);
}
}
void ScopedThresholdTrace::endTraceImpl(const char*) {
if (CC_UNLIKELY(shouldEnableTracing())) {
thresholdTrace_end();
}
}
void beginThresholdTrace(const char* name, uint64_t thresholdUs) {
if (CC_UNLIKELY(shouldEnableTracing())) {
thresholdTrace_begin(name, thresholdUs);
}
}
void endThresholdTrace() {
if (CC_UNLIKELY(shouldEnableTracing())) {
thresholdTrace_end();
}
}
} // namespace base
} // namespace android