diff --git a/.jules/bolt.md b/.jules/bolt.md new file mode 100644 index 0000000..e59eafe --- /dev/null +++ b/.jules/bolt.md @@ -0,0 +1,3 @@ +## 2024-04-30 - Map Allocation Overhead in Statusline Plugins +**Learning:** In performance-sensitive areas like concurrent plugin execution in the status line, calling functions like `colors.ColorMap()` repeatedly causes expensive map allocations per plugin execution, increasing memory usage and GC pressure. +**Action:** Cache static data maps at the instance level (e.g., in the `StatusLine` struct) during initialization to ensure thread-safety, minimize allocations, and improve plugin dispatch performance. diff --git a/internal/statusline/statusline.go b/internal/statusline/statusline.go index ebbc115..87b260b 100644 --- a/internal/statusline/statusline.go +++ b/internal/statusline/statusline.go @@ -35,6 +35,8 @@ type StatusLine struct { isIdle bool bashPlugins []plugin.Plugin // Cached discovered bash plugins bashPluginsOnce sync.Once + colorsMap map[string]string // Cached static colors map to avoid allocations + colorsMapOnce sync.Once } // New creates a new StatusLine renderer @@ -48,6 +50,14 @@ func New(input Input, cfg config.Config) *StatusLine { } } +// getColorsMap returns a cached colors map for plugin execution +func (sl *StatusLine) getColorsMap() map[string]string { + sl.colorsMapOnce.Do(func() { + sl.colorsMap = colors.ColorMap() + }) + return sl.colorsMap +} + // discoverBashPlugins discovers bash plugins once and caches them func (sl *StatusLine) discoverBashPlugins() []plugin.Plugin { sl.bashPluginsOnce.Do(func() { @@ -634,7 +644,7 @@ func (sl *StatusLine) runPlugin(name string) string { ContextWindowSize: sl.input.Context.ContextWindow, }, Config: sl.getPluginConfig(name), - Colors: colors.ColorMap(), + Colors: sl.getColorsMap(), // Use cached instance-level map to avoid allocations per execution } // Try native plugin first (much faster - no subprocess)