-
-
Notifications
You must be signed in to change notification settings - Fork 1.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Implement while #1066
Implement while #1066
Conversation
Impressive! Amazing to see the backwards gotos. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of handling the continues/breaks in the various other control flow statements, would we be able to keep track of which loop we're in (with stacks of their BasicBlocks) and then implement them by emitting branches in void CodegenLLVM::visit(Jump &jump)
? It might help to isolate the complexity.
Just having bpftrace emit the IR without lots of other junk would be useful, but I think it'd be better to have it as an option under the -d
flag (#131) for flexibility and to avoid growing the list of arguments. Then we can run bpftrace -d ir input.bt > filename
to get it in a file if that's desired.
Oh I missed that you already were keeping a stack of BasicBlocks, still, the idea about emitting the branches in the Jump visitor instead might help. There's no harm in emitting more instructions at this stage than are actually needed - the optimiser will get rid of any that can't be reached later on - keeping things simple is more important. This might also help with implementing What's the point of reserving the |
Now that I have a working base it should be easier to shuffle things around and improve the logic a bit. Moving the jumps will indeed help a bit.
I've bumped into quite a few segfaults and hangs that seem to have ben caused empty labels and multiple sequential unconditional branches. E.g:
It crashes:
I'm not sure why it happens. The current
Not much, I initially wanted to implement is but might leave it for another PR.
I'll give that a go :) |
@ajor I've pushed a new version which I think improved the readability of I've also added a few TODOs for warnings, I'm not sure how to handle those, (@brendangregg )
|
Hmm I guess LLVM is expecting well formed basic blocks, it's a bit crap that it just segfaults though. If we do need valid basic blocks though, would creating a new one at the end of e.g.
|
Might as well allow jumps since they'll be forward only in an unrolled loop. I'm not sure why anyone would want a regular loop inside an unrolled one but don't seem the harm in allowing it through (I'm assuming it would just work unless we explicitly block it). |
ca2342b
to
414aa7d
Compare
I need to add docs but other than that this is ready for review. |
d31dffe
to
dfb401f
Compare
@olsajiri @danobi . I think this is pretty much done for a first version. All the basic parts seem to work. Testing itself is a bit tricky as it requires a new kernel but also because LLVM unrolls loops quite aggressively. Some improvements we can make in a future version (ill create tickets at some point)
I'll fix any codegen tests failures when everyone is happy with the codegen. |
it's working nicely under fedora 31 with its 5.5 kernel
I guess kernel will stop such program from loading, it all looks good to me, let's have it in soon ;-) |
Rebased onto master |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe add some runtime tests too? You can gate it on loop support like I did here: https://github.com/iovisor/bpftrace/blob/master/tests/runtime/builtin#L193
ec3fde8
to
e6b7a12
Compare
With loops the log buffer can get really big quickly, 10MB of log output is not uncommon. Trying to allocate a 10M log buffer on the stack causes issues so let's use the heap instead.
With the loop supported added in the 5.0 kernel we're now able to implement C-style while and for loops. Allowing us to write code like: ``` i:s:1 { $i = 0; while ($i < 100) { if ( ($i/10) * 10 == $i ) { printf("\n"); } if ( ($i/6)*6 == $i ){ printf("XX "); $i+=1; continue; } printf("%2d ", $i); $i+=1; if ($i >= 50) { break; } } } ``` To generate: ``` Attaching 1 probe... XX 1 2 3 4 5 XX 7 8 9 10 11 XX 13 14 15 16 17 XX 19 20 21 22 23 XX 25 26 27 28 29 XX 31 32 33 34 35 XX 37 38 39 40 41 XX 43 44 45 46 47 XX 49 ``` Using only a few instructions: ``` 203: perf_event name 1 tag 4881cacfe5abad41 gpl loaded_at 2020-03-26T18:17:17+0000 uid 0 xlated 448B jited 340B memlock 4096B map_ids 85 ``` Note that LLVM tries to unroll quite aggressively causing a loop the following be fully unrolled: ``` i:s:1 { $i = 0; while ($i < 30) { @=$i; $i++ } } ```
For some reason it seems to fail ~50% of the time in the CI. Let's disable it for now.
Removed the flaky test and the CI seems to be happy now. I'll merge this tomorrow if there are no further comments :) |
With the loop supported added in the 5.0 kernel we're now able to
implement C-style while and for loops. Allowing us to write code like:
To generate:
Using only a fewinstructions:
Note that LLVM tries to unroll quite aggressively causing a loop the
following be fully unrolled: