Skip to content

PS-11428 get_rnd_index is limited by TSC resolution in newer CPU architectures - #6144

Open
marcinbabij wants to merge 2 commits into
percona:8.0from
marcinbabij:PS-11428-8.0
Open

PS-11428 get_rnd_index is limited by TSC resolution in newer CPU architectures#6144
marcinbabij wants to merge 2 commits into
percona:8.0from
marcinbabij:PS-11428-8.0

Conversation

@marcinbabij

Copy link
Copy Markdown

[1/2]

Problem:
With innodb_sync_array_size > 1, sync_array_get_and_reserve_cell
can hit ut_a(*cell != nullptr) and abort even though another
wait-array instance still has a free cell. A cell is expected
whenever any instance has space.

Root cause:
The retry loop calls sync_array_get() independently on every
iteration, up to sync_array_size times. That is sampling with
replacement: the same full instance can be chosen on every
try, so a free cell elsewhere is never visited. On 1024
instances with one free, P(miss) is (1023/1024)^1024 ~ 1/e
per call.

Fix:
Walk every instance once from a random start so a full
instance cannot hide a free cell in another instance.

[2/2]

Problem:
get_rnd_index() feeds sync wait-array start, ib_counter_t slots,
and sharded rw-lock S-latch. On CPUs whose RDTSC increments by
32, index % 32 is always 0, so those users hit one bucket.

Root cause:
my_timer_cycles() is used as the index with no mixing. A
constant TSC stride leaves low bits stuck.

Fix:
XOR the sample with itself shifted by 6. One shift and one
XOR after RDTSC. Covers strides up to 64 and keeps
increment-1 entropy.

Test plan

  • sync0arr-t
  • ut0rnd-t --gtest_filter='ut0counter.*'

…itectures [1/2]

Problem:
With innodb_sync_array_size > 1, sync_array_get_and_reserve_cell
can hit ut_a(*cell != nullptr) and abort even though another
wait-array instance still has a free cell. A cell is expected
whenever any instance has space.

Root cause:
The retry loop calls sync_array_get() independently on every
iteration, up to sync_array_size times. That is sampling with
replacement: the same full instance can be chosen on every
try, so a free cell elsewhere is never visited. On 1024
instances with one free, P(miss) is (1023/1024)^1024 ~ 1/e
per call.

Fix:
Walk every instance once from a random start so a full
instance cannot hide a free cell in another instance.
…itectures [2/2]

Problem:
get_rnd_index() feeds sync wait-array start, ib_counter_t slots,
and sharded rw-lock S-latch. On CPUs whose RDTSC increments by
32, `index % 32` is always 0, so those users hit one bucket.

Root cause:
my_timer_cycles() is used as the index with no mixing. A
constant TSC stride leaves low bits stuck.

Fix:
XOR the sample with itself shifted by 6. One shift and one
XOR after RDTSC. Covers strides up to 64 and keeps
increment-1 entropy.
@marcinbabij marcinbabij self-assigned this Sep 2, 2026
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.

1 participant