Skip to content

Commit 8485864

Browse files
committed
chore: optimize maps.Values and maps.Keys
This PR optimizes the performance of maps.Values and maps.Keys (around 125 usages in sidero code) by using the internal runtime functions runtime.keys and runtime.values. There is strong desire in Go Team to disable `go:linkname` usage in user code [^1], but this is a special case where we use `Push` `linkname` pattern which is said to be supported in the future. It is tested with both Go 1.22 and latest Go with CL 585556 [^2] applied. To further future-proof this code, we have added a build tag `go1.22 && !go1.24` to ensure this code is only compiled with Go 1.22 and 1.23 and falls back to the old implementation for Go 1.24 and above. This is because we don't know yet if `runtime.keys` and `runtime.values` are going to be present in Go 1.24. We will update this code when Go 1.24 freeze happens. Benchstat results below (overall 26% CPU usage reduction): ```bash ~ benchstat old.txt new.txt goos: darwin goarch: arm64 pkg: github.com/siderolabs/gen/maps │ old.txt │ new.txt │ │ sec/op │ sec/op vs base │ Keys/small-10 111.05n ± 0% 80.74n ± 3% -27.29% (p=0.000 n=10) Keys/mid-10 837.8n ± 1% 607.8n ± 2% -27.46% (p=0.000 n=10) Keys/large-10 7.717µ ± 4% 5.711µ ± 0% -26.00% (p=0.000 n=10) Values/small-10 110.40n ± 0% 83.69n ± 0% -24.19% (p=0.000 n=10) Values/mid-10 835.9n ± 1% 583.5n ± 1% -30.19% (p=0.000 n=10) Values/large-10 7.720µ ± 2% 5.696µ ± 1% -26.22% (p=0.000 n=10) geomean 894.3n 653.6n -26.92% │ old.txt │ new.txt │ │ B/op │ B/op vs base │ Keys/small-10 80.00 ± 0% 80.00 ± 0% ~ (p=1.000 n=10) ¹ Keys/mid-10 896.0 ± 0% 896.0 ± 0% ~ (p=1.000 n=10) ¹ Keys/large-10 8.000Ki ± 0% 8.000Ki ± 0% ~ (p=1.000 n=10) ¹ Values/small-10 80.00 ± 0% 80.00 ± 0% ~ (p=1.000 n=10) ¹ Values/mid-10 896.0 ± 0% 896.0 ± 0% ~ (p=1.000 n=10) ¹ Values/large-10 8.000Ki ± 0% 8.000Ki ± 0% ~ (p=1.000 n=10) ¹ geomean 837.4 837.4 +0.00% ¹ all samples are equal │ old.txt │ new.txt │ │ allocs/op │ allocs/op vs base │ Keys/small-10 1.000 ± 0% 1.000 ± 0% ~ (p=1.000 n=10) ¹ Keys/mid-10 1.000 ± 0% 1.000 ± 0% ~ (p=1.000 n=10) ¹ Keys/large-10 1.000 ± 0% 1.000 ± 0% ~ (p=1.000 n=10) ¹ Values/small-10 1.000 ± 0% 1.000 ± 0% ~ (p=1.000 n=10) ¹ Values/mid-10 1.000 ± 0% 1.000 ± 0% ~ (p=1.000 n=10) ¹ Values/large-10 1.000 ± 0% 1.000 ± 0% ~ (p=1.000 n=10) ¹ geomean 1.000 1.000 +0.00% ¹ all samples are equal ``` [^1]: golang/go#67401 [^2]: https://go-review.googlesource.com/c/go/+/585556 Signed-off-by: Dmitriy Matrenichev <dmitry.matrenichev@siderolabs.com>
1 parent 238baf9 commit 8485864

File tree

13 files changed

+238
-140
lines changed

13 files changed

+238
-140
lines changed

.dockerignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# THIS FILE WAS AUTOMATICALLY GENERATED, PLEASE DO NOT EDIT.
22
#
3-
# Generated on 2024-03-11T19:57:58Z by kres latest.
3+
# Generated on 2024-05-19T20:59:37Z by kres dccd292.
44

55
*
66
!channel

