Closed varshneydevansh closed 11 months ago
you'll need to update some tests, and run clang-format (Google style) to get the CI bots to be happy.
you'll need to update some tests, and run clang-format (Google style) to get the CI bots to be happy.
I think in the string_util_gtest.cc
file, there is a typo in the first comment. Should I also correct it?
Hi @dmah42 , Should I commit the changes? I also ran the clang-format. Furthermore, are these test cases correct?
I added the following test cases in the string_util_gtest.cc
file -
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
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 one_k = 1024.0
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 std::string ToBinaryStringFullySpecified()
works fine with the std::string HumanReadableNumber(double n, Counter::OneK one_k)
as we are sending the flag value along with this.
In that case, the comment "// Round down to the nearest SI prefix"
may be misleading or incorrect. If the intention is to use the IEC prefixes, the comment should reflect that, such as "// Round down to the nearest IEC prefix."
If that is not the intention, then we might need to send the value of kIs1000
in the ss << ToBinaryStringFullySpecified(n, 1.0, 0);
.
And regarding the test cases, I now only added test cases for these two methods HumanReadableNumber()
and AppendHumanReadable()
as they are only available in the string_util.h file and all of our changes depends on them.
one_k
from double to enum.The following is the updated code -
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) {
mantissa_stream << scaled;
*exponent = i + 1;
*mantissa = mantissa_stream.str();
return;
}
}
mantissa_stream << 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 << scaled;
*exponent = -static_cast<int64_t>(i + 1);
*mantissa = mantissa_stream.str();
return;
}
}
}
mantissa_stream << val;
*exponent = 0;
} else {
mantissa_stream << val;
*exponent = 0;
}
*mantissa = mantissa_stream.str();
}
And just for my clarification, could the below if be written like this for the for-loop? And I think the arraysize
macro is meant to be used with a statically sized array, and it cannot determine the size of an array determined at runtime.
if (val > big_threshold) {
// Positive powers
double scaled = val;
for (size_t i = 0; i < arraysize((one_k == Counter::kIs1024 ? kBigIECUnits : kBigSIUnits)); ++i) {
OR I may could store the result in a variable?
double checked_one_k = (one_k == Counter::kIs1024 ? 1024.0 : 1000.0)
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
one_k = 1024.0
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
std::string ToBinaryStringFullySpecified()
works fine with thestd::string HumanReadableNumber(double n, Counter::OneK one_k)
as we are sending the flag value along with this.In that case, the comment
"// Round down to the nearest SI prefix"
may be misleading or incorrect. If the intention is to use the IEC prefixes, the comment should reflect that, such as"// Round down to the nearest IEC prefix."
If that is not the intention, then we might need to send the value of
kIs1000
in thess << ToBinaryStringFullySpecified(n, 1.0, 0);
.
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.
And regarding the test cases, I now only added test cases for these two methods
HumanReadableNumber()
andAppendHumanReadable()
as they are only available in the string_util.h file and all of our changes depends on them.
perfect.
I did find my one mistake with the following function, where I missed changing the type of
one_k
from double to enum.The following is the updated code -
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) { mantissa_stream << scaled; *exponent = i + 1; *mantissa = mantissa_stream.str(); return; } } mantissa_stream << 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 << scaled; *exponent = -static_cast<int64_t>(i + 1); *mantissa = mantissa_stream.str(); return; } } } mantissa_stream << val; *exponent = 0; } else { mantissa_stream << val; *exponent = 0; } *mantissa = mantissa_stream.str(); }
And just for my clarification, could the below if be written like this for the for-loop? And I think the
arraysize
macro is meant to be used with a statically sized array, and it cannot determine the size of an array determined at runtime.if (val > big_threshold) { // Positive powers double scaled = val; for (size_t i = 0; i < arraysize((one_k == Counter::kIs1024 ? kBigIECUnits : kBigSIUnits)); ++i) {
OR I may could store the result in a variable?
double checked_one_k = (one_k == Counter::kIs1024 ? 1024.0 : 1000.0)
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 if-clause
inside the big_threshold
started to shoot-off -
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 -
TEST(StringUtilTest, AppendHumanReadable) {
std::string str;
benchmark::AppendHumanReadable(0, &str);
EXPECT_EQ("0", str);
str.clear();
benchmark::AppendHumanReadable(999, &str);
EXPECT_EQ("999", str);
str.clear();
benchmark::AppendHumanReadable(1000, &str);
EXPECT_EQ("1k", str);
str.clear();
benchmark::AppendHumanReadable(1000000, &str);
EXPECT_EQ("1M", str);
str.clear();
benchmark::AppendHumanReadable(1000000000, &str);
EXPECT_EQ("1G", str);
str.clear();
}
TEST(StringUtilTest, HumanReadableNumber) {
EXPECT_EQ("1.0", benchmark::HumanReadableNumber(1.0));
EXPECT_EQ("1.2Ki", benchmark::HumanReadableNumber(1234.0));
EXPECT_EQ("976.6Ki", benchmark::HumanReadableNumber(1.0e6));
EXPECT_EQ("953.7Mi", benchmark::HumanReadableNumber(1.0e9));
EXPECT_EQ("1.0",
benchmark::HumanReadableNumber(1.0, benchmark::Counter::kIs1000));
EXPECT_EQ("1.2k", benchmark::HumanReadableNumber(
1234.0, benchmark::Counter::kIs1000));
EXPECT_EQ("1M",
benchmark::HumanReadableNumber(1.0e6, benchmark::Counter::kIs1000));
EXPECT_EQ("1G",
benchmark::HumanReadableNumber(1.0e9, benchmark::Counter::kIs1000));
}
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
clause at the last -
It handles the case where the value val
falls within the range between the small threshold and the big threshold.
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 cout
for the debugging purpose only.
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.
there's a bug in the existing implementation, which is making your life harder.
std::string ToBinaryStringFullySpecified(double value, double threshold,
int precision, double one_k = 1024.0) {
std::string mantissa;
int64_t exponent;
ToExponentAndMantissa(value, threshold, precision, one_k, &mantissa,
&exponent);
return mantissa + ExponentToPrefix(exponent, false);
}
ie, we pass in one_k to ToExponentAndMantissa
and then ignore it in ExponentToPrefix
. i suspect "just" fixing this would make things more consistent directly.. i will try this locally to see if i can get some tests to pass. then we can see about what we need to improve.
i have tests locally that are passing with minimal changes to the code. i'll create a pull request for that and then we should rebase your work onto it.
i have tests locally that are passing with minimal changes to the code. i'll create a pull request for that and then we should rebase your work onto it.
i think you're bringing in some old changes here with the rebase.
i think the only thing we need is to decide if AppendHumanReadable
is intended to be SI (per the comment) or IEC (per the current implementation) and make that one change (and then update the tests).
i think "human readable" suggests SI units in which case the comment is correct and we just need to add the right enum to the call to ToBinaryStringFullySpecified
. i'd also remove the default while you're there so all the calls are explicit.
This is exactly what I was going to ask you. I merged the changes introduced by you in my current local repo.
void AppendHumanReadable(int n, std::string* str) {
std::stringstream ss;
// Round down to the nearest SI prefix.
ss << ToBinaryStringFullySpecified(n, 0, Counter::kIs1000);
*str += ss.str();
}
std::string HumanReadableNumber(double n, Counter::OneK one_k) {
// 1 means that we should show one decimal place of precision.
return ToBinaryStringFullySpecified(n, 1, one_k);
}
using AppendHumanReadableFixture =
::testing::TestWithParam<std::tuple<int, std::string>>;
INSTANTIATE_TEST_SUITE_P(
AppendHumanReadableTests, AppendHumanReadableFixture,
::testing::Values(std::make_tuple(0, "0"), std::make_tuple(999, "999"),
std::make_tuple(1000, "1000"),
std::make_tuple(1024, "1Ki"),
std::make_tuple(1000 * 1000, "976\\.56.Ki"),
std::make_tuple(1024 * 1024, "1Mi"),
std::make_tuple(1000 * 1000 * 1000, "953\\.674Mi"),
std::make_tuple(1024 * 1024 * 1024, "1Gi")));
TEST_P(AppendHumanReadableFixture, AppendHumanReadable) {
std::string str;
benchmark::AppendHumanReadable(std::get<0>(GetParam()), &str);
ASSERT_THAT(str, ::testing::MatchesRegex(std::get<1>(GetParam())));
}
This is the output which we are now getting -
I want to ask since appendHumanReadable()
is going to return
the SI values
, which means Testing for IEC values is also going to return the result in the term of SI value.
[----------] 4 tests from StringUtilTest (1 ms total)
[----------] 8 tests from AppendHumanReadableTests/AppendHumanReadableFixture
[ RUN ] AppendHumanReadableTests/AppendHumanReadableFixture.AppendHumanReadable/0
[ OK ] AppendHumanReadableTests/AppendHumanReadableFixture.AppendHumanReadable/0 (0 ms)
[ RUN ] AppendHumanReadableTests/AppendHumanReadableFixture.AppendHumanReadable/1
[ OK ] AppendHumanReadableTests/AppendHumanReadableFixture.AppendHumanReadable/1 (0 ms)
[ RUN ] AppendHumanReadableTests/AppendHumanReadableFixture.AppendHumanReadable/2
/home/devansh/benchmark/test/string_util_gtest.cc:180: Failure
Value of: str
Expected: matches regular expression "1000"
Actual: "1k"
[ FAILED ] AppendHumanReadableTests/AppendHumanReadableFixture.AppendHumanReadable/2, where GetParam() = (1000, "1000") (0 ms)
[ RUN ] AppendHumanReadableTests/AppendHumanReadableFixture.AppendHumanReadable/3
/home/devansh/benchmark/test/string_util_gtest.cc:180: Failure
Value of: str
Expected: matches regular expression "1Ki"
Actual: "1k"
[ FAILED ] AppendHumanReadableTests/AppendHumanReadableFixture.AppendHumanReadable/3, where GetParam() = (1024, "1Ki") (0 ms)
[ RUN ] AppendHumanReadableTests/AppendHumanReadableFixture.AppendHumanReadable/4
/home/devansh/benchmark/test/string_util_gtest.cc:180: Failure
Value of: str
Expected: matches regular expression "976\\.56.Ki"
Actual: "1M"
[ FAILED ] AppendHumanReadableTests/AppendHumanReadableFixture.AppendHumanReadable/4, where GetParam() = (1000000, "976\\.56.Ki") (0 ms)
[ RUN ] AppendHumanReadableTests/AppendHumanReadableFixture.AppendHumanReadable/5
/home/devansh/benchmark/test/string_util_gtest.cc:180: Failure
Value of: str
Expected: matches regular expression "1Mi"
Actual: "1M"
[ FAILED ] AppendHumanReadableTests/AppendHumanReadableFixture.AppendHumanReadable/5, where GetParam() = (1048576, "1Mi") (0 ms)
[ RUN ] AppendHumanReadableTests/AppendHumanReadableFixture.AppendHumanReadable/6
/home/devansh/benchmark/test/string_util_gtest.cc:180: Failure
Value of: str
Expected: matches regular expression "953\\.674Mi"
Actual: "1G"
[ FAILED ] AppendHumanReadableTests/AppendHumanReadableFixture.AppendHumanReadable/6, where GetParam() = (1000000000, "953\\.674Mi") (0 ms)
[ RUN ] AppendHumanReadableTests/AppendHumanReadableFixture.AppendHumanReadable/7
/home/devansh/benchmark/test/string_util_gtest.cc:180: Failure
Value of: str
Expected: matches regular expression "1Gi"
Actual: "1G"
[ FAILED ] AppendHumanReadableTests/AppendHumanReadableFixture.AppendHumanReadable/7, where GetParam() = (1073741824, "1Gi") (0 ms)
[----------] 8 tests from AppendHumanReadableTests/AppendHumanReadableFixture (0 ms total)
[----------] 16 tests from HumanReadableTests/HumanReadableFixture
[ RUN ] HumanReadableTests/HumanReadableFixture.HumanReadableNumber/0
/home/devansh/benchmark/test/string_util_gtest.cc:215: Failure
Value of: str
Expected: matches regular expression "0"
Actual: "0.0"
[ FAILED ] HumanReadableTests/HumanReadableFixture.HumanReadableNumber/0, where GetParam() = (0, 1024, "0") (0 ms)
[ RUN ] HumanReadableTests/HumanReadableFixture.HumanReadableNumber/1
/home/devansh/benchmark/test/string_util_gtest.cc:215: Failure
Value of: str
Expected: matches regular expression "999"
Actual: "999.0"
[ FAILED ] HumanReadableTests/HumanReadableFixture.HumanReadableNumber/1, where GetParam() = (999, 1024, "999") (0 ms)
[ RUN ] HumanReadableTests/HumanReadableFixture.HumanReadableNumber/2
/home/devansh/benchmark/test/string_util_gtest.cc:215: Failure
Value of: str
Expected: matches regular expression "1000"
Actual: "1000.0"
[ FAILED ] HumanReadableTests/HumanReadableFixture.HumanReadableNumber/2, where GetParam() = (1000, 1024, "1000") (0 ms)
[ RUN ] HumanReadableTests/HumanReadableFixture.HumanReadableNumber/3
/home/devansh/benchmark/test/string_util_gtest.cc:215: Failure
Value of: str
Expected: matches regular expression "1Ki"
Actual: "1.0k"
[ FAILED ] HumanReadableTests/HumanReadableFixture.HumanReadableNumber/3, where GetParam() = (1024, 1024, "1Ki") (0 ms)
[ RUN ] HumanReadableTests/HumanReadableFixture.HumanReadableNumber/4
/home/devansh/benchmark/test/string_util_gtest.cc:215: Failure
Value of: str
Expected: matches regular expression "976\\.56.Ki"
Actual: "976.6k"
[ FAILED ] HumanReadableTests/HumanReadableFixture.HumanReadableNumber/4, where GetParam() = (1e+06, 1024, "976\\.56.Ki") (0 ms)
[ RUN ] HumanReadableTests/HumanReadableFixture.HumanReadableNumber/5
/home/devansh/benchmark/test/string_util_gtest.cc:215: Failure
Value of: str
Expected: matches regular expression "1Mi"
Actual: "1.0M"
[ FAILED ] HumanReadableTests/HumanReadableFixture.HumanReadableNumber/5, where GetParam() = (1.04858e+06, 1024, "1Mi") (0 ms)
[ RUN ] HumanReadableTests/HumanReadableFixture.HumanReadableNumber/6
/home/devansh/benchmark/test/string_util_gtest.cc:215: Failure
Value of: str
Expected: matches regular expression "953\\.674Mi"
Actual: "953.7M"
[ FAILED ] HumanReadableTests/HumanReadableFixture.HumanReadableNumber/6, where GetParam() = (1e+09, 1024, "953\\.674Mi") (0 ms)
[ RUN ] HumanReadableTests/HumanReadableFixture.HumanReadableNumber/7
/home/devansh/benchmark/test/string_util_gtest.cc:215: Failure
Value of: str
Expected: matches regular expression "1Gi"
Actual: "1.0G"
[ FAILED ] HumanReadableTests/HumanReadableFixture.HumanReadableNumber/7, where GetParam() = (1.07374e+09, 1024, "1Gi") (0 ms)
[ RUN ] HumanReadableTests/HumanReadableFixture.HumanReadableNumber/8
/home/devansh/benchmark/test/string_util_gtest.cc:215: Failure
Value of: str
Expected: matches regular expression "0"
Actual: "0.0"
[ FAILED ] HumanReadableTests/HumanReadableFixture.HumanReadableNumber/8, where GetParam() = (0, 1000, "0") (0 ms)
[ RUN ] HumanReadableTests/HumanReadableFixture.HumanReadableNumber/9
/home/devansh/benchmark/test/string_util_gtest.cc:215: Failure
Value of: str
Expected: matches regular expression "999"
Actual: "999.0"
[ FAILED ] HumanReadableTests/HumanReadableFixture.HumanReadableNumber/9, where GetParam() = (999, 1000, "999") (0 ms)
[ RUN ] HumanReadableTests/HumanReadableFixture.HumanReadableNumber/10
/home/devansh/benchmark/test/string_util_gtest.cc:215: Failure
Value of: str
Expected: matches regular expression "1k"
Actual: "1.0k"
[ FAILED ] HumanReadableTests/HumanReadableFixture.HumanReadableNumber/10, where GetParam() = (1000, 1000, "1k") (0 ms)
[ RUN ] HumanReadableTests/HumanReadableFixture.HumanReadableNumber/11
/home/devansh/benchmark/test/string_util_gtest.cc:215: Failure
Value of: str
Expected: matches regular expression "1.024k"
Actual: "1.0k"
[ FAILED ] HumanReadableTests/HumanReadableFixture.HumanReadableNumber/11, where GetParam() = (1024, 1000, "1.024k") (0 ms)
[ RUN ] HumanReadableTests/HumanReadableFixture.HumanReadableNumber/12
/home/devansh/benchmark/test/string_util_gtest.cc:215: Failure
Value of: str
Expected: matches regular expression "1M"
Actual: "1.0M"
[ FAILED ] HumanReadableTests/HumanReadableFixture.HumanReadableNumber/12, where GetParam() = (1e+06, 1000, "1M") (0 ms)
[ RUN ] HumanReadableTests/HumanReadableFixture.HumanReadableNumber/13
/home/devansh/benchmark/test/string_util_gtest.cc:215: Failure
Value of: str
Expected: matches regular expression "1\\.04858M"
Actual: "1.0M"
[ FAILED ] HumanReadableTests/HumanReadableFixture.HumanReadableNumber/13, where GetParam() = (1.04858e+06, 1000, "1\\.04858M") (0 ms)
[ RUN ] HumanReadableTests/HumanReadableFixture.HumanReadableNumber/14
/home/devansh/benchmark/test/string_util_gtest.cc:215: Failure
Value of: str
Expected: matches regular expression "1G"
Actual: "1.0G"
[ FAILED ] HumanReadableTests/HumanReadableFixture.HumanReadableNumber/14, where GetParam() = (1e+09, 1000, "1G") (0 ms)
[ RUN ] HumanReadableTests/HumanReadableFixture.HumanReadableNumber/15
/home/devansh/benchmark/test/string_util_gtest.cc:215: Failure
Value of: str
Expected: matches regular expression "1\\.07374G"
Actual: "1.1G"
[ FAILED ] HumanReadableTests/HumanReadableFixture.HumanReadableNumber/15, where GetParam() = (1.07374e+09, 1000, "1\\.07374G") (0 ms)
[----------] 16 tests from HumanReadableTests/HumanReadableFixture (1 ms total)
[----------] Global test environment tear-down
[==========] 28 tests from 3 test suites ran. (3 ms total)
[ PASSED ] 6 tests.
[ FAILED ] 22 tests, listed below:
[ FAILED ] AppendHumanReadableTests/AppendHumanReadableFixture.AppendHumanReadable/2, where GetParam() = (1000, "1000")
[ FAILED ] AppendHumanReadableTests/AppendHumanReadableFixture.AppendHumanReadable/3, where GetParam() = (1024, "1Ki")
[ FAILED ] AppendHumanReadableTests/AppendHumanReadableFixture.AppendHumanReadable/4, where GetParam() = (1000000, "976\\.56.Ki")
[ FAILED ] AppendHumanReadableTests/AppendHumanReadableFixture.AppendHumanReadable/5, where GetParam() = (1048576, "1Mi")
[ FAILED ] AppendHumanReadableTests/AppendHumanReadableFixture.AppendHumanReadable/6, where GetParam() = (1000000000, "953\\.674Mi")
[ FAILED ] AppendHumanReadableTests/AppendHumanReadableFixture.AppendHumanReadable/7, where GetParam() = (1073741824, "1Gi")
[ FAILED ] HumanReadableTests/HumanReadableFixture.HumanReadableNumber/0, where GetParam() = (0, 1024, "0")
[ FAILED ] HumanReadableTests/HumanReadableFixture.HumanReadableNumber/1, where GetParam() = (999, 1024, "999")
[ FAILED ] HumanReadableTests/HumanReadableFixture.HumanReadableNumber/2, where GetParam() = (1000, 1024, "1000")
[ FAILED ] HumanReadableTests/HumanReadableFixture.HumanReadableNumber/3, where GetParam() = (1024, 1024, "1Ki")
[ FAILED ] HumanReadableTests/HumanReadableFixture.HumanReadableNumber/4, where GetParam() = (1e+06, 1024, "976\\.56.Ki")
[ FAILED ] HumanReadableTests/HumanReadableFixture.HumanReadableNumber/5, where GetParam() = (1.04858e+06, 1024, "1Mi")
[ FAILED ] HumanReadableTests/HumanReadableFixture.HumanReadableNumber/6, where GetParam() = (1e+09, 1024, "953\\.674Mi")
[ FAILED ] HumanReadableTests/HumanReadableFixture.HumanReadableNumber/7, where GetParam() = (1.07374e+09, 1024, "1Gi")
[ FAILED ] HumanReadableTests/HumanReadableFixture.HumanReadableNumber/8, where GetParam() = (0, 1000, "0")
[ FAILED ] HumanReadableTests/HumanReadableFixture.HumanReadableNumber/9, where GetParam() = (999, 1000, "999")
[ FAILED ] HumanReadableTests/HumanReadableFixture.HumanReadableNumber/10, where GetParam() = (1000, 1000, "1k")
[ FAILED ] HumanReadableTests/HumanReadableFixture.HumanReadableNumber/11, where GetParam() = (1024, 1000, "1.024k")
[ FAILED ] HumanReadableTests/HumanReadableFixture.HumanReadableNumber/12, where GetParam() = (1e+06, 1000, "1M")
[ FAILED ] HumanReadableTests/HumanReadableFixture.HumanReadableNumber/13, where GetParam() = (1.04858e+06, 1000, "1\\.04858M")
[ FAILED ] HumanReadableTests/HumanReadableFixture.HumanReadableNumber/14, where GetParam() = (1e+09, 1000, "1G")
[ FAILED ] HumanReadableTests/HumanReadableFixture.HumanReadableNumber/15, where GetParam() = (1.07374e+09, 1000, "1\\.07374G")
22 FAILED TESTS
And yes, I have created a new branch where I am just modifying your updated changes with the proposed one.
Changing the -
const char* const kBigSIUnits[] = {"k", "M", "G", "T", "P", "E", "Z", "Y"};
// Kibi, Mebi, Gibi, Tebi, Pebi, Exbi, Zebi, Yobi.
const char* const kBigIECUnits[] = {"Ki", "Mi", "Gi", "Ti",
"Pi", "Ei", "Zi", "Yi"};
// milli, micro, nano, pico, femto, atto, zepto, yocto.
const char* const kSmallSIUnits[] = {"m", "u", "n", "p", "f", "a", "z", "y"};
and
void AppendHumanReadable(int n, std::string* str) {
std::stringstream ss;
// Round down to the nearest SI prefix.
ss << ToBinaryStringFullySpecified(n, 0, Counter::kIs1000);
*str += ss.str();
}
std::string HumanReadableNumber(double n, Counter::OneK one_k) {
return ToBinaryStringFullySpecified(n, 1, one_k);
}
I made a couple of changes to the test case for AppendHumanReadable()
in my new branch and are left with 3 failing test cases -
[ RUN ] AppendHumanReadableTests/AppendHumanReadableFixture.AppendHumanReadable/3
/home/devansh/benchmark/test/string_util_gtest.cc:179: Failure
Value of: str
Expected: matches regular expression "1Ki"
Actual: "1.024k"
[ FAILED ] AppendHumanReadableTests/AppendHumanReadableFixture.AppendHumanReadable/3, where GetParam() = (1024, "1Ki") (0 ms)
[ RUN ] AppendHumanReadableTests/AppendHumanReadableFixture.AppendHumanReadable/4
[ OK ] AppendHumanReadableTests/AppendHumanReadableFixture.AppendHumanReadable/4 (0 ms)
[ RUN ] AppendHumanReadableTests/AppendHumanReadableFixture.AppendHumanReadable/5
/home/devansh/benchmark/test/string_util_gtest.cc:179: Failure
Value of: str
Expected: matches regular expression "1Mi"
Actual: "1.04858M"
[ FAILED ] AppendHumanReadableTests/AppendHumanReadableFixture.AppendHumanReadable/5, where GetParam() = (1048576, "1Mi") (0 ms)
[ RUN ] AppendHumanReadableTests/AppendHumanReadableFixture.AppendHumanReadable/6
[ OK ] AppendHumanReadableTests/AppendHumanReadableFixture.AppendHumanReadable/6 (0 ms)
[ RUN ] AppendHumanReadableTests/AppendHumanReadableFixture.AppendHumanReadable/7
/home/devansh/benchmark/test/string_util_gtest.cc:179: Failure
Value of: str
Expected: matches regular expression "1Gi"
Actual: "1.07374G"
[ FAILED ] AppendHumanReadableTests/AppendHumanReadableFixture.AppendHumanReadable/7, where GetParam() = (1073741824, "1Gi") (0 ms)
[----------] 8 tests from AppendHumanReadableTests/AppendHumanReadableFixture (0 ms total)
Should, I merge this branch with this PR or copy the changes from this new branch to the current PR branch?
AppendHumanReadable()
why it's giving more decimal places for those IEC values.From past two days I have been thinking of creating a new PR for this as I think I have messed a lot of code here.
From past two days I have been thinking of creating a new PR for this as I think I have messed a lot of code here.
From past two days I have been thinking of creating a new PR for this as I think I have messed a lot of code here.
i think your current set of changes are fine, you just need to figure out what you expect AppendHumanReadable to return and then update the test to match. the HEAD version assumes kIs1024. that's changed. so what test cases are now invalid?
Hi @dmah42,
I have been tweaking the code for the past 4 hours to determine the correct patch/ behavior which I want from AppendHumanReadable(int n, std::string* str)
.
As far as I am able to understand, the behavior of the methods void AppendHumanReadable(int n, std::string* str)
and std::string HumanReadableNumber(double n, Counter::OneK one_k)
are the same with the only difference is that when user just wanna see the result quickly they will use the AppendHumanReadable which is somewhat the same as Big O analysis where we are somewhat concerned with the highest degree of the polynomial.
The same goes with the case of AppendHumanReadable here we want the result to be rounded down to the nearest SI prefix by that I mean is they are not particularly not concerned with the other value in the same number.
I even tried to convert the returning string from ToBinaryStringFullySpecified
in this method to an integer, then appending the last SI value to it.
As per my understanding, the test cases should be like this (quick readable number) -
INSTANTIATE_TEST_SUITE_P(
AppendHumanReadableTests, AppendHumanReadableFixture,
::testing::Values(std::make_tuple(0, "0"), std::make_tuple(999, "999"),
std::make_tuple(1000, "1k"), std::make_tuple(1024, "1k"),
std::make_tuple(1000 * 1000, "1M"),
std::make_tuple(1234 * 1000, "1M"),
std::make_tuple(1024 * 1024, "1M"),
std::make_tuple(1000 * 1000 * 1000, "1G"),
std::make_tuple(1024 * 1024 * 1024, "1G")));
But, if we want the precise values, then we have the method HumanReadableNumber()
which works as expected.
I was even looking into this PR - https://github.com/google/benchmark/pull/1607/files
I don't think we want it rounded down, just consistent. so if it should be SI then we should use SI. the issue today is that we expect SI but get IEC (and before my PR we got IEC with SI suffixes I think...).
so just switching from kIs1024 to kIs1000 and updating the tests should be sufficient for the main issue, as I understand it.
Passing all the test cases. Pushing the changes from the test file- string_util_gtest.cc
[----------] Global test environment tear-down
[==========] 29 tests from 3 test suites ran. (1 ms total)
[ PASSED ] 29 tests.
➜ test git:(inconsistent_suffixes_console_reporter_1009) ✗
using AppendHumanReadableFixture =
::testing::TestWithParam<std::tuple<int, std::string>>;
INSTANTIATE_TEST_SUITE_P(
AppendHumanReadableTests, AppendHumanReadableFixture,
::testing::Values(std::make_tuple(0, "0"), std::make_tuple(999, "999"),
std::make_tuple(1000, "1k"), std::make_tuple(1024, "1.024k"),
std::make_tuple(1000 * 1000, "1M"),
std::make_tuple(1234 * 1000, "1.234M"),
std::make_tuple(1024 * 1024, "1.04858M"),
std::make_tuple(1000 * 1000 * 1000, "1G"),
std::make_tuple(1024 * 1024 * 1024, "1.07374G")));
TEST_P(AppendHumanReadableFixture, AppendHumanReadable) {
std::string str;
benchmark::AppendHumanReadable(std::get<0>(GetParam()), &str);
ASSERT_THAT(str, ::testing::MatchesRegex(std::get<1>(GetParam())));
}
Can I pick this challenge? [FR] cc_libraries should use "includes", not "strip_include_prefix"- 1512 https://github.com/google/benchmark/issues/1512
I did understand how Bazel works
@dmah42 i do not understand where the change to the
kBigIECUnits
should manifest. We seem to be missing test coverage for that.
https://github.com/google/benchmark/blob/27d64a2351b98d48dd5b18c75ff536982a4ce26a/src/string_util.cc#L110 is where we determine IEC vs SI (and previously didn't).
called https://github.com/google/benchmark/blob/27d64a2351b98d48dd5b18c75ff536982a4ce26a/src/string_util.cc#L153 and tested directly https://github.com/google/benchmark/blob/27d64a2351b98d48dd5b18c75ff536982a4ce26a/test/string_util_gtest.cc#L212 and through console reporter https://github.com/google/benchmark/blob/27d64a2351b98d48dd5b18c75ff536982a4ce26a/test/user_counters_test.cc and https://github.com/google/benchmark/blob/27d64a2351b98d48dd5b18c75ff536982a4ce26a/test/user_counters_thousands_test.cc
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.
@dmah42 i do not understand where the change to the
kBigIECUnits
should manifest. We seem to be missing test coverage for that. <...>but we still use SI for user counters by default unless it's overridden in the Counter constructor.
user_counters_test.cc
does test the overrides, yes?
My question is more like: why does this not show up in any tests?
@dmah42 i do not understand where the change to the
kBigIECUnits
should manifest. We seem to be missing test coverage for that. <...>but we still use SI for user counters by default unless it's overridden in the Counter constructor.
user_counters_test.cc
does test the overrides, yes? My question is more like: why does this not show up in any tests?
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,
not in the AppendHumanReadable()
test) behavior change?
Should I remove the function AppendHumanReadable()
? I even looked at other places, but HumanReadableNumber()
was the one which is getting used in the code base.
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?)
(@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 ->
1009
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