Hi Jan, Thanks for the additional results and for the suggestion.
I agree that it makes sense to separate the changes that are independent of the block-size question. I have split them into two patches: 0001 returns early when count == 0 or the source string is empty. 0002 uses memset() when the source string is one byte long. The doubling change is left out for now while the block-size behavior is investigated further. I also checked the glibc tunables on both of my x86 systems. On the i5-13500H system: glibc.cpu.x86_shared_cache_size: 0x1c0000 glibc.cpu.x86_non_temporal_threshold: 0x150000 glibc.cpu.x86_data_cache_size: 0xc000 The non-temporal threshold is 1.3125 MiB, so the first tested cap at or above it is 2 MiB. This matches the range that performed well in my earlier measurements. On the i9-12900H system: glibc.cpu.x86_shared_cache_size: 0x1940000 glibc.cpu.x86_non_temporal_threshold: 0xca0000 glibc.cpu.x86_data_cache_size: 0xc000 Here the non-temporal threshold is 12.625 MiB, so the first tested cap at or above it is 16 MiB. This also matches the earlier measurements, where cap16m was often the best choice for the larger-output cases. So the glibc non-temporal threshold appears to correlate well with the preferred cap on both of my x86 systems. I have attached the two smaller patches. The doubling change is not included in this version. Thanks, Chenhui
0001-Return-early-from-repeat-for-empty-results.patch
Description: Binary data
0002-Use-memset-in-repeat-for-single-byte-strings.patch
Description: Binary data
