summaryrefslogtreecommitdiff
path: root/vendor/github.com/KimMachineGun/automemlimit
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/KimMachineGun/automemlimit')
-rw-r--r--vendor/github.com/KimMachineGun/automemlimit/.gitignore15
-rw-r--r--vendor/github.com/KimMachineGun/automemlimit/LICENSE21
-rw-r--r--vendor/github.com/KimMachineGun/automemlimit/README.md42
-rw-r--r--vendor/github.com/KimMachineGun/automemlimit/automemlimit.go9
-rw-r--r--vendor/github.com/KimMachineGun/automemlimit/memlimit/cgroups.go63
-rw-r--r--vendor/github.com/KimMachineGun/automemlimit/memlimit/cgroups_unsupported.go16
-rw-r--r--vendor/github.com/KimMachineGun/automemlimit/memlimit/memlimit.go105
7 files changed, 271 insertions, 0 deletions
diff --git a/vendor/github.com/KimMachineGun/automemlimit/.gitignore b/vendor/github.com/KimMachineGun/automemlimit/.gitignore
new file mode 100644
index 000000000..66fd13c90
--- /dev/null
+++ b/vendor/github.com/KimMachineGun/automemlimit/.gitignore
@@ -0,0 +1,15 @@
+# Binaries for programs and plugins
+*.exe
+*.exe~
+*.dll
+*.so
+*.dylib
+
+# Test binary, built with `go test -c`
+*.test
+
+# Output of the go coverage tool, specifically when used with LiteIDE
+*.out
+
+# Dependency directories (remove the comment below to include it)
+# vendor/
diff --git a/vendor/github.com/KimMachineGun/automemlimit/LICENSE b/vendor/github.com/KimMachineGun/automemlimit/LICENSE
new file mode 100644
index 000000000..1f5b8f6b3
--- /dev/null
+++ b/vendor/github.com/KimMachineGun/automemlimit/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2022 Geon Kim
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/vendor/github.com/KimMachineGun/automemlimit/README.md b/vendor/github.com/KimMachineGun/automemlimit/README.md
new file mode 100644
index 000000000..804ee7b08
--- /dev/null
+++ b/vendor/github.com/KimMachineGun/automemlimit/README.md
@@ -0,0 +1,42 @@
+# automemlimit
+
+[![Go Reference](https://pkg.go.dev/badge/github.com/KimMachineGun/automemlimit.svg)](https://pkg.go.dev/github.com/KimMachineGun/automemlimit)
+[![Go Report Card](https://goreportcard.com/badge/github.com/KimMachineGun/automemlimit)](https://goreportcard.com/report/github.com/KimMachineGun/automemlimit)
+[![Test](https://github.com/KimMachineGun/automemlimit/actions/workflows/test.yml/badge.svg?branch=main)](https://github.com/KimMachineGun/automemlimit/actions/workflows/test.yml)
+
+Automatically set `GOMEMLIMIT` to match Linux [cgroups(7)](https://man7.org/linux/man-pages/man7/cgroups.7.html) memory limit.
+
+See more details about `GOMEMLIMIT` [here](https://tip.golang.org/doc/gc-guide#Memory_limit).
+
+## Installation
+
+```shell
+go get github.com/KimMachineGun/automemlimit@latest
+```
+
+## Usage
+
+```go
+package main
+
+// By default, it sets `GOMEMLIMIT` to 90% of cgroup's memory limit.
+// You can find more details of its behavior from the doc comment of memlimit.SetGoMemLimitWithEnv.
+import _ "github.com/KimMachineGun/automemlimit"
+```
+
+or
+
+```go
+package main
+
+import "github.com/KimMachineGun/automemlimit/memlimit"
+
+func init() {
+ memlimit.SetGoMemLimitWithEnv()
+ memlimit.SetGoMemLimit(0.9)
+ memlimit.SetGoMemLimitWithProvider(memlimit.Limit(1024*1024), 0.9)
+ memlimit.SetGoMemLimitWithProvider(memlimit.FromCgroup, 0.9)
+ memlimit.SetGoMemLimitWithProvider(memlimit.FromCgroupV1, 0.9)
+ memlimit.SetGoMemLimitWithProvider(memlimit.FromCgroupV2, 0.9)
+}
+```
diff --git a/vendor/github.com/KimMachineGun/automemlimit/automemlimit.go b/vendor/github.com/KimMachineGun/automemlimit/automemlimit.go
new file mode 100644
index 000000000..0480208ff
--- /dev/null
+++ b/vendor/github.com/KimMachineGun/automemlimit/automemlimit.go
@@ -0,0 +1,9 @@
+package automemlimit
+
+import (
+ "github.com/KimMachineGun/automemlimit/memlimit"
+)
+
+func init() {
+ memlimit.SetGoMemLimitWithEnv()
+}
diff --git a/vendor/github.com/KimMachineGun/automemlimit/memlimit/cgroups.go b/vendor/github.com/KimMachineGun/automemlimit/memlimit/cgroups.go
new file mode 100644
index 000000000..9e3f4cc07
--- /dev/null
+++ b/vendor/github.com/KimMachineGun/automemlimit/memlimit/cgroups.go
@@ -0,0 +1,63 @@
+//go:build linux
+// +build linux
+
+package memlimit
+
+import (
+ "github.com/containerd/cgroups"
+ v2 "github.com/containerd/cgroups/v2"
+)
+
+const (
+ cgroupMountPoint = "/sys/fs/cgroup"
+)
+
+// FromCgroup returns the memory limit based on the cgroups version on this system.
+func FromCgroup() (uint64, error) {
+ switch cgroups.Mode() {
+ case cgroups.Legacy:
+ return FromCgroupV1()
+ case cgroups.Hybrid, cgroups.Unified:
+ return FromCgroupV2()
+ }
+ return 0, ErrNoCgroup
+}
+
+// FromCgroupV1 returns the memory limit from the cgroup v1.
+func FromCgroupV1() (uint64, error) {
+ cg, err := cgroups.Load(cgroups.SingleSubsystem(cgroups.V1, cgroups.Memory), cgroups.RootPath)
+ if err != nil {
+ return 0, err
+ }
+
+ metrics, err := cg.Stat(cgroups.IgnoreNotExist)
+ if err != nil {
+ return 0, err
+ } else if metrics.Memory == nil {
+ return 0, ErrNoLimit
+ }
+
+ return metrics.Memory.HierarchicalMemoryLimit, nil
+}
+
+// FromCgroupV2 returns the memory limit from the cgroup v2.
+func FromCgroupV2() (uint64, error) {
+ path, err := v2.NestedGroupPath("")
+ if err != nil {
+ return 0, err
+ }
+
+ m, err := v2.LoadManager(cgroupMountPoint, path)
+ if err != nil {
+ return 0, err
+ }
+
+ stats, err := m.Stat()
+ if err != nil {
+ return 0, err
+ } else if stats.Memory == nil {
+ return 0, ErrNoLimit
+ }
+
+ return stats.Memory.UsageLimit, nil
+}
diff --git a/vendor/github.com/KimMachineGun/automemlimit/memlimit/cgroups_unsupported.go b/vendor/github.com/KimMachineGun/automemlimit/memlimit/cgroups_unsupported.go
new file mode 100644
index 000000000..3ccf77992
--- /dev/null
+++ b/vendor/github.com/KimMachineGun/automemlimit/memlimit/cgroups_unsupported.go
@@ -0,0 +1,16 @@
+//go:build !linux
+// +build !linux
+
+package memlimit
+
+func FromCgroup() (uint64, error) {
+ return 0, ErrCgroupsNotSupported
+}
+
+func FromCgroupV1() (uint64, error) {
+ return 0, ErrCgroupsNotSupported
+}
+
+func FromCgroupV2() (uint64, error) {
+ return 0, ErrCgroupsNotSupported
+}
diff --git a/vendor/github.com/KimMachineGun/automemlimit/memlimit/memlimit.go b/vendor/github.com/KimMachineGun/automemlimit/memlimit/memlimit.go
new file mode 100644
index 000000000..7b49bb33b
--- /dev/null
+++ b/vendor/github.com/KimMachineGun/automemlimit/memlimit/memlimit.go
@@ -0,0 +1,105 @@
+package memlimit
+
+import (
+ "errors"
+ "io"
+ "log"
+ "math"
+ "os"
+ "runtime/debug"
+ "strconv"
+)
+
+const (
+ envGOMEMLIMIT = "GOMEMLIMIT"
+ envAUTOMEMLIMIT = "AUTOMEMLIMIT"
+ envAUTOMEMLIMIT_DEBUG = "AUTOMEMLIMIT_DEBUG"
+
+ defaultAUTOMEMLIMIT = 0.9
+)
+
+var (
+ // ErrNoLimit is returned when the memory limit is not set.
+ ErrNoLimit = errors.New("memory is not limited")
+ // ErrNoCgroup is returned when the process is not in cgroup.
+ ErrNoCgroup = errors.New("process is not in cgroup")
+ // ErrCgroupsNotSupported is returned when the system does not support cgroups.
+ ErrCgroupsNotSupported = errors.New("cgroups is not supported on this system")
+
+ logger = log.New(io.Discard, "", log.LstdFlags)
+)
+
+// SetGoMemLimitWithEnv sets GOMEMLIMIT with the value from the environment variable.
+// You can configure how much memory of the cgroup's memory limit to set as GOMEMLIMIT
+// through AUTOMEMLIMIT in the half-open range (0.0,1.0].
+//
+// If AUTOMEMLIMIT is not set, it defaults to 0.9. (10% is the headroom for memory sources the Go runtime is unaware of.)
+// If GOMEMLIMIT is already set or AUTOMEMLIMIT=off, this function does nothing.
+func SetGoMemLimitWithEnv() {
+ if os.Getenv(envAUTOMEMLIMIT_DEBUG) == "true" {
+ logger = log.Default()
+ }
+
+ if val, ok := os.LookupEnv(envGOMEMLIMIT); ok {
+ logger.Printf("GOMEMLIMIT is set already, skipping: %s\n", val)
+ return
+ }
+
+ ratio := defaultAUTOMEMLIMIT
+ if val, ok := os.LookupEnv(envAUTOMEMLIMIT); ok {
+ if val == "off" {
+ logger.Printf("AUTOMEMLIMIT is set to off, skipping\n")
+ return
+ }
+ _ratio, err := strconv.ParseFloat(val, 64)
+ if err != nil {
+ logger.Printf("cannot parse AUTOMEMLIMIT: %s\n", val)
+ return
+ }
+ ratio = _ratio
+ }
+ if ratio <= 0 || ratio > 1 {
+ logger.Printf("invalid AUTOMEMLIMIT: %f\n", ratio)
+ return
+ }
+
+ limit, err := SetGoMemLimit(ratio)
+ if err != nil {
+ logger.Printf("failed to set GOMEMLIMIT: %v\n", err)
+ return
+ }
+
+ logger.Printf("GOMEMLIMIT=%d\n", limit)
+}
+
+// SetGoMemLimit sets GOMEMLIMIT with the value from the cgroup's memory limit and given ratio.
+func SetGoMemLimit(ratio float64) (int64, error) {
+ return SetGoMemLimitWithProvider(FromCgroup, ratio)
+}
+
+// Provider is a function that returns the memory limit.
+type Provider func() (uint64, error)
+
+// SetGoMemLimitWithProvider sets GOMEMLIMIT with the value from the given provider and ratio.
+func SetGoMemLimitWithProvider(provider Provider, ratio float64) (int64, error) {
+ limit, err := provider()
+ if err != nil {
+ return 0, err
+ }
+ goMemLimit := cappedFloat2Int(float64(limit) * ratio)
+ debug.SetMemoryLimit(goMemLimit)
+ return goMemLimit, nil
+}
+
+func cappedFloat2Int(f float64) int64 {
+ if f > math.MaxInt64 {
+ return math.MaxInt64
+ }
+ return int64(f)
+}
+// Limit is a helper Provider function that returns the given limit.
+func Limit(limit uint64) func() (uint64, error) {
+ return func() (uint64, error) {
+ return limit, nil
+ }
+}