.github/workflows/ci.yaml

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# THIS FILE WAS AUTOMATICALLY GENERATED, PLEASE DO NOT EDIT.
22
#
3-
# Generated on 2024-03-11T19:57:58Z by kres latest.
3+
# Generated on 2024-05-19T18:27:53Z by kres dccd292.
44

55
name: default
66
concurrency:
@@ -31,7 +31,7 @@ jobs:
3131
if: (!startsWith(github.head_ref, 'renovate/') && !startsWith(github.head_ref, 'dependabot/'))
3232
services:
3333
buildkitd:
34-
image: moby/buildkit:v0.12.5
34+
image: moby/buildkit:v0.13.2
3535
options: --privileged
3636
ports:
3737
- 1234:1234
@@ -45,11 +45,12 @@ jobs:
4545
run: |
4646
git fetch --prune --unshallow
4747
- name: Set up Docker Buildx
48+
id: setup-buildx
4849
uses: docker/setup-buildx-action@v3
4950
with:
5051
driver: remote
5152
endpoint: tcp://127.0.0.1:1234
52-
timeout-minutes: 1
53+
timeout-minutes: 10
5354
- name: base
5455
run: |
5556
make base
@@ -60,8 +61,11 @@ jobs:
6061
run: |
6162
make unit-tests-race
6263
- name: coverage
63-
run: |
64-
make coverage
64+
uses: codecov/codecov-action@v4
65+
with:
66+
files: _out/coverage-unit-tests.txt
67+
token: ${{ secrets.CODECOV_TOKEN }}
68+
timeout-minutes: 3
6569
- name: lint
6670
run: |
6771
make lint

.golangci.yml

Lines changed: 32 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,20 @@
11
# THIS FILE WAS AUTOMATICALLY GENERATED, PLEASE DO NOT EDIT.
22
#
3-
# Generated on 2024-03-11T19:57:58Z by kres latest.
3+
# Generated on 2024-05-19T20:58:19Z by kres dccd292.
44

55
# options for analysis running
66
run:
77
timeout: 10m
88
issues-exit-code: 1
99
tests: true
10-
build-tags: []
11-
skip-dirs: []
12-
skip-dirs-use-default: true
13-
skip-files: []
10+
build-tags: [ ]
1411
modules-download-mode: readonly
1512

