diff options
| author | Hagen Paul Pfeifer <hagen@jauu.net> | 2010-06-19 13:05:36 -0400 |
|---|---|---|
| committer | David S. Miller <davem@davemloft.net> | 2010-06-26 00:33:12 -0400 |
| commit | 01f2f3f6ef4d076c0c10a8a7b42624416d56b523 (patch) | |
| tree | 188ee181f2fe21e42f402c4a955cb6ea2e70f118 /include/linux | |
| parent | bd97a63f7d9892b4536f331d263c2695cc52d08c (diff) | |
net: optimize Berkeley Packet Filter (BPF) processing
Gcc is currenlty not in the ability to optimize the switch statement in
sk_run_filter() because of dense case labels. This patch replace the
OR'd labels with ordered sequenced case labels. The sk_chk_filter()
function is modified to patch/replace the original OPCODES in a
ordered but equivalent form. gcc is now in the ability to transform the
switch statement in sk_run_filter into a jump table of complexity O(1).
Until this patch gcc generates a sequence of conditional branches (O(n) of 567
byte .text segment size (arch x86_64):
7ff: 8b 06 mov (%rsi),%eax
801: 66 83 f8 35 cmp $0x35,%ax
805: 0f 84 d0 02 00 00 je adb <sk_run_filter+0x31d>
80b: 0f 87 07 01 00 00 ja 918 <sk_run_filter+0x15a>
811: 66 83 f8 15 cmp $0x15,%ax
815: 0f 84 c5 02 00 00 je ae0 <sk_run_filter+0x322>
81b: 77 73 ja 890 <sk_run_filter+0xd2>
81d: 66 83 f8 04 cmp $0x4,%ax
821: 0f 84 17 02 00 00 je a3e <sk_run_filter+0x280>
827: 77 29 ja 852 <sk_run_filter+0x94>
829: 66 83 f8 01 cmp $0x1,%ax
[...]
With the modification the compiler translate the switch statement into
the following jump table fragment:
7ff: 66 83 3e 2c cmpw $0x2c,(%rsi)
803: 0f 87 1f 02 00 00 ja a28 <sk_run_filter+0x26a>
809: 0f b7 06 movzwl (%rsi),%eax
80c: ff 24 c5 00 00 00 00 jmpq *0x0(,%rax,8)
813: 44 89 e3 mov %r12d,%ebx
816: e9 43 03 00 00 jmpq b5e <sk_run_filter+0x3a0>
81b: 41 89 dc mov %ebx,%r12d
81e: e9 3b 03 00 00 jmpq b5e <sk_run_filter+0x3a0>
Furthermore, I reordered the instructions to reduce cache line misses by
order the most common instruction to the start.
Signed-off-by: Hagen Paul Pfeifer <hagen@jauu.net>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'include/linux')
| -rw-r--r-- | include/linux/filter.h | 48 |
1 files changed, 48 insertions, 0 deletions
diff --git a/include/linux/filter.h b/include/linux/filter.h index 151f5d703b7e..69b43dbea6c6 100644 --- a/include/linux/filter.h +++ b/include/linux/filter.h | |||
| @@ -91,6 +91,54 @@ struct sock_fprog { /* Required for SO_ATTACH_FILTER. */ | |||
| 91 | #define BPF_TAX 0x00 | 91 | #define BPF_TAX 0x00 |
| 92 | #define BPF_TXA 0x80 | 92 | #define BPF_TXA 0x80 |
| 93 | 93 | ||
| 94 | enum { | ||
| 95 | BPF_S_RET_K = 0, | ||
| 96 | BPF_S_RET_A, | ||
| 97 | BPF_S_ALU_ADD_K, | ||
| 98 | BPF_S_ALU_ADD_X, | ||
| 99 | BPF_S_ALU_SUB_K, | ||
| 100 | BPF_S_ALU_SUB_X, | ||
| 101 | BPF_S_ALU_MUL_K, | ||
| 102 | BPF_S_ALU_MUL_X, | ||
| 103 | BPF_S_ALU_DIV_X, | ||
| 104 | BPF_S_ALU_AND_K, | ||
| 105 | BPF_S_ALU_AND_X, | ||
| 106 | BPF_S_ALU_OR_K, | ||
| 107 | BPF_S_ALU_OR_X, | ||
| 108 | BPF_S_ALU_LSH_K, | ||
| 109 | BPF_S_ALU_LSH_X, | ||
| 110 | BPF_S_ALU_RSH_K, | ||
| 111 | BPF_S_ALU_RSH_X, | ||
| 112 | BPF_S_ALU_NEG, | ||
| 113 | BPF_S_LD_W_ABS, | ||
| 114 | BPF_S_LD_H_ABS, | ||
| 115 | BPF_S_LD_B_ABS, | ||
| 116 | BPF_S_LD_W_LEN, | ||
| 117 | BPF_S_LD_W_IND, | ||
| 118 | BPF_S_LD_H_IND, | ||
| 119 | BPF_S_LD_B_IND, | ||
| 120 | BPF_S_LD_IMM, | ||
| 121 | BPF_S_LDX_W_LEN, | ||
| 122 | BPF_S_LDX_B_MSH, | ||
| 123 | BPF_S_LDX_IMM, | ||
| 124 | BPF_S_MISC_TAX, | ||
| 125 | BPF_S_MISC_TXA, | ||
| 126 | BPF_S_ALU_DIV_K, | ||
| 127 | BPF_S_LD_MEM, | ||
| 128 | BPF_S_LDX_MEM, | ||
| 129 | BPF_S_ST, | ||
| 130 | BPF_S_STX, | ||
| 131 | BPF_S_JMP_JA, | ||
| 132 | BPF_S_JMP_JEQ_K, | ||
| 133 | BPF_S_JMP_JEQ_X, | ||
| 134 | BPF_S_JMP_JGE_K, | ||
| 135 | BPF_S_JMP_JGE_X, | ||
| 136 | BPF_S_JMP_JGT_K, | ||
| 137 | BPF_S_JMP_JGT_X, | ||
| 138 | BPF_S_JMP_JSET_K, | ||
| 139 | BPF_S_JMP_JSET_X, | ||
| 140 | }; | ||
| 141 | |||
| 94 | #ifndef BPF_MAXINSNS | 142 | #ifndef BPF_MAXINSNS |
| 95 | #define BPF_MAXINSNS 4096 | 143 | #define BPF_MAXINSNS 4096 |
| 96 | #endif | 144 | #endif |
