Skip to content

Optimize Key.Strings by reducing memory re-allocations and simplifying control flow#385

Merged
unknwon merged 3 commits into
go-ini:mainfrom
gitKashish:optimize/strings_to_list
Jun 8, 2026
Merged

Optimize Key.Strings by reducing memory re-allocations and simplifying control flow#385
unknwon merged 3 commits into
go-ini:mainfrom
gitKashish:optimize/strings_to_list

Conversation

@gitKashish

Copy link
Copy Markdown
Contributor

Describe the pull request

Key.Strings was reimplemented to improve performance on large INI arrays. The original implementation converted the entire string to []rune upfront on every call, used bytes.Buffer with no pre-sizing, and assumed a fixed slice capacity of 2 regardless of actual delimiter count. On large arrays this caused excessive heap allocations that made the function a significant bottleneck.

This was identified as the root cause of a Forgejo startup performance regression where instances with large lists in config files experienced severely degraded startup times due to repeated calls to Key.Strings during config parsing.

Link to the issue: https://codeberg.org/forgejo/forgejo/issues/11453

The new implementation:

  • Works directly on the raw string, decoding runes lazily with utf8.DecodeRuneInString only at write time — avoiding the full []rune allocation
  • Uses strings.Builder pre-grown to len(str) to eliminate internal buffer reallocations
  • Pre-sizes the result slice using strings.Count(str, delim) + 1 so the slice is correctly sized on the first allocation

Benchmarks on a large INI array (10 runs, Windows/amd64, i5-11300H):

                      ns/op        ±stddev      B/op         allocs/op
NEW  Strings         379,108       ±21,950      116,384        3,854
OLD  _Strings      1,987,842       ±89,800      400,248       29,074

delta ns/op:   -80.9% (5.24x faster)
delta B/op:    -70.9% (116KB vs 390KB)
delta allocs:  -86.8% (3,854 vs 29,074)

Raw go bench output

Checklist

@gitKashish gitKashish force-pushed the optimize/strings_to_list branch from d4147f4 to 909c75e Compare June 4, 2026 19:43
@gitKashish gitKashish force-pushed the optimize/strings_to_list branch from 909c75e to 3fb878a Compare June 4, 2026 19:43
@gitKashish gitKashish changed the title Optimize key.Strings() by reducing memory re-allocations and simplifying control flow Optimize Key.Strings by reducing memory re-allocations and simplifying control flow Jun 4, 2026
@unknwon

unknwon commented Jun 8, 2026

Copy link
Copy Markdown
Member

@gitKashish looks like the code is not compiling.

@gitKashish

Copy link
Copy Markdown
Contributor Author

Apologies for the oversight! While cleaning up the code after running the benchmarks, I accidentally removed the new unicode/utf8 import instead of the old bytes import. I've just pushed a fix and verified that everything compiles cleanly with go build.

@unknwon unknwon left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you!

@unknwon unknwon merged commit 360a98b into go-ini:main Jun 8, 2026
4 checks passed
@unknwon

unknwon commented Jun 8, 2026

Copy link
Copy Markdown
Member

@gitKashish

Copy link
Copy Markdown
Contributor Author

Thank you very much! @unknwon

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants