[PATCH] md/raid6 algorithms: scale test duration for speedier boots

From: Colin King
Date: Thu Sep 09 2021 - 10:01:39 EST


From: Colin Ian King <colin.king@xxxxxxxxxxxxx>

The original code runs for a set run time based on the duration of
2^RAID6_TIME_JIFFIES_LG2. The default kernel value for
RAID6_TIME_JIFFIES_LG2 is 4, however, emperical testing shows that a
value of 3.5 is the sweet spot for getting consistent benchmarking
results and speeding up the run time of the benchmarking.

To achieve 2^3.5 we use the following:
2^3.5 = 2^4 / 2^0.5
= 2^4 / sqrt(2)
= 2^4 * 0.707106781

Too keep this as integer math that is as accurate as required and avoiding
overflow, this becomes:
= 2^4 * 181 / 256
= (2^4 * 181) >> 8

We also need to scale down perf by the same factor, however, to
get a good approximate integer result without an overflow we scale
by 2^4.0 * sqrt(2) =
= 2 ^ 4 * 1.41421356237
= 2 ^ 4 * 1448 / 1024
= (2 ^ 4 * 1448) >> 10

This has been tested on 2 AWS instances, a small t2 and a medium m3
with 30 boot tests each and compared to the same instances booted 30
times on an umodified kernel. In all results, we get the same
algorithms being selected and a 100% consistent result over the 30
boots, showing that this optimised jiffy timing scaling does not break
the original functionality.

On the t2.small we see a saving of ~0.126 seconds and t3.medium a saving of
~0.18 seconds.

Tested on a 4 CPU VM on an 8 thread Xeon server; seeing a saving of ~0.35
seconds (average over 50 boots).

The testing included double checking the algorithm chosen by the optimized
selection and seeing the same as pre-optimised version.

Signed-off-by: Colin Ian King <colin.king@xxxxxxxxxxxxx>
---
lib/raid6/algos.c | 20 ++++++++++++--------
1 file changed, 12 insertions(+), 8 deletions(-)

diff --git a/lib/raid6/algos.c b/lib/raid6/algos.c
index 6d5e5000fdd7..5d5b04632168 100644
--- a/lib/raid6/algos.c
+++ b/lib/raid6/algos.c
@@ -152,6 +152,10 @@ static inline const struct raid6_calls *raid6_choose_gen(

for (bestgenperf = 0, bestxorperf = 0, best = NULL, algo = raid6_algos; *algo; algo++) {
if (!best || (*algo)->prefer >= best->prefer) {
+ /* 2 ^ (RAID6_TIME_JIFFIES_LG2 - 0.5) */
+ const unsigned long raid6_time_jiffies =
+ ((1 << RAID6_TIME_JIFFIES_LG2) * 181) >> 8;
+
if ((*algo)->valid && !(*algo)->valid())
continue;

@@ -167,7 +171,7 @@ static inline const struct raid6_calls *raid6_choose_gen(
while ((j1 = jiffies) == j0)
cpu_relax();
while (time_before(jiffies,
- j1 + (1<<RAID6_TIME_JIFFIES_LG2))) {
+ j1 + raid6_time_jiffies)) {
(*algo)->gen_syndrome(disks, PAGE_SIZE, *dptrs);
perf++;
}
@@ -178,8 +182,8 @@ static inline const struct raid6_calls *raid6_choose_gen(
best = *algo;
}
pr_info("raid6: %-8s gen() %5ld MB/s\n", (*algo)->name,
- (perf * HZ * (disks-2)) >>
- (20 - PAGE_SHIFT + RAID6_TIME_JIFFIES_LG2));
+ (((perf * HZ * (disks-2)) >>
+ (20 - 16 + RAID6_TIME_JIFFIES_LG2)) * 1448) >> 10);

if (!(*algo)->xor_syndrome)
continue;
@@ -191,7 +195,7 @@ static inline const struct raid6_calls *raid6_choose_gen(
while ((j1 = jiffies) == j0)
cpu_relax();
while (time_before(jiffies,
- j1 + (1<<RAID6_TIME_JIFFIES_LG2))) {
+ j1 + raid6_time_jiffies)) {
(*algo)->xor_syndrome(disks, start, stop,
PAGE_SIZE, *dptrs);
perf++;
@@ -202,8 +206,8 @@ static inline const struct raid6_calls *raid6_choose_gen(
bestxorperf = perf;

pr_info("raid6: %-8s xor() %5ld MB/s\n", (*algo)->name,
- (perf * HZ * (disks-2)) >>
- (20 - PAGE_SHIFT + RAID6_TIME_JIFFIES_LG2 + 1));
+ (((perf * HZ * (disks-2)) >>
+ (20 - 16 + RAID6_TIME_JIFFIES_LG2 + 1)) * 1448) >> 10);
}
}

@@ -215,8 +219,8 @@ static inline const struct raid6_calls *raid6_choose_gen(
(20 - PAGE_SHIFT+RAID6_TIME_JIFFIES_LG2));
if (best->xor_syndrome)
pr_info("raid6: .... xor() %ld MB/s, rmw enabled\n",
- (bestxorperf * HZ * (disks-2)) >>
- (20 - PAGE_SHIFT + RAID6_TIME_JIFFIES_LG2 + 1));
+ (((bestxorperf * HZ * (disks-2)) >>
+ (20 - 16 + RAID6_TIME_JIFFIES_LG2 + 1)) * 1448) >> 10);
} else
pr_info("raid6: skip pq benchmark and using algorithm %s\n",
best->name);
--
2.32.0