internal/beatcmd/maxprocs.go (37 lines of code) (raw):

// Licensed to Elasticsearch B.V. under one or more contributor // license agreements. See the NOTICE file distributed with // this work for additional information regarding copyright // ownership. Elasticsearch B.V. licenses this file to you under // the Apache License, Version 2.0 (the "License"); you may // not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, // software distributed under the License is distributed on an // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. package beatcmd import ( "context" "fmt" "time" "go.uber.org/automaxprocs/maxprocs" "github.com/elastic/elastic-agent-libs/logp" ) // adjustMaxProcs uses `maxprocs` to change the GOMAXPROCS respecting any // CFS quotas, if set. // // This is necessary since the Go runtime will default to the number of CPUs // available in the machine it's running in, however, when running in a // container or in a cgroup with resource limits, the disparity can be extreme. // // Having a significantly greater GOMAXPROCS set than the granted CFS quota // results in a significant amount of time spent "throttling", essentially // pausing the the running OS threads for the throttled period. // Since the quotas may be updated without restarting the process, the // GOMAXPROCS are adjusted every 30s. func adjustMaxProcs(ctx context.Context, d time.Duration, logger *logp.Logger) error { infof := diffInfof(logger) setMaxProcs := func() { if _, err := maxprocs.Set(maxprocs.Logger(infof)); err != nil { logger.Errorf("failed to set GOMAXPROCS: %v", err) } } // set the gomaxprocs immediately. setMaxProcs() ticker := time.NewTicker(d) defer ticker.Stop() for { select { case <-ctx.Done(): return ctx.Err() case <-ticker.C: setMaxProcs() } } } func diffInfof(logger *logp.Logger) func(string, ...interface{}) { var last string return func(format string, args ...interface{}) { msg := fmt.Sprintf(format, args...) if msg != last { logger.Info(msg) last = msg } } }