Skip to content

Commit

Permalink
Reduce agent RSS
Browse files Browse the repository at this point in the history
  • Loading branch information
L3n41c committed Dec 18, 2024
1 parent 593c137 commit 599de27
Show file tree
Hide file tree
Showing 9 changed files with 161 additions and 0 deletions.
4 changes: 4 additions & 0 deletions cmd/agent/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ import (

"github.com/DataDog/datadog-agent/cmd/agent/command"
"github.com/DataDog/datadog-agent/cmd/agent/subcommands"

"github.com/DataDog/datadog-agent/cmd/internal/rssshrinker"
"github.com/DataDog/datadog-agent/cmd/internal/runcmd"
"github.com/spf13/cobra"
)
Expand All @@ -37,6 +39,8 @@ func init() {
}

func main() {
rssshrinker.Setup()

process := strings.TrimSpace(os.Getenv("DD_BUNDLED_AGENT"))

if process == "" {
Expand Down
3 changes: 3 additions & 0 deletions cmd/cluster-agent/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,15 @@ import (

"github.com/DataDog/datadog-agent/cmd/cluster-agent/command"
"github.com/DataDog/datadog-agent/cmd/cluster-agent/subcommands"
"github.com/DataDog/datadog-agent/cmd/internal/rssshrinker"

"github.com/DataDog/datadog-agent/pkg/util/flavor"
"github.com/DataDog/datadog-agent/pkg/util/log"
)

func main() {
rssshrinker.Setup()

// set the Agent flavor
flavor.SetFlavor(flavor.ClusterAgent)

Expand Down
127 changes: 127 additions & 0 deletions cmd/internal/rssshrinker/rssshrinker_linux.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
// Unless explicitly stated otherwise all files in this repository are licensed
// under the Apache License Version 2.0.
// This product includes software developed at Datadog (https://www.datadoghq.com/).
// Copyright 2024-present Datadog, Inc.

//go:build linux

// Package rssshrinker provides functions to reduce the process’ RSS
package rssshrinker

import (
"bufio"
"fmt"
"os"
"runtime/debug"
"strconv"
"strings"
"syscall"
"time"
"unsafe"
)

/*
#include <malloc.h>
*/
import "C"

//revive:disable:var-naming

// MADV_PAGEOUT Reclaim these pages.
const MADV_PAGEOUT = 21

//revive:enable:var-naming

func Setup() {
// Release the memory garbage collected by the Go runtime to the kernel every 2 minutes.
go func() {
ticker := time.NewTicker(2 * time.Minute)
defer ticker.Stop()
for range ticker.C {
debug.FreeOSMemory()
}
}()

// Release the memory allocated by C malloc to the kernel every 2 minutes.
// This is for the native libraries pulled by Python.
go func() {
ticker := time.NewTicker(2 * time.Minute)
defer ticker.Stop()
for range ticker.C {
C.malloc_trim(0)
}
}()

// Release file-backed memory to the kernel every 30 minutes.
// This is for the GO code that isn’t actively used.
go func() {
ticker := time.NewTicker(30 * time.Minute)
defer ticker.Stop()
for range ticker.C {
if err := pageOutFileBackedMemory(); err != nil {
fmt.Fprintf(os.Stderr, "Failed to release memory: %s\n", err)
}
}
}()
}

// PageOutFileBackedMemory releases file-backed memory by advising the kernel to page out the memory.
func pageOutFileBackedMemory() error {
selfMap, err := os.Open("/proc/self/maps")
if err != nil {
return fmt.Errorf("failed to open /proc/self/maps: %w", err)
}
defer selfMap.Close()

scanner := bufio.NewScanner(selfMap)
for scanner.Scan() {
// Each line in /proc/self/maps has the following format:
// address perms offset dev inode pathname
// 00400000-0291f000 r--p 00000000 00:53 5009645 /opt/datadog-agent/bin/agent/agent
// 0291f000-08038000 r-xp 0251f000 00:53 5009645 /opt/datadog-agent/bin/agent/agent
// 08038000-0eb30000 r--p 07c38000 00:53 5009645 /opt/datadog-agent/bin/agent/agent
// 0eb30000-0eb31000 r--p 0e730000 00:53 5009645 /opt/datadog-agent/bin/agent/agent
// 0eb31000-0efed000 rw-p 0e731000 00:53 5009645 /opt/datadog-agent/bin/agent/agent
fields := strings.Fields(scanner.Text())

// If the 6th column is missing, the line is about an anonymous mapping.
// We ignore it as we want to page out only file-backed memory.
if len(fields) != 6 {
continue
}

address, perms, _ /* offset */, _ /* device */, _ /* inode */, pathname := fields[0], fields[1], fields[2], fields[3], fields[4], fields[5]

// Ignore pseudo-paths about stack, heap, vdso, named anonymous mapping, etc.
if strings.HasPrefix(pathname, "[") {
continue
}

// We only want to page out read-only memory.
if len(perms) != 4 || perms[0] != 'r' || perms[1] != '-' {
continue
}

beginStr, endStr, found := strings.Cut(address, "-")
if !found {
continue
}

begin, err := strconv.ParseUint(beginStr, 16, 64)
if err != nil {
return fmt.Errorf("failed to parse begin address %q: %w", beginStr, err)
}

end, err := strconv.ParseUint(endStr, 16, 64)
if err != nil {
return fmt.Errorf("failed to parse end address %q: %w", endStr, err)
}

// nolint:govet
if err := syscall.Madvise(unsafe.Slice((*byte)(unsafe.Pointer(uintptr(begin))), end-begin), MADV_PAGEOUT); err != nil {
return fmt.Errorf("failed to madvise: %w", err)
}
}

return nil
}
12 changes: 12 additions & 0 deletions cmd/internal/rssshrinker/rssshrinker_stub.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// Unless explicitly stated otherwise all files in this repository are licensed
// under the Apache License Version 2.0.
// This product includes software developed at Datadog (https://www.datadoghq.com/).
// Copyright 2024-present Datadog, Inc.

//go:build !linux

// Package rssshrinker provides functions to reduce the process’ RSS
package rssshrinker

// Setup isn’t implemented on this platform
func Setup() {}
3 changes: 3 additions & 0 deletions cmd/otel-agent/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,16 @@ package main
import (
"os"

"github.com/DataDog/datadog-agent/cmd/internal/rssshrinker"
"github.com/DataDog/datadog-agent/cmd/internal/runcmd"
"github.com/DataDog/datadog-agent/cmd/otel-agent/command"
"github.com/DataDog/datadog-agent/pkg/util/flavor"
_ "github.com/DataDog/datadog-agent/pkg/version"
)

func main() {
rssshrinker.Setup()

flavor.SetFlavor(flavor.OTelAgent)
os.Exit(runcmd.Run(command.MakeRootCommand()))
}
3 changes: 3 additions & 0 deletions cmd/process-agent/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
_ "net/http/pprof"
"os"

"github.com/DataDog/datadog-agent/cmd/internal/rssshrinker"
"github.com/DataDog/datadog-agent/cmd/internal/runcmd"
"github.com/DataDog/datadog-agent/cmd/process-agent/command"
"github.com/DataDog/datadog-agent/cmd/process-agent/subcommands"
Expand All @@ -18,6 +19,8 @@ import (

// main is the main application entry point
func main() {
rssshrinker.Setup()

flavor.SetFlavor(flavor.ProcessAgent)

os.Args = command.FixDeprecatedFlags(os.Args, os.Stdout)
Expand Down
3 changes: 3 additions & 0 deletions cmd/security-agent/main_nix.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,16 @@ import (
_ "expvar" // Blank import used because this isn't directly used in this file
_ "net/http/pprof" // Blank import used because this isn't directly used in this file

"github.com/DataDog/datadog-agent/cmd/internal/rssshrinker"
"github.com/DataDog/datadog-agent/cmd/internal/runcmd"
"github.com/DataDog/datadog-agent/cmd/security-agent/command"
"github.com/DataDog/datadog-agent/cmd/security-agent/subcommands"
"github.com/DataDog/datadog-agent/pkg/util/flavor"
)

func main() {
rssshrinker.Setup()

// set the Agent flavor
flavor.SetFlavor(flavor.SecurityAgent)

Expand Down
3 changes: 3 additions & 0 deletions cmd/system-probe/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,15 @@ package main
import (
"os"

"github.com/DataDog/datadog-agent/cmd/internal/rssshrinker"
"github.com/DataDog/datadog-agent/cmd/internal/runcmd"
"github.com/DataDog/datadog-agent/cmd/system-probe/command"
"github.com/DataDog/datadog-agent/cmd/system-probe/subcommands"
)

func main() {
rssshrinker.Setup()

rootCmd := command.MakeCommand(subcommands.SysprobeSubcommands())
command.SetDefaultCommandIfNonePresent(rootCmd)
os.Exit(runcmd.Run(rootCmd))
Expand Down
3 changes: 3 additions & 0 deletions cmd/trace-agent/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,15 @@ package main
import (
"os"

"github.com/DataDog/datadog-agent/cmd/internal/rssshrinker"
"github.com/DataDog/datadog-agent/cmd/internal/runcmd"
"github.com/DataDog/datadog-agent/cmd/trace-agent/command"
"github.com/DataDog/datadog-agent/pkg/util/flavor"
)

func main() {
rssshrinker.Setup()

flavor.SetFlavor(flavor.TraceAgent)

os.Args = command.FixDeprecatedFlags(os.Args, os.Stdout)
Expand Down

0 comments on commit 599de27

Please sign in to comment.