185 lines
5.0 KiB
C++
185 lines
5.0 KiB
C++
/* Copyright 2024 The TensorFlow Authors. All Rights Reserved.
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
you may not use this file except in compliance with the License.
|
|
You may obtain a copy of the License at
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
See the License for the specific language governing permissions and
|
|
limitations under the License.
|
|
==============================================================================*/
|
|
#include "tensorflow/lite/delegates/xnnpack/file_util.h"
|
|
|
|
#include <fcntl.h>
|
|
|
|
#if defined(_WIN32)
|
|
#include <io.h>
|
|
#define F_OK 0
|
|
#define ftruncate _chsize_s
|
|
#define XNN_LSEEK _lseeki64
|
|
#else
|
|
#include <unistd.h>
|
|
#define XNN_LSEEK lseek
|
|
#endif // defined(_WIN32)
|
|
|
|
// We currently use the memfd_create system call to create in-memory files which
|
|
// is only supported on Linux and Android.
|
|
#if defined(__linux__) || defined(__ANDROID__)
|
|
#ifndef TFLITE_XNNPACK_IN_MEMORY_FILE_ENABLED
|
|
// Some systems have syscall.h but don't define the SYS_memfd_create macro. We
|
|
// detect those by actually doing the include and checking for its definition.
|
|
#include <sys/syscall.h>
|
|
#ifdef SYS_memfd_create
|
|
#define TFLITE_XNNPACK_IN_MEMORY_FILE_ENABLED 1
|
|
#endif // SYS_memfd_create
|
|
#endif // TFLITE_XNNPACK_IN_MEMORY_FILE_ENABLED
|
|
#endif // defined(__linux__) || defined(__ANDROID__)
|
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <cerrno>
|
|
#include <cstdio>
|
|
#include <cstring>
|
|
|
|
#include "tensorflow/lite/delegates/xnnpack/macros.h"
|
|
|
|
#if !TFLITE_XNNPACK_IN_MEMORY_FILE_ENABLED
|
|
#include "tensorflow/lite/logger.h"
|
|
#include "tensorflow/lite/minimal_logging.h"
|
|
#endif
|
|
|
|
namespace tflite {
|
|
namespace xnnpack {
|
|
|
|
FileDescriptor FileDescriptor::Duplicate(int fd) {
|
|
return FileDescriptor(dup(fd));
|
|
}
|
|
|
|
FileDescriptor FileDescriptor::Duplicate() const {
|
|
if (!IsValid()) {
|
|
return FileDescriptor(-1);
|
|
}
|
|
return FileDescriptor::Duplicate(fd_);
|
|
}
|
|
|
|
void FileDescriptor::Reset(int new_fd) {
|
|
if (fd_ == new_fd) {
|
|
return;
|
|
}
|
|
if (IsValid()) {
|
|
close(fd_);
|
|
}
|
|
fd_ = new_fd;
|
|
}
|
|
|
|
FileDescriptor::Offset FileDescriptorView::GetPos() const {
|
|
return XNN_LSEEK(fd_, 0, SEEK_CUR);
|
|
}
|
|
|
|
FileDescriptor::Offset FileDescriptorView::SetPos(
|
|
FileDescriptor::Offset position) const {
|
|
return XNN_LSEEK(fd_, position, SEEK_SET);
|
|
}
|
|
|
|
FileDescriptor::Offset FileDescriptorView::SetPosFromEnd(
|
|
FileDescriptor::Offset offset) const {
|
|
return XNN_LSEEK(fd_, offset, SEEK_END);
|
|
}
|
|
|
|
FileDescriptor::Offset FileDescriptorView::MovePos(
|
|
FileDescriptor::Offset offset) const {
|
|
return XNN_LSEEK(fd_, offset, SEEK_CUR);
|
|
}
|
|
|
|
FileDescriptor FileDescriptor::Open(const char* path, int flags, mode_t mode) {
|
|
if (!path) {
|
|
return {};
|
|
}
|
|
#if defined(_WIN32)
|
|
if (!(flags & O_TEXT)) {
|
|
flags |= O_BINARY;
|
|
}
|
|
#endif
|
|
return FileDescriptor(open(path, flags, mode));
|
|
}
|
|
|
|
void FileDescriptor::Close() { Reset(-1); }
|
|
|
|
bool FileDescriptorView::Read(void* dst, size_t count) const {
|
|
char* dst_it = reinterpret_cast<char*>(dst);
|
|
while (count > 0) {
|
|
const auto bytes = read(fd_, dst_it, count);
|
|
if (bytes == -1 /* error */ || bytes == 0 /* EOF */) {
|
|
return false;
|
|
}
|
|
count -= bytes;
|
|
dst_it += bytes;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool FileDescriptorView::Write(const void* src, size_t count) const {
|
|
const char* src_it = reinterpret_cast<const char*>(src);
|
|
while (count > 0) {
|
|
const auto bytes = write(fd_, src_it, count);
|
|
if (bytes == -1) {
|
|
return false;
|
|
}
|
|
count -= bytes;
|
|
src_it += bytes;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool FileDescriptorView::Truncate(size_t size) const {
|
|
return ftruncate(fd_, size) == 0;
|
|
}
|
|
|
|
bool InMemoryFileDescriptorAvailable() {
|
|
#if TFLITE_XNNPACK_IN_MEMORY_FILE_ENABLED
|
|
// Test if the syscall memfd_create is available.
|
|
const int test_fd = syscall(SYS_memfd_create, "test fd", 0);
|
|
if (test_fd != -1) {
|
|
close(test_fd);
|
|
return true;
|
|
}
|
|
#endif
|
|
return false;
|
|
}
|
|
|
|
FileDescriptor CreateInMemoryFileDescriptor(const char* path) {
|
|
#ifdef TFLITE_XNNPACK_IN_MEMORY_FILE_ENABLED
|
|
return FileDescriptor(syscall(
|
|
SYS_memfd_create, path ? path : "XNNPack in-memory weight cache", 0));
|
|
#else
|
|
TFLITE_LOG_PROD(tflite::TFLITE_LOG_ERROR,
|
|
"XNNPack weight cache: in-memory cache is not enabled for "
|
|
"this build.");
|
|
return FileDescriptor(-1);
|
|
#endif
|
|
}
|
|
|
|
bool IsFileEmpty(const char* path, const FileDescriptor& fd) {
|
|
#if defined(_WIN32)
|
|
struct _stat64 file_stats{};
|
|
const int res = fd.IsValid() ? _fstat64(fd.Value(), &file_stats)
|
|
: _stat64(path, &file_stats);
|
|
#else
|
|
struct stat file_stats{};
|
|
const int res =
|
|
fd.IsValid() ? fstat(fd.Value(), &file_stats) : stat(path, &file_stats);
|
|
#endif
|
|
XNNPACK_RETURN_CHECK(
|
|
res == 0 || errno == ENOENT,
|
|
"could not access file descriptor %d stats to get size ('%s'): %s.",
|
|
fd.Value(), path, strerror(errno));
|
|
return file_stats.st_size == 0;
|
|
}
|
|
|
|
} // namespace xnnpack
|
|
} // namespace tflite
|