Merge "[zip] Save 1 malloc and memset for each added file in ZipWriter"
diff --git a/libziparchive/zip_archive_benchmark.cpp b/libziparchive/zip_archive_benchmark.cpp
index 23ed408..09d3b8a 100644
--- a/libziparchive/zip_archive_benchmark.cpp
+++ b/libziparchive/zip_archive_benchmark.cpp
@@ -58,7 +58,7 @@
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 @@
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 @@
}
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();
diff --git a/libziparchive/zip_writer.cc b/libziparchive/zip_writer.cc
index 3c53209..198154b 100644
--- a/libziparchive/zip_writer.cc
+++ b/libziparchive/zip_writer.cc
@@ -247,13 +247,24 @@
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 @@
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);
}