1613
# output configuration options
1714
output:
18-
format: colored-line-number
15+
formats:
16+
- format: colored-line-number
17+
path: stdout
1918
print-issued-lines: true
2019
print-linter-name: true
2120
uniq-by-line: true
@@ -32,54 +31,35 @@ linters-settings:
3231
check-blank: true
3332
exhaustive:
3433
default-signifies-exhaustive: false
35-
funlen:
36-
lines: 60
37-
statements: 40
3834
gci:
39-
local-prefixes: github.com/siderolabs/gen/
35+
sections:
36+
- standard # Standard section: captures all standard packages.
37+
- default # Default section: contains all imports that could not be matched to another section type.
38+
- localmodule # Imports from the same module.
4039
gocognit:
4140
min-complexity: 30
42-
ireturn:
43-
allow:
44-
- anon
45-
- error
46-
- empty
47-
- stdlib
48-
- github.com\/talos-systems\/kres\/internal\/dag.Node
4941
nestif:
5042
min-complexity: 5
5143
goconst:
5244
min-len: 3
5345
min-occurrences: 3
5446
gocritic:
55-
disabled-checks: []
47+
disabled-checks: [ ]
5648
gocyclo:
5749
min-complexity: 20
5850
godot:
59-
check-all: false
60-
godox:
61-
keywords: # default keywords are TODO, BUG, and FIXME, these can be overwritten by this setting
62-
- NOTE
63-
- OPTIMIZE # marks code that should be optimized before merging
64-
- HACK # marks hack-arounds that should be removed before merging
51+
scope: declarations
6552
gofmt:
6653
simplify: true
67-
goimports:
68-
local-prefixes: github.com/siderolabs/gen/
69-
golint:
70-
min-confidence: 0.8
71-
gomnd:
72-
settings: {}
73-
gomodguard: {}
54+
gomodguard: { }
7455
govet:
75-
check-shadowing: true
7656
enable-all: true
7757
lll:
7858
line-length: 200
7959
tab-width: 4
8060
misspell:
8161
locale: US
82-
ignore-words: []
62+
ignore-words: [ ]
8363
nakedret:
8464
max-func-lines: 30
8565
prealloc:
@@ -88,16 +68,15 @@ linters-settings:
8868
for-loops: false # Report preallocation suggestions on for loops, false by default
8969
nolintlint:
9070
allow-unused: false
91-
allow-leading-space: false
92-
allow-no-explanation: []
71+
allow-no-explanation: [ ]
9372
require-explanation: false
9473
require-specific: true
95-
rowserrcheck: {}
96-
testpackage: {}
74+
rowserrcheck: { }
75+
testpackage: { }
9776
unparam:
9877
check-exported: false
9978
unused:
100-
check-exported: false
79+
local-variables-are-used: false
10180
whitespace:
10281
multi-if: false # Enforces newlines (or comments) after every multi-line if statement
10382
multi-func: false # Enforces newlines (or comments) after every multi-line function signature
@@ -113,8 +92,8 @@ linters-settings:
11392
gofumpt:
11493
extra-rules: false
11594
cyclop:
116-
# the maximal code complexity to report
117-
max-complexity: 20
95+
# the maximal code complexity to report
96+
max-complexity: 20
11897
# depguard:
11998
# Main:
12099
# deny:
@@ -125,48 +104,50 @@ linters:
125104
disable-all: false
126105
fast: false
127106
disable:
128-
- exhaustruct
129107
- exhaustivestruct
108+
- exhaustruct
109+
- err113
130110
- forbidigo
131111
- funlen
132-
- gas
133112
- gochecknoglobals
134113
- gochecknoinits
135114
- godox
136-
- goerr113
137115
- gomnd
138116
- gomoddirectives
117+
- gosec
118+
- inamedparam
139119
- ireturn
120+
- mnd
140121
- nestif
141122
- nonamedreturns
142123
- nosnakecase
143124
- paralleltest
125+
- tagalign
144126
- tagliatelle
145127
- thelper
146128
- typecheck
147129
- varnamelen
148130
- wrapcheck
149131
- depguard # Disabled because starting with golangci-lint 1.53.0 it doesn't allow denylist alone anymore
150-
- tagalign
151-
- inamedparam
152132
- testifylint # complains about our assert recorder and has a number of false positives for assert.Greater(t, thing, 1)
153133
- protogetter # complains about us using Value field on typed spec, instead of GetValue which has a different signature
154134
- perfsprint # complains about us using fmt.Sprintf in non-performance critical code, updating just kres took too long
155135
# abandoned linters for which golangci shows the warning that the repo is archived by the owner
136+
- deadcode
137+
- golint
138+
- ifshort
156139
- interfacer
157140
- maligned
158-
- golint
159141
- scopelint
160-
- varcheck
161-
- deadcode
162142
- structcheck
163-
- ifshort
143+
- varcheck
164144
# disabled as it seems to be broken - goes into imported libraries and reports issues there
165145
- musttag
146+
- goimports # same as gci
166147

167148
issues:
168-
exclude: []
169-
exclude-rules: []
149+
exclude: [ ]
150+
exclude-rules: [ ]
170151
exclude-use-default: false
171152
exclude-case-sensitive: false
172153
max-issues-per-linter: 10

Dockerfile

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
1-
# syntax = docker/dockerfile-upstream:1.7.0-labs
1+
# syntax = docker/dockerfile-upstream:1.7.1-labs
22

33
# THIS FILE WAS AUTOMATICALLY GENERATED, PLEASE DO NOT EDIT.
44
#
5-
# Generated on 2024-03-11T19:57:58Z by kres latest.
5+
# Generated on 2024-05-19T20:59:37Z by kres dccd292.
66

77
ARG TOOLCHAIN
88

99
# cleaned up specs and compiled versions
1010
FROM scratch AS generate
1111

