Skip to content

Commit

Permalink
perf(exec): improve performance (#433)
Browse files Browse the repository at this point in the history
...by only parsing installed packages for their environment variables if
we are in a deactivated hermit environment. When activated, the parent
shell will have already passed the new process all environment
variables, including packages that were installed after initial
activation. Parsing the HCL configs of all installed packages introduces
some overhead. This can be non-negligible when hermit-managed packages
are used a large number of times - for instance with javac or rustc.

Here is a very exaggerated example on a project with 42 installed
packages:

Before change:
```bash
$ time make --version > /dev/null

real    0m0.143s
user    0m0.136s
sys     0m0.033s
```

After change:
```bash
$ time make --version > /dev/null

real    0m0.013s
user    0m0.013s
sys     0m0.000s
```

No hermit:
```bash
$ time /usr/bin/make --version > /dev/null

real    0m0.002s
user    0m0.001s
sys     0m0.001s
```
  • Loading branch information
nickajacks1 authored Feb 9, 2025
1 parent 2929077 commit 9a9737e
Showing 1 changed file with 17 additions and 7 deletions.
24 changes: 17 additions & 7 deletions env.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ var (
//go:embed "files/install.sh.tmpl"
InstallerTemplateSource string

// UserStateDir should be passed to Open()/Init() in most cases.
// UserStateDir should be passed to OpenEnv()/Init() in most cases.
UserStateDir = func() string {
// Check if state dir is explicitly set
explicit := os.Getenv("HERMIT_STATE_DIR")
Expand Down Expand Up @@ -114,6 +114,7 @@ type Env struct {
configFile string
httpClient *http.Client
scriptSums []string
activated bool

// Lazily initialized fields
lazyResolver *manifest.Resolver
Expand Down Expand Up @@ -349,6 +350,7 @@ func OpenEnv(
ephemeralEnvars: envars.Infer(ephemeral.System()),
httpClient: httpClient,
scriptSums: scriptSums,
activated: os.Getenv("DEACTIVATED_HERMIT") == "",
}, nil
}

Expand Down Expand Up @@ -783,10 +785,21 @@ func (e *Env) Exec(l *ui.UI, pkg *manifest.Package, binary string, args []string
return errors.WithStack(err)
}

installed, err := e.ListInstalled(l)
if err != nil {
return errors.WithStack(err)
var installed []*manifest.Package

// If we are activated, the parent shell already has
// already passed us all necessary environment variables.
// This may not be the case if the user manually ran
// e.g. ./bin/go
// We still need to call e.allEnvarOpsForPackages to ensure
// the selected package's env vars take precedence.
if !e.activated {
installed, err = e.ListInstalled(l)
if err != nil {
return errors.WithStack(err)
}
}

ops := e.allEnvarOpsForPackages(runtimeDeps, pkg, installed...)
packageHermitBin, err := e.getPackageRuntimeEnvops(pkg)
if err != nil {
Expand All @@ -797,9 +810,6 @@ func (e *Env) Exec(l *ui.UI, pkg *manifest.Package, binary string, args []string
}
env := e.envarsFromOps(true, ops)

if err != nil {
return errors.WithStack(err)
}
for _, bin := range binaries {
if filepath.Base(bin) != filepath.Base(binary) {
continue
Expand Down

0 comments on commit 9a9737e

Please sign in to comment.