Explorar o código

Merge pull request #45848 from thaJeztah/improve_fd_count

pkg/fileutils: GetTotalUsedFds: reduce allocations
Sebastiaan van Stijn %!s(int64=2) %!d(string=hai) anos
pai
achega
b6ad25bf5e

+ 52 - 0
pkg/fileutils/fileutils_linux.go

@@ -0,0 +1,52 @@
+package fileutils
+
+import (
+	"context"
+	"fmt"
+	"io"
+	"os"
+
+	"github.com/containerd/containerd/log"
+	"golang.org/x/sys/unix"
+)
+
+// GetTotalUsedFds Returns the number of used File Descriptors by
+// reading it via /proc filesystem.
+func GetTotalUsedFds() int {
+	name := fmt.Sprintf("/proc/%d/fd", os.Getpid())
+
+	// Fast-path for Linux 6.2 (since [f1f1f2569901ec5b9d425f2e91c09a0e320768f3]).
+	// From the [Linux docs]:
+	//
+	// "The number of open files for the process is stored in 'size' member of
+	// stat() output for /proc/<pid>/fd for fast access."
+	//
+	// [Linux docs]: https://docs.kernel.org/filesystems/proc.html#proc-pid-fd-list-of-symlinks-to-open-files:
+	// [f1f1f2569901ec5b9d425f2e91c09a0e320768f3]: https://github.com/torvalds/linux/commit/f1f1f2569901ec5b9d425f2e91c09a0e320768f3
+	var stat unix.Stat_t
+	if err := unix.Stat(name, &stat); err == nil && stat.Size > 0 {
+		return int(stat.Size)
+	}
+
+	f, err := os.Open(name)
+	if err != nil {
+		log.G(context.TODO()).WithError(err).Error("Error listing file descriptors")
+		return -1
+	}
+	defer f.Close()
+
+	var fdCount int
+	for {
+		names, err := f.Readdirnames(100)
+		fdCount += len(names)
+		if err == io.EOF {
+			break
+		} else if err != nil {
+			log.G(context.TODO()).WithError(err).Error("Error listing file descriptors")
+			return -1
+		}
+	}
+	// Note that the slow path has 1 more file-descriptor, due to the open
+	// file-handle for /proc/<pid>/fd during the calculation.
+	return fdCount
+}

+ 7 - 0
pkg/fileutils/fileutils_test.go

@@ -240,3 +240,10 @@ func TestCreateIfNotExistsFile(t *testing.T) {
 		t.Errorf("Should have been a file, seems it's not")
 		t.Errorf("Should have been a file, seems it's not")
 	}
 	}
 }
 }
+
+func BenchmarkGetTotalUsedFds(b *testing.B) {
+	b.ReportAllocs()
+	for i := 0; i < b.N; i++ {
+		_ = GetTotalUsedFds()
+	}
+}

+ 0 - 22
pkg/fileutils/fileutils_unix.go

@@ -1,22 +0,0 @@
-//go:build linux || freebsd
-
-package fileutils // import "github.com/docker/docker/pkg/fileutils"
-
-import (
-	"context"
-	"fmt"
-	"os"
-
-	"github.com/containerd/containerd/log"
-)
-
-// GetTotalUsedFds Returns the number of used File Descriptors by
-// reading it via /proc filesystem.
-func GetTotalUsedFds() int {
-	if fds, err := os.ReadDir(fmt.Sprintf("/proc/%d/fd", os.Getpid())); err != nil {
-		log.G(context.TODO()).Errorf("Error opening /proc/%d/fd: %s", os.Getpid(), err)
-	} else {
-		return len(fds)
-	}
-	return -1
-}