diff --git a/config/config.go b/config/config.go index 1a820c422..659fb5933 100644 --- a/config/config.go +++ b/config/config.go @@ -65,6 +65,7 @@ type Config struct { TLS TLSConfig Middleware []middleware.Middleware Startup []func() error + MaxCPU int } // Address returns the host:port of c as a string. diff --git a/config/directives.go b/config/directives.go index 85a677f4a..c7347aa12 100644 --- a/config/directives.go +++ b/config/directives.go @@ -1,6 +1,11 @@ package config -import "os" +import ( + "os" + "runtime" + "strconv" + "strings" +) // dirFunc is a type of parsing function which processes // a particular directive and populates the config. @@ -64,5 +69,45 @@ func init() { p.cfg.TLS = tls return nil }, + "cpu": func(p *parser) error { + sysCores := runtime.NumCPU() + + if !p.nextArg() { + return p.argErr() + } + strNum := p.tkn() + + setCPU := func(val int) { + if val < 1 { + val = 1 + } + if val > sysCores { + val = sysCores + } + if val > p.cfg.MaxCPU { + p.cfg.MaxCPU = val + } + } + + if strings.HasSuffix(strNum, "%") { + // Percent + var percent float32 + pctStr := strNum[:len(strNum)-1] + pctInt, err := strconv.Atoi(pctStr) + if err != nil || pctInt < 1 || pctInt > 100 { + return p.err("Parse", "Invalid number '"+strNum+"' (must be a positive percentage between 1 and 100)") + } + percent = float32(pctInt) / 100 + setCPU(int(float32(sysCores) * percent)) + } else { + // Number + num, err := strconv.Atoi(strNum) + if err != nil || num < 0 { + return p.err("Parse", "Invalid number '"+strNum+"' (requires positive integer or percent)") + } + setCPU(num) + } + return nil + }, } } diff --git a/server/server.go b/server/server.go index 0776b521d..a12d91eb6 100644 --- a/server/server.go +++ b/server/server.go @@ -4,6 +4,7 @@ import ( "errors" "log" "net/http" + "runtime" "github.com/mholt/caddy/config" "github.com/mholt/caddy/middleware" @@ -36,6 +37,11 @@ func New(conf config.Config) (*Server, error) { return nil, errors.New("Address " + addr + " is already in use") } + // Use all CPUs (if needed) by default + if conf.MaxCPU == 0 { + conf.MaxCPU = runtime.NumCPU() + } + // Initialize s := new(Server) s.config = conf @@ -53,6 +59,10 @@ func (s *Server) Serve() error { return err } + if s.config.MaxCPU > 0 { + runtime.GOMAXPROCS(s.config.MaxCPU) + } + if s.config.TLS.Enabled { return http.ListenAndServeTLS(s.config.Address(), s.config.TLS.Certificate, s.config.TLS.Key, s) } else {