Split benchmarks and test tools into separate targets.
This lets us remove main() from snappy_bench.cc and snappy_unittest.cc, which simplifies integrating these tests and benchmarks with other suites. PiperOrigin-RevId: 347857427
This commit is contained in:
@@ -26,10 +26,9 @@
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <cstdlib>
|
||||
|
||||
#include <algorithm>
|
||||
#include <random>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
@@ -37,31 +36,12 @@
|
||||
|
||||
#include "snappy-test.h"
|
||||
|
||||
#include "benchmark/benchmark.h"
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#include "snappy.h"
|
||||
#include "snappy-internal.h"
|
||||
#include "snappy-sinksource.h"
|
||||
|
||||
DEFINE_int32(start_len, -1,
|
||||
"Starting prefix size for testing (-1: just full file contents)");
|
||||
DEFINE_int32(end_len, -1,
|
||||
"Starting prefix size for testing (-1: just full file contents)");
|
||||
DEFINE_int32(bytes, 10485760,
|
||||
"How many bytes to compress/uncompress per file for timing");
|
||||
|
||||
DEFINE_bool(zlib, false,
|
||||
"Run zlib compression (http://www.zlib.net)");
|
||||
DEFINE_bool(lzo, false,
|
||||
"Run LZO compression (http://www.oberhumer.com/opensource/lzo/)");
|
||||
DEFINE_bool(lz4, false, "Run LZ4 compression (https://github.com/lz4/lz4)");
|
||||
DEFINE_bool(snappy, true, "Run snappy compression");
|
||||
|
||||
DEFINE_bool(write_compressed, false,
|
||||
"Write compressed versions of each file to <file>.comp");
|
||||
DEFINE_bool(write_uncompressed, false,
|
||||
"Write uncompressed versions of each file to <file>.uncomp");
|
||||
#include "snappy.h"
|
||||
#include "snappy_test_data.h"
|
||||
|
||||
DEFINE_bool(snappy_dump_decompression_table, false,
|
||||
"If true, we print the decompression table during tests.");
|
||||
@@ -123,273 +103,6 @@ using DataEndingAtUnreadablePage = std::string;
|
||||
|
||||
#endif
|
||||
|
||||
enum CompressorType { ZLIB, LZO, LZ4, SNAPPY };
|
||||
|
||||
const char* names[] = {"ZLIB", "LZO", "LZ4", "SNAPPY"};
|
||||
|
||||
size_t MinimumRequiredOutputSpace(size_t input_size, CompressorType comp) {
|
||||
switch (comp) {
|
||||
#ifdef ZLIB_VERSION
|
||||
case ZLIB:
|
||||
return ZLib::MinCompressbufSize(input_size);
|
||||
#endif // ZLIB_VERSION
|
||||
|
||||
#ifdef LZO_VERSION
|
||||
case LZO:
|
||||
return input_size + input_size/64 + 16 + 3;
|
||||
#endif // LZO_VERSION
|
||||
|
||||
#ifdef LZ4_VERSION_NUMBER
|
||||
case LZ4:
|
||||
return LZ4_compressBound(input_size);
|
||||
#endif // LZ4_VERSION_NUMBER
|
||||
|
||||
case SNAPPY:
|
||||
return snappy::MaxCompressedLength(input_size);
|
||||
|
||||
default:
|
||||
LOG(FATAL) << "Unknown compression type number " << comp;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Returns true if we successfully compressed, false otherwise.
|
||||
//
|
||||
// If compressed_is_preallocated is set, do not resize the compressed buffer.
|
||||
// This is typically what you want for a benchmark, in order to not spend
|
||||
// time in the memory allocator. If you do set this flag, however,
|
||||
// "compressed" must be preinitialized to at least MinCompressbufSize(comp)
|
||||
// number of bytes, and may contain junk bytes at the end after return.
|
||||
bool Compress(const char* input, size_t input_size, CompressorType comp,
|
||||
std::string* compressed, bool compressed_is_preallocated) {
|
||||
if (!compressed_is_preallocated) {
|
||||
compressed->resize(MinimumRequiredOutputSpace(input_size, comp));
|
||||
}
|
||||
|
||||
switch (comp) {
|
||||
#ifdef ZLIB_VERSION
|
||||
case ZLIB: {
|
||||
ZLib zlib;
|
||||
uLongf destlen = compressed->size();
|
||||
int ret = zlib.Compress(
|
||||
reinterpret_cast<Bytef*>(string_as_array(compressed)),
|
||||
&destlen,
|
||||
reinterpret_cast<const Bytef*>(input),
|
||||
input_size);
|
||||
CHECK_EQ(Z_OK, ret);
|
||||
if (!compressed_is_preallocated) {
|
||||
compressed->resize(destlen);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
#endif // ZLIB_VERSION
|
||||
|
||||
#ifdef LZO_VERSION
|
||||
case LZO: {
|
||||
unsigned char* mem = new unsigned char[LZO1X_1_15_MEM_COMPRESS];
|
||||
lzo_uint destlen;
|
||||
int ret = lzo1x_1_15_compress(
|
||||
reinterpret_cast<const uint8_t*>(input),
|
||||
input_size,
|
||||
reinterpret_cast<uint8_t*>(string_as_array(compressed)),
|
||||
&destlen,
|
||||
mem);
|
||||
CHECK_EQ(LZO_E_OK, ret);
|
||||
delete[] mem;
|
||||
if (!compressed_is_preallocated) {
|
||||
compressed->resize(destlen);
|
||||
}
|
||||
break;
|
||||
}
|
||||
#endif // LZO_VERSION
|
||||
|
||||
#ifdef LZ4_VERSION_NUMBER
|
||||
case LZ4: {
|
||||
int destlen = compressed->size();
|
||||
destlen = LZ4_compress_default(input, string_as_array(compressed),
|
||||
input_size, destlen);
|
||||
CHECK(destlen != 0);
|
||||
if (!compressed_is_preallocated) {
|
||||
compressed->resize(destlen);
|
||||
}
|
||||
break;
|
||||
}
|
||||
#endif // LZ4_VERSION_NUMBER
|
||||
|
||||
case SNAPPY: {
|
||||
size_t destlen;
|
||||
snappy::RawCompress(input, input_size,
|
||||
string_as_array(compressed),
|
||||
&destlen);
|
||||
CHECK_LE(destlen, snappy::MaxCompressedLength(input_size));
|
||||
if (!compressed_is_preallocated) {
|
||||
compressed->resize(destlen);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default: {
|
||||
return false; // the asked-for library wasn't compiled in
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Uncompress(const std::string& compressed, CompressorType comp, int size,
|
||||
std::string* output) {
|
||||
switch (comp) {
|
||||
#ifdef ZLIB_VERSION
|
||||
case ZLIB: {
|
||||
output->resize(size);
|
||||
ZLib zlib;
|
||||
uLongf destlen = output->size();
|
||||
int ret = zlib.Uncompress(
|
||||
reinterpret_cast<Bytef*>(string_as_array(output)),
|
||||
&destlen,
|
||||
reinterpret_cast<const Bytef*>(compressed.data()),
|
||||
compressed.size());
|
||||
CHECK_EQ(Z_OK, ret);
|
||||
CHECK_EQ(static_cast<uLongf>(size), destlen);
|
||||
break;
|
||||
}
|
||||
#endif // ZLIB_VERSION
|
||||
|
||||
#ifdef LZO_VERSION
|
||||
case LZO: {
|
||||
output->resize(size);
|
||||
lzo_uint destlen;
|
||||
int ret = lzo1x_decompress(
|
||||
reinterpret_cast<const uint8_t*>(compressed.data()),
|
||||
compressed.size(),
|
||||
reinterpret_cast<uint8_t*>(string_as_array(output)),
|
||||
&destlen,
|
||||
NULL);
|
||||
CHECK_EQ(LZO_E_OK, ret);
|
||||
CHECK_EQ(static_cast<lzo_uint>(size), destlen);
|
||||
break;
|
||||
}
|
||||
#endif // LZO_VERSION
|
||||
|
||||
#ifdef LZ4_VERSION_NUMBER
|
||||
case LZ4: {
|
||||
output->resize(size);
|
||||
int destlen = output->size();
|
||||
destlen = LZ4_decompress_safe(compressed.data(), string_as_array(output),
|
||||
compressed.size(), destlen);
|
||||
CHECK(destlen != 0);
|
||||
CHECK_EQ(size, destlen);
|
||||
break;
|
||||
}
|
||||
#endif // LZ4_VERSION_NUMBER
|
||||
case SNAPPY: {
|
||||
snappy::RawUncompress(compressed.data(), compressed.size(),
|
||||
string_as_array(output));
|
||||
break;
|
||||
}
|
||||
|
||||
default: {
|
||||
return false; // the asked-for library wasn't compiled in
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void Measure(const char* data, size_t length, CompressorType comp, int repeats,
|
||||
int block_size) {
|
||||
// Run tests a few time and pick median running times
|
||||
static const int kRuns = 5;
|
||||
double ctime[kRuns];
|
||||
double utime[kRuns];
|
||||
int compressed_size = 0;
|
||||
|
||||
{
|
||||
// Chop the input into blocks
|
||||
int num_blocks = (length + block_size - 1) / block_size;
|
||||
std::vector<const char*> input(num_blocks);
|
||||
std::vector<size_t> input_length(num_blocks);
|
||||
std::vector<std::string> compressed(num_blocks);
|
||||
std::vector<std::string> output(num_blocks);
|
||||
for (int b = 0; b < num_blocks; ++b) {
|
||||
int input_start = b * block_size;
|
||||
int input_limit = std::min<int>((b+1)*block_size, length);
|
||||
input[b] = data+input_start;
|
||||
input_length[b] = input_limit-input_start;
|
||||
}
|
||||
|
||||
// Pre-grow the output buffers so we don't measure string append time.
|
||||
for (std::string& compressed_block : compressed) {
|
||||
compressed_block.resize(MinimumRequiredOutputSpace(block_size, comp));
|
||||
}
|
||||
|
||||
// First, try one trial compression to make sure the code is compiled in
|
||||
if (!Compress(input[0], input_length[0], comp, &compressed[0], true)) {
|
||||
LOG(WARNING) << "Skipping " << names[comp] << ": "
|
||||
<< "library not compiled in";
|
||||
return;
|
||||
}
|
||||
|
||||
for (int run = 0; run < kRuns; ++run) {
|
||||
CycleTimer ctimer, utimer;
|
||||
|
||||
// Pre-grow the output buffers so we don't measure string append time.
|
||||
for (std::string& compressed_block : compressed) {
|
||||
compressed_block.resize(MinimumRequiredOutputSpace(block_size, comp));
|
||||
}
|
||||
|
||||
ctimer.Start();
|
||||
for (int b = 0; b < num_blocks; ++b) {
|
||||
for (int i = 0; i < repeats; ++i)
|
||||
Compress(input[b], input_length[b], comp, &compressed[b], true);
|
||||
}
|
||||
ctimer.Stop();
|
||||
|
||||
// Compress once more, with resizing, so we don't leave junk
|
||||
// at the end that will confuse the decompressor.
|
||||
for (int b = 0; b < num_blocks; ++b) {
|
||||
Compress(input[b], input_length[b], comp, &compressed[b], false);
|
||||
}
|
||||
|
||||
for (int b = 0; b < num_blocks; ++b) {
|
||||
output[b].resize(input_length[b]);
|
||||
}
|
||||
|
||||
utimer.Start();
|
||||
for (int i = 0; i < repeats; ++i) {
|
||||
for (int b = 0; b < num_blocks; ++b)
|
||||
Uncompress(compressed[b], comp, input_length[b], &output[b]);
|
||||
}
|
||||
utimer.Stop();
|
||||
|
||||
ctime[run] = ctimer.Get();
|
||||
utime[run] = utimer.Get();
|
||||
}
|
||||
|
||||
compressed_size = 0;
|
||||
for (const std::string& compressed_item : compressed) {
|
||||
compressed_size += compressed_item.size();
|
||||
}
|
||||
}
|
||||
|
||||
std::sort(ctime, ctime + kRuns);
|
||||
std::sort(utime, utime + kRuns);
|
||||
const int med = kRuns/2;
|
||||
|
||||
float comp_rate = (length / ctime[med]) * repeats / 1048576.0;
|
||||
float uncomp_rate = (length / utime[med]) * repeats / 1048576.0;
|
||||
std::string x = names[comp];
|
||||
x += ":";
|
||||
std::string urate = (uncomp_rate >= 0) ? StrFormat("%.1f", uncomp_rate)
|
||||
: std::string("?");
|
||||
std::printf("%-7s [b %dM] bytes %6d -> %6d %4.1f%% "
|
||||
"comp %5.1f MB/s uncomp %5s MB/s\n",
|
||||
x.c_str(),
|
||||
block_size/(1<<20),
|
||||
static_cast<int>(length), static_cast<uint32_t>(compressed_size),
|
||||
(compressed_size * 100.0) / std::max<int>(1, length),
|
||||
comp_rate,
|
||||
urate.c_str());
|
||||
}
|
||||
|
||||
int VerifyString(const std::string& input) {
|
||||
std::string compressed;
|
||||
DataEndingAtUnreadablePage i(input);
|
||||
@@ -633,7 +346,7 @@ TEST(CorruptedTest, VerifyCorrupted) {
|
||||
// These mirror the compression code in snappy.cc, but are copied
|
||||
// here so that we can bypass some limitations in the how snappy.cc
|
||||
// invokes these routines.
|
||||
static void AppendLiteral(std::string* dst, const std::string& literal) {
|
||||
void AppendLiteral(std::string* dst, const std::string& literal) {
|
||||
if (literal.empty()) return;
|
||||
int n = literal.size() - 1;
|
||||
if (n < 60) {
|
||||
@@ -653,7 +366,7 @@ static void AppendLiteral(std::string* dst, const std::string& literal) {
|
||||
*dst += literal;
|
||||
}
|
||||
|
||||
static void AppendCopy(std::string* dst, int offset, int length) {
|
||||
void AppendCopy(std::string* dst, int offset, int length) {
|
||||
while (length > 0) {
|
||||
// Figure out how much to copy in one shot
|
||||
int to_copy;
|
||||
@@ -1241,382 +954,13 @@ TEST(Snappy, VerifyCharTable) {
|
||||
}
|
||||
}
|
||||
|
||||
void CompressFile(const char* fname) {
|
||||
std::string fullinput;
|
||||
CHECK_OK(file::GetContents(fname, &fullinput, file::Defaults()));
|
||||
|
||||
std::string compressed;
|
||||
Compress(fullinput.data(), fullinput.size(), SNAPPY, &compressed, false);
|
||||
|
||||
CHECK_OK(file::SetContents(std::string(fname).append(".comp"), compressed,
|
||||
file::Defaults()));
|
||||
}
|
||||
|
||||
void UncompressFile(const char* fname) {
|
||||
std::string fullinput;
|
||||
CHECK_OK(file::GetContents(fname, &fullinput, file::Defaults()));
|
||||
|
||||
size_t uncompLength;
|
||||
CHECK(CheckUncompressedLength(fullinput, &uncompLength));
|
||||
|
||||
std::string uncompressed;
|
||||
uncompressed.resize(uncompLength);
|
||||
CHECK(snappy::Uncompress(fullinput.data(), fullinput.size(), &uncompressed));
|
||||
|
||||
CHECK_OK(file::SetContents(std::string(fname).append(".uncomp"), uncompressed,
|
||||
file::Defaults()));
|
||||
}
|
||||
|
||||
void MeasureFile(const char* fname) {
|
||||
std::string fullinput;
|
||||
CHECK_OK(file::GetContents(fname, &fullinput, file::Defaults()));
|
||||
std::printf("%-40s :\n", fname);
|
||||
|
||||
int start_len = (FLAGS_start_len < 0) ? fullinput.size() : FLAGS_start_len;
|
||||
int end_len = fullinput.size();
|
||||
if (FLAGS_end_len >= 0) {
|
||||
end_len = std::min<int>(fullinput.size(), FLAGS_end_len);
|
||||
}
|
||||
for (int len = start_len; len <= end_len; ++len) {
|
||||
const char* const input = fullinput.data();
|
||||
int repeats = (FLAGS_bytes + len) / (len + 1);
|
||||
if (FLAGS_zlib) Measure(input, len, ZLIB, repeats, 1024 << 10);
|
||||
if (FLAGS_lzo) Measure(input, len, LZO, repeats, 1024 << 10);
|
||||
if (FLAGS_lz4) Measure(input, len, LZ4, repeats, 1024 << 10);
|
||||
if (FLAGS_snappy) Measure(input, len, SNAPPY, repeats, 4096 << 10);
|
||||
|
||||
// For block-size based measurements
|
||||
if (0 && FLAGS_snappy) {
|
||||
Measure(input, len, SNAPPY, repeats, 8<<10);
|
||||
Measure(input, len, SNAPPY, repeats, 16<<10);
|
||||
Measure(input, len, SNAPPY, repeats, 32<<10);
|
||||
Measure(input, len, SNAPPY, repeats, 64<<10);
|
||||
Measure(input, len, SNAPPY, repeats, 256<<10);
|
||||
Measure(input, len, SNAPPY, repeats, 1024<<10);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static struct {
|
||||
const char* label;
|
||||
const char* filename;
|
||||
size_t size_limit;
|
||||
} files[] = {
|
||||
{ "html", "html", 0 },
|
||||
{ "urls", "urls.10K", 0 },
|
||||
{ "jpg", "fireworks.jpeg", 0 },
|
||||
{ "jpg_200", "fireworks.jpeg", 200 },
|
||||
{ "pdf", "paper-100k.pdf", 0 },
|
||||
{ "html4", "html_x_4", 0 },
|
||||
{ "txt1", "alice29.txt", 0 },
|
||||
{ "txt2", "asyoulik.txt", 0 },
|
||||
{ "txt3", "lcet10.txt", 0 },
|
||||
{ "txt4", "plrabn12.txt", 0 },
|
||||
{ "pb", "geo.protodata", 0 },
|
||||
{ "gaviota", "kppkn.gtb", 0 },
|
||||
};
|
||||
|
||||
TEST(Snappy, TestBenchmarkFiles) {
|
||||
for (int i = 0; i < ARRAYSIZE(files); ++i) {
|
||||
Verify(ReadTestDataFile(files[i].filename, files[i].size_limit));
|
||||
for (int i = 0; i < ARRAYSIZE(kTestDataFiles); ++i) {
|
||||
Verify(ReadTestDataFile(kTestDataFiles[i].filename,
|
||||
kTestDataFiles[i].size_limit));
|
||||
}
|
||||
}
|
||||
|
||||
void BM_UFlat(benchmark::State& state) {
|
||||
// Pick file to process based on state.range(0).
|
||||
int file_index = state.range(0);
|
||||
|
||||
CHECK_GE(file_index, 0);
|
||||
CHECK_LT(file_index, ARRAYSIZE(files));
|
||||
std::string contents = ReadTestDataFile(files[file_index].filename,
|
||||
files[file_index].size_limit);
|
||||
|
||||
std::string zcontents;
|
||||
snappy::Compress(contents.data(), contents.size(), &zcontents);
|
||||
char* dst = new char[contents.size()];
|
||||
|
||||
for (auto s : state) {
|
||||
CHECK(snappy::RawUncompress(zcontents.data(), zcontents.size(), dst));
|
||||
benchmark::DoNotOptimize(dst);
|
||||
}
|
||||
state.SetBytesProcessed(static_cast<int64_t>(state.iterations()) *
|
||||
static_cast<int64_t>(contents.size()));
|
||||
state.SetLabel(files[file_index].label);
|
||||
|
||||
delete[] dst;
|
||||
}
|
||||
BENCHMARK(BM_UFlat)->DenseRange(0, ARRAYSIZE(files) - 1);
|
||||
|
||||
struct SourceFiles {
|
||||
SourceFiles() {
|
||||
for (int i = 0; i < kFiles; i++) {
|
||||
std::string contents =
|
||||
ReadTestDataFile(files[i].filename, files[i].size_limit);
|
||||
max_size = std::max(max_size, contents.size());
|
||||
sizes[i] = contents.size();
|
||||
snappy::Compress(contents.data(), contents.size(), &zcontents[i]);
|
||||
}
|
||||
}
|
||||
static constexpr int kFiles = ARRAYSIZE(files);
|
||||
std::string zcontents[kFiles];
|
||||
size_t sizes[kFiles];
|
||||
size_t max_size = 0;
|
||||
};
|
||||
|
||||
void BM_UFlatMedley(benchmark::State& state) {
|
||||
static const SourceFiles* const source = new SourceFiles();
|
||||
|
||||
std::vector<char> dst(source->max_size);
|
||||
|
||||
for (auto s : state) {
|
||||
for (int i = 0; i < SourceFiles::kFiles; i++) {
|
||||
CHECK(snappy::RawUncompress(source->zcontents[i].data(),
|
||||
source->zcontents[i].size(), dst.data()));
|
||||
benchmark::DoNotOptimize(dst);
|
||||
}
|
||||
}
|
||||
|
||||
int64_t source_sizes = 0;
|
||||
for (int i = 0; i < SourceFiles::kFiles; i++) {
|
||||
source_sizes += static_cast<int64_t>(source->sizes[i]);
|
||||
}
|
||||
state.SetBytesProcessed(static_cast<int64_t>(state.iterations()) *
|
||||
source_sizes);
|
||||
}
|
||||
BENCHMARK(BM_UFlatMedley);
|
||||
|
||||
void BM_UValidate(benchmark::State& state) {
|
||||
// Pick file to process based on state.range(0).
|
||||
int file_index = state.range(0);
|
||||
|
||||
CHECK_GE(file_index, 0);
|
||||
CHECK_LT(file_index, ARRAYSIZE(files));
|
||||
std::string contents = ReadTestDataFile(files[file_index].filename,
|
||||
files[file_index].size_limit);
|
||||
|
||||
std::string zcontents;
|
||||
snappy::Compress(contents.data(), contents.size(), &zcontents);
|
||||
|
||||
for (auto s : state) {
|
||||
CHECK(snappy::IsValidCompressedBuffer(zcontents.data(), zcontents.size()));
|
||||
}
|
||||
state.SetBytesProcessed(static_cast<int64_t>(state.iterations()) *
|
||||
static_cast<int64_t>(contents.size()));
|
||||
state.SetLabel(files[file_index].label);
|
||||
}
|
||||
BENCHMARK(BM_UValidate)->DenseRange(0, ARRAYSIZE(files) - 1);
|
||||
|
||||
void BM_UValidateMedley(benchmark::State& state) {
|
||||
static const SourceFiles* const source = new SourceFiles();
|
||||
|
||||
for (auto s : state) {
|
||||
for (int i = 0; i < SourceFiles::kFiles; i++) {
|
||||
CHECK(snappy::IsValidCompressedBuffer(source->zcontents[i].data(),
|
||||
source->zcontents[i].size()));
|
||||
}
|
||||
}
|
||||
|
||||
int64_t source_sizes = 0;
|
||||
for (int i = 0; i < SourceFiles::kFiles; i++) {
|
||||
source_sizes += static_cast<int64_t>(source->sizes[i]);
|
||||
}
|
||||
state.SetBytesProcessed(static_cast<int64_t>(state.iterations()) *
|
||||
source_sizes);
|
||||
}
|
||||
BENCHMARK(BM_UValidateMedley);
|
||||
|
||||
void BM_UIOVec(benchmark::State& state) {
|
||||
// Pick file to process based on state.range(0).
|
||||
int file_index = state.range(0);
|
||||
|
||||
CHECK_GE(file_index, 0);
|
||||
CHECK_LT(file_index, ARRAYSIZE(files));
|
||||
std::string contents = ReadTestDataFile(files[file_index].filename,
|
||||
files[file_index].size_limit);
|
||||
|
||||
std::string zcontents;
|
||||
snappy::Compress(contents.data(), contents.size(), &zcontents);
|
||||
|
||||
// Uncompress into an iovec containing ten entries.
|
||||
const int kNumEntries = 10;
|
||||
struct iovec iov[kNumEntries];
|
||||
char *dst = new char[contents.size()];
|
||||
size_t used_so_far = 0;
|
||||
for (int i = 0; i < kNumEntries; ++i) {
|
||||
iov[i].iov_base = dst + used_so_far;
|
||||
if (used_so_far == contents.size()) {
|
||||
iov[i].iov_len = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (i == kNumEntries - 1) {
|
||||
iov[i].iov_len = contents.size() - used_so_far;
|
||||
} else {
|
||||
iov[i].iov_len = contents.size() / kNumEntries;
|
||||
}
|
||||
used_so_far += iov[i].iov_len;
|
||||
}
|
||||
|
||||
for (auto s : state) {
|
||||
CHECK(snappy::RawUncompressToIOVec(zcontents.data(), zcontents.size(), iov,
|
||||
kNumEntries));
|
||||
benchmark::DoNotOptimize(iov);
|
||||
}
|
||||
state.SetBytesProcessed(static_cast<int64_t>(state.iterations()) *
|
||||
static_cast<int64_t>(contents.size()));
|
||||
state.SetLabel(files[file_index].label);
|
||||
|
||||
delete[] dst;
|
||||
}
|
||||
BENCHMARK(BM_UIOVec)->DenseRange(0, 4);
|
||||
|
||||
void BM_UFlatSink(benchmark::State& state) {
|
||||
// Pick file to process based on state.range(0).
|
||||
int file_index = state.range(0);
|
||||
|
||||
CHECK_GE(file_index, 0);
|
||||
CHECK_LT(file_index, ARRAYSIZE(files));
|
||||
std::string contents = ReadTestDataFile(files[file_index].filename,
|
||||
files[file_index].size_limit);
|
||||
|
||||
std::string zcontents;
|
||||
snappy::Compress(contents.data(), contents.size(), &zcontents);
|
||||
char* dst = new char[contents.size()];
|
||||
|
||||
for (auto s : state) {
|
||||
snappy::ByteArraySource source(zcontents.data(), zcontents.size());
|
||||
snappy::UncheckedByteArraySink sink(dst);
|
||||
CHECK(snappy::Uncompress(&source, &sink));
|
||||
benchmark::DoNotOptimize(sink);
|
||||
}
|
||||
state.SetBytesProcessed(static_cast<int64_t>(state.iterations()) *
|
||||
static_cast<int64_t>(contents.size()));
|
||||
state.SetLabel(files[file_index].label);
|
||||
|
||||
std::string s(dst, contents.size());
|
||||
CHECK_EQ(contents, s);
|
||||
|
||||
delete[] dst;
|
||||
}
|
||||
|
||||
BENCHMARK(BM_UFlatSink)->DenseRange(0, ARRAYSIZE(files) - 1);
|
||||
|
||||
void BM_ZFlat(benchmark::State& state) {
|
||||
// Pick file to process based on state.range(0).
|
||||
int file_index = state.range(0);
|
||||
|
||||
CHECK_GE(file_index, 0);
|
||||
CHECK_LT(file_index, ARRAYSIZE(files));
|
||||
std::string contents = ReadTestDataFile(files[file_index].filename,
|
||||
files[file_index].size_limit);
|
||||
char* dst = new char[snappy::MaxCompressedLength(contents.size())];
|
||||
|
||||
size_t zsize = 0;
|
||||
for (auto s : state) {
|
||||
snappy::RawCompress(contents.data(), contents.size(), dst, &zsize);
|
||||
benchmark::DoNotOptimize(dst);
|
||||
}
|
||||
state.SetBytesProcessed(static_cast<int64_t>(state.iterations()) *
|
||||
static_cast<int64_t>(contents.size()));
|
||||
const double compression_ratio =
|
||||
static_cast<double>(zsize) / std::max<size_t>(1, contents.size());
|
||||
state.SetLabel(StrFormat("%s (%.2f %%)", files[file_index].label,
|
||||
100.0 * compression_ratio));
|
||||
VLOG(0) << StrFormat("compression for %s: %d -> %d bytes",
|
||||
files[file_index].label, contents.size(), zsize);
|
||||
delete[] dst;
|
||||
}
|
||||
BENCHMARK(BM_ZFlat)->DenseRange(0, ARRAYSIZE(files) - 1);
|
||||
|
||||
void BM_ZFlatAll(benchmark::State& state) {
|
||||
const int num_files = ARRAYSIZE(files);
|
||||
|
||||
std::vector<std::string> contents(num_files);
|
||||
std::vector<char*> dst(num_files);
|
||||
|
||||
int64_t total_contents_size = 0;
|
||||
for (int i = 0; i < num_files; ++i) {
|
||||
contents[i] = ReadTestDataFile(files[i].filename, files[i].size_limit);
|
||||
dst[i] = new char[snappy::MaxCompressedLength(contents[i].size())];
|
||||
total_contents_size += contents[i].size();
|
||||
}
|
||||
|
||||
size_t zsize = 0;
|
||||
for (auto s : state) {
|
||||
for (int i = 0; i < num_files; ++i) {
|
||||
snappy::RawCompress(contents[i].data(), contents[i].size(), dst[i],
|
||||
&zsize);
|
||||
benchmark::DoNotOptimize(dst);
|
||||
}
|
||||
}
|
||||
|
||||
state.SetBytesProcessed(static_cast<int64_t>(state.iterations()) *
|
||||
total_contents_size);
|
||||
|
||||
for (char* dst_item : dst) {
|
||||
delete[] dst_item;
|
||||
}
|
||||
state.SetLabel(StrFormat("%d files", num_files));
|
||||
}
|
||||
BENCHMARK(BM_ZFlatAll);
|
||||
|
||||
void BM_ZFlatIncreasingTableSize(benchmark::State& state) {
|
||||
CHECK_GT(ARRAYSIZE(files), 0);
|
||||
const std::string base_content =
|
||||
ReadTestDataFile(files[0].filename, files[0].size_limit);
|
||||
|
||||
std::vector<std::string> contents;
|
||||
std::vector<char*> dst;
|
||||
int64_t total_contents_size = 0;
|
||||
for (int table_bits = kMinHashTableBits; table_bits <= kMaxHashTableBits;
|
||||
++table_bits) {
|
||||
std::string content = base_content;
|
||||
content.resize(1 << table_bits);
|
||||
dst.push_back(new char[snappy::MaxCompressedLength(content.size())]);
|
||||
total_contents_size += content.size();
|
||||
contents.push_back(std::move(content));
|
||||
}
|
||||
|
||||
size_t zsize = 0;
|
||||
for (auto s : state) {
|
||||
for (size_t i = 0; i < contents.size(); ++i) {
|
||||
snappy::RawCompress(contents[i].data(), contents[i].size(), dst[i],
|
||||
&zsize);
|
||||
benchmark::DoNotOptimize(dst);
|
||||
}
|
||||
}
|
||||
|
||||
state.SetBytesProcessed(static_cast<int64_t>(state.iterations()) *
|
||||
total_contents_size);
|
||||
|
||||
for (char* dst_item : dst) {
|
||||
delete[] dst_item;
|
||||
}
|
||||
state.SetLabel(StrFormat("%d tables", contents.size()));
|
||||
}
|
||||
BENCHMARK(BM_ZFlatIncreasingTableSize);
|
||||
|
||||
} // namespace
|
||||
|
||||
} // namespace snappy
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
testing::InitGoogleTest(&argc, argv);
|
||||
InitGoogle(argv[0], &argc, &argv, true);
|
||||
::benchmark::RunSpecifiedBenchmarks();
|
||||
|
||||
if (argc >= 2) {
|
||||
for (int arg = 1; arg < argc; ++arg) {
|
||||
if (FLAGS_write_compressed) {
|
||||
snappy::CompressFile(argv[arg]);
|
||||
} else if (FLAGS_write_uncompressed) {
|
||||
snappy::UncompressFile(argv[arg]);
|
||||
} else {
|
||||
snappy::MeasureFile(argv[arg]);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
return RUN_ALL_TESTS();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user