mirror of https://github.com/google/benchmark.git
Auto-detect whether Benchmark should produce colorized output (#126)
* Auto-detect whether to produce colorized output Rename --color_print to --benchmark_color for consistency with the other flags (and Google Test). Old flag name is kept around for compatibility. The --benchmark_color/--color_print flag takes a third option, "auto", which is the new default. In this mode, we attempt to auto-detect whether to produce colorized output. (The logic for deciding whether to use colorized output was lifted from GTest: <https://github.com/google/googletest/blob/master/googletest/src/gtest.cc#L2925>.) * Update CONTRIBUTORS, AUTHORS
This commit is contained in:
parent
b826143ac2
commit
917b86e615
1
AUTHORS
1
AUTHORS
|
@ -24,6 +24,7 @@ Jussi Knuuttila <jussi.knuuttila@gmail.com>
|
||||||
Kaito Udagawa <umireon@gmail.com>
|
Kaito Udagawa <umireon@gmail.com>
|
||||||
Lei Xu <eddyxu@gmail.com>
|
Lei Xu <eddyxu@gmail.com>
|
||||||
Matt Clarkson <mattyclarkson@gmail.com>
|
Matt Clarkson <mattyclarkson@gmail.com>
|
||||||
|
Nick Hutchinson <nshutchinson@gmail.com>
|
||||||
Oleksandr Sochka <sasha.sochka@gmail.com>
|
Oleksandr Sochka <sasha.sochka@gmail.com>
|
||||||
Paul Redmond <paul.redmond@gmail.com>
|
Paul Redmond <paul.redmond@gmail.com>
|
||||||
Radoslav Yovchev <radoslav.tm@gmail.com>
|
Radoslav Yovchev <radoslav.tm@gmail.com>
|
||||||
|
|
|
@ -40,6 +40,7 @@ Kaito Udagawa <umireon@gmail.com>
|
||||||
Kai Wolf <kai.wolf@gmail.com>
|
Kai Wolf <kai.wolf@gmail.com>
|
||||||
Lei Xu <eddyxu@gmail.com>
|
Lei Xu <eddyxu@gmail.com>
|
||||||
Matt Clarkson <mattyclarkson@gmail.com>
|
Matt Clarkson <mattyclarkson@gmail.com>
|
||||||
|
Nick Hutchinson <nshutchinson@gmail.com>
|
||||||
Oleksandr Sochka <sasha.sochka@gmail.com>
|
Oleksandr Sochka <sasha.sochka@gmail.com>
|
||||||
Pascal Leroy <phl@google.com>
|
Pascal Leroy <phl@google.com>
|
||||||
Paul Redmond <paul.redmond@gmail.com>
|
Paul Redmond <paul.redmond@gmail.com>
|
||||||
|
|
|
@ -34,6 +34,7 @@
|
||||||
#include <thread>
|
#include <thread>
|
||||||
|
|
||||||
#include "check.h"
|
#include "check.h"
|
||||||
|
#include "colorprint.h"
|
||||||
#include "commandlineflags.h"
|
#include "commandlineflags.h"
|
||||||
#include "complexity.h"
|
#include "complexity.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
|
@ -82,7 +83,12 @@ DEFINE_string(benchmark_out_format, "json",
|
||||||
|
|
||||||
DEFINE_string(benchmark_out, "", "The file to write additonal output to");
|
DEFINE_string(benchmark_out, "", "The file to write additonal output to");
|
||||||
|
|
||||||
DEFINE_bool(color_print, true, "Enables colorized logging.");
|
DEFINE_string(benchmark_color, "auto",
|
||||||
|
"Whether to use colors in the output. Valid values: "
|
||||||
|
"'true'/'yes'/1, 'false'/'no'/0, and 'auto'. 'auto' means to use "
|
||||||
|
"colors if the output is being sent to a terminal and the TERM "
|
||||||
|
"environment variable is set to a terminal type that supports "
|
||||||
|
"colors.");
|
||||||
|
|
||||||
DEFINE_int32(v, 0, "The level of verbose logging to output");
|
DEFINE_int32(v, 0, "The level of verbose logging to output");
|
||||||
|
|
||||||
|
@ -546,8 +552,14 @@ size_t RunSpecifiedBenchmarks(BenchmarkReporter* console_reporter,
|
||||||
std::unique_ptr<BenchmarkReporter> default_console_reporter;
|
std::unique_ptr<BenchmarkReporter> default_console_reporter;
|
||||||
std::unique_ptr<BenchmarkReporter> default_file_reporter;
|
std::unique_ptr<BenchmarkReporter> default_file_reporter;
|
||||||
if (!console_reporter) {
|
if (!console_reporter) {
|
||||||
auto output_opts = FLAGS_color_print ? ConsoleReporter::OO_Color
|
auto output_opts = ConsoleReporter::OO_None;
|
||||||
: ConsoleReporter::OO_None;
|
if (FLAGS_benchmark_color == "auto")
|
||||||
|
output_opts = IsColorTerminal() ? ConsoleReporter::OO_Color
|
||||||
|
: ConsoleReporter::OO_None;
|
||||||
|
else
|
||||||
|
output_opts = IsTruthyFlagValue(FLAGS_benchmark_color)
|
||||||
|
? ConsoleReporter::OO_Color
|
||||||
|
: ConsoleReporter::OO_None;
|
||||||
default_console_reporter = internal::CreateReporter(
|
default_console_reporter = internal::CreateReporter(
|
||||||
FLAGS_benchmark_format, output_opts);
|
FLAGS_benchmark_format, output_opts);
|
||||||
console_reporter = default_console_reporter.get();
|
console_reporter = default_console_reporter.get();
|
||||||
|
@ -602,7 +614,7 @@ void PrintUsageAndExit() {
|
||||||
" [--benchmark_format=<console|json|csv>]\n"
|
" [--benchmark_format=<console|json|csv>]\n"
|
||||||
" [--benchmark_out=<filename>]\n"
|
" [--benchmark_out=<filename>]\n"
|
||||||
" [--benchmark_out_format=<json|console|csv>]\n"
|
" [--benchmark_out_format=<json|console|csv>]\n"
|
||||||
" [--color_print={true|false}]\n"
|
" [--benchmark_color={auto|true|false}]\n"
|
||||||
" [--v=<verbosity>]\n");
|
" [--v=<verbosity>]\n");
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
|
@ -627,8 +639,12 @@ void ParseCommandLineFlags(int* argc, char** argv) {
|
||||||
&FLAGS_benchmark_out) ||
|
&FLAGS_benchmark_out) ||
|
||||||
ParseStringFlag(argv[i], "benchmark_out_format",
|
ParseStringFlag(argv[i], "benchmark_out_format",
|
||||||
&FLAGS_benchmark_out_format) ||
|
&FLAGS_benchmark_out_format) ||
|
||||||
ParseBoolFlag(argv[i], "color_print",
|
ParseStringFlag(argv[i], "benchmark_color",
|
||||||
&FLAGS_color_print) ||
|
&FLAGS_benchmark_color) ||
|
||||||
|
// "color_print" is the deprecated name for "benchmark_color".
|
||||||
|
// TODO: Remove this.
|
||||||
|
ParseStringFlag(argv[i], "color_print",
|
||||||
|
&FLAGS_benchmark_color) ||
|
||||||
ParseInt32Flag(argv[i], "v", &FLAGS_v)) {
|
ParseInt32Flag(argv[i], "v", &FLAGS_v)) {
|
||||||
for (int j = i; j != *argc; ++j) argv[j] = argv[j + 1];
|
for (int j = i; j != *argc; ++j) argv[j] = argv[j + 1];
|
||||||
|
|
||||||
|
@ -643,6 +659,9 @@ void ParseCommandLineFlags(int* argc, char** argv) {
|
||||||
if (*flag != "console" && *flag != "json" && *flag != "csv") {
|
if (*flag != "console" && *flag != "json" && *flag != "csv") {
|
||||||
PrintUsageAndExit();
|
PrintUsageAndExit();
|
||||||
}
|
}
|
||||||
|
if (FLAGS_benchmark_color.empty()) {
|
||||||
|
PrintUsageAndExit();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int InitializeStreams() {
|
int InitializeStreams() {
|
||||||
|
|
|
@ -16,16 +16,20 @@
|
||||||
|
|
||||||
#include <cstdarg>
|
#include <cstdarg>
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <cstdarg>
|
#include <cstdlib>
|
||||||
#include <string>
|
#include <cstring>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
#include "check.h"
|
#include "check.h"
|
||||||
#include "internal_macros.h"
|
#include "internal_macros.h"
|
||||||
|
|
||||||
#ifdef BENCHMARK_OS_WINDOWS
|
#ifdef BENCHMARK_OS_WINDOWS
|
||||||
|
#include <io.h>
|
||||||
#include <Windows.h>
|
#include <Windows.h>
|
||||||
#endif
|
#else
|
||||||
|
#include <unistd.h>
|
||||||
|
#endif // BENCHMARK_OS_WINDOWS
|
||||||
|
|
||||||
namespace benchmark {
|
namespace benchmark {
|
||||||
namespace {
|
namespace {
|
||||||
|
@ -151,4 +155,34 @@ void ColorPrintf(std::ostream& out, LogColor color, const char* fmt, va_list arg
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool IsColorTerminal() {
|
||||||
|
#if BENCHMARK_OS_WINDOWS
|
||||||
|
// On Windows the TERM variable is usually not set, but the
|
||||||
|
// console there does support colors.
|
||||||
|
return 0 != _isatty(_fileno(stdout));
|
||||||
|
#else
|
||||||
|
// On non-Windows platforms, we rely on the TERM variable. This list of
|
||||||
|
// supported TERM values is copied from Google Test:
|
||||||
|
// <https://github.com/google/googletest/blob/master/googletest/src/gtest.cc#L2925>.
|
||||||
|
const char* const SUPPORTED_TERM_VALUES[] = {
|
||||||
|
"xterm", "xterm-color", "xterm-256color",
|
||||||
|
"screen", "screen-256color", "tmux",
|
||||||
|
"tmux-256color", "rxvt-unicode", "rxvt-unicode-256color",
|
||||||
|
"linux", "cygwin",
|
||||||
|
};
|
||||||
|
|
||||||
|
const char* const term = getenv("TERM");
|
||||||
|
|
||||||
|
bool term_supports_color = false;
|
||||||
|
for (const char* candidate : SUPPORTED_TERM_VALUES) {
|
||||||
|
if (term && 0 == strcmp(term, candidate)) {
|
||||||
|
term_supports_color = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0 != isatty(fileno(stdout)) && term_supports_color;
|
||||||
|
#endif // BENCHMARK_OS_WINDOWS
|
||||||
|
}
|
||||||
|
|
||||||
} // end namespace benchmark
|
} // end namespace benchmark
|
||||||
|
|
|
@ -23,6 +23,10 @@ std::string FormatString(const char* msg, ...);
|
||||||
void ColorPrintf(std::ostream& out, LogColor color, const char* fmt, va_list args);
|
void ColorPrintf(std::ostream& out, LogColor color, const char* fmt, va_list args);
|
||||||
void ColorPrintf(std::ostream& out, LogColor color, const char* fmt, ...);
|
void ColorPrintf(std::ostream& out, LogColor color, const char* fmt, ...);
|
||||||
|
|
||||||
|
// Returns true if stdout appears to be a terminal that supports colored
|
||||||
|
// output, false otherwise.
|
||||||
|
bool IsColorTerminal();
|
||||||
|
|
||||||
} // end namespace benchmark
|
} // end namespace benchmark
|
||||||
|
|
||||||
#endif // BENCHMARK_COLORPRINT_H_
|
#endif // BENCHMARK_COLORPRINT_H_
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
|
|
||||||
#include "commandlineflags.h"
|
#include "commandlineflags.h"
|
||||||
|
|
||||||
|
#include <cctype>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
@ -74,17 +75,6 @@ bool ParseDouble(const std::string& src_text, const char* str, double* value) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline const char* GetEnv(const char* name) {
|
|
||||||
#if defined(__BORLANDC__) || defined(__SunOS_5_8) || defined(__SunOS_5_9)
|
|
||||||
// Environment variables which we programmatically clear will be set to the
|
|
||||||
// empty string rather than unset (nullptr). Handle that case.
|
|
||||||
const char* const env = getenv(name);
|
|
||||||
return (env != nullptr && env[0] != '\0') ? env : nullptr;
|
|
||||||
#else
|
|
||||||
return getenv(name);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns the name of the environment variable corresponding to the
|
// Returns the name of the environment variable corresponding to the
|
||||||
// given flag. For example, FlagToEnvVar("foo") will return
|
// given flag. For example, FlagToEnvVar("foo") will return
|
||||||
// "BENCHMARK_FOO" in the open-source version.
|
// "BENCHMARK_FOO" in the open-source version.
|
||||||
|
@ -104,7 +94,7 @@ static std::string FlagToEnvVar(const char* flag) {
|
||||||
// The value is considered true iff it's not "0".
|
// The value is considered true iff it's not "0".
|
||||||
bool BoolFromEnv(const char* flag, bool default_value) {
|
bool BoolFromEnv(const char* flag, bool default_value) {
|
||||||
const std::string env_var = FlagToEnvVar(flag);
|
const std::string env_var = FlagToEnvVar(flag);
|
||||||
const char* const string_value = GetEnv(env_var.c_str());
|
const char* const string_value = getenv(env_var.c_str());
|
||||||
return string_value == nullptr ? default_value : strcmp(string_value, "0") != 0;
|
return string_value == nullptr ? default_value : strcmp(string_value, "0") != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -113,7 +103,7 @@ bool BoolFromEnv(const char* flag, bool default_value) {
|
||||||
// doesn't represent a valid 32-bit integer, returns default_value.
|
// doesn't represent a valid 32-bit integer, returns default_value.
|
||||||
int32_t Int32FromEnv(const char* flag, int32_t default_value) {
|
int32_t Int32FromEnv(const char* flag, int32_t default_value) {
|
||||||
const std::string env_var = FlagToEnvVar(flag);
|
const std::string env_var = FlagToEnvVar(flag);
|
||||||
const char* const string_value = GetEnv(env_var.c_str());
|
const char* const string_value = getenv(env_var.c_str());
|
||||||
if (string_value == nullptr) {
|
if (string_value == nullptr) {
|
||||||
// The environment variable is not set.
|
// The environment variable is not set.
|
||||||
return default_value;
|
return default_value;
|
||||||
|
@ -133,7 +123,7 @@ int32_t Int32FromEnv(const char* flag, int32_t default_value) {
|
||||||
// the given flag; if it's not set, returns default_value.
|
// the given flag; if it's not set, returns default_value.
|
||||||
const char* StringFromEnv(const char* flag, const char* default_value) {
|
const char* StringFromEnv(const char* flag, const char* default_value) {
|
||||||
const std::string env_var = FlagToEnvVar(flag);
|
const std::string env_var = FlagToEnvVar(flag);
|
||||||
const char* const value = GetEnv(env_var.c_str());
|
const char* const value = getenv(env_var.c_str());
|
||||||
return value == nullptr ? default_value : value;
|
return value == nullptr ? default_value : value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -175,7 +165,7 @@ bool ParseBoolFlag(const char* str, const char* flag, bool* value) {
|
||||||
if (value_str == nullptr) return false;
|
if (value_str == nullptr) return false;
|
||||||
|
|
||||||
// Converts the string value to a bool.
|
// Converts the string value to a bool.
|
||||||
*value = !(*value_str == '0' || *value_str == 'f' || *value_str == 'F');
|
*value = IsTruthyFlagValue(value_str);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -217,4 +207,12 @@ bool ParseStringFlag(const char* str, const char* flag, std::string* value) {
|
||||||
bool IsFlag(const char* str, const char* flag) {
|
bool IsFlag(const char* str, const char* flag) {
|
||||||
return (ParseFlagValue(str, flag, true) != nullptr);
|
return (ParseFlagValue(str, flag, true) != nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool IsTruthyFlagValue(const std::string& str) {
|
||||||
|
if (str.empty())
|
||||||
|
return true;
|
||||||
|
char ch = str[0];
|
||||||
|
return isalnum(ch) &&
|
||||||
|
!(ch == '0' || ch == 'f' || ch == 'F' || ch == 'n' || ch == 'N');
|
||||||
|
}
|
||||||
} // end namespace benchmark
|
} // end namespace benchmark
|
||||||
|
|
|
@ -38,8 +38,7 @@ const char* StringFromEnv(const char* flag, const char* default_val);
|
||||||
// Parses a string for a bool flag, in the form of either
|
// Parses a string for a bool flag, in the form of either
|
||||||
// "--flag=value" or "--flag".
|
// "--flag=value" or "--flag".
|
||||||
//
|
//
|
||||||
// In the former case, the value is taken as true as long as it does
|
// In the former case, the value is taken as true if it passes IsTruthyValue().
|
||||||
// not start with '0', 'f', or 'F'.
|
|
||||||
//
|
//
|
||||||
// In the latter case, the value is taken as true.
|
// In the latter case, the value is taken as true.
|
||||||
//
|
//
|
||||||
|
@ -71,6 +70,10 @@ bool ParseStringFlag(const char* str, const char* flag, std::string* value);
|
||||||
// Returns true if the string matches the flag.
|
// Returns true if the string matches the flag.
|
||||||
bool IsFlag(const char* str, const char* flag);
|
bool IsFlag(const char* str, const char* flag);
|
||||||
|
|
||||||
|
// Returns true unless value starts with one of: '0', 'f', 'F', 'n' or 'N', or
|
||||||
|
// some non-alphanumeric character. As a special case, also returns true if
|
||||||
|
// value is the empty string.
|
||||||
|
bool IsTruthyFlagValue(const std::string& value);
|
||||||
} // end namespace benchmark
|
} // end namespace benchmark
|
||||||
|
|
||||||
#endif // BENCHMARK_COMMANDLINEFLAGS_H_
|
#endif // BENCHMARK_COMMANDLINEFLAGS_H_
|
||||||
|
|
Loading…
Reference in New Issue