Skip to content

reconciler: Shrink Status type #101

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jul 31, 2025
Merged

reconciler: Shrink Status type #101

merged 2 commits into from
Jul 31, 2025

Conversation

joamaki
Copy link
Contributor

@joamaki joamaki commented Jul 31, 2025

  1. Change Error from string to *string as it's rarely set (64 => 56 bytes)
  2. Change StatusKind from string to uint8 (56 => 48 bytes)

The StatusKind is struct { uint8 } to make sure code that used to do string(foo.Status.Kind) won't compile and is forced to change to foo.Status.Kind.String(). Note that we're going to release v0.5.0 with few other breaking API changes in addition to this one and tooling in cilium/cilium only bumps StateDB on patch version changes.

@joamaki joamaki requested a review from a team as a code owner July 31, 2025 12:40
@joamaki joamaki requested review from derailed and removed request for a team July 31, 2025 12:40
Copy link

github-actions bot commented Jul 31, 2025

$ make
go build ./...
go: downloading go1.24.0 (linux/amd64)
go: downloading go.yaml.in/yaml/v3 v3.0.3
go: downloading github.com/cilium/hive v0.0.0-20250731144630-28e7a35ed227
go: downloading golang.org/x/time v0.5.0
go: downloading github.com/spf13/cobra v1.8.0
go: downloading github.com/spf13/pflag v1.0.5
go: downloading github.com/cilium/stream v0.0.0-20240209152734-a0792b51812d
go: downloading github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de
go: downloading github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc
go: downloading github.com/mitchellh/mapstructure v1.5.0
go: downloading go.uber.org/dig v1.17.1
go: downloading golang.org/x/term v0.16.0
go: downloading github.com/spf13/viper v1.18.2
go: downloading golang.org/x/sys v0.17.0
go: downloading golang.org/x/tools v0.17.0
go: downloading github.com/spf13/cast v1.6.0
go: downloading github.com/fsnotify/fsnotify v1.7.0
go: downloading github.com/sagikazarmark/slog-shim v0.1.0
go: downloading github.com/spf13/afero v1.11.0
go: downloading github.com/subosito/gotenv v1.6.0
go: downloading github.com/hashicorp/hcl v1.0.0
go: downloading gopkg.in/ini.v1 v1.67.0
go: downloading github.com/magiconair/properties v1.8.7
go: downloading github.com/pelletier/go-toml/v2 v2.1.0
go: downloading gopkg.in/yaml.v3 v3.0.1
go: downloading golang.org/x/text v0.14.0
go test ./... -cover -vet=all -test.count 1
go: downloading github.com/stretchr/testify v1.8.4
go: downloading go.uber.org/goleak v1.3.0
go: downloading golang.org/x/exp v0.0.0-20240119083558-1b970713d09a
go: downloading github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2
ok  	github.com/cilium/statedb	22.586s	coverage: 80.9% of statements
ok  	github.com/cilium/statedb/index	0.006s	coverage: 28.7% of statements
ok  	github.com/cilium/statedb/internal	0.008s	coverage: 46.7% of statements
ok  	github.com/cilium/statedb/part	4.797s	coverage: 87.6% of statements
ok  	github.com/cilium/statedb/reconciler	0.261s	coverage: 89.1% of statements
	github.com/cilium/statedb/reconciler/benchmark		coverage: 0.0% of statements
	github.com/cilium/statedb/reconciler/example		coverage: 0.0% of statements
