Skip to content

Commit ccd684f

Browse files
authored
Use pread() in FileDataLoader.
Differential Revision: D61408840 Pull Request resolved: #4760
1 parent 48e4d29 commit ccd684f

File tree

1 file changed

+36
-20
lines changed

1 file changed

+36
-20
lines changed

extension/data_loader/file_data_loader.cpp

Lines changed: 36 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,20 @@
2323
#include <executorch/runtime/core/result.h>
2424
#include <executorch/runtime/platform/log.h>
2525

26+
// Some platforms (e.g. Xtensa) do not support pread() that we use to read the
27+
// file at different offsets simultaneously from multiple threads not affecting
28+
// each other. We list them below and use a workaround for them.
29+
#if defined(__xtensa__)
30+
#define ET_HAVE_PREAD 0
31+
#endif // defined(__xtensa__)
32+
33+
#ifndef ET_HAVE_PREAD
34+
#define ET_HAVE_PREAD 1
35+
#endif // !ET_HAVE_PREAD
36+
2637
namespace torch {
2738
namespace executor {
2839
namespace util {
29-
3040
namespace {
3141

3242
/**
@@ -226,29 +236,28 @@ ET_NODISCARD Error FileDataLoader::load_into(
226236
ET_CHECK_OR_RETURN_ERROR(
227237
buffer != nullptr, InvalidArgument, "Provided buffer cannot be null");
228238

229-
// Seek to the right place in the file.
230-
off_t seek_offset = ::lseek(fd_, offset, SEEK_SET);
231-
if (seek_offset != offset) {
232-
ET_LOG(
233-
Error,
234-
"Seeking %s to offset %zu returned %zd: %s",
235-
file_name_,
236-
offset,
237-
(ssize_t)seek_offset,
238-
strerror(errno));
239-
return Error::AccessFailed;
240-
}
241-
242239
// Read the data into the aligned address.
243240
size_t needed = size;
244241
uint8_t* buf = reinterpret_cast<uint8_t*>(buffer);
242+
243+
// Make a duplicate fd if pread() is not available and we have to seek().
244+
// Cannot use the standard dup() or fcntl() calls because the returned
245+
// duplicate will share the underlying file record and affect the original fd
246+
// when seeking on multiple threads simultaneously.
247+
const auto dup_fd = ET_HAVE_PREAD ? fd_ : ::open(file_name_, O_RDONLY);
248+
245249
while (needed > 0) {
246-
// Reads on macos will fail with EINVAL if size > INT32_MAX.
247-
ssize_t nread = ::read(
248-
fd_,
249-
buf,
250-
std::min<size_t>(
251-
needed, static_cast<size_t>(std::numeric_limits<int32_t>::max())));
250+
// Reads on macOS will fail with EINVAL if size > INT32_MAX.
251+
const auto chunk_size = std::min<size_t>(
252+
needed, static_cast<size_t>(std::numeric_limits<int32_t>::max()));
253+
const auto nread =
254+
#if ET_HAVE_PREAD
255+
::pread(dup_fd, buf, chunk_size, offset);
256+
#else
257+
(::lseek(dup_fd, offset, SEEK_SET) == (off_t)-1)
258+
? -1
259+
: ::read(dup_fd, buf, chunk_size);
260+
#endif
252261
if (nread < 0 && errno == EINTR) {
253262
// Interrupted by a signal; zero bytes read.
254263
continue;
@@ -263,10 +272,17 @@ ET_NODISCARD Error FileDataLoader::load_into(
263272
size,
264273
offset,
265274
nread == 0 ? "EOF" : strerror(errno));
275+
if (!ET_HAVE_PREAD) {
276+
::close(dup_fd);
277+
}
266278
return Error::AccessFailed;
267279
}
268280
needed -= nread;
269281
buf += nread;
282+
offset += nread;
283+
}
284+
if (!ET_HAVE_PREAD) {
285+
::close(dup_fd);
270286
}
271287
return Error::Ok;
272288
}

0 commit comments

Comments
 (0)