sys_fs: Optimize concurrent file reads

This commit is contained in:
Eladash 2023-10-02 18:23:21 +03:00 committed by Elad Ashkenazi
parent f07e17f6aa
commit 4b827a8d9c
3 changed files with 36 additions and 14 deletions

View File

@ -1854,8 +1854,9 @@ static NEVER_INLINE error_code savedata_op(ppu_thread& ppu, u32 operation, u32 v
}
const auto file = std::as_const(all_files).find(file_path);
const u64 pos = fileSet->fileOffset;
if (file == all_files.cend() || file->second.size() <= fileSet->fileOffset)
if (file == all_files.cend() || file->second.size() <= pos)
{
cellSaveData.error("Failed to open file %s%s (size=%d, fileOffset=%d)", dir_path, file_path, file == all_files.cend() ? -1 : file->second.size(), fileSet->fileOffset);
savedata_result = CELL_SAVEDATA_ERROR_FAILURE;
@ -1863,8 +1864,7 @@ static NEVER_INLINE error_code savedata_op(ppu_thread& ppu, u32 operation, u32 v
}
// Read from memory file to vm
file->second.seek(fileSet->fileOffset);
const u64 rr = lv2_file::op_read(file->second, fileSet->fileBuf, fileSet->fileSize);
const u64 rr = lv2_file::op_read(file->second, fileSet->fileBuf, fileSet->fileSize, pos);
fileGet->excSize = ::narrow<u32>(rr);
break;
}

View File

@ -16,6 +16,7 @@
#include <filesystem>
#include <span>
#include <shared_mutex>
LOG_CHANNEL(sys_fs);
@ -371,7 +372,7 @@ lv2_fs_object::lv2_fs_object(utils::serial& ar, bool)
{
}
u64 lv2_file::op_read(const fs::file& file, vm::ptr<void> buf, u64 size)
u64 lv2_file::op_read(const fs::file& file, vm::ptr<void> buf, u64 size, u64 opt_pos)
{
// Copy data from intermediate buffer (avoid passing vm pointer to a native API)
std::vector<uchar> local_buf(std::min<u64>(size, 65536));
@ -381,7 +382,7 @@ u64 lv2_file::op_read(const fs::file& file, vm::ptr<void> buf, u64 size)
while (result < size)
{
const u64 block = std::min<u64>(size - result, local_buf.size());
const u64 nread = file.read(+local_buf.data(), block);
const u64 nread = (opt_pos == umax ? file.read(local_buf.data(), block) : file.read_at(opt_pos + result, local_buf.data(), block));
std::memcpy(static_cast<uchar*>(buf.get_ptr()) + result, local_buf.data(), nread);
result += nread;
@ -1930,7 +1931,19 @@ error_code sys_fs_fcntl(ppu_thread& ppu, u32 fd, u32 op, vm::ptr<void> _arg, u32
sys_fs.error("%s type: Writing %u bytes to FD=%d (path=%s)", file->type, arg->size, file->name.data());
}
std::lock_guard lock(file->mp->mutex);
std::unique_lock wlock(file->mp->mutex, std::defer_lock);
std::shared_lock rlock(file->mp->mutex, std::defer_lock);
if (op == 0x8000000b)
{
// Writer lock
wlock.lock();
}
else
{
// Reader lock (not needing exclusivity in this special case because the state should not change)
rlock.lock();
}
if (!file->file)
{
@ -1947,14 +1960,23 @@ error_code sys_fs_fcntl(ppu_thread& ppu, u32 fd, u32 op, vm::ptr<void> _arg, u32
return CELL_EBUSY;
}
const u64 old_pos = file->file.pos();
file->file.seek(arg->offset);
u64 old_pos = umax;
const u64 op_pos = arg->offset;
if (op == 0x8000000b)
{
old_pos = file->file.pos();
file->file.seek(op_pos);
}
arg->out_size = op == 0x8000000a
? file->op_read(arg->buf, arg->size)
? file->op_read(arg->buf, arg->size, op_pos)
: file->op_write(arg->buf, arg->size);
ensure(old_pos == file->file.seek(old_pos));
if (op == 0x8000000b)
{
ensure(old_pos == file->file.seek(old_pos));
}
// TODO: EDATA corruption detection

View File

@ -157,7 +157,7 @@ struct lv2_fs_mount_point
const bs_t<lv2_mp_flag> flags{};
lv2_fs_mount_point* const next = nullptr;
mutable std::recursive_mutex mutex;
mutable shared_mutex mutex;
};
extern lv2_fs_mount_point g_mp_sys_dev_hdd0;
@ -340,11 +340,11 @@ struct lv2_file final : lv2_fs_object
static open_result_t open(std::string_view vpath, s32 flags, s32 mode, const void* arg = {}, u64 size = 0);
// File reading with intermediate buffer
static u64 op_read(const fs::file& file, vm::ptr<void> buf, u64 size);
static u64 op_read(const fs::file& file, vm::ptr<void> buf, u64 size, u64 opt_pos = umax);
u64 op_read(vm::ptr<void> buf, u64 size) const
u64 op_read(vm::ptr<void> buf, u64 size, u64 opt_pos = umax) const
{
return op_read(file, buf, size);
return op_read(file, buf, size, opt_pos);
}
// File writing with intermediate buffer