diff options
| author | 2024-01-22 09:35:23 +0000 | |
|---|---|---|
| committer | 2024-01-22 09:35:23 +0000 | |
| commit | a858831387f5e423c855ff3c5611fc80209f44b0 (patch) | |
| tree | 059dcfc37228670e1e2aa20db4a36bb3cef40ef6 /vendor/github.com/KimMachineGun/automemlimit | |
| parent | [bugfix] fix array type for also_known_as_uris (#2553) (diff) | |
| download | gotosocial-a858831387f5e423c855ff3c5611fc80209f44b0.tar.xz | |
[chore]: Bump github.com/KimMachineGun/automemlimit from 0.4.0 to 0.5.0 (#2560)
Diffstat (limited to 'vendor/github.com/KimMachineGun/automemlimit')
6 files changed, 221 insertions, 104 deletions
diff --git a/vendor/github.com/KimMachineGun/automemlimit/README.md b/vendor/github.com/KimMachineGun/automemlimit/README.md index 192bc0b6f..c0e66d2a7 100644 --- a/vendor/github.com/KimMachineGun/automemlimit/README.md +++ b/vendor/github.com/KimMachineGun/automemlimit/README.md @@ -8,6 +8,14 @@ Automatically set `GOMEMLIMIT` to match Linux [cgroups(7)](https://man7.org/linu  See more details about `GOMEMLIMIT` [here](https://tip.golang.org/doc/gc-guide#Memory_limit). +## Notice + +Version `v0.5.0` introduces a fallback to system memory limits as an experimental feature when cgroup limits are unavailable. Activate this by setting `AUTOMEMLIMIT_EXPERIMENT=system`. +You can also use system memory limits via `memlimit.FromSystem` provider directly. + +This feature is under evaluation and might become a default or be removed based on user feedback. +If you have any feedback about this feature, please open an issue. +  ## Installation  ```shell @@ -34,9 +42,17 @@ import "github.com/KimMachineGun/automemlimit/memlimit"  func init() {  	memlimit.SetGoMemLimitWithOpts(  		memlimit.WithRatio(0.9), -		memlimit.WithEnv(),  		memlimit.WithProvider(memlimit.FromCgroup),  	) +	memlimit.SetGoMemLimitWithOpts( +		memlimit.WithRatio(0.9), +		memlimit.WithProvider( +			memlimit.ApplyFallback( +				memlimit.FromCgroup, +				memlimit.FromSystem, +			), +		), +	)  	memlimit.SetGoMemLimitWithEnv()  	memlimit.SetGoMemLimit(0.9)  	memlimit.SetGoMemLimitWithProvider(memlimit.Limit(1024*1024), 0.9) diff --git a/vendor/github.com/KimMachineGun/automemlimit/memlimit/cgroups.go b/vendor/github.com/KimMachineGun/automemlimit/memlimit/cgroups.go index cfe6d0f60..979bd3937 100644 --- a/vendor/github.com/KimMachineGun/automemlimit/memlimit/cgroups.go +++ b/vendor/github.com/KimMachineGun/automemlimit/memlimit/cgroups.go @@ -1,91 +1,12 @@ -//go:build linux -// +build linux -  package memlimit  import ( -	"path/filepath" - -	"github.com/containerd/cgroups/v3" -	"github.com/containerd/cgroups/v3/cgroup1" -	"github.com/containerd/cgroups/v3/cgroup2" +	"errors"  ) -const ( -	cgroupMountPoint = "/sys/fs/cgroup" +var ( +	// 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")  ) - -// 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: -		return FromCgroupHybrid() -	case cgroups.Unified: -		return FromCgroupV2() -	} -	return 0, ErrNoCgroup -} - -// FromCgroupV1 returns the memory limit from the cgroup v1. -func FromCgroupV1() (uint64, error) { -	cg, err := cgroup1.Load(cgroup1.RootPath, cgroup1.WithHiearchy( -		cgroup1.SingleSubsystem(cgroup1.Default, cgroup1.Memory), -	)) -	if err != nil { -		return 0, err -	} - -	metrics, err := cg.Stat(cgroup1.IgnoreNotExist) -	if err != nil { -		return 0, err -	} - -	if limit := metrics.GetMemory().GetHierarchicalMemoryLimit(); limit != 0 { -		return limit, nil -	} - -	return 0, ErrNoLimit -} - -// FromCgroupHybrid returns the memory limit from the cgroup v1 or v2. -// It checks the cgroup v2 first, and if it fails, it falls back to cgroup v1. -func FromCgroupHybrid() (uint64, error) { -	limit, err := fromCgroupV2(filepath.Join(cgroupMountPoint, "unified")) -	if err == nil { -		return limit, nil -	} else if err != ErrNoLimit { -		return 0, err -	} - -	return FromCgroupV1() -} - -// FromCgroupV2 returns the memory limit from the cgroup v2. -func FromCgroupV2() (uint64, error) { -	return fromCgroupV2(cgroupMountPoint) -} - -func fromCgroupV2(mountPoint string) (uint64, error) { -	path, err := cgroup2.NestedGroupPath("") -	if err != nil { -		return 0, err -	} - -	m, err := cgroup2.Load(path, cgroup2.WithMountpoint(mountPoint)) -	if err != nil { -		return 0, err -	} - -	stats, err := m.Stat() -	if err != nil { -		return 0, err -	} - -	if limit := stats.GetMemory().GetUsageLimit(); limit != 0 { -		return limit, nil -	} - -	return 0, ErrNoLimit -} diff --git a/vendor/github.com/KimMachineGun/automemlimit/memlimit/cgroups_linux.go b/vendor/github.com/KimMachineGun/automemlimit/memlimit/cgroups_linux.go new file mode 100644 index 000000000..98a954873 --- /dev/null +++ b/vendor/github.com/KimMachineGun/automemlimit/memlimit/cgroups_linux.go @@ -0,0 +1,98 @@ +//go:build linux +// +build linux + +package memlimit + +import ( +	"math" +	"os" +	"path/filepath" + +	"github.com/containerd/cgroups/v3" +	"github.com/containerd/cgroups/v3/cgroup1" +	"github.com/containerd/cgroups/v3/cgroup2" +) + +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: +		return FromCgroupHybrid() +	case cgroups.Unified: +		return FromCgroupV2() +	} +	return 0, ErrNoCgroup +} + +// FromCgroupV1 returns the memory limit from the cgroup v1. +func FromCgroupV1() (uint64, error) { +	cg, err := cgroup1.Load(cgroup1.RootPath, cgroup1.WithHiearchy( +		cgroup1.SingleSubsystem(cgroup1.Default, cgroup1.Memory), +	)) +	if err != nil { +		return 0, err +	} + +	metrics, err := cg.Stat(cgroup1.IgnoreNotExist) +	if err != nil { +		return 0, err +	} + +	if limit := metrics.GetMemory().GetHierarchicalMemoryLimit(); limit != 0 && limit != getCgroupV1NoLimit() { +		return limit, nil +	} + +	return 0, ErrNoLimit +} + +func getCgroupV1NoLimit() uint64 { +	ps := uint64(os.Getpagesize()) +	return math.MaxInt64 / ps * ps +} + +// FromCgroupHybrid returns the memory limit from the cgroup v1 or v2. +// It checks the cgroup v2 first, and if it fails, it falls back to cgroup v1. +func FromCgroupHybrid() (uint64, error) { +	limit, err := fromCgroupV2(filepath.Join(cgroupMountPoint, "unified")) +	if err == nil { +		return limit, nil +	} else if err != ErrNoLimit { +		return 0, err +	} + +	return FromCgroupV1() +} + +// FromCgroupV2 returns the memory limit from the cgroup v2. +func FromCgroupV2() (uint64, error) { +	return fromCgroupV2(cgroupMountPoint) +} + +func fromCgroupV2(mountPoint string) (uint64, error) { +	path, err := cgroup2.NestedGroupPath("") +	if err != nil { +		return 0, err +	} + +	m, err := cgroup2.Load(path, cgroup2.WithMountpoint(mountPoint)) +	if err != nil { +		return 0, err +	} + +	stats, err := m.Stat() +	if err != nil { +		return 0, err +	} + +	if limit := stats.GetMemory().GetUsageLimit(); limit != 0 && limit != math.MaxUint64 { +		return limit, nil +	} + +	return 0, ErrNoLimit +} diff --git a/vendor/github.com/KimMachineGun/automemlimit/memlimit/exp_system.go b/vendor/github.com/KimMachineGun/automemlimit/memlimit/exp_system.go new file mode 100644 index 000000000..dee95f520 --- /dev/null +++ b/vendor/github.com/KimMachineGun/automemlimit/memlimit/exp_system.go @@ -0,0 +1,14 @@ +package memlimit + +import ( +	"github.com/pbnjay/memory" +) + +// FromSystem returns the total memory of the system. +func FromSystem() (uint64, error) { +	limit := memory.TotalMemory() +	if limit == 0 { +		return 0, ErrNoLimit +	} +	return limit, nil +} diff --git a/vendor/github.com/KimMachineGun/automemlimit/memlimit/experiment.go b/vendor/github.com/KimMachineGun/automemlimit/memlimit/experiment.go new file mode 100644 index 000000000..2a7c320ed --- /dev/null +++ b/vendor/github.com/KimMachineGun/automemlimit/memlimit/experiment.go @@ -0,0 +1,59 @@ +package memlimit + +import ( +	"fmt" +	"os" +	"reflect" +	"strings" +) + +const ( +	envAUTOMEMLIMIT_EXPERIMENT = "AUTOMEMLIMIT_EXPERIMENT" +) + +// Experiments is a set of experiment flags. +// It is used to enable experimental features. +// +// You can set the flags by setting the environment variable AUTOMEMLIMIT_EXPERIMENT. +// The value of the environment variable is a comma-separated list of experiment names. +// +// The following experiment names are known: +// +//   - none: disable all experiments +//   - system: enable fallback to system memory limit +type Experiments struct { +	// System enables fallback to system memory limit. +	System bool +} + +func parseExperiments() (Experiments, error) { +	var exp Experiments + +	// Create a map of known experiment names. +	names := make(map[string]func(bool)) +	rv := reflect.ValueOf(&exp).Elem() +	rt := rv.Type() +	for i := 0; i < rt.NumField(); i++ { +		field := rv.Field(i) +		names[strings.ToLower(rt.Field(i).Name)] = field.SetBool +	} + +	// Parse names. +	for _, f := range strings.Split(os.Getenv(envAUTOMEMLIMIT_EXPERIMENT), ",") { +		if f == "" { +			continue +		} +		if f == "none" { +			exp = Experiments{} +			continue +		} +		val := true +		set, ok := names[f] +		if !ok { +			return Experiments{}, fmt.Errorf("unknown AUTOMEMLIMIT_EXPERIMENT %s", f) +		} +		set(val) +	} + +	return exp, nil +} diff --git a/vendor/github.com/KimMachineGun/automemlimit/memlimit/memlimit.go b/vendor/github.com/KimMachineGun/automemlimit/memlimit/memlimit.go index dbb4d1c72..0d7a9853c 100644 --- a/vendor/github.com/KimMachineGun/automemlimit/memlimit/memlimit.go +++ b/vendor/github.com/KimMachineGun/automemlimit/memlimit/memlimit.go @@ -22,16 +22,11 @@ const (  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")  )  type config struct {  	logger   *log.Logger  	ratio    float64 -	env      bool  	provider Provider  } @@ -50,10 +45,10 @@ func WithRatio(ratio float64) Option {  // WithEnv configures whether to use environment variables.  //  // Default: false +// +// Deprecated: currently this does nothing.  func WithEnv() Option { -	return func(cfg *config) { -		cfg.env = true -	} +	return func(cfg *config) {}  }  // WithProvider configures the provider. @@ -65,17 +60,24 @@ func WithProvider(provider Provider) Option {  	}  } -// SetGoMemLimitWithOpts sets GOMEMLIMIT with options. +// SetGoMemLimitWithOpts sets GOMEMLIMIT with options and environment variables. +// +// You can configure how much memory of the cgroup's memory limit to set as GOMEMLIMIT +// through AUTOMEMLIMIT envrironment variable 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. +// +// If AUTOMEMLIMIT_EXPERIMENT is set, it enables experimental features. +// Please see the documentation of Experiments for more details.  //  // Options:  //   - WithRatio -//   - WithEnv (see more SetGoMemLimitWithEnv)  //   - WithProvider  func SetGoMemLimitWithOpts(opts ...Option) (_ int64, _err error) {  	cfg := &config{  		logger:   log.New(io.Discard, "", log.LstdFlags),  		ratio:    defaultAUTOMEMLIMIT, -		env:      false,  		provider: FromCgroup,  	}  	if os.Getenv(envAUTOMEMLIMIT_DEBUG) == "true" { @@ -90,6 +92,15 @@ func SetGoMemLimitWithOpts(opts ...Option) (_ int64, _err error) {  		}  	}() +	exps, err := parseExperiments() +	if err != nil { +		return 0, fmt.Errorf("failed to parse experiments: %w", err) +	} +	if exps.System { +		cfg.logger.Println("system experiment is enabled: using system memory limit as a fallback") +		cfg.provider = ApplyFallback(cfg.provider, FromSystem) +	} +  	snapshot := debug.SetMemoryLimit(-1)  	defer func() {  		err := recover() @@ -122,6 +133,10 @@ func SetGoMemLimitWithOpts(opts ...Option) (_ int64, _err error) {  	limit, err := setGoMemLimit(ApplyRatio(cfg.provider, ratio))  	if err != nil { +		if errors.Is(err, ErrNoLimit) { +			cfg.logger.Printf("memory is not limited, skipping: %v\n", err) +			return 0, nil +		}  		return 0, fmt.Errorf("failed to set GOMEMLIMIT: %w", err)  	} @@ -130,14 +145,8 @@ func SetGoMemLimitWithOpts(opts ...Option) (_ int64, _err error) {  	return limit, nil  } -// 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() { -	_, _ = SetGoMemLimitWithOpts(WithEnv()) +	_, _ = SetGoMemLimitWithOpts()  }  // SetGoMemLimit sets GOMEMLIMIT with the value from the cgroup's memory limit and given ratio.  | 
