pkg/fileutils: GetTotalUsedFds(): slight optimization for macOS
- https://github.com/moby/moby/pull/45848

This patch contains some optimizations I still had stashed when working on eaa9494b71c046227264359beeaf80ddd4296ecf (https://github.com/moby/moby/pull/45848).

- Use the bytes package for handling the output of "lsof", instead of converting to a string.
- Count the number of newlines in the output, instead of splitting the output into a slice of strings. We're only interested in the number of lines in the output.
- Use lsof's -F option to only print the file-descriptor for each line, as we don't need other information.
- Use the -l, -n, and -P options to omit converting usernames, host names, and port numbers.

From the [LSOF(8)][1] man-page:

   -l    This option inhibits the conversion of user ID numbers to
         login names. It is also useful when login name lookup is
         working improperly or slowly.

   -n    This option inhibits the conversion of network numbers to host
         names for network files. Inhibiting conversion can make lsof run faster.
         It is also useful when host name lookup is not working properly.

   -P    This option inhibits the conversion of port numbers to port names for network files.
         Inhibiting the conversion can make lsof run a little faster.
         It is also useful when host name lookup is not working properly.

Output looks something like;

    lsof -lnP -Ff -p 39849
    p39849
    fcwd
    ftxt
    ftxt
    f0
    f1
    f2
    f3
    f4
    f5
    f6
    f7
    f8
    f9
    f10
    f11

Before/After:

    BenchmarkGetTotalUsedFds-10  122  9479384 ns/op   10816 B/op  63 allocs/op
    BenchmarkGetTotalUsedFds-10  154  7814697 ns/op    7257 B/op  60 allocs/op

[1]: https://opensource.apple.com/source/lsof/lsof-49/lsof/lsof.man.auto.html

**- Description for the changelog**
<!--
Write a short (one line) summary that describes the changes in this
pull request for inclusion in the changelog:
-->


**- A picture of a cute animal (not mandatory but encouraged)**


pkg/fileutils/fileutils_darwin.go
package fileutils // import "github.com/docker/docker/pkg/fileutils"

import (
	"os"
	"os/exec"
	"strconv"
	"strings"
)

// GetTotalUsedFds returns the number of used File Descriptors by
// executing `lsof -p PID`
func GetTotalUsedFds() int {
	pid := os.Getpid()

	cmd := exec.Command("lsof", "-p", strconv.Itoa(pid))

	output, err := cmd.CombinedOutput()
	if err != nil {
		return -1
	}

	outputStr := strings.TrimSpace(string(output))

	fds := strings.Split(outputStr, "\n")

	return len(fds) - 1
}

package fileutils // import "github.com/docker/docker/pkg/fileutils"

import (
	"bytes"
	"os"
	"os/exec"
	"strconv"
)

// GetTotalUsedFds returns the number of used File Descriptors by executing
// "lsof -lnP -Ff -p PID".
//
// It uses the "-F" option to only print file-descriptors (f), and the "-l",
// "-n", and "-P" options to omit looking up user-names, host-names, and port-
// names. See [LSOF(8)].
//
// [LSOF(8)]: https://opensource.apple.com/source/lsof/lsof-49/lsof/lsof.man.auto.html
func GetTotalUsedFds() int {
	output, err := exec.Command("lsof", "-lnP", "-Ff", "-p", strconv.Itoa(os.Getpid())).CombinedOutput()
	if err != nil {
		return -1
	}

	return bytes.Count(output, []byte("\nf")) // Count number of file descriptor fields in output.
}

Each field is prefixed with a one-char field identifier, so there is no need to do any math to discard the process-id field:
```suggestion
	return bytes.Count(output, []byte("\nf")) // Count number of file descriptor fields in output
```