From ddf887d95c1cef95746f9881dc4180d983e7a351 Mon Sep 17 00:00:00 2001 From: kim Date: Wed, 5 Nov 2025 17:53:47 +0100 Subject: [performance] when transforming media, perform read operations of large files using mmap (#4541) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit the performance gains aren't as substantial as i was hoping, but benchmarks did show it averaged out faster using this method. unfortunately i managed to lose the benchmarks i wrote with a poorly timed `git checkout -- .` 😭 Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4541 Co-authored-by: kim Co-committed-by: kim --- vendor/codeberg.org/gruf/go-mmap/mmap.go | 142 +++++++++++++++++++++++++++++++ 1 file changed, 142 insertions(+) create mode 100644 vendor/codeberg.org/gruf/go-mmap/mmap.go (limited to 'vendor/codeberg.org/gruf/go-mmap/mmap.go') diff --git a/vendor/codeberg.org/gruf/go-mmap/mmap.go b/vendor/codeberg.org/gruf/go-mmap/mmap.go new file mode 100644 index 000000000..797ed3e73 --- /dev/null +++ b/vendor/codeberg.org/gruf/go-mmap/mmap.go @@ -0,0 +1,142 @@ +package mmap + +import ( + "errors" + "io" + "io/fs" + "runtime" + "syscall" +) + +// MmapFile maps file at path into memory using syscall.mmap(), +// and returns a protected MmapReader{} for accessing the mapped data. +// Note that the mapped memory is not concurrency safe (other than +// concurrent ReadAt() calls). Any other calls made concurrently to +// Read() or Close() (including ReadAt()) require protection. +func MmapFile(path string) (*MmappedFile, error) { + + // Stat file information. + stat, err := stat(path) + if err != nil { + return nil, err + } + + // Mmap file into memory. + return openMmap(path, stat) +} + +func openMmap(path string, stat *fileStat) (*MmappedFile, error) { + if stat.Size() <= 0 { + // Empty file, no-op read. + return &MmappedFile{}, nil + } + + // Check file data size is accessible. + if stat.Size() != int64(int(stat.Size())) { + return nil, errors.New("file is too large") + } + + // Open file at path for read-only access. + fd, err := open(path, syscall.O_RDONLY, 0) + if err != nil { + return nil, err + } + + // Map this file into memory as slice. + mem, err := mmap(fd, 0, int(stat.Size()), + syscall.PROT_READ, syscall.MAP_PRIVATE) + + // Done with file. + _ = close_(fd) + + if err != nil { + return nil, err + } + + // Return as wrapped reader type. + return newMmapReader(mem, stat), nil +} + +// newMmapReader wraps a mapped memory slice in an +// MmappedFile{}, also setting a GC finalizer function. +func newMmapReader(mem []byte, stat *fileStat) *MmappedFile { + r := &MmappedFile{b: mem, s: stat} + runtime.SetFinalizer(r, (*MmappedFile).Close) + return r +} + +type MmappedFile struct { + b []byte // mapped memory + n int // read index + s *fileStat // file info +} + +func (r *MmappedFile) Name() string { + return r.s.name +} + +func (r *MmappedFile) Stat() (fs.FileInfo, error) { + return r.s, nil +} + +func (r *MmappedFile) Read(b []byte) (n int, err error) { + if r.n >= len(r.b) { + return 0, io.EOF + } + n = copy(b, r.b[r.n:]) + r.n += n + return +} + +func (r *MmappedFile) ReadAt(b []byte, off int64) (n int, err error) { + if off > int64(len(r.b)) { + return 0, io.EOF + } + n = copy(b, r.b[off:]) + return n, nil +} + +func (r *MmappedFile) WriteTo(w io.Writer) (int64, error) { + if r.n >= len(r.b) { + return 0, io.EOF + } + n, err := w.Write(r.b[r.n:]) + r.n += n + return int64(n), err +} + +func (r *MmappedFile) Seek(off int64, whence int) (int64, error) { + var n int + switch whence { + case io.SeekCurrent: + n = r.n + int(off) + case io.SeekStart: + n = 0 + int(off) + case io.SeekEnd: + n = len(r.b) + int(off) + default: + return 0, errors.New("invalid argument") + } + if n < 0 || n > len(r.b) { + return 0, errors.New("invalid argument") + } + r.n = n + return int64(n), nil +} + +func (r *MmappedFile) Len() int { + return len(r.b) - r.n +} + +func (r *MmappedFile) Size() int64 { + return int64(len(r.b)) +} + +func (r *MmappedFile) Close() error { + if b := r.b; b != nil { + r.b = nil + runtime.SetFinalizer(r, nil) + return munmap(b) + } + return nil +} -- cgit v1.2.3