1212
# runs markdownlint
13-
FROM docker.io/node:21.6.2-alpine3.19 AS lint-markdown
13+
FROM docker.io/node:21.7.3-alpine3.19 AS lint-markdown
1414
WORKDIR /src
1515
RUN npm i -g markdownlint-cli@0.39.0
1616
RUN npm i sentences-per-line@0.2.1
@@ -40,9 +40,6 @@ RUN --mount=type=cache,target=/root/.cache/go-build --mount=type=cache,target=/g
4040
&& mv /go/bin/golangci-lint /bin/golangci-lint
4141
RUN --mount=type=cache,target=/root/.cache/go-build --mount=type=cache,target=/go/pkg go install golang.org/x/vuln/cmd/govulncheck@latest \
4242
&& mv /go/bin/govulncheck /bin/govulncheck
43-
ARG GOIMPORTS_VERSION
44-
RUN --mount=type=cache,target=/root/.cache/go-build --mount=type=cache,target=/go/pkg go install golang.org/x/tools/cmd/goimports@${GOIMPORTS_VERSION} \
45-
&& mv /go/bin/goimports /bin/goimports
4643
ARG GOFUMPT_VERSION
4744
RUN go install mvdan.cc/gofumpt@${GOFUMPT_VERSION} \
4845
&& mv /go/bin/gofumpt /bin/gofumpt
@@ -71,15 +68,12 @@ RUN --mount=type=cache,target=/go/pkg go list -mod=readonly all >/dev/null
7168
FROM base AS lint-gofumpt
7269
RUN FILES="$(gofumpt -l .)" && test -z "${FILES}" || (echo -e "Source code is not formatted with 'gofumpt -w .':\n${FILES}"; exit 1)
7370

74-
# runs goimports
75-
FROM base AS lint-goimports
76-
RUN FILES="$(goimports -l -local github.com/siderolabs/gen/ .)" && test -z "${FILES}" || (echo -e "Source code is not formatted with 'goimports -w -local github.com/siderolabs/gen/ .':\n${FILES}"; exit 1)
77-
7871
# runs golangci-lint
7972
FROM base AS lint-golangci-lint
8073
WORKDIR /src
8174
COPY .golangci.yml .
8275
ENV GOGC 50
76+
RUN golangci-lint config verify --config .golangci.yml
8377
RUN --mount=type=cache,target=/root/.cache/go-build --mount=type=cache,target=/root/.cache/golangci-lint --mount=type=cache,target=/go/pkg golangci-lint run --config .golangci.yml
8478

8579
# runs govulncheck

Makefile

Lines changed: 14 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# THIS FILE WAS AUTOMATICALLY GENERATED, PLEASE DO NOT EDIT.
22
#
3-
# Generated on 2024-03-11T19:51:28Z by kres latest.
3+
# Generated on 2024-05-19T18:27:53Z by kres dccd292.
44

55
# common variables
66

@@ -9,6 +9,9 @@ TAG := $(shell git describe --tag --always --dirty --match v[0-9]\*)
99
ABBREV_TAG := $(shell git describe --tags >/dev/null 2>/dev/null && git describe --tag --always --match v[0-9]\* --abbrev=0 || echo 'undefined')
1010
BRANCH := $(shell git rev-parse --abbrev-ref HEAD)
1111
ARTIFACTS := _out
12+
IMAGE_TAG ?= $(TAG)
13+
OPERATING_SYSTEM := $(shell uname -s | tr '[:upper:]' '[:lower:]')
14+
GOARCH := $(shell uname -m | sed 's/x86_64/amd64/' | sed 's/aarch64/arm64/')
1215
WITH_DEBUG ?= false
1316
WITH_RACE ?= false
1417
REGISTRY ?= ghcr.io
@@ -18,11 +21,11 @@ PROTOBUF_GO_VERSION ?= 1.33.0
1821
GRPC_GO_VERSION ?= 1.3.0
1922
GRPC_GATEWAY_VERSION ?= 2.19.1
2023
VTPROTOBUF_VERSION ?= 0.6.0
24+
GOIMPORTS_VERSION ?= 0.21.0
2125
DEEPCOPY_VERSION ?= v0.5.6
22-
GOLANGCILINT_VERSION ?= v1.56.2
26+
GOLANGCILINT_VERSION ?= v1.58.0
2327
GOFUMPT_VERSION ?= v0.6.0
24-
GO_VERSION ?= 1.22.1
25-
GOIMPORTS_VERSION ?= v0.19.0
28+
GO_VERSION ?= 1.22.3
2629
GO_BUILDFLAGS ?=
2730
GO_LDFLAGS ?=
2831
CGO_ENABLED ?= 0
@@ -59,9 +62,9 @@ COMMON_ARGS += --build-arg=PROTOBUF_GO_VERSION="$(PROTOBUF_GO_VERSION)"
5962
COMMON_ARGS += --build-arg=GRPC_GO_VERSION="$(GRPC_GO_VERSION)"
6063
COMMON_ARGS += --build-arg=GRPC_GATEWAY_VERSION="$(GRPC_GATEWAY_VERSION)"
6164
COMMON_ARGS += --build-arg=VTPROTOBUF_VERSION="$(VTPROTOBUF_VERSION)"
65+
COMMON_ARGS += --build-arg=GOIMPORTS_VERSION="$(GOIMPORTS_VERSION)"
6266
COMMON_ARGS += --build-arg=DEEPCOPY_VERSION="$(DEEPCOPY_VERSION)"
6367
COMMON_ARGS += --build-arg=GOLANGCILINT_VERSION="$(GOLANGCILINT_VERSION)"
64-
COMMON_ARGS += --build-arg=GOIMPORTS_VERSION="$(GOIMPORTS_VERSION)"
6568
COMMON_ARGS += --build-arg=GOFUMPT_VERSION="$(GOFUMPT_VERSION)"
6669
COMMON_ARGS += --build-arg=TESTPKGS="$(TESTPKGS)"
6770
TOOLCHAIN ?= docker.io/golang:1.22-alpine
@@ -110,7 +113,7 @@ If you already have a compatible builder instance, you may use that instead.
110113
## Artifacts
111114

