Skip to content

Place all long jumps in one pass over the flowgraph - #1718

Open
cicku wants to merge 1 commit into
the-tcpdump-group:masterfrom
cicku:optimize-long-jump-passes
Open

Place all long jumps in one pass over the flowgraph#1718
cicku wants to merge 1 commit into
the-tcpdump-group:masterfrom
cicku:optimize-long-jump-passes

Conversation

@cicku

@cicku cicku commented Aug 8, 2026

Copy link
Copy Markdown

A branch whose target is more than 255 instructions away needs an extra BPF_JA, and reserving room for one means laying the program out again. convert_code_r() returned on the first such branch it found, so a program needing N long jumps took N passes over the whole flowgraph to place them. That is most of the time spent compiling a filter with a few hundred "or"ed host/port pairs, with or without the optimizer.

Attempt to fix #1255.

@infrastation

Copy link
Copy Markdown
Member

Thank you for preparing this change. The commit message conceptually makes sense. The comment before the function makes sense except "A pass that marked something computes offsets that are too small, so a later pass can find more branches, but in practice only a few passes are needed." — this would need a bit more context or rewording to be comprehensible. The substantial part of the code changes looks roughly consistent with the comments, but I am not ready to reason whether the modified code would correctly handle all input in all scenarios and edge cases.

Unfortunately, there is no direct coverage of optimize.c at this point, and none of the existing tests are complex enough to exercise the target scenario indirectly even once. This is a very common code path and it would be highly desirable to cover this code with at least some tests before changing it.

As far as I understand, that would be generally difficult because it would require serialisation of graphs that are the input, the output and the intermediate data within iterations and recursions. However, in this specific case what convert_code_r() does with the current block at one recursion level looks mostly independent of what it does at other recursion levels with other blocks, so if block-scope code could be made an independent function or several functions, it would be much easier to test each such independent function using one sequence of statements as input and another as output. Of course, it would take some prototyping to confirm whether this approach works as expected. I may be able to do that later.

A branch whose target is more than 255 instructions away needs an extra
BPF_JA, and reserving room for one means laying the program out again.
convert_code_r() returned on the first such branch it found, so a program
needing N long jumps took N passes over the whole flowgraph to place
them.  That is most of the time spent compiling a filter with a few
hundred "or"ed host/port pairs, with or without the optimizer.

Mark them all in a pass instead.  A long jump only ever makes the program
longer, so a branch that does not fit now will not fit in a later pass
either.  The emitted BPF program is the same as before.
@cicku
cicku force-pushed the optimize-long-jump-passes branch from 2efa1be to a78bc05 Compare August 8, 2026 14:36
@cicku

cicku commented Sep 1, 2026

Copy link
Copy Markdown
Author

I updated the message a bit. Let me know what coverage test do you wish to have. If you want to implement, I can definitely wait.

@infrastation

Copy link
Copy Markdown
Member

Thank you, let me have a look later, I am currently busy with other work.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

Simple filter of 1000 hosts takes O(n²) to compile

2 participants