go test -race ./... -test.count 1
ok  	github.com/cilium/statedb	103.390s
ok  	github.com/cilium/statedb/index	1.017s
ok  	github.com/cilium/statedb/internal	1.028s
ok  	github.com/cilium/statedb/part	35.082s
ok  	github.com/cilium/statedb/reconciler	1.339s
?   	github.com/cilium/statedb/reconciler/benchmark	[no test files]
?   	github.com/cilium/statedb/reconciler/example	[no test files]
go test ./... -bench . -benchmem -test.run xxx
goos: linux
goarch: amd64
pkg: github.com/cilium/statedb
cpu: AMD EPYC 7763 64-Core Processor                
BenchmarkDB_WriteTxn_1-4                    	  484164	      2220 ns/op	    450531 objects/sec	    1416 B/op	      26 allocs/op
BenchmarkDB_WriteTxn_10-4                   	 1424526	       844.5 ns/op	   1184116 objects/sec	     481 B/op	       9 allocs/op
BenchmarkDB_WriteTxn_100-4                  	 1915128	       681.6 ns/op	   1467189 objects/sec	     400 B/op	       7 allocs/op
BenchmarkDB_WriteTxn_1000-4                 	 1823721	       663.0 ns/op	   1508312 objects/sec	     363 B/op	       7 allocs/op
BenchmarkDB_WriteTxn_100_SecondaryIndex-4   	  557384	      2006 ns/op	    498399 objects/sec	    1213 B/op	      37 allocs/op
BenchmarkDB_NewWriteTxn-4                   	 1504737	       797.5 ns/op	     544 B/op	       8 allocs/op
BenchmarkDB_NewReadTxn-4                    	551082380	         2.179 ns/op	       0 B/op	       0 allocs/op
BenchmarkDB_Modify-4                        	    1666	    723427 ns/op	   1382309 objects/sec	  423373 B/op	    8143 allocs/op
BenchmarkDB_GetInsert-4                     	    1484	    818235 ns/op	   1222142 objects/sec	  404506 B/op	    8140 allocs/op
BenchmarkDB_RandomInsert-4                  	    1771	    695990 ns/op	   1436801 objects/sec	  397545 B/op	    7141 allocs/op
BenchmarkDB_RandomReplace-4                 	     369	   3265983 ns/op	    306186 objects/sec	 1975356 B/op	   49160 allocs/op
BenchmarkDB_SequentialInsert-4              	    1843	    668643 ns/op	   1495566 objects/sec	  364127 B/op	    7114 allocs/op
BenchmarkDB_SequentialInsert_Prefix-4       	     400	   2990806 ns/op	    334358 objects/sec	 3718042 B/op	   58568 allocs/op
BenchmarkDB_Changes_Baseline-4              	    1393	    853841 ns/op	   1171179 objects/sec	  433544 B/op	   10214 allocs/op
BenchmarkDB_Changes-4                       	     784	   1502553 ns/op	    665534 objects/sec	  755956 B/op	   14420 allocs/op
BenchmarkDB_RandomLookup-4                  	   21368	     55903 ns/op	  17888222 objects/sec	       0 B/op	       0 allocs/op
BenchmarkDB_SequentialLookup-4              	   25028	     47899 ns/op	  20877168 objects/sec	       0 B/op	       0 allocs/op
BenchmarkDB_Prefix_SecondaryIndex-4         	    6820	    163023 ns/op	   6134103 objects/sec	  125114 B/op	    1031 allocs/op
BenchmarkDB_FullIteration_All-4             	     912	   1309616 ns/op	  76358290 objects/sec	     320 B/op	      11 allocs/op
BenchmarkDB_FullIteration_Get-4             	     181	   6588408 ns/op	  15178173 objects/sec	       0 B/op	       0 allocs/op
BenchmarkDB_FullIteration_ReadTxnGet-4      	     170	   7072038 ns/op	  14140196 objects/sec	       0 B/op	       0 allocs/op
BenchmarkDB_PropagationDelay-4              	  601501	      1989 ns/op	        17.00 50th_µs	        19.00 90th_µs	        44.00 99th_µs	    1070 B/op	      22 allocs/op
BenchmarkWatchSet_4-4                       	 1337082	       896.9 ns/op	     499 B/op	       7 allocs/op
BenchmarkWatchSet_16-4                      	  510795	      2403 ns/op	    1701 B/op	       8 allocs/op
BenchmarkWatchSet_128-4                     	   61345	     19457 ns/op	   13348 B/op	       8 allocs/op
BenchmarkWatchSet_1024-4                    	    6610	    192544 ns/op	  105240 B/op	       8 allocs/op
PASS
ok  	github.com/cilium/statedb	33.785s
PASS
ok  	github.com/cilium/statedb/index	0.003s
PASS
ok  	github.com/cilium/statedb/internal	0.003s
goos: linux
goarch: amd64
pkg: github.com/cilium/statedb/part
cpu: AMD EPYC 7763 64-Core Processor                
Benchmark_Uint64Map_Random-4        	    1262	    910565 ns/op	   1098219 items/sec	 2812922 B/op	   11034 allocs/op
Benchmark_Uint64Map_Sequential-4    	    1164	    882092 ns/op	   1133668 items/sec	 2591252 B/op	   11749 allocs/op
Benchmark_Insert_RootOnlyWatch-4    	    9835	    122720 ns/op	   8148645 objects/sec	   74538 B/op	    2044 allocs/op
Benchmark_Insert-4                  	    6726	    174721 ns/op	   5723420 objects/sec	  190507 B/op	    3076 allocs/op
Benchmark_Modify-4                  	   12034	     99519 ns/op	  10048331 objects/sec	   72053 B/op	    1028 allocs/op
Benchmark_GetInsert-4               	    8286	    142679 ns/op	   7008748 objects/sec	   72025 B/op	    1028 allocs/op
Benchmark_Replace-4                 	27663211	        43.08 ns/op	  23213011 objects/sec	       0 B/op	       0 allocs/op
Benchmark_Replace_RootOnlyWatch-4   	27652220	        42.96 ns/op	  23276364 objects/sec	       0 B/op	       0 allocs/op
Benchmark_txn_1-4                   	 3258708	       369.1 ns/op	   2709194 objects/sec	     280 B/op	       5 allocs/op
Benchmark_txn_10-4                  	 8461717	       140.6 ns/op	   7114282 objects/sec	      97 B/op	       2 allocs/op
Benchmark_txn_100-4                 	10354808	       114.8 ns/op	   8707537 objects/sec	      91 B/op	       2 allocs/op
Benchmark_txn_1000-4                	 9527649	       125.6 ns/op	   7963963 objects/sec	      78 B/op	       2 allocs/op
Benchmark_txn_delete_1-4            	 1533434	       787.0 ns/op	   1270698 objects/sec	    3272 B/op	       8 allocs/op
Benchmark_txn_delete_10-4           	 7151032	       168.5 ns/op	   5935174 objects/sec	     368 B/op	       2 allocs/op
Benchmark_txn_delete_100-4          	11090254	       108.3 ns/op	   9230326 objects/sec	      82 B/op	       1 allocs/op
Benchmark_txn_delete_1000-4         	11897160	       100.6 ns/op	   9942834 objects/sec	      28 B/op	       1 allocs/op
Benchmark_Get-4                     	   33943	     35767 ns/op	  27958370 objects/sec	       0 B/op	       0 allocs/op
Benchmark_Iterate-4                 	  173980	      7309 ns/op	 136825120 objects/sec	     104 B/op	       4 allocs/op
Benchmark_Hashmap_Insert-4          	   14761	     81216 ns/op	  12312838 objects/sec	   74265 B/op	      20 allocs/op
Benchmark_Hashmap_Get_Uint64-4      	  138540	      8627 ns/op	 115921129 objects/sec	       0 B/op	       0 allocs/op
Benchmark_Hashmap_Get_Bytes-4       	  111524	     10754 ns/op	  92984533 objects/sec	       0 B/op	       0 allocs/op
PASS
ok  	github.com/cilium/statedb/part	26.954s
PASS
ok  	github.com/cilium/statedb/reconciler	0.004s
?   	github.com/cilium/statedb/reconciler/benchmark	[no test files]
?   	github.com/cilium/statedb/reconciler/example	[no test files]
go run ./reconciler/benchmark -quiet
1000000 objects reconciled in 2.39 seconds (batch size 1000)
Throughput 418068.22 objects per second
1136MB total allocated, 6011143 in-use objects, 338MB bytes in use

