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>
|
||||
Lei Xu <eddyxu@gmail.com>
|
||||
Matt Clarkson <mattyclarkson@gmail.com>
|
||||
Nick Hutchinson <nshutchinson@gmail.com>
|
||||
Oleksandr Sochka <sasha.sochka@gmail.com>
|
||||
Paul Redmond <paul.redmond@gmail.com>
|
||||
Radoslav Yovchev <radoslav.tm@gmail.com>
|
||||
|
|
|
@ -40,6 +40,7 @@ Kaito Udagawa <umireon@gmail.com>
|
|||
Kai Wolf <kai.wolf@gmail.com>
|
||||
Lei Xu <eddyxu@gmail.com>
|
||||
Matt Clarkson <mattyclarkson@gmail.com>
|
||||
Nick Hutchinson <nshutchinson@gmail.com>
|
||||
Oleksandr Sochka <sasha.sochka@gmail.com>
|
||||
Pascal Leroy <phl@google.com>
|
||||
Paul Redmond <paul.redmond@gmail.com>
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
#include <thread>
|
||||
|
||||
#include "check.h"
|
||||
#include "colorprint.h"
|
||||
#include "commandlineflags.h"
|
||||
#include "complexity.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_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");
|
||||
|
||||
|
@ -546,7 +552,13 @@ size_t RunSpecifiedBenchmarks(BenchmarkReporter* console_reporter,
|
|||
std::unique_ptr<BenchmarkReporter> default_console_reporter;
|
||||
std::unique_ptr<BenchmarkReporter> default_file_reporter;
|
||||
if (!console_reporter) {
|
||||
auto output_opts = FLAGS_color_print ? ConsoleReporter::OO_Color
|
||||
auto output_opts = 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(
|
||||
FLAGS_benchmark_format, output_opts);
|
||||
|
@ -602,7 +614,7 @@ void PrintUsageAndExit() {
|
|||
" [--benchmark_format=<console|json|csv>]\n"
|
||||
" [--benchmark_out=<filename>]\n"
|
||||
" [--benchmark_out_format=<json|console|csv>]\n"
|
||||
" [--color_print={true|false}]\n"
|
||||
" [--benchmark_color={auto|true|false}]\n"
|
||||
" [--v=<verbosity>]\n");
|
||||
exit(0);
|
||||
}
|
||||
|
@ -627,8 +639,12 @@ void ParseCommandLineFlags(int* argc, char** argv) {
|
|||
&FLAGS_benchmark_out) ||
|
||||
ParseStringFlag(argv[i], "benchmark_out_format",
|
||||
&FLAGS_benchmark_out_format) ||
|
||||
ParseBoolFlag(argv[i], "color_print",
|
||||
&FLAGS_color_print) ||
|
||||
ParseStringFlag(argv[i], "benchmark_color",
|
||||
&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)) {
|
||||
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") {
|
||||
PrintUsageAndExit();
|
||||
}
|
||||
if (FLAGS_benchmark_color.empty()) {
|
||||
PrintUsageAndExit();
|
||||
}
|
||||
}
|
||||
|
||||
int InitializeStreams() {
|
||||
|
|
|
@ -16,16 +16,20 @@
|
|||
|
||||
#include <cstdarg>
|
||||
#include <cstdio>
|
||||
#include <cstdarg>
|
||||
#include <string>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "check.h"
|
||||
#include "internal_macros.h"
|
||||
|
||||
#ifdef BENCHMARK_OS_WINDOWS
|
||||
#include <io.h>
|
||||
#include <Windows.h>
|
||||
#endif
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#endif // BENCHMARK_OS_WINDOWS
|
||||
|
||||
namespace benchmark {
|
||||
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
|
||||
|
|
|
@ -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, ...);
|
||||
|
||||
// Returns true if stdout appears to be a terminal that supports colored
|
||||
// output, false otherwise.
|
||||
bool IsColorTerminal();
|
||||
|
||||
} // end namespace benchmark
|
||||
|
||||
#endif // BENCHMARK_COLORPRINT_H_
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
|
||||
#include "commandlineflags.h"
|
||||
|
||||
#include <cctype>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
|
@ -74,17 +75,6 @@ bool ParseDouble(const std::string& src_text, const char* str, double* value) {
|
|||
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
|
||||
// given flag. For example, FlagToEnvVar("foo") will return
|
||||
// "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".
|
||||
bool BoolFromEnv(const char* flag, bool default_value) {
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -113,7 +103,7 @@ bool BoolFromEnv(const char* flag, bool default_value) {
|
|||
// doesn't represent a valid 32-bit integer, returns default_value.
|
||||
int32_t Int32FromEnv(const char* flag, int32_t default_value) {
|
||||
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) {
|
||||
// The environment variable is not set.
|
||||
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.
|
||||
const char* StringFromEnv(const char* flag, const char* default_value) {
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -175,7 +165,7 @@ bool ParseBoolFlag(const char* str, const char* flag, bool* value) {
|
|||
if (value_str == nullptr) return false;
|
||||
|
||||
// Converts the string value to a bool.
|
||||
*value = !(*value_str == '0' || *value_str == 'f' || *value_str == 'F');
|
||||
*value = IsTruthyFlagValue(value_str);
|
||||
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) {
|
||||
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
|
||||
|
|
|
@ -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
|
||||
// "--flag=value" or "--flag".
|
||||
//
|
||||
// In the former case, the value is taken as true as long as it does
|
||||
// not start with '0', 'f', or 'F'.
|
||||
// In the former case, the value is taken as true if it passes IsTruthyValue().
|
||||
//
|
||||
// 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.
|
||||
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
|
||||
|
||||
#endif // BENCHMARK_COMMANDLINEFLAGS_H_
|
||||
|
|
Loading…
Reference in New Issue