diff options
| author | Paul Buetow <paul@buetow.org> | 2026-03-03 11:03:13 +0200 |
|---|---|---|
| committer | Paul Buetow <paul@buetow.org> | 2026-03-03 11:03:13 +0200 |
| commit | acc1e2f0759c4d232242950c7f54faa9763a9bb4 (patch) | |
| tree | a77d493ee97ed72ada511a8778f132dfbebc93b7 /internal/eventloop.go | |
| parent | 49885cfc8cba02d378a615c7383ea778afd5aaf9 (diff) | |
Cache procfs fd metadata for unknown descriptors
Diffstat (limited to 'internal/eventloop.go')
| -rw-r--r-- | internal/eventloop.go | 69 |
1 files changed, 51 insertions, 18 deletions
diff --git a/internal/eventloop.go b/internal/eventloop.go index 440fdd6..a917613 100644 --- a/internal/eventloop.go +++ b/internal/eventloop.go @@ -169,7 +169,8 @@ type eventLoop struct { pendingHandles map[uint32]string // map of TID to pathname from name_to_handle_at files map[int32]file.File // Track all open files by file descriptor. fdTracker *fdTracker - comms map[uint32]string // Program or thread name of the current Tid. + procFdCache map[uint64]file.FdFile // Cache procfs-resolved metadata for unknown fds. + comms map[uint32]string // Program or thread name of the current Tid. commResolver *commResolver prevPairTimes map[uint32]uint64 // Previous event's time (to calculate time differences between two events) rawHandlers map[EventType]rawEventHandler @@ -198,6 +199,7 @@ func newEventLoop(cfg eventLoopConfig) *eventLoop { pendingHandles: make(map[uint32]string), files: filesByFD, fdTracker: newFDTracker(filesByFD), + procFdCache: make(map[uint64]file.FdFile), comms: commsByTID, commResolver: newCommResolver(commsByTID), prevPairTimes: make(map[uint32]uint64), @@ -553,13 +555,10 @@ func (e *eventLoop) handlePathExit(ep *event.Pair, pathEv *PathEvent) bool { func (e *eventLoop) handleFdExit(ep *event.Pair, fdEv *FdEvent) bool { fd := fdEv.Fd - if fdFile, ok := e.fdState().get(fd); ok { - ep.File = fdFile - if ep.Is(SYS_ENTER_CLOSE) { - e.fdState().delete(fd) - } - } else { - ep.File = file.NewFdWithPid(fd, fdEv.Pid) + ep.File = e.resolveFdFile(fd, fdEv.Pid) + if ep.Is(SYS_ENTER_CLOSE) { + e.fdState().delete(fd) + e.deleteProcFdCache(fd, fdEv.Pid) } if ep.Is(SYS_ENTER_CLOSE_RANGE) { // close_range provides (first, last), but fd_event only carries the first @@ -609,11 +608,7 @@ func (e *eventLoop) handleFdExit(ep *event.Pair, fdEv *FdEvent) bool { func (e *eventLoop) handleDup3Exit(ep *event.Pair, dup3Ev *Dup3Event) bool { fd := int32(dup3Ev.Fd) - if fdFile, ok := e.fdState().get(fd); ok { - ep.File = fdFile - } else { - ep.File = file.NewFdWithPid(fd, dup3Ev.Pid) - } + ep.File = e.resolveFdFile(fd, dup3Ev.Pid) ep.Comm = e.comm(dup3Ev.GetTid()) if !e.filter.eventPair(ep) { ep.Recycle() @@ -701,11 +696,7 @@ func (e *eventLoop) handleNullExit(ep *event.Pair, nullEv *NullEvent) bool { func (e *eventLoop) handleFcntlExit(ep *event.Pair, fcntlEv *FcntlEvent) bool { ep.Comm = e.comm(fcntlEv.GetTid()) fd := int32(fcntlEv.Fd) - if fdFile, ok := e.fdState().get(fd); ok { - ep.File = fdFile - } else { - ep.File = file.NewFdWithPid(fd, fcntlEv.Pid) - } + ep.File = e.resolveFdFile(fd, fcntlEv.Pid) if !e.filter.eventPair(ep) { ep.Recycle() return false @@ -765,6 +756,48 @@ func (e *eventLoop) notifyWarning(message string) { e.warningCb(message) } +func (e *eventLoop) resolveFdFile(fd int32, pid uint32) file.File { + if fdFile, ok := e.fdState().get(fd); ok { + return fdFile + } + if fd < 0 { + return file.NewFd(fd, "", -1) + } + + if cached, ok := e.cachedProcFdFile(fd, pid); ok { + return cached + } + + // Cache first procfs resolution to avoid repeated /proc lookups for hot unknown FDs. + discovered := file.NewFdWithPid(fd, pid) + e.setProcFdCache(fd, pid, discovered) + return discovered +} + +func (e *eventLoop) cachedProcFdFile(fd int32, pid uint32) (file.FdFile, bool) { + cache, ok := e.procFdCacheState()[procFdCacheKey(pid, fd)] + return cache, ok +} + +func (e *eventLoop) setProcFdCache(fd int32, pid uint32, resolved file.FdFile) { + e.procFdCacheState()[procFdCacheKey(pid, fd)] = resolved +} + +func (e *eventLoop) deleteProcFdCache(fd int32, pid uint32) { + delete(e.procFdCacheState(), procFdCacheKey(pid, fd)) +} + +func (e *eventLoop) procFdCacheState() map[uint64]file.FdFile { + if e.procFdCache == nil { + e.procFdCache = make(map[uint64]file.FdFile) + } + return e.procFdCache +} + +func procFdCacheKey(pid uint32, fd int32) uint64 { + return uint64(pid)<<32 | uint64(uint32(fd)) +} + func (e *eventLoop) comm(tid uint32) string { return e.commState().comm(tid) } |
