blob: 62c8b41d736d57304577fe4512e341b4df0b9fd7 [file]
/*
* Copyright 2018 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.
*/
#pragma once
#include <android/log.h>
#include <android/trace.h>
#include <dlfcn.h>
#include <memory>
namespace gamesdk {
class Trace {
public:
using ATrace_beginSection_type = void (*)(const char *sectionName);
using ATrace_endSection_type = void (*)();
using ATrace_isEnabled_type = bool (*)();
using ATrace_beginAsyncSection_type = void (*)(const char *sectionName,
int32_t cookie);
using ATrace_endAsyncSection_type = void (*)(const char *sectionName,
int32_t cookie);
using ATrace_setCounter_type = void (*)(const char *counterName,
int64_t counterValue);
Trace() {
__android_log_print(ANDROID_LOG_INFO, "Trace",
"Unable to load NDK tracing APIs");
}
Trace(ATrace_beginSection_type beginSection,
ATrace_endSection_type endSection, ATrace_isEnabled_type isEnabled,
ATrace_beginAsyncSection_type beginAsyncSection,
ATrace_endAsyncSection_type endAsyncSection,
ATrace_setCounter_type setCounter)
: ATrace_beginSection(beginSection),
ATrace_endSection(endSection),
ATrace_isEnabled(isEnabled),
ATrace_beginAsyncSection(beginAsyncSection),
ATrace_endAsyncSection(endAsyncSection),
ATrace_setCounter(setCounter) {}
static std::unique_ptr<Trace> create() {
void *libandroid = dlopen("libandroid.so", RTLD_NOW | RTLD_LOCAL);
if (!libandroid) {
return std::make_unique<Trace>();
}
auto beginSection = reinterpret_cast<ATrace_beginSection_type>(
dlsym(libandroid, "ATrace_beginSection"));
if (!beginSection) {
return std::make_unique<Trace>();
}
auto endSection = reinterpret_cast<ATrace_endSection_type>(
dlsym(libandroid, "ATrace_endSection"));
if (!endSection) {
return std::make_unique<Trace>();
}
auto isEnabled = reinterpret_cast<ATrace_isEnabled_type>(
dlsym(libandroid, "ATrace_isEnabled"));
if (!isEnabled) {
return std::make_unique<Trace>();
}
auto setCounter = reinterpret_cast<ATrace_setCounter_type>(
dlsym(libandroid, "ATrace_setCounter"));
/* ATrace_setCounter was added in API 29, continue even if it is not
* available */
auto beginAsyncSection = reinterpret_cast<ATrace_beginAsyncSection_type>(
dlsym(libandroid, "ATrace_beginAsyncSection"));
/* ATrace_beginAsyncSection was added in API 29, continue even if it is
* not available */
auto endAsyncSection = reinterpret_cast<ATrace_endAsyncSection_type>(
dlsym(libandroid, "ATrace_endAsyncSection"));
/* ATrace_endAsyncSection was added in API 29, continue even if it is
* not available */
return std::make_unique<Trace>(beginSection, endSection, isEnabled,
beginAsyncSection, endAsyncSection,
setCounter);
}
bool isAvailable() const { return ATrace_beginSection != nullptr; }
bool isEnabled() const {
return (ATrace_isEnabled != nullptr) && ATrace_isEnabled();
}
void beginSection(const char *name) const {
if (!ATrace_beginSection) {
return;
}
ATrace_beginSection(name);
}
void endSection() const {
if (!ATrace_endSection) {
return;
}
ATrace_endSection();
}
void beginAsyncSection(const char *name, int64_t value) {
if (!ATrace_beginAsyncSection || !isEnabled()) {
return;
}
ATrace_beginAsyncSection(name, value);
}
void endAsyncSection(const char *name, int64_t value) {
if (!ATrace_endAsyncSection || !isEnabled()) {
return;
}
ATrace_endAsyncSection(name, value);
}
void setCounter(const char *name, int64_t value) {
if (!ATrace_setCounter || !isEnabled()) {
return;
}
ATrace_setCounter(name, value);
}
bool supportsBasicATrace() const {
return ATrace_beginSection && ATrace_endSection;
}
bool supportsFullATrace() const {
return supportsBasicATrace() && ATrace_beginAsyncSection &&
ATrace_endAsyncSection && ATrace_setCounter;
}
static Trace *getInstance() {
static std::unique_ptr<Trace> trace = Trace::create();
return trace.get();
};
private:
const ATrace_beginSection_type ATrace_beginSection = nullptr;
const ATrace_endSection_type ATrace_endSection = nullptr;
const ATrace_isEnabled_type ATrace_isEnabled = nullptr;
const ATrace_beginAsyncSection_type ATrace_beginAsyncSection = nullptr;
const ATrace_endAsyncSection_type ATrace_endAsyncSection = nullptr;
const ATrace_setCounter_type ATrace_setCounter = nullptr;
};
struct ScopedTrace {
ScopedTrace(const char *name) {
Trace *trace = Trace::getInstance();
if (!trace->isAvailable() || !trace->isEnabled()) {
return;
}
trace->beginSection(name);
mIsTracing = true;
}
~ScopedTrace() {
if (!mIsTracing) {
return;
}
Trace *trace = Trace::getInstance();
trace->endSection();
}
private:
bool mIsTracing = false;
};
} // namespace gamesdk
#define PASTE_HELPER_HELPER(a, b) a##b
#define PASTE_HELPER(a, b) PASTE_HELPER_HELPER(a, b)
#define TRACE_CALL() \
gamesdk::ScopedTrace PASTE_HELPER(scopedTrace, __LINE__)(__PRETTY_FUNCTION__)
#define TRACE_INT(name, value) \
gamesdk::Trace::getInstance()->setCounter(name, value)
#define TRACE_ENABLED() gamesdk::Trace::getInstance()->isEnabled()