[zip] Save 1 malloc and memset for each added file in ZipWriter

+ add a benchmark for the function.

This change speeds up the function by about 3%: 910ns->880ns

Change-Id: I33c8c31de18d10eb38f109917ecbcbdda45b4034
This commit is contained in:
Yurii Zubrytskyi 2019-06-17 15:43:16 -07:00
parent 2b283118a0
commit a6633d7739
2 changed files with 39 additions and 5 deletions

View file

@ -58,7 +58,7 @@ static void FindEntry_no_match(benchmark::State& state) {
std::string_view name("thisFileNameDoesNotExist");
// Start the benchmark.
while (state.KeepRunning()) {
for (auto _ : state) {
OpenArchive(temp_file->path, &handle);
FindEntry(handle, name, &data);
CloseArchive(handle);
@ -73,7 +73,7 @@ static void Iterate_all_files(benchmark::State& state) {
ZipEntry data;
std::string name;
while (state.KeepRunning()) {
for (auto _ : state) {
OpenArchive(temp_file->path, &handle);
StartIteration(handle, &iteration_cookie);
while (Next(iteration_cookie, &data, &name) == 0) {
@ -84,4 +84,27 @@ static void Iterate_all_files(benchmark::State& state) {
}
BENCHMARK(Iterate_all_files);
static void StartAlignedEntry(benchmark::State& state) {
TemporaryFile file;
FILE* fp = fdopen(file.fd, "w");
ZipWriter writer(fp);
auto alignment = uint32_t(state.range(0));
std::string name = "name";
int counter = 0;
for (auto _ : state) {
writer.StartAlignedEntry(name + std::to_string(counter++), 0, alignment);
state.PauseTiming();
writer.WriteBytes("hola", 4);
writer.FinishEntry();
state.ResumeTiming();
}
writer.Finish();
fclose(fp);
}
BENCHMARK(StartAlignedEntry)->Arg(2)->Arg(16)->Arg(1024)->Arg(4096);
BENCHMARK_MAIN();

View file

@ -247,13 +247,24 @@ int32_t ZipWriter::StartAlignedEntryWithTime(std::string_view path, size_t flags
ExtractTimeAndDate(time, &file_entry.last_mod_time, &file_entry.last_mod_date);
off_t offset = current_offset_ + sizeof(LocalFileHeader) + file_entry.path.size();
std::vector<char> zero_padding;
// prepare a pre-zeroed memory page in case when we need to pad some aligned data.
static constexpr auto kPageSize = 4096;
static constexpr char kSmallZeroPadding[kPageSize] = {};
// use this buffer if our preallocated one is too small
std::vector<char> zero_padding_big;
const char* zero_padding = nullptr;
if (alignment != 0 && (offset & (alignment - 1))) {
// Pad the extra field so the data will be aligned.
uint16_t padding = static_cast<uint16_t>(alignment - (offset % alignment));
file_entry.padding_length = padding;
offset += padding;
zero_padding.resize(padding, 0);
if (padding <= std::size(kSmallZeroPadding)) {
zero_padding = kSmallZeroPadding;
} else {
zero_padding_big.resize(padding, 0);
zero_padding = zero_padding_big.data();
}
}
LocalFileHeader header = {};
@ -269,7 +280,7 @@ int32_t ZipWriter::StartAlignedEntryWithTime(std::string_view path, size_t flags
return HandleError(kIoError);
}
if (file_entry.padding_length != 0 && fwrite(zero_padding.data(), 1, file_entry.padding_length,
if (file_entry.padding_length != 0 && fwrite(zero_padding, 1, file_entry.padding_length,
file_) != file_entry.padding_length) {
return HandleError(kIoError);
}