112115
All artifacts will be output to ./$(ARTIFACTS). Images will be tagged with the
113-
registry "$(REGISTRY)", username "$(USERNAME)", and a dynamic tag (e.g. $(IMAGE):$(TAG)).
116+
registry "$(REGISTRY)", username "$(USERNAME)", and a dynamic tag (e.g. $(IMAGE):$(IMAGE_TAG)).
114117
The registry and username can be overridden by exporting REGISTRY, and USERNAME
115118
respectively.
116119

@@ -130,6 +133,9 @@ endif
130133

131134
all: unit-tests lint
132135

136+
$(ARTIFACTS): ## Creates artifacts directory.
137+
@mkdir -p $(ARTIFACTS)
138+
133139
.PHONY: clean
134140
clean: ## Cleans up all artifacts.
135141
@rm -rf $(ARTIFACTS)
@@ -157,9 +163,6 @@ fmt: ## Formats the source code
157163
lint-govulncheck: ## Runs govulncheck linter.
158164
@$(MAKE) target-$@
159165

160-
lint-goimports: ## Runs goimports linter.
161-
@$(MAKE) target-$@
162-
163166
.PHONY: base
164167
base: ## Prepare base toolchain
165168
@$(MAKE) target-$@
@@ -172,16 +175,12 @@ unit-tests: ## Performs unit tests
172175
unit-tests-race: ## Performs unit tests with race detection enabled.
173176
@$(MAKE) target-$@
174177

175-
.PHONY: coverage
176-
coverage: ## Upload coverage data to codecov.io.
177-
bash -c "bash <(curl -s https://codecov.io/bash) -f $(ARTIFACTS)/coverage-unit-tests.txt -X fix"
178-
179178
.PHONY: lint-markdown
180179
lint-markdown: ## Runs markdownlint.
181180
@$(MAKE) target-$@
182181

183182
.PHONY: lint
184-
lint: lint-golangci-lint lint-gofumpt lint-govulncheck lint-goimports lint-markdown ## Run all linters for the project.
183+
lint: lint-golangci-lint lint-gofumpt lint-govulncheck lint-markdown ## Run all linters for the project.
185184

186185
.PHONY: rekres
187186
rekres:
@@ -194,8 +193,7 @@ help: ## This help menu.
194193
@grep -E '^[a-zA-Z%_-]+:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'
195194

196195
.PHONY: release-notes
197-
release-notes:
198-
mkdir -p $(ARTIFACTS)
196+
release-notes: $(ARTIFACTS)
199197
@ARTIFACTS=$(ARTIFACTS) ./hack/release.sh $@ $(ARTIFACTS)/RELEASE_NOTES.md $(TAG)
200198

201199
.PHONY: conformance

0 commit comments

Comments
 (0)