xref: /linux/lib/dim/dim_kunit.c (revision 7e170da2edec9fb0717543571cc14b0aabee2b46)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * KUnit tests for the Dynamic Interrupt Moderation library
4  */
5 
6 #include <kunit/test.h>
7 #include <linux/dim.h>
8 #include <linux/ktime.h>
9 #include <linux/module.h>
10 
11 struct dim_calc_stats_case {
12 	const char *name;
13 	u32 delta_us;
14 	u32 start_pkts, end_pkts;
15 	u32 start_bytes, end_bytes;
16 	u32 start_comps, end_comps;
17 	int ppms, bpms, cpms;
18 };
19 
20 static const struct dim_calc_stats_case dim_calc_stats_cases[] = {
21 	{
22 		.name = "small",
23 		.delta_us = 1000,
24 		.end_pkts = 640, .end_bytes = 640 * 1500, .end_comps = 64,
25 		.ppms = 640, .bpms = 960000, .cpms = 64,
26 	},
27 	{
28 		.name = "round_up",
29 		.delta_us = 3000,
30 		.end_pkts = 10, .end_bytes = 10, .end_comps = 1,
31 		.ppms = 4, .bpms = 4, .cpms = 1,
32 	},
33 	{
34 		.name = "counter_wrap",
35 		.delta_us = 1000,
36 		.start_pkts = 0xffffff00, .end_pkts = 0x100,
37 		.start_bytes = 0xfffff000, .end_bytes = 0x1000,
38 		.start_comps = 0xfffffff0, .end_comps = 0x10,
39 		.ppms = 0x200, .bpms = 0x2000, .cpms = 0x20,
40 	},
41 	{
42 		/* 30 MB in 10 ms (24 Gbit/s): nbytes * 1000 exceeds 32 bits */
43 		.name = "many_bytes",
44 		.delta_us = 10000,
45 		.end_pkts = 20000, .end_bytes = 30000000, .end_comps = 64,
46 		.ppms = 2000, .bpms = 3000000, .cpms = 7,
47 	},
48 	{
49 		/* 4.3 MB in 16 ms (2.15 Gbit/s), just above the 32-bit limit */
50 		.name = "bytes_32bit_limit",
51 		.delta_us = 16000,
52 		.end_pkts = 2900, .end_bytes = 4300000, .end_comps = 64,
53 		.ppms = 182, .bpms = 268750, .cpms = 4,
54 	},
55 	{
56 		/* 5 MB in 40 ms: a 1 Gbit/s link at line rate */
57 		.name = "gigabit",
58 		.delta_us = 40000,
59 		.end_pkts = 3300, .end_bytes = 5000000, .end_comps = 64,
60 		.ppms = 83, .bpms = 125000, .cpms = 2,
61 	},
62 	{
63 		/* 5 million packets and completions in 2 s */
64 		.name = "many_packets",
65 		.delta_us = 2000000,
66 		.end_pkts = 5000000, .end_bytes = 5000000, .end_comps = 5000000,
67 		.ppms = 2500, .bpms = 2500, .cpms = 2500,
68 	},
69 };
70 
71 static void dim_calc_stats_case_desc(const struct dim_calc_stats_case *t,
72 				     char *desc)
73 {
74 	strscpy(desc, t->name, KUNIT_PARAM_DESC_SIZE);
75 }
76 
77 KUNIT_ARRAY_PARAM(dim_calc_stats, dim_calc_stats_cases,
78 		  dim_calc_stats_case_desc);
79 
80 static void dim_calc_stats_test(struct kunit *test)
81 {
82 	const struct dim_calc_stats_case *t = test->param_value;
83 	struct dim_sample start = {}, end = {};
84 	struct dim_stats stats = {};
85 
86 	dim_update_sample_with_comps(0, t->start_pkts, t->start_bytes,
87 				     t->start_comps, &start);
88 	dim_update_sample_with_comps(DIM_NEVENTS, t->end_pkts, t->end_bytes,
89 				     t->end_comps, &end);
90 	/* dim_update_sample() stamps ktime_get(); use fixed times instead */
91 	start.time = ktime_set(1000, 0);
92 	end.time = ktime_add_us(start.time, t->delta_us);
93 
94 	KUNIT_ASSERT_TRUE(test, dim_calc_stats(&start, &end, &stats));
95 	KUNIT_EXPECT_EQ(test, stats.ppms, t->ppms);
96 	KUNIT_EXPECT_EQ(test, stats.bpms, t->bpms);
97 	KUNIT_EXPECT_EQ(test, stats.cpms, t->cpms);
98 	KUNIT_EXPECT_EQ(test, stats.epms,
99 			(int)DIV_ROUND_UP(DIM_NEVENTS * USEC_PER_MSEC,
100 					  t->delta_us));
101 }
102 
103 static void dim_calc_stats_no_time_test(struct kunit *test)
104 {
105 	struct dim_sample sample = {};
106 	struct dim_stats stats = {};
107 
108 	dim_update_sample_with_comps(0, 100, 1000, 10, &sample);
109 	KUNIT_EXPECT_FALSE(test, dim_calc_stats(&sample, &sample, &stats));
110 }
111 
112 static struct kunit_case dim_test_cases[] = {
113 	KUNIT_CASE_PARAM(dim_calc_stats_test, dim_calc_stats_gen_params),
114 	KUNIT_CASE(dim_calc_stats_no_time_test),
115 	{}
116 };
117 
118 static struct kunit_suite dim_test_suite = {
119 	.name = "dim",
120 	.test_cases = dim_test_cases,
121 };
122 
123 kunit_test_suite(dim_test_suite);
124 
125 MODULE_DESCRIPTION("KUnit tests for the DIM library");
126 MODULE_LICENSE("GPL");
127