History

x86/csum: clean up `csum_partial' further

Commit 688eb8191b47 ("x86/csum: Improve performance of `csum_partial`") ended up improving the code generation for the IP csum calculations, and in particular special-casing the 40-byte case that is a hot case for IPv6 headers. It then had _another_ special case for the 64-byte unrolled loop, which did two chains of 32-byte blocks, which allows modern CPU's to improve performance by doing the chains in parallel thanks to renaming the carry flag. This just unifies the special cases and combines them into just one single helper the 40-byte csum case, and replaces the 64-byte case by a 80-byte case that just does that single helper twice. It avoids having all these different versions of inline assembly, and actually improved performance further in my tests. There was never anything magical about the 64-byte unrolled case, even though it happens to be a common size (and typically is the cacheline size).

Linus Torvalds committed 3 years ago

Commit a476aae1 parent 5d4acb61 file · +37 −44Browse files

Unified · Split

arch/x86/lib/csum-partial_64.c+37−44
@@ -16,6 +16,20 @@ static inline __wsum csum_finalize_sum(u64 temp64) · 15 unmodified lines
16 return (__force __wsum)((temp64 + ror64(temp64, 32)) >> 32);16 return (__force __wsum)((temp64 + ror64(temp64, 32)) >> 32);
17}17}
18 18
19static inline unsigned long update_csum_40b(unsigned long sum, const unsigned long m[5])
20{
21 asm("addq %1,%0\n\t"
22 "adcq %2,%0\n\t"
23 "adcq %3,%0\n\t"
24 "adcq %4,%0\n\t"
25 "adcq %5,%0\n\t"
26 "adcq $0,%0"
27 :"+r" (sum)
28 :"m" (m[0]), "m" (m[1]), "m" (m[2]),
29 "m" (m[3]), "m" (m[4]));
30 return sum;
31}
32
19/*33/*
20 * Do a checksum on an arbitrary memory area.34 * Do a checksum on an arbitrary memory area.
21 * Returns a 32bit checksum.35 * Returns a 32bit checksum.
@@ -31,52 +45,31 @@ __wsum csum_partial(const void *buff, int len, __wsum sum) · 9 unmodified lines
31{45{
32 u64 temp64 = (__force u64)sum;46 u64 temp64 = (__force u64)sum;
33 47
34 /*48 /* Do two 40-byte chunks in parallel to get better ILP */
35 * len == 40 is the hot case due to IPv6 headers, but annotating it likely()49 if (likely(len >= 80)) {
36 * has noticeable negative affect on codegen for all other cases with50 u64 temp64_2 = 0;
37 * minimal performance benefit here.51 do {
38 */52 temp64 = update_csum_40b(temp64, buff);
39 if (len == 40) {53 temp64_2 = update_csum_40b(temp64_2, buff + 40);
40 asm("addq 0*8(%[src]),%[res]\n\t"54 buff += 80;
41 "adcq 1*8(%[src]),%[res]\n\t"55 len -= 80;
42 "adcq 2*8(%[src]),%[res]\n\t"56 } while (len >= 80);
43 "adcq 3*8(%[src]),%[res]\n\t"57
44 "adcq 4*8(%[src]),%[res]\n\t"58 asm("addq %1,%0\n\t"
45 "adcq $0,%[res]"59 "adcq $0,%0"
46 : [res] "+r"(temp64)60 :"+r" (temp64): "r" (temp64_2));
47 : [src] "r"(buff), "m"(*(const char(*)[40])buff));
48 return csum_finalize_sum(temp64);
49 }61 }
50 if (unlikely(len >= 64)) {
51 /*
52 * Extra accumulators for better ILP in the loop.
53 */
54 u64 tmp_accum, tmp_carries;
55 62
56 asm("xorl %k[tmp_accum],%k[tmp_accum]\n\t"63 /*
57 "xorl %k[tmp_carries],%k[tmp_carries]\n\t"64 * len == 40 is the hot case due to IPv6 headers, so return
58 "subl $64, %[len]\n\t"65 * early for that exact case without checking the tail bytes.
59 "1:\n\t"66 */
60 "addq 0*8(%[src]),%[res]\n\t"67 if (len >= 40) {
61 "adcq 1*8(%[src]),%[res]\n\t"68 temp64 = update_csum_40b(temp64, buff);
62 "adcq 2*8(%[src]),%[res]\n\t"69 len -= 40;
63 "adcq 3*8(%[src]),%[res]\n\t"70 if (!len)
64 "adcl $0,%k[tmp_carries]\n\t"71 return csum_finalize_sum(temp64);
65 "addq 4*8(%[src]),%[tmp_accum]\n\t"72 buff += 40;
66 "adcq 5*8(%[src]),%[tmp_accum]\n\t"
67 "adcq 6*8(%[src]),%[tmp_accum]\n\t"
68 "adcq 7*8(%[src]),%[tmp_accum]\n\t"
69 "adcl $0,%k[tmp_carries]\n\t"
70 "addq $64, %[src]\n\t"
71 "subl $64, %[len]\n\t"
72 "jge 1b\n\t"
73 "addq %[tmp_accum],%[res]\n\t"
74 "adcq %[tmp_carries],%[res]\n\t"
75 "adcq $0,%[res]"
76 : [tmp_accum] "=&r"(tmp_accum),
77 [tmp_carries] "=&r"(tmp_carries), [res] "+r"(temp64),
78 [len] "+r"(len), [src] "+r"(buff)
79 : "m"(*(const char *)buff));
80 }73 }
81 74
82 if (len & 32) {75 if (len & 32) {

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t