-
Notifications
You must be signed in to change notification settings - Fork 1.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
bug: Inconsistent suffixes console reporter 1009 #1631
bug: Inconsistent suffixes console reporter 1009 #1631
Conversation
…/github.com/varshneydevansh/benchmark into inconsistent_suffixes_console_reporter_1009
…/github.com/varshneydevansh/benchmark into inconsistent_suffixes_console_reporter_1009
you'll need to update some tests, and run clang-format (Google style) to get the CI bots to be happy. |
Hi @dmah42 , I added the following test cases in the TEST(StringUtilTest, ExponentToPrefix) {
EXPECT_EQ("", benchmark::ExponentToPrefix(0, true));
EXPECT_EQ("", benchmark::ExponentToPrefix(0, false));
EXPECT_EQ("k", benchmark::ExponentToPrefix(1, true));
EXPECT_EQ("K", benchmark::ExponentToPrefix(1, false));
EXPECT_EQ("Mi", benchmark::ExponentToPrefix(2, true));
EXPECT_EQ("M", benchmark::ExponentToPrefix(2, false));
EXPECT_EQ("Gi", benchmark::ExponentToPrefix(3, true));
EXPECT_EQ("G", benchmark::ExponentToPrefix(3, false));
EXPECT_EQ("m", benchmark::ExponentToPrefix(-1, true));
EXPECT_EQ("m", benchmark::ExponentToPrefix(-1, false));
EXPECT_EQ("u", benchmark::ExponentToPrefix(-2, true));
EXPECT_EQ("u", benchmark::ExponentToPrefix(-2, false));
EXPECT_EQ("n", benchmark::ExponentToPrefix(-3, true));
EXPECT_EQ("n", benchmark::ExponentToPrefix(-3, false));
}
TEST(StringUtilTest, ToBinaryStringFullySpecified) {
// Test with Counter::kIs1024
EXPECT_EQ("1.00", benchmark::ToBinaryStringFullySpecified(1.0, 1.0, 2));
EXPECT_EQ("1.23k", benchmark::ToBinaryStringFullySpecified(1234.0, 1.0, 2));
EXPECT_EQ("1.00M", benchmark::ToBinaryStringFullySpecified(1.0e6, 1.0, 2));
EXPECT_EQ("1.00G", benchmark::ToBinaryStringFullySpecified(1.0e9, 1.0, 2));
// Test with Counter::kIs1000
EXPECT_EQ("1.00", benchmark::ToBinaryStringFullySpecified(
1.0, 1.0, 2, benchmark::Counter::kIs1000));
EXPECT_EQ("1.23k", benchmark::ToBinaryStringFullySpecified(
1234.0, 1.0, 2, benchmark::Counter::kIs1000));
EXPECT_EQ("1.00M", benchmark::ToBinaryStringFullySpecified(
1.0e6, 1.0, 2, benchmark::Counter::kIs1000));
EXPECT_EQ("1.00G", benchmark::ToBinaryStringFullySpecified(
1.0e9, 1.0, 2, benchmark::Counter::kIs1000));
}
TEST(StringUtilTest, AppendHumanReadable) {
std::string str;
benchmark::AppendHumanReadable(0, &str);
EXPECT_EQ("0", str);
benchmark::AppendHumanReadable(999, &str);
EXPECT_EQ("999", str);
benchmark::AppendHumanReadable(1000, &str);
EXPECT_EQ("1.00k", str);
benchmark::AppendHumanReadable(1000000, &str);
EXPECT_EQ("1.00M", str);
benchmark::AppendHumanReadable(1000000000, &str);
EXPECT_EQ("1.00G", str);
}
TEST(StringUtilTest, HumanReadableNumber) {
EXPECT_EQ("1.00", benchmark::HumanReadableNumber(1.0));
EXPECT_EQ("1.23k", benchmark::HumanReadableNumber(1234.0));
EXPECT_EQ("1.00M", benchmark::HumanReadableNumber(1.0e6));
EXPECT_EQ("1.00G", benchmark::HumanReadableNumber(1.0e9));
EXPECT_EQ("1.00",
benchmark::HumanReadableNumber(1.0, benchmark::Counter::kIs1000));
EXPECT_EQ("1.23k", benchmark::HumanReadableNumber(
1234.0, benchmark::Counter::kIs1000));
EXPECT_EQ("1.00M",
benchmark::HumanReadableNumber(1.0e6, benchmark::Counter::kIs1000));
EXPECT_EQ("1.00G",
benchmark::HumanReadableNumber(1.0e9, benchmark::Counter::kIs1000));
}
and the result is this ➜ test git:(inconsistent_suffixes_console_reporter_1009) ✗ ./string_util_gtest
Running main() from gmock_main.cc
[==========] Running 8 tests from 1 test suite.
[----------] Global test environment set-up.
[----------] 8 tests from StringUtilTest
[ RUN ] StringUtilTest.stoul
[ OK ] StringUtilTest.stoul (2 ms)
[ RUN ] StringUtilTest.stoi
[ OK ] StringUtilTest.stoi (0 ms)
[ RUN ] StringUtilTest.stod
[ OK ] StringUtilTest.stod (0 ms)
[ RUN ] StringUtilTest.StrSplit
[ OK ] StringUtilTest.StrSplit (0 ms)
[ RUN ] StringUtilTest.ExponentToPrefix
/home/devansh/benchmark/test/string_util_gtest.cc:168: Failure
Expected equality of these values:
"k"
benchmark::ExponentToPrefix(1, true)
Which is: "Ki"
/home/devansh/benchmark/test/string_util_gtest.cc:169: Failure
Expected equality of these values:
"K"
benchmark::ExponentToPrefix(1, false)
Which is: "k"
[ FAILED ] StringUtilTest.ExponentToPrefix (0 ms)
[ RUN ] StringUtilTest.ToBinaryStringFullySpecified
/home/devansh/benchmark/test/string_util_gtest.cc:189: Failure
Expected equality of these values:
"1.00"
benchmark::ToBinaryStringFullySpecified(1.0, 1.0, 2)
Which is: "1"
/home/devansh/benchmark/test/string_util_gtest.cc:190: Failure
Expected equality of these values:
"1.23k"
benchmark::ToBinaryStringFullySpecified(1234.0, 1.0, 2)
Which is: "1.20508Ki"
/home/devansh/benchmark/test/string_util_gtest.cc:191: Failure
Expected equality of these values:
"1.00M"
benchmark::ToBinaryStringFullySpecified(1.0e6, 1.0, 2)
Which is: "976.562Ki"
/home/devansh/benchmark/test/string_util_gtest.cc:192: Failure
Expected equality of these values:
"1.00G"
benchmark::ToBinaryStringFullySpecified(1.0e9, 1.0, 2)
Which is: "953.674Mi"
/home/devansh/benchmark/test/string_util_gtest.cc:195: Failure
Expected equality of these values:
"1.00"
benchmark::ToBinaryStringFullySpecified( 1.0, 1.0, 2, benchmark::Counter::kIs1000)
Which is: "1"
/home/devansh/benchmark/test/string_util_gtest.cc:197: Failure
Expected equality of these values:
"1.23k"
benchmark::ToBinaryStringFullySpecified( 1234.0, 1.0, 2, benchmark::Counter::kIs1000)
Which is: "1.234k"
/home/devansh/benchmark/test/string_util_gtest.cc:199: Failure
Expected equality of these values:
"1.00M"
benchmark::ToBinaryStringFullySpecified( 1.0e6, 1.0, 2, benchmark::Counter::kIs1000)
Which is: "1000k"
/home/devansh/benchmark/test/string_util_gtest.cc:201: Failure
Expected equality of these values:
"1.00G"
benchmark::ToBinaryStringFullySpecified( 1.0e9, 1.0, 2, benchmark::Counter::kIs1000)
Which is: "1000M"
[ FAILED ] StringUtilTest.ToBinaryStringFullySpecified (0 ms)
[ RUN ] StringUtilTest.AppendHumanReadable
/home/devansh/benchmark/test/string_util_gtest.cc:212: Failure
Expected equality of these values:
"999"
str
Which is: "0999"
/home/devansh/benchmark/test/string_util_gtest.cc:215: Failure
Expected equality of these values:
"1.00k"
str
Which is: "09991000"
/home/devansh/benchmark/test/string_util_gtest.cc:218: Failure
Expected equality of these values:
"1.00M"
str
Which is: "09991000976.562Ki"
/home/devansh/benchmark/test/string_util_gtest.cc:221: Failure
Expected equality of these values:
"1.00G"
str
Which is: "09991000976.562Ki953.674Mi"
[ FAILED ] StringUtilTest.AppendHumanReadable (0 ms)
[ RUN ] StringUtilTest.HumanReadableNumber
/home/devansh/benchmark/test/string_util_gtest.cc:225: Failure
Expected equality of these values:
"1.00"
benchmark::HumanReadableNumber(1.0)
Which is: "1"
/home/devansh/benchmark/test/string_util_gtest.cc:226: Failure
Expected equality of these values:
"1.23k"
benchmark::HumanReadableNumber(1234.0)
Which is: "1.20508Ki"
/home/devansh/benchmark/test/string_util_gtest.cc:227: Failure
Expected equality of these values:
"1.00M"
benchmark::HumanReadableNumber(1.0e6)
Which is: "976.562Ki"
/home/devansh/benchmark/test/string_util_gtest.cc:228: Failure
Expected equality of these values:
"1.00G"
benchmark::HumanReadableNumber(1.0e9)
Which is: "953.674Mi"
/home/devansh/benchmark/test/string_util_gtest.cc:230: Failure
Expected equality of these values:
"1.00"
benchmark::HumanReadableNumber(1.0, benchmark::Counter::kIs1000)
Which is: "1"
/home/devansh/benchmark/test/string_util_gtest.cc:232: Failure
Expected equality of these values:
"1.23k"
benchmark::HumanReadableNumber( 1234.0, benchmark::Counter::kIs1000)
Which is: "1.234k"
/home/devansh/benchmark/test/string_util_gtest.cc:234: Failure
Expected equality of these values:
"1.00M"
benchmark::HumanReadableNumber(1.0e6, benchmark::Counter::kIs1000)
Which is: "1000k"
/home/devansh/benchmark/test/string_util_gtest.cc:236: Failure
Expected equality of these values:
"1.00G"
benchmark::HumanReadableNumber(1.0e9, benchmark::Counter::kIs1000)
Which is: "1000M"
[ FAILED ] StringUtilTest.HumanReadableNumber (0 ms)
[----------] 8 tests from StringUtilTest (3 ms total)
[----------] Global test environment tear-down
[==========] 8 tests from 1 test suite ran. (3 ms total)
[ PASSED ] 4 tests.
[ FAILED ] 4 tests, listed below:
[ FAILED ] StringUtilTest.ExponentToPrefix
[ FAILED ] StringUtilTest.ToBinaryStringFullySpecified
[ FAILED ] StringUtilTest.AppendHumanReadable
[ FAILED ] StringUtilTest.HumanReadableNumber
4 FAILED TESTS |
…/github.com/varshneydevansh/benchmark into inconsistent_suffixes_console_reporter_1009
I wanna know something about this function - in the string_util.cc file void AppendHumanReadable(int n, std::string* str) {
std::stringstream ss;
// Round down to the nearest SI prefix.
ss << ToBinaryStringFullySpecified(n, 1.0, 0);
*str += ss.str();
} and the function which this is calling has a default value for std::string ToBinaryStringFullySpecified(
double value, double threshold, int precision,
Counter::OneK one_k = Counter::kIs1024) {
std::string mantissa;
int64_t exponent;
ToExponentAndMantissa(value, threshold, precision, one_k, &mantissa,
&exponent);
return mantissa + ExponentToPrefix(exponent, one_k == Counter::kIs1024);
} And this In that case, the comment If that is not the intention, then we might need to send the value of And regarding the test cases, I now only added test cases for these two methods |
I did find my one mistake with the following function, where I missed changing the type of
|
that's a good observation. yes, we should change the behaviour to match the comment as the comment describes the intent. (kIs1000 is more "natural" for human readable). in future we may make this an option on the outer function.
perfect. |
there's readability benefits to pull the calculation out of the for loop into a local variable (and small performance benefits if it's marked const, though most compilers will figure that out anyway). |
#include <iomanip.h>
void ToExponentAndMantissa(double val, double thresh, int precision,
Counter::OneK one_k, std::string* mantissa,
int64_t* exponent) {
std::stringstream mantissa_stream;
if (val < 0) {
mantissa_stream << "-";
val = -val;
}
// Adjust threshold so that it never excludes things which can't be rendered
// in 'precision' digits.
const double adjusted_threshold =
std::max(thresh, 1.0 / std::pow(10.0, precision));
const double big_threshold =
adjusted_threshold * (one_k == Counter::kIs1024 ? 1024.0 : 1000.0);
const double small_threshold = adjusted_threshold;
// Values in ]simple_threshold,small_threshold[ will be printed as-is
const double simple_threshold = 0.01;
if (val > big_threshold) {
// Positive powers
double scaled = val;
for (size_t i = 0; i < arraysize(kBigSIUnits); ++i) {
scaled /= (one_k == Counter::kIs1024 ? 1024.0 : 1000.0);
if (scaled < big_threshold) {
const double tolerance = 1e-9;
if (std::abs(scaled - 1.0) <= tolerance) {
mantissa_stream << std::setprecision(precision) << std::fixed
<< scaled;
*exponent = i + 2;
} else {
mantissa_stream << std::setprecision(precision) << std::fixed
<< scaled;
*exponent = i + 1;
}
*mantissa = mantissa_stream.str();
return;
}
}
mantissa_stream << std::setprecision(precision) << std::fixed << val;
*exponent = 0;
} else if (val < small_threshold) {
// Negative powers
if (val < simple_threshold) {
double scaled = val;
for (size_t i = 0; i < arraysize(kSmallSIUnits); ++i) {
scaled *= (one_k == Counter::kIs1024 ? 1024.0 : 1000.0);
if (scaled >= small_threshold) {
mantissa_stream << std::setprecision(precision) << std::fixed
<< scaled;
*exponent = -static_cast<int64_t>(i + 1);
*mantissa = mantissa_stream.str();
return;
}
}
}
mantissa_stream << std::setprecision(precision) << std::fixed << val;
*exponent = 0;
} else {
mantissa_stream << std::setprecision(precision) << std::fixed << val;
*exponent = 0;
}
*mantissa = mantissa_stream.str();
}
I did try to modify the above function, but the const double tolerance = 1e-9;
if (std::abs(scaled - 1.0) <= tolerance) {
mantissa_stream << std::setprecision(precision) << std::fixed
<< scaled;
*exponent = i + 2;
}
These are the test cases -
Output for the modified code - ➜ test git:(inconsistent_suffixes_console_reporter_1009) ✗ ./string_util_gtest
Running main() from gmock_main.cc
[==========] Running 6 tests from 1 test suite.
[----------] Global test environment set-up.
[----------] 6 tests from StringUtilTest
[ RUN ] StringUtilTest.stoul
[ OK ] StringUtilTest.stoul (0 ms)
[ RUN ] StringUtilTest.stoi
[ OK ] StringUtilTest.stoi (0 ms)
[ RUN ] StringUtilTest.stod
[ OK ] StringUtilTest.stod (0 ms)
[ RUN ] StringUtilTest.StrSplit
[ OK ] StringUtilTest.StrSplit (0 ms)
[ RUN ] StringUtilTest.AppendHumanReadable
/home/devansh/benchmark/test/string_util_gtest.cc:175: Failure
Expected equality of these values:
"1k"
str
Which is: "1000"
/home/devansh/benchmark/test/string_util_gtest.cc:179: Failure
Expected equality of these values:
"1M"
str
Which is: "1G"
/home/devansh/benchmark/test/string_util_gtest.cc:183: Failure
Expected equality of these values:
"1G"
str
Which is: "1T"
[ FAILED ] StringUtilTest.AppendHumanReadable (0 ms)
[ RUN ] StringUtilTest.HumanReadableNumber
/home/devansh/benchmark/test/string_util_gtest.cc:197: Failure
Expected equality of these values:
"1M"
benchmark::HumanReadableNumber(1.0e6, benchmark::Counter::kIs1000)
Which is: "1000.0k"
/home/devansh/benchmark/test/string_util_gtest.cc:199: Failure
Expected equality of these values:
"1G"
benchmark::HumanReadableNumber(1.0e9, benchmark::Counter::kIs1000)
Which is: "1000.0M"
[ FAILED ] StringUtilTest.HumanReadableNumber (0 ms)
[----------] 6 tests from StringUtilTest (0 ms total)
[----------] Global test environment tear-down
[==========] 6 tests from 1 test suite ran. (0 ms total)
[ PASSED ] 4 tests.
[ FAILED ] 2 tests, listed below:
[ FAILED ] StringUtilTest.AppendHumanReadable
[ FAILED ] StringUtilTest.HumanReadableNumber
2 FAILED TESTS Although, I have reverted these changes back to our latest discussion. |
I need help with the test cases. As I think I am missing something. This is the code which I am currently modifying - void ToExponentAndMantissa(double val, double thresh, int precision,
Counter::OneK one_k, std::string* mantissa,
int64_t* exponent) {
std::stringstream mantissa_stream;
if (val < 0) {
mantissa_stream << "-";
val = -val;
}
// Adjust threshold so that it never excludes things which can't be rendered
// in 'precision' digits.
const double adjusted_threshold =
std::max(thresh, 1.0 / std::pow(10.0, precision));
const double which_one_k = (one_k == Counter::kIs1024 ? 1024.0 : 1000.0);
const double big_threshold = adjusted_threshold * which_one_k;
const double small_threshold = adjusted_threshold;
// Values in ]simple_threshold,small_threshold[ will be printed as-is
const double simple_threshold = 0.01;
if (val > big_threshold) {
// Positive powers
double scaled = val;
for (size_t i = 0; i < arraysize(kBigSIUnits); ++i) {
scaled /= which_one_k;
if (scaled < big_threshold) {
mantissa_stream << std::fixed << std::setprecision(precision) << scaled;
*exponent = i + 1;
*mantissa = mantissa_stream.str();
return;
}
}
mantissa_stream << std::fixed << std::setprecision(precision) << val;
*exponent = 0;
} else if (val < small_threshold) {
// Negative powers
if (val < simple_threshold) {
double scaled = val;
for (size_t i = 0; i < arraysize(kSmallSIUnits); ++i) {
scaled *= which_one_k;
if (scaled >= small_threshold) {
mantissa_stream << std::fixed << std::setprecision(precision)
<< scaled;
*exponent = -static_cast<int64_t>(i + 1);
*mantissa = mantissa_stream.str();
return;
}
}
}
mantissa_stream << std::fixed << std::setprecision(precision) << val;
*exponent = 0;
} else {
double scaled = val;
size_t i = 0;
while (scaled >= which_one_k && i < arraysize(kBigSIUnits)) {
scaled /= which_one_k;
i++;
}
mantissa_stream << std::fixed << std::setprecision(precision) << scaled;
*exponent = i;
}
*mantissa = mantissa_stream.str();
} I modified this else {
double scaled = val;
size_t i = 0;
while (scaled >= which_one_k && i < arraysize(kBigSIUnits)) {
scaled /= which_one_k;
i++;
}
mantissa_stream << std::fixed << std::setprecision(precision) << scaled;
*exponent = i;
}
*mantissa = mantissa_stream.str();
} Now I am left with one failing test case - ➜ test git:(inconsistent_suffixes_console_reporter_1009) ✗ ./string_util_gtest
Running main() from gmock_main.cc
[==========] Running 6 tests from 1 test suite.
[----------] Global test environment set-up.
[----------] 6 tests from StringUtilTest
[ RUN ] StringUtilTest.stoul
[ OK ] StringUtilTest.stoul (0 ms)
[ RUN ] StringUtilTest.stoi
[ OK ] StringUtilTest.stoi (0 ms)
[ RUN ] StringUtilTest.stod
[ OK ] StringUtilTest.stod (0 ms)
[ RUN ] StringUtilTest.StrSplit
[ OK ] StringUtilTest.StrSplit (0 ms)
[ RUN ] StringUtilTest.AppendHumanReadable
n: 0, mantissa: 0, exponent: 0
n: 999, mantissa: 999, exponent: 0
n: 1000, mantissa: 1, exponent: 1
n: 1e+06, mantissa: 1, exponent: 2
n: 1e+09, mantissa: 1, exponent: 3
[ OK ] StringUtilTest.AppendHumanReadable (0 ms)
[ RUN ] StringUtilTest.HumanReadableNumber
n: 1, mantissa: 1.0, exponent: 0
n: 1234, mantissa: 1.2, exponent: 1
n: 1e+06, mantissa: 976.6, exponent: 1
n: 1e+09, mantissa: 953.7, exponent: 2
n: 1, mantissa: 1.0, exponent: 0
n: 1234, mantissa: 1.2, exponent: 1
n: 1e+06, mantissa: 1000.0, exponent: 1
/home/devansh/benchmark/test/string_util_gtest.cc:197: Failure
Expected equality of these values:
"1.0M"
benchmark::HumanReadableNumber(1.0e6, benchmark::Counter::kIs1000)
Which is: "1000.0k"
n: 1e+09, mantissa: 1000.0, exponent: 2
/home/devansh/benchmark/test/string_util_gtest.cc:199: Failure
Expected equality of these values:
"1.0G"
benchmark::HumanReadableNumber(1.0e9, benchmark::Counter::kIs1000)
Which is: "1000.0M"
[ FAILED ] StringUtilTest.HumanReadableNumber (0 ms)
[----------] 6 tests from StringUtilTest (0 ms total)
[----------] Global test environment tear-down
[==========] 6 tests from 1 test suite ran. (0 ms total)
[ PASSED ] 5 tests.
[ FAILED ] 1 test, listed below:
[ FAILED ] StringUtilTest.HumanReadableNumber
1 FAILED TEST added this std::string ToBinaryStringFullySpecified(
double value, double threshold, int precision,
Counter::OneK one_k = Counter::kIs1024) {
std::string mantissa;
int64_t exponent;
ToExponentAndMantissa(value, threshold, precision, one_k, &mantissa,
&exponent);
std::cout << "n: " << value << ", mantissa: " << mantissa
<< ", exponent: " << exponent << std::endl;
return mantissa + ExponentToPrefix(exponent, one_k == Counter::kIs1024);
} |
can you commit and push your local version of the code to the PR? then i can see the diff and the test failures here clearly. |
Line 110 in 27d64a2
called Line 153 in 27d64a2
benchmark/test/string_util_gtest.cc Line 212 in 27d64a2
the latter tests were updated as part of my change, but we still use SI for user counters by default unless it's overridden in the Counter constructor. |
|
I'm missing something, sorry. user counter thousands test has all the counter variants including the default. what are you looking for and can't find in the tests? |
Is this change as it is now supposed to still cause externally-observable (in reporters, |
Should I remove the function |
…/github.com/varshneydevansh/benchmark into inconsistent_suffixes_console_reporter_1009
Please fix the missing newlines at the end of files i mentioned, otherwise i suppose this is good to go? |
I have checked it with clang-format and even have run the test cases, these new lines have no impact on as of my understanding. I think we are good to go. |
(@dmah42 merge?) |
still shows as changes requested.. I was waiting for those. |
amazing. thank you. |
I actually got a little lost with the statement regarding the new line. I did ask about this from a few of my friends, but they also couldn't get it well as English is not our native language. Maybe I should have asked with you guys regarding that. Thank you, Dominic and Roman, for guiding me. The use of pointers and memory access and how to improve efficiency of code by carefully getting rid of assignment headers. I learned so much. 🙌 |
Issue ->
Proposed Solution ->
Setting
true
orfalse
based on the value ofone_k
which is being converted from adouble to enum
instd::string ToBinaryStringFullySpecified()
in file string_util.ccand changed the
SI
andIEC
single character suffixes to multi-character strings