// SPDX-License-Identifier: GPL-2.0
#include <kunit/test.h>
#include "mean_and_variance.h"
#define MAX_SQR (SQRT_U64_MAX*SQRT_U64_MAX)
static void mean_and_variance_basic_test(
struct kunit *test)
{
struct mean_and_variance s = {};
mean_and_variance_update(&s,
2 );
mean_and_variance_update(&s,
2 );
KUNIT_EXPECT_EQ(test, mean_and_variance_get_mean(s),
2 );
KUNIT_EXPECT_EQ(test, mean_and_variance_get_variance(s),
0 );
KUNIT_EXPECT_EQ(test, s.n,
2 );
mean_and_variance_update(&s,
4 );
mean_and_variance_update(&s,
4 );
KUNIT_EXPECT_EQ(test, mean_and_variance_get_mean(s),
3 );
KUNIT_EXPECT_EQ(test, mean_and_variance_get_variance(s),
1 );
KUNIT_EXPECT_EQ(test, s.n,
4 );
}
/*
* Test values computed using a spreadsheet from the psuedocode at the bottom:
* https://fanf2.user.srcf.net/hermes/doc/antiforgery/stats.pdf
*/
static void mean_and_variance_weighted_test(
struct kunit *test)
{
struct mean_and_variance_weighted s = { };
mean_and_variance_weighted_update(&s,
10 ,
false ,
2 );
KUNIT_EXPECT_EQ(test, mean_and_variance_weighted_get_mean(s,
2 ),
10 );
KUNIT_EXPECT_EQ(test, mean_and_variance_weighted_get_variance(s,
2 ),
0 );
mean_and_variance_weighted_update(&s,
20 ,
true ,
2 );
KUNIT_EXPECT_EQ(test, mean_and_variance_weighted_get_mean(s,
2 ),
12 );
KUNIT_EXPECT_EQ(test, mean_and_variance_weighted_get_variance(s,
2 ),
18 );
mean_and_variance_weighted_update(&s,
30 ,
true ,
2 );
KUNIT_EXPECT_EQ(test, mean_and_variance_weighted_get_mean(s,
2 ),
16 );
KUNIT_EXPECT_EQ(test, mean_and_variance_weighted_get_variance(s,
2 ),
72 );
s = (
struct mean_and_variance_weighted) { };
mean_and_variance_weighted_update(&s, -
10 ,
false ,
2 );
KUNIT_EXPECT_EQ(test, mean_and_variance_weighted_get_mean(s,
2 ), -
10 );
KUNIT_EXPECT_EQ(test, mean_and_variance_weighted_get_variance(s,
2 ),
0 );
mean_and_variance_weighted_update(&s, -
20 ,
true ,
2 );
KUNIT_EXPECT_EQ(test, mean_and_variance_weighted_get_mean(s,
2 ), -
12 );
KUNIT_EXPECT_EQ(test, mean_and_variance_weighted_get_variance(s,
2 ),
18 );
mean_and_variance_weighted_update(&s, -
30 ,
true ,
2 );
KUNIT_EXPECT_EQ(test, mean_and_variance_weighted_get_mean(s,
2 ), -
16 );
KUNIT_EXPECT_EQ(test, mean_and_variance_weighted_get_variance(s,
2 ),
72 );
}
static void mean_and_variance_weighted_advanced_test(
struct kunit *test)
{
struct mean_and_variance_weighted s = { };
bool initted =
false ;
s64 i;
for (i =
10 ; i <=
100 ; i +=
10 ) {
mean_and_variance_weighted_update(&s, i, initted,
8 );
initted =
true ;
}
KUNIT_EXPECT_EQ(test, mean_and_variance_weighted_get_mean(s,
8 ),
11 );
KUNIT_EXPECT_EQ(test, mean_and_variance_weighted_get_variance(s,
8 ),
107 );
s = (
struct mean_and_variance_weighted) { };
initted =
false ;
for (i = -
10 ; i >= -
100 ; i -=
10 ) {
mean_and_variance_weighted_update(&s, i, initted,
8 );
initted =
true ;
}
KUNIT_EXPECT_EQ(test, mean_and_variance_weighted_get_mean(s,
8 ), -
11 );
KUNIT_EXPECT_EQ(test, mean_and_variance_weighted_get_variance(s,
8 ),
107 );
}
static void do_mean_and_variance_test(
struct kunit *test,
s64 initial_value,
s64 initial_n,
s64 n,
unsigned weight,
s64 *data,
s64 *mean,
s64 *stddev,
s64 *weighted_mean,
s64 *weighted_stddev)
{
struct mean_and_variance mv = {};
struct mean_and_variance_weighted vw = { };
for (
unsigned i =
0 ; i < initial_n; i++) {
mean_and_variance_update(&mv, initial_value);
mean_and_variance_weighted_update(&vw, initial_value,
false , weight);
KUNIT_EXPECT_EQ(test, mean_and_variance_get_mean(mv), initial_value);
KUNIT_EXPECT_EQ(test, mean_and_variance_get_stddev(mv),
0 );
KUNIT_EXPECT_EQ(test, mean_and_variance_weighted_get_mean(vw, weight), initial_valu
e);
KUNIT_EXPECT_EQ(test, mean_and_variance_weighted_get_stddev(vw, weight),0 );
}
for (unsigned i = 0 ; i < n; i++) {
mean_and_variance_update(&mv, data[i]);
mean_and_variance_weighted_update(&vw, data[i], true , weight);
KUNIT_EXPECT_EQ(test, mean_and_variance_get_mean(mv), mean[i]);
KUNIT_EXPECT_EQ(test, mean_and_variance_get_stddev(mv), stddev[i]);
KUNIT_EXPECT_EQ(test, mean_and_variance_weighted_get_mean(vw, weight), weighted_mean[i]);
KUNIT_EXPECT_EQ(test, mean_and_variance_weighted_get_stddev(vw, weight),weighted_stddev[i]);
}
KUNIT_EXPECT_EQ(test, mv.n, initial_n + n);
}
/* Test behaviour with a single outlier, then back to steady state: */
static void mean_and_variance_test_1(struct kunit *test)
{
s64 d[] = { 100 , 10 , 10 , 10 , 10 , 10 , 10 };
s64 mean[] = { 22 , 21 , 20 , 19 , 18 , 17 , 16 };
s64 stddev[] = { 32 , 29 , 28 , 27 , 26 , 25 , 24 };
s64 weighted_mean[] = { 32 , 27 , 22 , 19 , 17 , 15 , 14 };
s64 weighted_stddev[] = { 38 , 35 , 31 , 27 , 24 , 21 , 18 };
do_mean_and_variance_test(test, 10 , 6 , ARRAY_SIZE(d), 2 ,
d, mean, stddev, weighted_mean, weighted_stddev);
}
/* Test behaviour where we switch from one steady state to another: */
static void mean_and_variance_test_2(struct kunit *test)
{
s64 d[] = { 100 , 100 , 100 , 100 , 100 };
s64 mean[] = { 22 , 32 , 40 , 46 , 50 };
s64 stddev[] = { 32 , 39 , 42 , 44 , 45 };
s64 weighted_mean[] = { 32 , 49 , 61 , 71 , 78 };
s64 weighted_stddev[] = { 38 , 44 , 44 , 41 , 38 };
do_mean_and_variance_test(test, 10 , 6 , ARRAY_SIZE(d), 2 ,
d, mean, stddev, weighted_mean, weighted_stddev);
}
static void mean_and_variance_fast_divpow2(struct kunit *test)
{
s64 i;
u8 d;
for (i = 0 ; i < 100 ; i++) {
d = 0 ;
KUNIT_EXPECT_EQ(test, fast_divpow2(i, d), div_u64(i, 1 LLU << d));
KUNIT_EXPECT_EQ(test, abs(fast_divpow2(-i, d)), div_u64(i, 1 LLU << d));
for (d = 1 ; d < 32 ; d++) {
KUNIT_EXPECT_EQ_MSG(test, abs(fast_divpow2(i, d)),
div_u64(i, 1 << d), "%lld %u" , i, d);
KUNIT_EXPECT_EQ_MSG(test, abs(fast_divpow2(-i, d)),
div_u64(i, 1 << d), "%lld %u" , -i, d);
}
}
}
static void mean_and_variance_u128_basic_test(struct kunit *test)
{
u128_u a = u64s_to_u128(0 , U64_MAX);
u128_u a1 = u64s_to_u128(0 , 1 );
u128_u b = u64s_to_u128(1 , 0 );
u128_u c = u64s_to_u128(0 , 1 LLU << 63 );
u128_u c2 = u64s_to_u128(U64_MAX, U64_MAX);
KUNIT_EXPECT_EQ(test, u128_hi(u128_add(a, a1)), 1 );
KUNIT_EXPECT_EQ(test, u128_lo(u128_add(a, a1)), 0 );
KUNIT_EXPECT_EQ(test, u128_hi(u128_add(a1, a)), 1 );
KUNIT_EXPECT_EQ(test, u128_lo(u128_add(a1, a)), 0 );
KUNIT_EXPECT_EQ(test, u128_lo(u128_sub(b, a1)), U64_MAX);
KUNIT_EXPECT_EQ(test, u128_hi(u128_sub(b, a1)), 0 );
KUNIT_EXPECT_EQ(test, u128_hi(u128_shl(c, 1 )), 1 );
KUNIT_EXPECT_EQ(test, u128_lo(u128_shl(c, 1 )), 0 );
KUNIT_EXPECT_EQ(test, u128_hi(u128_square(U64_MAX)), U64_MAX - 1 );
KUNIT_EXPECT_EQ(test, u128_lo(u128_square(U64_MAX)), 1 );
KUNIT_EXPECT_EQ(test, u128_lo(u128_div(b, 2 )), 1 LLU << 63 );
KUNIT_EXPECT_EQ(test, u128_hi(u128_div(c2, 2 )), U64_MAX >> 1 );
KUNIT_EXPECT_EQ(test, u128_lo(u128_div(c2, 2 )), U64_MAX);
KUNIT_EXPECT_EQ(test, u128_hi(u128_div(u128_shl(u64_to_u128(U64_MAX), 32 ), 2 )), U32_MAX >> 1 );
KUNIT_EXPECT_EQ(test, u128_lo(u128_div(u128_shl(u64_to_u128(U64_MAX), 32 ), 2 )), U64_MAX << 31 );
}
static struct kunit_case mean_and_variance_test_cases[] = {
KUNIT_CASE(mean_and_variance_fast_divpow2),
KUNIT_CASE(mean_and_variance_u128_basic_test),
KUNIT_CASE(mean_and_variance_basic_test),
KUNIT_CASE(mean_and_variance_weighted_test),
KUNIT_CASE(mean_and_variance_weighted_advanced_test),
KUNIT_CASE(mean_and_variance_test_1),
KUNIT_CASE(mean_and_variance_test_2),
{}
};
static struct kunit_suite mean_and_variance_test_suite = {
.name = "mean and variance tests" ,
.test_cases = mean_and_variance_test_cases
};
kunit_test_suite(mean_and_variance_test_suite);
MODULE_AUTHOR("Daniel B. Hill" );
MODULE_DESCRIPTION("bcachefs filesystem mean and variance unit tests" );
MODULE_LICENSE("GPL" );
Messung V0.5 in Prozent C=96 H=93 G=94
¤ Dauer der Verarbeitung: 0.9 Sekunden
(vorverarbeitet am 2026-06-07)
¤
*© Formatika GbR, Deutschland