Files
compute-runtime/runtime/os_interface/debug_settings_manager.h
Pawel Wilma 86ecd1a4b8 Memory leak reported for long string debug variables in ULTs
This commit eliminates ULTs memory leaks reported for string debug variables
exceeding small string optimization size by calling shrink_to_fit() method
on string debug variables in DebugManagerStateRestore destructor.

Change-Id: I304c5c5c23c80f01fdf13f38cea5b4eceb18a94f
Signed-off-by: Pawel Wilma <pawel.wilma@intel.com>
2018-11-27 10:07:42 +01:00

287 lines
9.7 KiB
C++

/*
* Copyright (C) 2017-2018 Intel Corporation
*
* SPDX-License-Identifier: MIT
*
*/
#pragma once
#include <sstream>
#include <stdint.h>
#include <string>
#include <fstream>
#include <condition_variable>
#include <mutex>
#include <thread>
enum class DebugFunctionalityLevel {
None, // Debug functionality disabled
Full, // Debug functionality fully enabled
RegKeys // Only registry key reads enabled
};
#if defined(_DEBUG)
constexpr DebugFunctionalityLevel globalDebugFunctionalityLevel = DebugFunctionalityLevel::Full;
#elif defined(_RELEASE_INTERNAL) || defined(_RELEASE_BUILD_WITH_REGKEYS)
constexpr DebugFunctionalityLevel globalDebugFunctionalityLevel = DebugFunctionalityLevel::RegKeys;
#else
constexpr DebugFunctionalityLevel globalDebugFunctionalityLevel = DebugFunctionalityLevel::None;
#endif
namespace OCLRT {
template <typename... Args>
void printDebugString(bool showDebugLogs, Args &&... args) {
if (showDebugLogs) {
fprintf(std::forward<Args>(args)...);
}
}
#if defined(__clang__)
#define NO_SANITIZE __attribute__((no_sanitize("undefined")))
#else
#define NO_SANITIZE
#endif
class Kernel;
struct MultiDispatchInfo;
class SettingsReader;
// clang-format off
#define DECLARE_DEBUG_VARIABLE(dataType, variableName, defaultValue, description) \
struct DebugVar##variableName \
{ \
DebugVar##variableName() { \
value = (dataType)defaultValue; \
} \
dataType get() const { \
return value; \
} \
void set(dataType data) { \
value = data; \
} \
dataType& getRef() { \
return value; \
} \
private: \
dataType value; \
};
#include "debug_variables.inl"
#undef DECLARE_DEBUG_VARIABLE
// clang-format on
template <DebugFunctionalityLevel DebugLevel>
class DebugSettingsManager {
public:
struct DebugVariables {
#define DECLARE_DEBUG_VARIABLE(dataType, variableName, defaultValue, description) \
DebugVar##variableName variableName;
#include "debug_variables.inl"
#undef DECLARE_DEBUG_VARIABLE
};
DebugSettingsManager();
~DebugSettingsManager();
DebugSettingsManager(const DebugSettingsManager &) = delete;
DebugSettingsManager &operator=(const DebugSettingsManager &) = delete;
static constexpr bool debugLoggingAvailable() {
return DebugLevel == DebugFunctionalityLevel::Full;
}
static constexpr bool debugKernelDumpingAvailable() {
return DebugLevel == DebugFunctionalityLevel::Full;
}
static constexpr bool kernelArgDumpingAvailable() {
return DebugLevel == DebugFunctionalityLevel::Full;
}
static constexpr bool registryReadAvailable() {
return (DebugLevel == DebugFunctionalityLevel::Full) || (DebugLevel == DebugFunctionalityLevel::RegKeys);
}
static constexpr bool disabled() {
return DebugLevel == DebugFunctionalityLevel::None;
}
void getHardwareInfoOverride(std::string &hwInfoConfig);
void dumpKernel(const std::string &name, const std::string &src);
void logApiCall(const char *function, bool enter, int32_t errorCode);
size_t getInput(const size_t *input, int32_t index);
const std::string getEvents(const uintptr_t *input, uint32_t numOfEvents);
const std::string getMemObjects(const uintptr_t *input, uint32_t numOfObjects);
MOCKABLE_VIRTUAL void writeToFile(std::string filename, const char *str, size_t length, std::ios_base::openmode mode);
void dumpBinaryProgram(int32_t numDevices, const size_t *lengths, const unsigned char **binaries);
void dumpKernelArgs(const Kernel *kernel);
void dumpKernelArgs(const MultiDispatchInfo *multiDispatchInfo);
const std::string getSizes(const uintptr_t *input, uint32_t workDim, bool local) {
if (false == debugLoggingAvailable()) {
return "";
}
std::stringstream os;
std::string workSize;
if (local) {
workSize = "localWorkSize";
} else {
workSize = "globalWorkSize";
}
for (uint32_t i = 0; i < workDim; i++) {
if (input != nullptr) {
os << workSize << "[" << i << "]: \t" << input[i] << "\n";
}
}
return os.str();
}
const std::string infoPointerToString(const void *paramValue, size_t paramSize) {
if (false == debugLoggingAvailable()) {
return "";
}
std::stringstream os;
if (paramValue) {
switch (paramSize) {
case sizeof(uint32_t):
os << *(uint32_t *)paramValue;
break;
case sizeof(uint64_t):
os << *(uint64_t *)paramValue;
break;
case sizeof(uint8_t):
os << (uint32_t)(*(uint8_t *)paramValue);
break;
default:
break;
}
}
return os.str();
}
// Expects pairs of args (even number of args)
template <typename... Types>
void logInputs(Types &&... params) {
if (debugLoggingAvailable()) {
if (this->flags.LogApiCalls.get()) {
std::unique_lock<std::mutex> theLock(mtx);
std::thread::id thisThread = std::this_thread::get_id();
std::stringstream ss;
ss << "------------------------------\n";
printInputs(ss, "ThreadID", thisThread, params...);
ss << "------------------------------" << std::endl;
writeToFile(logFileName, ss.str().c_str(), ss.str().length(), std::ios::app);
}
}
}
template <typename FT>
void logLazyEvaluateArgs(bool predicate, FT &&callable) {
if (debugLoggingAvailable()) {
if (predicate) {
callable();
}
}
}
template <typename... Types>
void log(bool enableLog, Types... params) {
if (debugLoggingAvailable()) {
if (enableLog) {
std::unique_lock<std::mutex> theLock(mtx);
std::thread::id thisThread = std::this_thread::get_id();
std::stringstream ss;
print(ss, "ThreadID", thisThread, params...);
writeToFile(logFileName, ss.str().c_str(), ss.str().length(), std::ios::app);
}
}
}
DebugVariables flags;
void *injectFcn = nullptr;
const char *getLogFileName() {
return logFileName.c_str();
}
void setLogFileName(std::string filename) {
logFileName = filename;
}
protected:
SettingsReader *readerImpl = nullptr;
std::mutex mtx;
std::string logFileName;
// Required for variadic template with 0 args passed
void printInputs(std::stringstream &ss) {}
// Prints inputs in format: InputName: InputValue \newline
template <typename T1, typename... Types>
void printInputs(std::stringstream &ss, T1 first, Types... params) {
if (debugLoggingAvailable()) {
const size_t argsLeft = sizeof...(params);
ss << "\t" << first;
if (argsLeft % 2) {
ss << ": ";
} else {
ss << std::endl;
}
printInputs(ss, params...);
}
}
// Required for variadic template with 0 args passed
void print(std::stringstream &ss) {}
template <typename T1, typename... Types>
void print(std::stringstream &ss, T1 first, Types... params) {
if (debugLoggingAvailable()) {
const size_t argsLeft = sizeof...(params);
ss << first << " ";
if (argsLeft == 0) {
ss << std::endl;
}
print(ss, params...);
}
}
};
extern DebugSettingsManager<globalDebugFunctionalityLevel> DebugManager;
template <bool Enabled>
class DebugSettingsApiEnterWrapper {
public:
DebugSettingsApiEnterWrapper(const char *funcName, const int *errorCode)
: funcName(funcName), errorCode(errorCode) {
if (Enabled) {
DebugManager.logApiCall(funcName, true, 0);
}
}
~DebugSettingsApiEnterWrapper() {
if (Enabled) {
DebugManager.logApiCall(funcName, false, (errorCode != nullptr) ? *errorCode : 0);
}
}
const char *funcName;
const int *errorCode;
};
}; // namespace OCLRT
#define DECLARE_DEBUG_VARIABLE(dataType, variableName, defaultValue, description)
#define DBG_LOG_LAZY_EVALUATE_ARGS(DBG_MANAGER, PREDICATE, LOG_FUNCTION, ...) \
DBG_MANAGER.logLazyEvaluateArgs(DBG_MANAGER.flags.PREDICATE.get(), [&] { DBG_MANAGER.LOG_FUNCTION(__VA_ARGS__); })
#define DBG_LOG(PREDICATE, ...) \
DBG_LOG_LAZY_EVALUATE_ARGS(OCLRT::DebugManager, PREDICATE, log, OCLRT::DebugManager.flags.PREDICATE.get(), __VA_ARGS__)
#define DBG_LOG_INPUTS(...) \
DBG_LOG_LAZY_EVALUATE_ARGS(OCLRT::DebugManager, LogApiCalls, logInputs, __VA_ARGS__)