blob: 159e4b4a4cfa106f22b3977ae185dac508982432 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 <tvm/runtime/logging.h>
#include <string>
#if (TVM_LOG_CUSTOMIZE == 0)
namespace tvm {
namespace runtime {
namespace detail {
const char* ::tvm::runtime::detail::LogMessage::level_strings_[] = {
": Debug: ", // TVM_LOG_LEVEL_DEBUG
": ", // TVM_LOG_LEVEL_INFO
": Warning: ", // TVM_LOG_LEVEL_WARNING
": Error: ", // TVM_LOG_LEVEL_ERROR
};
namespace {
constexpr const char* kSrcPrefix = "/src/";
// Note: Better would be std::char_traits<const char>::length(kSrcPrefix) but it is not
// a constexpr on all compilation targets.
constexpr const size_t kSrcPrefixLength = 5;
constexpr const char* kDefaultKeyword = "DEFAULT";
} // namespace
namespace {
/*! \brief Convert __FILE__ to a vlog_level_map_ key, which strips any prefix ending iwth src/ */
std::string FileToVLogMapKey(const std::string& filename) {
// Canonicalize the filename.
// TODO(mbs): Not Windows friendly.
size_t last_src = filename.rfind(kSrcPrefix, std::string::npos, kSrcPrefixLength);
if (last_src == std::string::npos) {
std::string no_slash_src{kSrcPrefix + 1};
if (filename.substr(0, no_slash_src.size()) == no_slash_src) {
return filename.substr(no_slash_src.size());
}
}
// Strip anything before the /src/ prefix, on the assumption that will yield the
// TVM project relative filename. If no such prefix fallback to filename without
// canonicalization.
return (last_src == std::string::npos) ? filename : filename.substr(last_src + kSrcPrefixLength);
}
} // namespace
/* static */
TvmLogDebugSettings TvmLogDebugSettings::ParseSpec(const char* opt_spec) {
TvmLogDebugSettings settings;
if (opt_spec == nullptr) {
// DLOG and VLOG disabled.
return settings;
}
std::string spec(opt_spec);
if (spec.empty() || spec == "0") {
// DLOG and VLOG disabled.
return settings;
}
settings.dlog_enabled_ = true;
if (spec == "1") {
// Legacy specification for enabling just DLOG.
return settings;
}
std::istringstream spec_stream(spec);
auto tell_pos = [&](const std::string& last_read) {
int pos = spec_stream.tellg();
if (pos == -1) {
LOG(INFO) << "override pos: " << last_read;
// when pos == -1, failbit was set due to std::getline reaching EOF without seeing delimiter.
pos = spec.size() - last_read.size();
}
return pos;
};
while (spec_stream) {
std::string name;
if (!std::getline(spec_stream, name, '=')) {
// Reached end.
break;
}
if (name.empty()) {
TVM_FFI_THROW(InternalError)
<< "TVM_LOG_DEBUG ill-formed at position " << tell_pos(name) << ": empty filename";
}
name = FileToVLogMapKey(name);
std::string level;
if (!std::getline(spec_stream, level, ',')) {
TVM_FFI_THROW(InternalError) << "TVM_LOG_DEBUG ill-formed at position " << tell_pos(level)
<< ": expecting \"=<level>\" after \"" << name << "\"";
return settings;
}
if (level.empty()) {
TVM_FFI_THROW(InternalError) << "TVM_LOG_DEBUG ill-formed at position " << tell_pos(level)
<< ": empty level after \"" << name << "\"";
return settings;
}
// Parse level, default to 0 if ill-formed which we don't detect.
char* end_of_level = nullptr;
int level_val = static_cast<int>(strtol(level.c_str(), &end_of_level, 10));
if (end_of_level != level.c_str() + level.size()) {
TVM_FFI_THROW(InternalError) << "TVM_LOG_DEBUG ill-formed at position " << tell_pos(level)
<< ": invalid level: \"" << level << "\"";
return settings;
}
LOG(INFO) << "TVM_LOG_DEBUG enables VLOG statements in '" << name << "' up to level " << level;
settings.vlog_level_map_.emplace(name, level_val);
}
return settings;
}
bool TvmLogDebugSettings::VerboseEnabledImpl(const std::string& filename, int level) const {
// Check for exact match.
auto itr = vlog_level_map_.find(FileToVLogMapKey(filename));
if (itr != vlog_level_map_.end()) {
return level <= itr->second;
}
// Check for default.
itr = vlog_level_map_.find(kDefaultKeyword);
if (itr != vlog_level_map_.end()) {
return level <= itr->second;
}
return false;
}
LogFatal::Entry& LogFatal::GetEntry() {
static thread_local LogFatal::Entry result;
return result;
}
std::string VLogContext::str() const {
std::stringstream result;
for (const auto* entry : context_stack_) {
TVM_FFI_ICHECK_NOTNULL(entry);
result << entry->str();
result << ": ";
}
return result.str();
}
} // namespace detail
} // namespace runtime
} // namespace tvm
#endif // TVM_LOG_CUSTOMIZE