@joamaki joamaki force-pushed the pr/joamaki/shrink-status branch from eb85019 to 86ffd17 Compare July 31, 2025 12:53
@joamaki
Copy link
Contributor Author

joamaki commented Jul 31, 2025

On main the reconciler benchmark gives:

1166MB total allocated, 6011116 in-use objects, 353MB bytes in use

And in this PR:

1137MB total allocated, 6011120 in-use objects, 338MB bytes in use

So for 1M objects with Status we're using ~4% less memory.

Copy link

@derailed derailed left a comment

Choose a reason for hiding this comment

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

@joamaki Nice work! few comments but out of context so feel free to discard...

ID: nextID(),
}
}

// statusError constructs the status that marks the object
// as failed to be reconciled.
func StatusError(err error) Status {
errStr := err.Error()

Choose a reason for hiding this comment

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

this will panic if called with nil

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ah indeed! Fixed and added test.

StatusKindRefreshing StatusKind = "Refreshing"
StatusKindDone StatusKind = "Done"
StatusKindError StatusKind = "Error"
var (

Choose a reason for hiding this comment

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

Could be out of context here but this feels a little odd aka consts -> global variables. Not sure if applicable but perhaps we could have gone with StatusKind uint8 and generate the string equivalent of the consts via go:generate.
Aka have the compiler generate the map vs manually curating statusKindToString

Copy link
Contributor Author

@joamaki joamaki Jul 31, 2025

Choose a reason for hiding this comment

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

I wish I could do that, but since we have existing code doing string(foo.Status.Kind) we cannot do type StatusKind uint8 since string(uint8(0)) compiles and we want to force the code to switch to foo.Status.Kind.String(). Maybe in the future once all use-sites have converted over? For now I'd like to err on the safe side and do this trick here to force the use-sites to be fixed.

Also this has to be var instead of const since struct{...} cannot be const.

joamaki added 2 commits July 31, 2025 17:49
Error is rarely set, so we can save 8 bytes by using *string
instead of string.

This brings 'Status' size down to 56 from 64 bytes.

Signed-off-by: Jussi Maki <jussi.maki@isovalent.com>
This brings 'Status' size to 48 bytes from 56.
The struct fields were rearranged by "betteralign".

Signed-off-by: Jussi Maki <jussi.maki@isovalent.com>
@joamaki joamaki force-pushed the pr/joamaki/shrink-status branch from 86ffd17 to e4cada2 Compare July 31, 2025 15:49
@joamaki joamaki merged commit 7cc0def into main Jul 31, 2025
1 check passed
@joamaki joamaki deleted the pr/joamaki/shrink-status branch July 31, 2025 15:54
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