2017-12-21 07:45:38 +08:00
|
|
|
/*
|
2018-02-28 00:29:17 +08:00
|
|
|
* Copyright (c) 2017-2018, Intel Corporation
|
2017-12-21 07:45:38 +08:00
|
|
|
*
|
|
|
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
|
|
|
* copy of this software and associated documentation files (the "Software"),
|
|
|
|
* to deal in the Software without restriction, including without limitation
|
|
|
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
|
|
* and/or sell copies of the Software, and to permit persons to whom the
|
|
|
|
* Software is furnished to do so, subject to the following conditions:
|
|
|
|
*
|
|
|
|
* The above copyright notice and this permission notice shall be included
|
|
|
|
* in all copies or substantial portions of the Software.
|
|
|
|
*
|
|
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
|
|
|
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
|
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
|
|
|
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
|
|
|
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
|
|
|
* OTHER DEALINGS IN THE SOFTWARE.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#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)
|
|
|
|
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; \
|
|
|
|
} \
|
|
|
|
private: \
|
|
|
|
dataType value; \
|
|
|
|
};
|
|
|
|
|
2018-02-28 00:29:17 +08:00
|
|
|
#include "DebugVariables.inl"
|
2017-12-21 07:45:38 +08:00
|
|
|
#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;
|
2018-02-28 00:29:17 +08:00
|
|
|
#include "DebugVariables.inl"
|
2017-12-21 07:45:38 +08:00
|
|
|
#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 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);
|
|
|
|
|
|
|
|
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();
|
|
|
|
}
|
|
|
|
|
2018-07-31 15:44:53 +08:00
|
|
|
const std::string infoPointerToString(const void *paramValue, size_t paramSize) {
|
2017-12-21 07:45:38 +08:00
|
|
|
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__)
|