summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHenning Baldersheim <balder@yahoo-inc.com>2022-09-29 16:24:26 +0200
committerGitHub <noreply@github.com>2022-09-29 16:24:26 +0200
commit32ae3685347015219dee34e6a2f5a3d3c14caab4 (patch)
tree3140c969c6ea8ee8bd4bb35510cc4fab4863d83a
parenta4141f8564378037f2c1261a39ef6734e41eed79 (diff)
parent81a431c874b780fd7cfb38062e03c036c0895220 (diff)
Merge pull request #24263 from vespa-engine/arnej/start-c-binary-5
Arnej/start c binary 5
-rw-r--r--client/go/script-utils/main.go7
-rw-r--r--client/go/script-utils/startcbinary/cmd.go28
-rw-r--r--client/go/script-utils/startcbinary/common_env.go67
-rw-r--r--client/go/script-utils/startcbinary/execvp.go38
-rw-r--r--client/go/script-utils/startcbinary/execvp_windows.go14
-rw-r--r--client/go/script-utils/startcbinary/numactl.go8
-rw-r--r--client/go/script-utils/startcbinary/numactl_test.go6
-rw-r--r--client/go/script-utils/startcbinary/progspec.go56
-rw-r--r--client/go/script-utils/startcbinary/setrlimit.go58
-rw-r--r--client/go/script-utils/startcbinary/setrlimit_windows.go18
-rw-r--r--client/go/script-utils/startcbinary/startcbinary.go37
-rw-r--r--client/go/script-utils/startcbinary/tuning.go50
-rw-r--r--client/go/script-utils/startcbinary/valgrind.go9
-rw-r--r--client/go/script-utils/startcbinary/valgrind_test.go4
-rw-r--r--client/go/script-utils/startcbinary/vespamalloc.go10
-rw-r--r--client/go/util/io.go8
16 files changed, 362 insertions, 56 deletions
diff --git a/client/go/script-utils/main.go b/client/go/script-utils/main.go
index 66fee5fba28..189140158ae 100644
--- a/client/go/script-utils/main.go
+++ b/client/go/script-utils/main.go
@@ -30,9 +30,7 @@ func main() {
_ = vespa.FindHome()
switch action {
case "start-c-binary":
- if !startcbinary.Run(os.Args[1:]) {
- os.Exit(1)
- }
+ os.Exit(startcbinary.Run(os.Args[1:]))
case "export-env":
vespa.ExportDefaultEnvToSh()
case "security-env":
@@ -59,6 +57,9 @@ func main() {
cobra := clusterstate.NewSetNodeStateCmd()
cobra.Execute()
default:
+ if startcbinary.IsCandidate(os.Args[0]) {
+ os.Exit(startcbinary.Run(os.Args))
+ }
fmt.Fprintf(os.Stderr, "unknown action '%s'\n", action)
fmt.Fprintln(os.Stderr, "actions: export-env, ipv6-only, security-env")
fmt.Fprintln(os.Stderr, "(also: vespa-deploy, vespa-logfmt)")
diff --git a/client/go/script-utils/startcbinary/cmd.go b/client/go/script-utils/startcbinary/cmd.go
index 49bc2c8aedc..faa9a3fa595 100644
--- a/client/go/script-utils/startcbinary/cmd.go
+++ b/client/go/script-utils/startcbinary/cmd.go
@@ -4,21 +4,41 @@
package startcbinary
import (
+ "os"
+ "strings"
+
"github.com/vespa-engine/vespa/client/go/trace"
+ "github.com/vespa-engine/vespa/client/go/util"
"github.com/vespa-engine/vespa/client/go/vespa"
)
-func Run(args []string) bool {
- trace.AdjustVerbosity(1)
+func Run(args []string) int {
+ trace.AdjustVerbosity(0)
if len(args) < 1 {
trace.Warning("missing program argument")
- return false
+ return 1
}
spec := ProgSpec{
Program: args[0],
- Args: args[1:],
+ Args: args,
}
spec.setup()
vespa.LoadDefaultEnv()
return startCbinary(spec)
}
+
+func IsCandidate(program string) bool {
+ binary := program + "-bin"
+ if strings.Contains(binary, "/") {
+ return util.IsRegularFile(binary)
+ } else {
+ path := strings.Split(os.Getenv(ENV_PATH), ":")
+ for _, dir := range path {
+ fn := dir + "/" + binary
+ if util.IsRegularFile(fn) {
+ return true
+ }
+ }
+ }
+ return false
+}
diff --git a/client/go/script-utils/startcbinary/common_env.go b/client/go/script-utils/startcbinary/common_env.go
index 908c61bb468..144a30b2ecb 100644
--- a/client/go/script-utils/startcbinary/common_env.go
+++ b/client/go/script-utils/startcbinary/common_env.go
@@ -5,34 +5,87 @@ package startcbinary
import (
"os"
+ "strings"
"github.com/vespa-engine/vespa/client/go/trace"
+ "github.com/vespa-engine/vespa/client/go/vespa"
)
const (
ENV_LD_PRELOAD = "LD_PRELOAD"
ENV_STD_THREAD_PREVENT_TRY_CATCH = "STD_THREAD_PREVENT_TRY_CATCH"
ENV_GLIBCXX_FORCE_NEW = "GLIBCXX_FORCE_NEW"
+ ENV_JAVA_HOME = "JAVA_HOME"
+ ENV_LD_LIBRARY_PATH = "LD_LIBRARY_PATH"
+ ENV_MALLOC_ARENA_MAX = "MALLOC_ARENA_MAX"
ENV_VESPA_AFFINITY_CPU_SOCKET = "VESPA_AFFINITY_CPU_SOCKET"
ENV_VESPA_LOAD_CODE_AS_HUGEPAGES = "VESPA_LOAD_CODE_AS_HUGEPAGES"
ENV_VESPA_MALLOC_HUGEPAGES = "VESPA_MALLOC_HUGEPAGES"
ENV_VESPA_MALLOC_MADVISE_LIMIT = "VESPA_MALLOC_MADVISE_LIMIT"
ENV_VESPA_NO_NUMACTL = "VESPA_NO_NUMACTL"
+ ENV_VESPA_TIMER_HZ = "VESPA_TIMER_HZ"
+ ENV_VESPA_USER = "VESPA_USER"
ENV_VESPA_USE_HUGEPAGES = "VESPA_USE_HUGEPAGES"
ENV_VESPA_USE_HUGEPAGES_LIST = "VESPA_USE_HUGEPAGES_LIST"
ENV_VESPA_USE_MADVISE_LIST = "VESPA_USE_MADVISE_LIST"
ENV_VESPA_USE_NO_VESPAMALLOC = "VESPA_USE_NO_VESPAMALLOC"
ENV_VESPA_USE_VALGRIND = "VESPA_USE_VALGRIND"
+ ENV_VESPA_USE_VESPAMALLOC = "VESPA_USE_VESPAMALLOC"
ENV_VESPA_USE_VESPAMALLOC_D = "VESPA_USE_VESPAMALLOC_D"
ENV_VESPA_USE_VESPAMALLOC_DST = "VESPA_USE_VESPAMALLOC_DST"
ENV_VESPA_VALGRIND_OPT = "VESPA_VALGRIND_OPT"
+
+ // backwards compatibility variables:
+ ENV_HUGEPAGES_LIST = "HUGEPAGES_LIST"
+ ENV_MADVISE_LIST = "MADVISE_LIST"
+ ENV_NO_VESPAMALLOC_LIST = "NO_VESPAMALLOC_LIST"
+ ENV_PATH = "PATH"
+ ENV_ROOT = "ROOT"
+ ENV_VESPAMALLOCDST_LIST = "VESPAMALLOCDST_LIST"
+ ENV_VESPAMALLOCD_LIST = "VESPAMALLOCD_LIST"
+ ENV_VESPAMALLOC_LIST = "VESPAMALLOCD_LIST"
)
+func (spec *ProgSpec) considerFallback(varName, varValue string) {
+ if spec.getenv(varName) == "" && varValue != "" {
+ spec.setenv(varName, varValue)
+ }
+}
+
+func (spec *ProgSpec) considerEnvFallback(targetVar, fallbackVar string) {
+ spec.considerFallback(targetVar, spec.getenv(fallbackVar))
+}
+
func (spec *ProgSpec) configureCommonEnv() {
os.Unsetenv(ENV_LD_PRELOAD)
spec.setenv(ENV_STD_THREAD_PREVENT_TRY_CATCH, "true")
spec.setenv(ENV_GLIBCXX_FORCE_NEW, "1")
+ spec.setenv(ENV_LD_LIBRARY_PATH, vespa.FindHome()+"/lib64")
+ spec.setenv(ENV_MALLOC_ARENA_MAX, "1")
+
+ // fallback from old env.vars:
+ spec.considerEnvFallback(ENV_VESPA_USE_HUGEPAGES_LIST, ENV_HUGEPAGES_LIST)
+ spec.considerEnvFallback(ENV_VESPA_USE_MADVISE_LIST, ENV_MADVISE_LIST)
+ spec.considerEnvFallback(ENV_VESPA_USE_VESPAMALLOC, ENV_VESPAMALLOC_LIST)
+ spec.considerEnvFallback(ENV_VESPA_USE_VESPAMALLOC_D, ENV_VESPAMALLOCD_LIST)
+ spec.considerEnvFallback(ENV_VESPA_USE_VESPAMALLOC_DST, ENV_VESPAMALLOCDST_LIST)
+ spec.considerEnvFallback(ENV_VESPA_USE_NO_VESPAMALLOC, ENV_NO_VESPAMALLOC_LIST)
+ // other fallbacks:
+ spec.considerFallback(ENV_ROOT, vespa.FindHome())
+ spec.considerFallback(ENV_VESPA_USER, vespa.FindVespaUser())
+ spec.considerFallback(ENV_VESPA_USE_HUGEPAGES_LIST, "all")
+ spec.considerFallback(ENV_VESPA_USE_VESPAMALLOC, "all")
+ spec.considerFallback(ENV_VESPA_USE_NO_VESPAMALLOC, strings.Join([]string{
+ "vespa-rpc-invoke",
+ "vespa-get-config",
+ "vespa-sentinel-cmd",
+ "vespa-route",
+ "vespa-proton-cmd",
+ "vespa-configproxy-cmd",
+ "vespa-config-status",
+ }, " "))
+
}
func (spec *ProgSpec) configureHugePages() {
@@ -49,3 +102,17 @@ func (spec *ProgSpec) configureUseMadvise() {
return
}
}
+
+func (spec *ProgSpec) configurePath() {
+ // Prefer newer gdb and pstack:
+ spec.prependPath("/opt/rh/gcc-toolset-11/root/usr/bin")
+ // Maven is needed for tester applications:
+ spec.prependPath(vespa.FindHome() + "/local/maven/bin")
+ spec.prependPath(vespa.FindHome() + "/bin64")
+ spec.prependPath(vespa.FindHome() + "/bin")
+ // how to find the "java" program?
+ // should be available in $VESPA_HOME/bin or JAVA_HOME
+ if javaHome := spec.getenv(ENV_JAVA_HOME); javaHome != "" {
+ spec.prependPath(javaHome + "/bin")
+ }
+}
diff --git a/client/go/script-utils/startcbinary/execvp.go b/client/go/script-utils/startcbinary/execvp.go
new file mode 100644
index 00000000000..1ceaf88b47a
--- /dev/null
+++ b/client/go/script-utils/startcbinary/execvp.go
@@ -0,0 +1,38 @@
+// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+// Author: arnej
+
+//go:build !windows
+
+package startcbinary
+
+import (
+ "fmt"
+ "os"
+ "strings"
+
+ "github.com/vespa-engine/vespa/client/go/trace"
+ "github.com/vespa-engine/vespa/client/go/util"
+ "golang.org/x/sys/unix"
+)
+
+func findInPath(prog string) string {
+ if strings.Contains(prog, "/") {
+ return prog
+ }
+ path := strings.Split(os.Getenv(ENV_PATH), ":")
+ for _, dir := range path {
+ fn := dir + "/" + prog
+ if util.IsRegularFile(fn) {
+ return fn
+ }
+ }
+ return prog
+}
+
+func myexecvp(prog string, argv []string, envv []string) error {
+ trace.Trace("run cmd", strings.Join(argv, " "))
+ prog = findInPath(prog)
+ argv[0] = prog
+ err := unix.Exec(prog, argv, envv)
+ return fmt.Errorf("cannot execute '%s': %v", prog, err)
+}
diff --git a/client/go/script-utils/startcbinary/execvp_windows.go b/client/go/script-utils/startcbinary/execvp_windows.go
new file mode 100644
index 00000000000..f0642dcf9a0
--- /dev/null
+++ b/client/go/script-utils/startcbinary/execvp_windows.go
@@ -0,0 +1,14 @@
+// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+// Author: arnej
+
+//go:build windows
+
+package startcbinary
+
+import (
+ "fmt"
+)
+
+func myexecvp(prog string, args []string, envv []string) error {
+ return fmt.Errorf("cannot execvp: %s", prog)
+}
diff --git a/client/go/script-utils/startcbinary/numactl.go b/client/go/script-utils/startcbinary/numactl.go
index 6f49d8b8d9f..1456fe05a5f 100644
--- a/client/go/script-utils/startcbinary/numactl.go
+++ b/client/go/script-utils/startcbinary/numactl.go
@@ -5,7 +5,6 @@ package startcbinary
import (
"fmt"
- "os"
"strconv"
"strings"
@@ -16,7 +15,7 @@ import (
func (p *ProgSpec) configureNumaCtl() {
p.shouldUseNumaCtl = false
p.numaSocket = -1
- if os.Getenv(ENV_VESPA_NO_NUMACTL) != "" {
+ if p.getenv(ENV_VESPA_NO_NUMACTL) != "" {
return
}
backticks := util.BackTicksIgnoreStderr
@@ -36,7 +35,7 @@ func (p *ProgSpec) configureNumaCtl() {
return
}
p.shouldUseNumaCtl = true
- if affinity := os.Getenv(ENV_VESPA_AFFINITY_CPU_SOCKET); affinity != "" {
+ if affinity := p.getenv(ENV_VESPA_AFFINITY_CPU_SOCKET); affinity != "" {
wantSocket, _ := strconv.Atoi(affinity)
trace.Debug("want socket:", wantSocket)
parts := strings.Fields(out)
@@ -57,7 +56,7 @@ func (p *ProgSpec) numaCtlBinary() string {
return "numactl"
}
-func (p *ProgSpec) prependNumaCtl(program string, args []string) []string {
+func (p *ProgSpec) prependNumaCtl(args []string) []string {
result := make([]string, 0, 5+len(args))
result = append(result, "numactl")
if p.numaSocket >= 0 {
@@ -67,7 +66,6 @@ func (p *ProgSpec) prependNumaCtl(program string, args []string) []string {
result = append(result, "--interleave")
result = append(result, "all")
}
- result = append(result, program)
for _, arg := range args {
result = append(result, arg)
}
diff --git a/client/go/script-utils/startcbinary/numactl_test.go b/client/go/script-utils/startcbinary/numactl_test.go
index a1d5586f57d..326ff088276 100644
--- a/client/go/script-utils/startcbinary/numactl_test.go
+++ b/client/go/script-utils/startcbinary/numactl_test.go
@@ -44,7 +44,7 @@ func TestNumaCtlDetection(t *testing.T) {
spec.configureNumaCtl()
assert.Equal(t, true, spec.shouldUseNumaCtl)
assert.Equal(t, -1, spec.numaSocket)
- argv = spec.prependNumaCtl("/bin/myprog", []string{"-c", "cfgid"})
+ argv = spec.prependNumaCtl([]string{"/bin/myprog", "-c", "cfgid"})
trace.Trace("argv:", argv)
assert.Equal(t, 6, len(argv))
assert.Equal(t, "numactl", argv[0])
@@ -56,7 +56,7 @@ func TestNumaCtlDetection(t *testing.T) {
spec.configureNumaCtl()
assert.Equal(t, true, spec.shouldUseNumaCtl)
assert.Equal(t, 0, spec.numaSocket)
- argv = spec.prependNumaCtl("/bin/myprog", []string{"-c", "cfgid", "-p", "param"})
+ argv = spec.prependNumaCtl([]string{"/bin/myprog", "-c", "cfgid", "-p", "param"})
trace.Trace("argv:", argv)
assert.Equal(t, 8, len(argv))
assert.Equal(t, "numactl", argv[0])
@@ -68,7 +68,7 @@ func TestNumaCtlDetection(t *testing.T) {
spec.configureNumaCtl()
assert.Equal(t, true, spec.shouldUseNumaCtl)
assert.Equal(t, 1, spec.numaSocket)
- argv = spec.prependNumaCtl("/bin/myprog", []string{})
+ argv = spec.prependNumaCtl([]string{"/bin/myprog"})
trace.Trace("argv:", argv)
assert.Equal(t, 4, len(argv))
assert.Equal(t, "numactl", argv[0])
diff --git a/client/go/script-utils/startcbinary/progspec.go b/client/go/script-utils/startcbinary/progspec.go
index 614764e09e8..10097419395 100644
--- a/client/go/script-utils/startcbinary/progspec.go
+++ b/client/go/script-utils/startcbinary/progspec.go
@@ -39,8 +39,31 @@ func (p *ProgSpec) setenv(k, v string) {
p.Env[k] = v
}
+func (p *ProgSpec) getenv(k string) string {
+ if v, ok := p.Env[k]; ok {
+ return v
+ }
+ return os.Getenv(k)
+}
+
+func (p *ProgSpec) prependPath(dirName string) {
+ pathList := []string{dirName}
+ oldPath := p.getenv(ENV_PATH)
+ if oldPath == "" {
+ oldPath = "/usr/bin"
+ }
+ for _, part := range strings.Split(oldPath, ":") {
+ if part != dirName {
+ pathList = append(pathList, part)
+ }
+ }
+ newPath := strings.Join(pathList, ":")
+ p.setenv(ENV_PATH, newPath)
+ os.Setenv(ENV_PATH, newPath)
+}
+
func (p *ProgSpec) matchesListEnv(envVarName string) bool {
- return p.matchesListString(os.Getenv(envVarName))
+ return p.matchesListString(p.getenv(envVarName))
}
func (p *ProgSpec) matchesListString(env string) bool {
@@ -60,11 +83,10 @@ func (p *ProgSpec) matchesListString(env string) bool {
}
func (p *ProgSpec) valueFromListEnv(envVarName string) string {
- return p.valueFromListString(os.Getenv(envVarName))
+ return p.valueFromListString(p.getenv(envVarName))
}
func (p *ProgSpec) valueFromListString(env string) string {
-
parts := strings.Fields(env)
for _, part := range parts {
idx := strings.Index(part, "=")
@@ -83,3 +105,31 @@ func (p *ProgSpec) valueFromListString(env string) string {
}
return ""
}
+
+func (spec *ProgSpec) effectiveEnv() []string {
+ env := make(map[string]string)
+ for _, entry := range os.Environ() {
+ addInMap := func(kv string) bool {
+ for idx, elem := range kv {
+ if elem == '=' {
+ k := kv[:idx]
+ env[k] = kv
+ return true
+ }
+ }
+ return false
+ }
+ if !addInMap(entry) {
+ env[entry] = ""
+ }
+ }
+ for k, v := range spec.Env {
+ trace.Trace("add to environment:", k, "=", v)
+ env[k] = k + "=" + v
+ }
+ envv := make([]string, 0, len(env))
+ for _, v := range env {
+ envv = append(envv, v)
+ }
+ return envv
+}
diff --git a/client/go/script-utils/startcbinary/setrlimit.go b/client/go/script-utils/startcbinary/setrlimit.go
new file mode 100644
index 00000000000..5d7f33d5a0e
--- /dev/null
+++ b/client/go/script-utils/startcbinary/setrlimit.go
@@ -0,0 +1,58 @@
+// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+//go:build !windows
+
+package startcbinary
+
+import (
+ "github.com/vespa-engine/vespa/client/go/trace"
+ "golang.org/x/sys/unix"
+ "os"
+)
+
+type ResourceId int
+
+const (
+ RLIMIT_CORE ResourceId = unix.RLIMIT_AS
+ RLIMIT_NOFILE ResourceId = unix.RLIMIT_NOFILE
+ RLIMIT_NPROC ResourceId = unix.RLIMIT_NPROC
+ NO_RLIMIT uint64 = ^uint64(0)
+)
+
+func (rid ResourceId) String() string {
+ switch rid {
+ case RLIMIT_CORE:
+ return "core file size"
+ case RLIMIT_NOFILE:
+ return "open files"
+ case RLIMIT_NPROC:
+ return "max user processes"
+ }
+ return "unknown resource id"
+}
+
+func setResourceLimit(resource ResourceId, newVal uint64) {
+ var current unix.Rlimit
+ err := unix.Getrlimit(int(resource), &current)
+ if err != nil {
+ trace.Warning("Could not get current resource limit:", err)
+ return
+ }
+ wanted := current
+ if current.Max < newVal {
+ if os.Getuid() == 0 {
+ wanted.Max = newVal
+ } else {
+ newVal = current.Max
+ }
+ }
+ if current.Cur < newVal {
+ wanted.Cur = newVal
+ }
+ err = unix.Setrlimit(int(resource), &wanted)
+ if err != nil {
+ trace.Trace("Failed setting resource limit:", err)
+ } else {
+ trace.Trace("Resource limit", resource, "adjusted OK:", wanted.Cur, "/", wanted.Max)
+ }
+}
diff --git a/client/go/script-utils/startcbinary/setrlimit_windows.go b/client/go/script-utils/startcbinary/setrlimit_windows.go
new file mode 100644
index 00000000000..5bed1916246
--- /dev/null
+++ b/client/go/script-utils/startcbinary/setrlimit_windows.go
@@ -0,0 +1,18 @@
+// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+//go:build windows
+
+package startcbinary
+
+type ResourceId int
+
+const (
+ RLIMIT_CORE ResourceId = iota
+ RLIMIT_NOFILE
+ RLIMIT_NPROC
+ NO_RLIMIT uint64 = ^uint64(0)
+)
+
+func setResourceLimit(resource ResourceId, max uint64) {
+ // nop
+}
diff --git a/client/go/script-utils/startcbinary/startcbinary.go b/client/go/script-utils/startcbinary/startcbinary.go
index 56b0c9a1063..9c06ead4d06 100644
--- a/client/go/script-utils/startcbinary/startcbinary.go
+++ b/client/go/script-utils/startcbinary/startcbinary.go
@@ -6,13 +6,12 @@ package startcbinary
import (
"fmt"
"os"
- "os/exec"
-
- "github.com/vespa-engine/vespa/client/go/trace"
)
-func startCbinary(spec ProgSpec) bool {
+func startCbinary(spec ProgSpec) int {
spec.configureCommonEnv()
+ spec.configurePath()
+ spec.configureTuning()
spec.configureValgrind()
spec.configureNumaCtl()
spec.configureHugePages()
@@ -21,35 +20,25 @@ func startCbinary(spec ProgSpec) bool {
err := spec.run()
if err != nil {
fmt.Fprintln(os.Stderr, err)
+ return 1
+ } else {
+ return 0
}
- return err == nil
}
func (spec *ProgSpec) run() error {
prog := spec.Program + "-bin"
args := spec.Args
- cmd := exec.Command(prog, args...)
if spec.shouldUseValgrind {
- cmd.Path = spec.valgrindBinary()
- cmd.Args = spec.prependValgrind(prog, args)
+ args = spec.prependValgrind(args)
+ prog = spec.valgrindBinary()
} else if spec.shouldUseNumaCtl {
- cmd.Path = spec.numaCtlBinary()
- cmd.Args = spec.prependNumaCtl(prog, args)
+ args = spec.prependNumaCtl(args)
+ prog = spec.numaCtlBinary()
}
if spec.shouldUseVespaMalloc {
- spec.setenv("LD_PRELOAD", spec.vespaMallocPreload)
- }
- if len(spec.Env) > 0 {
- env := os.Environ()
- for k, v := range spec.Env {
- trace.Trace("add to environment:", k, "=", v)
- env = append(env, k+"="+v)
- }
- cmd.Env = env
+ spec.setenv(ENV_LD_PRELOAD, spec.vespaMallocPreload)
}
- cmd.Stdin = os.Stdin
- cmd.Stdout = os.Stdout
- cmd.Stderr = os.Stderr
- trace.Trace("run cmd", cmd)
- return cmd.Run()
+ envv := spec.effectiveEnv()
+ return myexecvp(prog, args, envv)
}
diff --git a/client/go/script-utils/startcbinary/tuning.go b/client/go/script-utils/startcbinary/tuning.go
new file mode 100644
index 00000000000..80fec7cc6c2
--- /dev/null
+++ b/client/go/script-utils/startcbinary/tuning.go
@@ -0,0 +1,50 @@
+// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+// Author: arnej
+
+package startcbinary
+
+import (
+ "os"
+ "strconv"
+ "strings"
+
+ "github.com/vespa-engine/vespa/client/go/trace"
+ "github.com/vespa-engine/vespa/client/go/util"
+)
+
+func (spec *ProgSpec) optionallyReduceBaseFrequency() {
+ if spec.getenv(ENV_VESPA_TIMER_HZ) == "" {
+ backticks := util.BackTicksIgnoreStderr
+ out, _ := backticks.Run("uname", "-r")
+ if strings.Contains(out, "linuxkit") {
+ trace.Trace("Running docker on macos. Reducing base frequency from 1000hz to 100hz due to high cost of sampling time. This will reduce timeout accuracy.")
+ spec.setenv(ENV_VESPA_TIMER_HZ, "100")
+ }
+ }
+}
+
+func getThpSizeMb() int {
+ const fn = "/sys/kernel/mm/transparent_hugepage/hpage_pmd_size"
+ thp_size := 2
+ line, err := os.ReadFile(fn)
+ if err == nil {
+ chomped := strings.TrimSuffix(string(line), "\n")
+ number, err := strconv.Atoi(chomped)
+ if err == nil {
+ thp_size = number / (1024 * 1024)
+ trace.Trace("thp_size", chomped, "=>", thp_size)
+ } else {
+ trace.Trace("no thp_size:", err)
+ }
+ } else {
+ trace.Trace("no thp_size:", err)
+ }
+ return thp_size
+}
+
+func (spec *ProgSpec) configureTuning() {
+ spec.optionallyReduceBaseFrequency()
+ setResourceLimit(RLIMIT_CORE, NO_RLIMIT)
+ setResourceLimit(RLIMIT_NOFILE, 262144)
+ setResourceLimit(RLIMIT_NPROC, 409600)
+}
diff --git a/client/go/script-utils/startcbinary/valgrind.go b/client/go/script-utils/startcbinary/valgrind.go
index fb47fa36e9b..f474347016d 100644
--- a/client/go/script-utils/startcbinary/valgrind.go
+++ b/client/go/script-utils/startcbinary/valgrind.go
@@ -16,7 +16,7 @@ import (
func (p *ProgSpec) configureValgrind() {
p.shouldUseValgrind = false
p.shouldUseCallgrind = false
- env := os.Getenv(ENV_VESPA_USE_VALGRIND)
+ env := p.getenv(ENV_VESPA_USE_VALGRIND)
parts := strings.Split(env, " ")
for _, part := range parts {
if p.BaseName == part {
@@ -27,7 +27,7 @@ func (p *ProgSpec) configureValgrind() {
trace.Trace("no valgrind, 'which' fails:", err, "=>", out)
return
}
- if opts := os.Getenv(ENV_VESPA_VALGRIND_OPT); strings.Contains(opts, "callgrind") {
+ if opts := p.getenv(ENV_VESPA_VALGRIND_OPT); strings.Contains(opts, "callgrind") {
p.shouldUseCallgrind = true
}
p.shouldUseValgrind = true
@@ -42,7 +42,7 @@ func (p *ProgSpec) valgrindBinary() string {
}
func (p *ProgSpec) valgrindOptions() []string {
- env := os.Getenv(ENV_VESPA_VALGRIND_OPT)
+ env := p.getenv(ENV_VESPA_VALGRIND_OPT)
if env != "" {
return strings.Fields(env)
}
@@ -71,14 +71,13 @@ func (p *ProgSpec) valgrindLogOption() string {
return fmt.Sprintf("--log-file=%s/tmp/valgrind.%s.log.%d", vespa.FindHome(), p.BaseName, os.Getpid())
}
-func (p *ProgSpec) prependValgrind(program string, args []string) []string {
+func (p *ProgSpec) prependValgrind(args []string) []string {
result := make([]string, 0, 15+len(args))
result = append(result, p.valgrindBinary())
for _, arg := range p.valgrindOptions() {
result = append(result, arg)
}
result = append(result, p.valgrindLogOption())
- result = append(result, program)
for _, arg := range args {
result = append(result, arg)
}
diff --git a/client/go/script-utils/startcbinary/valgrind_test.go b/client/go/script-utils/startcbinary/valgrind_test.go
index 6c01945a828..906dfc054c6 100644
--- a/client/go/script-utils/startcbinary/valgrind_test.go
+++ b/client/go/script-utils/startcbinary/valgrind_test.go
@@ -63,7 +63,7 @@ func TestValgrindDetection(t *testing.T) {
assert.Equal(t, true, spec.shouldUseValgrind)
assert.Equal(t, false, spec.shouldUseCallgrind)
- argv = spec.prependValgrind("/bin/myprog", []string{"-c", "cfgid"})
+ argv = spec.prependValgrind([]string{"/bin/myprog", "-c", "cfgid"})
trace.Trace("argv:", argv)
assert.Equal(t, 11, len(argv))
assert.Equal(t, "valgrind", argv[0])
@@ -79,7 +79,7 @@ func TestValgrindDetection(t *testing.T) {
assert.Equal(t, true, spec.shouldUseValgrind)
assert.Equal(t, true, spec.shouldUseCallgrind)
- argv = spec.prependValgrind("/bin/myprog", []string{"-c", "cfgid"})
+ argv = spec.prependValgrind([]string{"/bin/myprog", "-c", "cfgid"})
trace.Trace("argv:", argv)
assert.Equal(t, 6, len(argv))
assert.Equal(t, "valgrind", argv[0])
diff --git a/client/go/script-utils/startcbinary/vespamalloc.go b/client/go/script-utils/startcbinary/vespamalloc.go
index 7105f4b5562..15b0fdc80bc 100644
--- a/client/go/script-utils/startcbinary/vespamalloc.go
+++ b/client/go/script-utils/startcbinary/vespamalloc.go
@@ -5,7 +5,6 @@ package startcbinary
import (
"fmt"
- "os"
"github.com/vespa-engine/vespa/client/go/trace"
"github.com/vespa-engine/vespa/client/go/vespa"
@@ -29,6 +28,7 @@ func (p *ProgSpec) configureVespaMalloc() {
p.shouldUseVespaMalloc = false
if p.matchesListEnv(ENV_VESPA_USE_NO_VESPAMALLOC) {
trace.Trace("use no vespamalloc:", p.BaseName)
+ return
}
if p.shouldUseValgrind && !p.shouldUseCallgrind {
trace.Trace("use valgrind, so no vespamalloc:", p.BaseName)
@@ -39,20 +39,18 @@ func (p *ProgSpec) configureVespaMalloc() {
useFile = vespaMallocLib("libvespamallocdst16.so")
} else if p.matchesListEnv(ENV_VESPA_USE_VESPAMALLOC_D) {
useFile = vespaMallocLib("libvespamallocd.so")
- } else {
+ } else if p.matchesListEnv(ENV_VESPA_USE_VESPAMALLOC) {
useFile = vespaMallocLib("libvespamalloc.so")
}
trace.Trace("use file:", useFile)
if useFile == "" {
return
}
- if loadAsHuge := os.Getenv(ENV_VESPA_LOAD_CODE_AS_HUGEPAGES); loadAsHuge != "" {
+ if loadAsHuge := p.getenv(ENV_VESPA_LOAD_CODE_AS_HUGEPAGES); loadAsHuge != "" {
otherFile := vespaMallocLib("libvespa_load_as_huge.so")
useFile = fmt.Sprintf("%s:%s", useFile, otherFile)
}
- if useHugePages := os.Getenv(ENV_VESPA_USE_HUGEPAGES); useHugePages != "" {
- p.setenv(ENV_VESPA_MALLOC_HUGEPAGES, useHugePages)
- }
+ p.considerEnvFallback(ENV_VESPA_MALLOC_HUGEPAGES, ENV_VESPA_USE_HUGEPAGES)
p.vespaMallocPreload = useFile
p.shouldUseVespaMalloc = true
}
diff --git a/client/go/util/io.go b/client/go/util/io.go
index 68e855b0c3e..89f14c1a643 100644
--- a/client/go/util/io.go
+++ b/client/go/util/io.go
@@ -20,12 +20,18 @@ func PathExists(path string) bool {
return !errors.Is(err, os.ErrNotExist)
}
-// Returns true is the given path points to an existing directory
+// Returns true if the given path points to an existing directory
func IsDirectory(path string) bool {
info, err := os.Stat(path)
return !errors.Is(err, os.ErrNotExist) && info.IsDir()
}
+// Returns true if the given path points to an existing file
+func IsRegularFile(path string) bool {
+ info, err := os.Stat(path)
+ return !errors.Is(err, os.ErrNotExist) && info.Mode().IsRegular()
+}
+
// Returns the content of a reader as a string
func ReaderToString(reader io.Reader) string {
var buffer strings.Builder