Skip to content

Commit 8bb90e9

Browse files
authored
Improve in memory link speed (#179)
This PR improves the performance of returning the linked payload in memory linking by: * reusing the in memory zip_source if link payload is in memory or * by re-reading from disk if the payload was originally on disk.
1 parent b21a2df commit 8bb90e9

File tree

3 files changed

+60
-70
lines changed

3 files changed

+60
-70
lines changed

include/Payload/PatchableZipPayload.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ class PatchableZipPayload : public PatchablePayload {
7474

7575
std::string const path;
7676
struct zip *zip;
77+
zip_source_t *inMemoryZipSource;
7778
bool enableInMemory;
7879

7980
std::unordered_map<std::string, TrackedFile> files;

lib/Arguments/Arguments.cpp

Lines changed: 36 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -84,18 +84,43 @@ llvm::Error bindArguments(llvm::StringRef moduleInput,
8484

8585
bool enableInMemoryOutput = payloadOutputPath == "";
8686

87-
llvm::StringRef payloadData =
88-
(enableInMemoryOutput) ? moduleInput : payloadOutputPath;
87+
// placeholder string for data on disk if required
88+
std::string inputFromDisk;
8989

90-
if (!enableInMemoryOutput) {
91-
std::error_code copyError =
92-
llvm::sys::fs::copy_file(moduleInput, payloadOutputPath);
90+
if (!enableInMemoryInput) {
91+
// compile payload on disk
92+
// copy to link payload if not returning in memory
93+
// load from disk into string if returning in memory
94+
if (!enableInMemoryOutput) {
95+
std::error_code copyError =
96+
llvm::sys::fs::copy_file(moduleInput, payloadOutputPath);
97+
if (copyError)
98+
return llvm::make_error<llvm::StringError>(
99+
"Failed to copy circuit module to payload", copyError);
100+
} else {
101+
// read from disk to process in memory
102+
std::ostringstream buf;
103+
std::ifstream input(moduleInput.str().c_str());
104+
buf << input.rdbuf();
105+
inputFromDisk = buf.str();
106+
moduleInput = inputFromDisk;
107+
enableInMemoryInput = true;
108+
}
109+
}
93110

94-
if (copyError)
95-
return llvm::make_error<llvm::StringError>(
96-
"Failed to copy circuit module to payload", copyError);
111+
if (!enableInMemoryOutput && enableInMemoryInput) {
112+
// if payload in memory but returning on disk
113+
// copy to disk and process from there
114+
std::ofstream payload;
115+
payload.open(payloadOutputPath.str(), std::ios::binary);
116+
payload.write(moduleInput.str().c_str(), moduleInput.str().length());
117+
payload.close();
118+
enableInMemoryInput = false;
97119
}
98120

121+
llvm::StringRef payloadData =
122+
(enableInMemoryInput) ? moduleInput : payloadOutputPath;
123+
99124
auto binary = std::unique_ptr<BindArgumentsImplementation>(
100125
factory.create(onDiagnostic));
101126
binary->setTreatWarningsAsErrors(treatWarningsAsErrors);
@@ -120,6 +145,8 @@ llvm::Error bindArguments(llvm::StringRef moduleInput,
120145
// dump string to disk and clear string
121146
// if enableInMemoryInput is false:
122147
// payload was on disk originally use writeBack
148+
if (auto err = payload->writeBack())
149+
return err;
123150
if (enableInMemoryOutput || enableInMemoryInput) {
124151
if (auto err = payload->writeString(inMemoryOutput))
125152
return err;
@@ -131,8 +158,7 @@ llvm::Error bindArguments(llvm::StringRef moduleInput,
131158
// clear output string
132159
*inMemoryOutput = "";
133160
}
134-
} else if (auto err = payload->writeBack())
135-
return err;
161+
}
136162

137163
return llvm::Error::success();
138164
}

lib/Payload/ZipPayload/PatchableZipPayload.cpp

Lines changed: 23 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#include "llvm/ADT/StringRef.h"
2626
#include "llvm/Support/Error.h"
2727

28+
#include <fstream>
2829
#include <string_view>
2930
#include <zip.h>
3031

@@ -98,12 +99,14 @@ llvm::Error PatchableZipPayload::ensureOpen() {
9899
retVal = extractLibZipError(
99100
"Failure while opening in memory circuit module (zip) ", zipError);
100101
}
102+
inMemoryZipSource = zs;
101103
} else {
102104
if ((zip = zip_open(path.c_str(), 0, &errorCode)) == nullptr) {
103105
zip_error_set(&zipError, errorCode, errno);
104106
retVal = extractLibZipError(
105107
"Failure while opening circuit module (zip) file ", zipError);
106108
}
109+
inMemoryZipSource = nullptr;
107110
}
108111

109112
zip_error_fini(&zipError);
@@ -156,6 +159,9 @@ llvm::Error PatchableZipPayload::writeBack() {
156159

157160
zip_error_fini(&err);
158161

162+
if (inMemoryZipSource)
163+
zip_source_keep(inMemoryZipSource);
164+
159165
if (zip_close(zip)) {
160166
auto *err = zip_get_error(zip);
161167
return extractLibZipError("writing payload file", *err);
@@ -174,68 +180,25 @@ llvm::Error PatchableZipPayload::writeString(std::string *outputString) {
174180
outStringStream.emplace(*outputString);
175181
llvm::raw_ostream *ostream = outStringStream.getPointer();
176182

177-
// load all files in zip if required
178-
179-
auto numEntries = zip_get_num_entries(zip, 0);
180-
zip_stat_t zs;
181-
assert(numEntries >= 0);
182-
zip_stat_init(&zs);
183-
for (ssize_t i = 0; i < numEntries; i++) {
184-
zip_stat_index(zip, i, 0, &zs);
185-
llvm::StringRef name(zs.name);
186-
auto binaryDataOrErr = readMember(name);
187-
188-
if (!binaryDataOrErr)
189-
return binaryDataOrErr.takeError();
190-
}
191-
192-
zip_source_t *new_zip_src;
193-
zip_t *new_zip;
194-
195-
zip_error_t err;
196-
197-
zip_error_init(&err);
198-
199-
// open a zip source, buffer is allocated internally to libzip
200-
if ((new_zip_src = zip_source_buffer_create(nullptr, 0, 0, &err)) == nullptr)
201-
return extractLibZipError("Can't create zip source for new archive", err);
202-
203-
zip_source_keep(new_zip_src);
204-
205-
if ((new_zip = zip_open_from_source(new_zip_src, ZIP_TRUNCATE, &err)) ==
206-
nullptr) {
207-
zip_source_free(new_zip_src);
208-
return extractLibZipError(
209-
"Can't create/open an archive from the new archive source:", err);
210-
}
211-
212-
for (auto &item : files) {
213-
auto &path = item.first;
214-
auto &buf = item.second.buf;
215-
216-
auto error = addFileToZip(new_zip, path, buf, err);
217-
if (error) {
218-
zip_source_free(new_zip_src);
219-
return error;
183+
if (inMemoryZipSource) {
184+
// read from in memory source
185+
zip_int64_t sz;
186+
char *outbuffer =
187+
qssc::payload::read_zip_src_to_buffer(inMemoryZipSource, sz);
188+
if (outbuffer) {
189+
ostream->write(outbuffer, sz);
190+
free(outbuffer);
220191
}
192+
zip_source_free(inMemoryZipSource);
193+
inMemoryZipSource = nullptr;
194+
} else {
195+
// re-read file from disk
196+
std::ostringstream buf;
197+
std::ifstream input(path.c_str());
198+
buf << input.rdbuf();
199+
ostream->write(buf.str().c_str(), buf.str().length());
221200
}
222-
223-
zip_error_fini(&err);
224-
225-
if (zip_close(new_zip)) {
226-
auto *err = zip_get_error(new_zip);
227-
return extractLibZipError("Closing in memory zip", *err);
228-
}
229-
230-
//===---- Reopen for copying ----===//
231-
zip_int64_t sz;
232-
char *outbuffer = qssc::payload::read_zip_src_to_buffer(new_zip_src, sz);
233-
if (outbuffer) {
234-
// output the new archive to the stream
235-
ostream->write(outbuffer, sz);
236-
ostream->flush();
237-
free(outbuffer);
238-
}
201+
ostream->flush();
239202
return llvm::Error::success();
240203
}
241204

0 commit comments

Comments
 (0)