blob: 56bad391532ce9475e61c3c60ab13cd2aa75e41b [file] [log] [blame]
/**
* Copyright (c) 2016-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/
#include "ErrorHolder.h"
#include "Options.h"
#include "Pzstd.h"
#include "utils/FileSystem.h"
#include "utils/Range.h"
#include "utils/ScopeGuard.h"
#include "utils/ThreadPool.h"
#include "utils/WorkQueue.h"
#include <chrono>
#include <cstdio>
#include <cstdlib>
using namespace pzstd;
namespace {
// Prints how many ns it was in scope for upon destruction
// Used for rough estimates of how long things took
struct BenchmarkTimer {
using Clock = std::chrono::system_clock;
Clock::time_point start;
FILE* fd;
explicit BenchmarkTimer(FILE* fd = stdout) : fd(fd) {
start = Clock::now();
}
~BenchmarkTimer() {
auto end = Clock::now();
size_t ticks =
std::chrono::duration_cast<std::chrono::milliseconds>(end - start)
.count();
ticks = std::max(ticks, size_t{1});
for (auto tmp = ticks; tmp < 100000; tmp *= 10) {
std::fprintf(fd, " ");
}
std::fprintf(fd, "%zu | ", ticks);
}
};
}
// Code I used for benchmarking
void testMain(const Options& options) {
if (!options.decompress) {
if (options.compressionLevel < 10) {
std::printf("0");
}
std::printf("%u | ", options.compressionLevel);
} else {
std::printf(" d | ");
}
if (options.numThreads < 10) {
std::printf("0");
}
std::printf("%u | ", options.numThreads);
FILE* inputFd = std::fopen(options.inputFile.c_str(), "rb");
if (inputFd == nullptr) {
std::abort();
}
size_t inputSize = 0;
if (inputFd != stdin) {
std::error_code ec;
inputSize = file_size(options.inputFile, ec);
if (ec) {
inputSize = 0;
}
}
FILE* outputFd = std::fopen(options.outputFile.c_str(), "wb");
if (outputFd == nullptr) {
std::abort();
}
auto guard = makeScopeGuard([&] {
std::fclose(inputFd);
std::fclose(outputFd);
});
WorkQueue<std::shared_ptr<BufferWorkQueue>> outs;
ErrorHolder errorHolder;
size_t bytesWritten;
{
ThreadPool executor(options.numThreads);
BenchmarkTimer timeIncludingClose;
if (!options.decompress) {
executor.add(
[&errorHolder, &outs, &executor, inputFd, inputSize, &options] {
asyncCompressChunks(
errorHolder,
outs,
executor,
inputFd,
inputSize,
options.numThreads,
options.determineParameters());
});
bytesWritten = writeFile(errorHolder, outs, outputFd, true);
} else {
executor.add([&errorHolder, &outs, &executor, inputFd] {
asyncDecompressFrames(errorHolder, outs, executor, inputFd);
});
bytesWritten = writeFile(
errorHolder, outs, outputFd, /* writeSkippableFrames */ false);
}
}
if (errorHolder.hasError()) {
std::fprintf(stderr, "Error: %s.\n", errorHolder.getError().c_str());
std::abort();
}
std::printf("%zu\n", bytesWritten);
}
int main(int argc, const char** argv) {
if (argc < 3) {
return 1;
}
Options options(0, 23, 0, false, "", "", true, true);
// Benchmarking code
for (size_t i = 0; i < 2; ++i) {
for (size_t compressionLevel = 1; compressionLevel <= 16;
compressionLevel <<= 1) {
for (size_t numThreads = 1; numThreads <= 16; numThreads <<= 1) {
options.numThreads = numThreads;
options.compressionLevel = compressionLevel;
options.decompress = false;
options.inputFile = argv[1];
options.outputFile = argv[2];
testMain(options);
options.decompress = true;
options.inputFile = argv[2];
options.outputFile = std::string(argv[1]) + ".d";
testMain(options);
std::fflush(stdout);
}
}
}
return 0;
}