A procfs file for runtime heap usage information for sentry.

Added a mechanism to query runtime sentry heap usage using procfs from inside
the sandbox. This may help with providing insight regarding sandbox hitting the
memory limit on the host despite reporting a lower application memory usage.
And added a test to `proc.cc`.

PiperOrigin-RevId: 470061488
This commit is contained in:
Sergey Madaminov
2022-08-25 12:58:43 -07:00
committed by gVisor bot
parent df5374fcfa
commit 60698ceed3
4 changed files with 75 additions and 24 deletions
+12 -11
View File
@@ -66,17 +66,18 @@ var _ kernfs.Inode = (*tasksInode)(nil)
func (fs *filesystem) newTasksInode(ctx context.Context, k *kernel.Kernel, pidns *kernel.PIDNamespace, fakeCgroupControllers map[string]string) *tasksInode {
root := auth.NewRootCredentials(pidns.UserNamespace())
contents := map[string]kernfs.Inode{
"cmdline": fs.newInode(ctx, root, 0444, &cmdLineData{}),
"cpuinfo": fs.newInode(ctx, root, 0444, newStaticFileSetStat(cpuInfoData(k))),
"filesystems": fs.newInode(ctx, root, 0444, &filesystemsData{}),
"loadavg": fs.newInode(ctx, root, 0444, &loadavgData{}),
"sys": fs.newSysDir(ctx, root, k),
"meminfo": fs.newInode(ctx, root, 0444, &meminfoData{}),
"mounts": kernfs.NewStaticSymlink(ctx, root, linux.UNNAMED_MAJOR, fs.devMinor, fs.NextIno(), "self/mounts"),
"net": kernfs.NewStaticSymlink(ctx, root, linux.UNNAMED_MAJOR, fs.devMinor, fs.NextIno(), "self/net"),
"stat": fs.newInode(ctx, root, 0444, &statData{}),
"uptime": fs.newInode(ctx, root, 0444, &uptimeData{}),
"version": fs.newInode(ctx, root, 0444, &versionData{}),
"cmdline": fs.newInode(ctx, root, 0444, &cmdLineData{}),
"cpuinfo": fs.newInode(ctx, root, 0444, newStaticFileSetStat(cpuInfoData(k))),
"filesystems": fs.newInode(ctx, root, 0444, &filesystemsData{}),
"loadavg": fs.newInode(ctx, root, 0444, &loadavgData{}),
"sys": fs.newSysDir(ctx, root, k),
"meminfo": fs.newInode(ctx, root, 0444, &meminfoData{}),
"mounts": kernfs.NewStaticSymlink(ctx, root, linux.UNNAMED_MAJOR, fs.devMinor, fs.NextIno(), "self/mounts"),
"net": kernfs.NewStaticSymlink(ctx, root, linux.UNNAMED_MAJOR, fs.devMinor, fs.NextIno(), "self/net"),
"sentry-meminfo": fs.newInode(ctx, root, 0444, &sentryMeminfoData{}),
"stat": fs.newInode(ctx, root, 0444, &statData{}),
"uptime": fs.newInode(ctx, root, 0444, &uptimeData{}),
"version": fs.newInode(ctx, root, 0444, &versionData{}),
}
// If fakeCgroupControllers are provided, don't create a cgroupfs backed
// /proc/cgroup as it will not match the fake controllers.
+27
View File
@@ -17,6 +17,7 @@ package proc
import (
"bytes"
"fmt"
"runtime"
"strconv"
"gvisor.dev/gvisor/pkg/abi/linux"
@@ -420,3 +421,29 @@ func kernelVersion(ctx context.Context) kernel.Version {
}
return init.Leader().SyscallTable().Version
}
// sentryMeminfoData implements vfs.DynamicBytesSource for /proc/sentry-meminfo.
//
// +stateify savable
type sentryMeminfoData struct {
dynamicBytesFileSetAttr
}
var _ dynamicInode = (*sentryMeminfoData)(nil)
// Generate implements vfs.DynamicBytesSource.Generate.
func (*sentryMeminfoData) Generate(ctx context.Context, buf *bytes.Buffer) error {
var sentryMeminfo runtime.MemStats
runtime.ReadMemStats(&sentryMeminfo)
fmt.Fprintf(buf, "Alloc: %8d kB\n", sentryMeminfo.Alloc/1024)
fmt.Fprintf(buf, "TotalAlloc: %8d kB\n", sentryMeminfo.TotalAlloc/1024)
fmt.Fprintf(buf, "Sys: %8d kB\n", sentryMeminfo.Sys/1024)
fmt.Fprintf(buf, "Mallocs: %8d\n", sentryMeminfo.Mallocs)
fmt.Fprintf(buf, "Frees: %8d\n", sentryMeminfo.Frees)
fmt.Fprintf(buf, "Live Objects: %8d\n", sentryMeminfo.Mallocs-sentryMeminfo.Frees)
fmt.Fprintf(buf, "HeapAlloc: %8d kB\n", sentryMeminfo.HeapAlloc/1024)
fmt.Fprintf(buf, "HeapSys: %8d kB\n", sentryMeminfo.HeapSys/1024)
fmt.Fprintf(buf, "HeapObjects: %8d\n", sentryMeminfo.HeapObjects)
return nil
}
+14 -13
View File
@@ -47,19 +47,20 @@ var (
var (
tasksStaticFiles = map[string]testutil.DirentType{
"cmdline": linux.DT_REG,
"cpuinfo": linux.DT_REG,
"filesystems": linux.DT_REG,
"loadavg": linux.DT_REG,
"meminfo": linux.DT_REG,
"mounts": linux.DT_LNK,
"net": linux.DT_LNK,
"self": linux.DT_LNK,
"stat": linux.DT_REG,
"sys": linux.DT_DIR,
"thread-self": linux.DT_LNK,
"uptime": linux.DT_REG,
"version": linux.DT_REG,
"cmdline": linux.DT_REG,
"cpuinfo": linux.DT_REG,
"filesystems": linux.DT_REG,
"loadavg": linux.DT_REG,
"meminfo": linux.DT_REG,
"mounts": linux.DT_LNK,
"net": linux.DT_LNK,
"self": linux.DT_LNK,
"sentry-meminfo": linux.DT_REG,
"stat": linux.DT_REG,
"sys": linux.DT_DIR,
"thread-self": linux.DT_LNK,
"uptime": linux.DT_REG,
"version": linux.DT_REG,
}
tasksStaticFilesNextOffs = map[string]int64{
"self": selfLink.NextOff,
+22
View File
@@ -1337,6 +1337,28 @@ TEST(ProcMeminfo, ContainsBasicFields) {
ContainsRegex(R"(MemFree:\s+[0-9]+ kB)")));
}
TEST(ProcSentryMeminfo, ContainsFieldsAndEndsWithNewline) {
SKIP_IF(!IsRunningOnGvisor());
std::string proc_sentry_meminfo =
ASSERT_NO_ERRNO_AND_VALUE(GetContents("/proc/sentry-meminfo"));
// Assert that all expected fields are present.
EXPECT_THAT(proc_sentry_meminfo,
AllOf(ContainsRegex(R"(Alloc:\s+[0-9]+ kB)"),
ContainsRegex(R"(TotalAlloc:\s+[0-9]+ kB)"),
ContainsRegex(R"(Sys:\s+[0-9]+ kB)"),
ContainsRegex(R"(Mallocs:\s+[0-9]+)"),
ContainsRegex(R"(Frees:\s+[0-9]+)"),
ContainsRegex(R"(Live Objects:\s+[0-9]+)"),
ContainsRegex(R"(HeapAlloc:\s+[0-9]+ kB)"),
ContainsRegex(R"(HeapSys:\s+[0-9]+ kB)"),
ContainsRegex(R"(HeapObjects:\s+[0-9]+)")));
// Assert that /proc/sentry-meminfo ends with a new line.
EXPECT_EQ(proc_sentry_meminfo.back(), '\n');
}
TEST(ProcStat, ContainsBasicFields) {
std::string proc_stat = ASSERT_NO_ERRNO_AND_VALUE(GetContents("/proc/stat"));