-
Notifications
You must be signed in to change notification settings - Fork 238
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
Edge-triggered epoll events #3243
Conversation
Just to clarify, we would like to better follow what Linux does, but we just didn't have time to work on it (look in-depth into the Linux behaviour, consider the best way to design it, any performance implications, etc). If Shadow can better model the Linux behaviour, have a bunch of tests for it, and not significantly slow down the simulator, then I think it would be great to have this behaviour. IIRC the old PR didn't pass all of the tests, and Shadow's old C epoll code was a bit difficult to follow, so we also were more worried about introducing bugs. Now with the epoll code in rust, we can hopefully be more confident in any changes. I'll leave a few comments that I have, but I'm not as knowledgeable about epoll so I'll let other people weigh in on this PR.
I think before merging we would want this to be consistent across Shadow for all file types, unless Linux does differently. And this is where tests would be useful, to make sure all of the file types behave this way. IIRC pipes also have this edge-triggered behaviour on Linux. |
I totally agree with @stevenengler here. We added epoll in rust but I never got around to adding the tests to help fuzz test the epoll api. Those fuzz tests would help us make sure we are following the Linux behavior, even if the Linux behavior is not the same as what is documented in the man pages. If we have the tests that show the Linux behavior and Shadow behaves exactly the same, that will give us a strong argument to merge. |
I'd expect that this causes more state updates, resulting in the event source running more callbacks, but the current version of this PR doesn't seem to effect tor simulation runtime performance. |
Totally agree, however, since this patch is quite hacky and we don't know yet how we should implement it. I will implement the rest when we know it, otherwise the effort will be wasted. |
@robgjansen @stevenengler Are you okay with the If you are okay to merge it with that, I will do all the necessary work on that to get it merged: fuzz tests, other tests, and edge-triggered event for all the file types. My current feeling is that, if we don't want Honestly, I'm not sure if the proper way will be really too big, I just feel that it will be. Let me think a moment to find a better way with small change. |
I think my opinion is that it's okay. In that case the flag should have a comment explaining why it's done this way, and that it's an exception. Alternatively, what do you think of the design in #3250? Do you think this covers everything that you'd need to support epoll? It adds a new argument for listeners so that files can emit signals and listeners can opt to receive them. It might be overkill for this, but we might want this ability to emit other types of signals in the future as well. |
We've now merged #3250, so it should be ready to use in this PR. So what we're looking for before we can merge this PR is:
Thanks for working on this! TestsWe have some existing C epoll tests in You can test the epoll syscalls using the libc library (ex: For us as maintainers, we don't really know exactly how linux behaves with this edge-triggered-but-not-really-edge-triggered epoll, so the the more tests you add the easier it will be to convince us that the changes accurately follow linux and that it's good to merge. |
From the test I implemented in #3274, the answer is no in Linux. However, it's surprising that the answer is yes in the current main branch of Shadow. Since I don't want to pay the effort fixing this and I don't know any application depending on that behaviour, I will not add such the test in this PR. |
Thanks for making that issue and writing a test case! If you want to, you can add the test to Shadow but in the |
@stevenengler What is the state of In order to implement edge-triggered epoll for pipe and unix sockets, it seems like I have to implement If you are planning to deprecate |
I found strange behaviour on the output buffer. This edge-triggered thing occurs on the output buffer of udp sockets, but not tcp sockets or unix datagram sockets. I think it will take too much effort doing research on this, so I will not add the tests for those cases. |
I think we still want it in the long term. We need some kind of shared buffer between two files (or sometimes more if there are multiple readers or writers).
I forgot about the
Okay thanks for checking. I think it's okay to leave the output buffer out of the scope of this PR then. But please open an issue so we can remember that this edge-triggered behaviour doesn't follow linux for all output buffers and that it needs more investigation. |
Yes, I have mine already and it looks exactly like yours in #3276 (except some in unix.rs) |
@stevenengler What is your preferred way to do
In test_epoll.rs, it uses |
The preferred is option (2). In the tests, if it's a syscall that you're specifically testing, then use plain So in |
@stevenengler it's ready for your eyes |
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.
It's looking good! I still have a few more files to look through (unix.rs, the rust tcp files, and only quickly looked through test_epoll_edge.rs), but thought I'd leave the comments I have so far. They're all minor comments, and two additional tests I think would be good to have.
In the old code when adding or removing data from a socket buffer, a socket.c function would update the file state (called the "status" in the C code), then a tcp.c function might also update the file state. For example `tcp_receiveUserData` would call `legacysocket_removeFromInputBuffer` which would update the state, and then `tcp_receiveUserData` would later also update the state. This would lead to situations where socket.c would remove the READABLE flag, and then tcp.c would immediately add it back. While the end result is that the flag would effectively appear unchanged, this would cause edge-triggered epoll to think that the file's state changed twice even though it effectively didn't, leading to #3274. Since the TCP code is the only C socket code left, now the socket.c code no longer updates the file state (with an exception of `legacysocket_pullOutPacket`) and the tcp.c code is responsible for updating the file state. The added test was authored by @ppoth in #3274. We should also be testing other socket/file types, but I think this will be easier once the new `test_epoll_edge.rs` tests in #3243 are merged. I did test udp and unix sockets manually and the new test passes for them as well. Closes #3274. **Edit:** The runtime performance is equivalent, but the simulation results change, so I want to take another look at this. https://github.com/shadow/benchmark-results/blob/master/tor/2024-01-07-T22-11-55/README.md **Edit 2:** I think it's expected that the simulation results would change. Before we would remove the `READABLE` flag and then add it back again, which would reset the epoll entry's priority each time a packet was pushed to a TCP socket. Now the priority is reset only when the event is collected. This means that epoll events will be processed in a different order than they previously were.
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.
Looks good! I think the improved edge-triggered epoll and tests will be a big improvement. All of the requested changes should be small, and then there are two additional tests I think would be good to have. After this I'll do a last benchmark run and then I expect we can merge it.
- use the new signal mechanism instead of the INPUT_BUFFER_PARITY state
Done.
- use the new edge-triggered epoll behaviour in all file types (udp, pipe, etc) and not just eventfd/tcp, as long as linux does as well (the tests should show which files do or don't)
Done.
- does this edge-triggered behaviour occur only on the input buffer, or also the output buffer?
@ppopth Once this is merged, can you make an issue for supporting the UDP output buffer behaviour you observed?
- for the input buffer, does the edge-triggered behaviour occur when either reading or writing from/to the buffer? (Does reading from the buffer also trigger epoll?)
Done. There was a related bug #3274 where a partial read would trigger edge-triggered epoll in shadow but not Linux. This was fixed in #3277. This current PR contains a test that checks this for all sockets and pipes.
- new syscall tests in rust that test edge-triggered epoll under these various conditions for different file types to make sure that shadow behaves the same as linux
Done. The new tests check tcp, udp, unix sockets (all three types), pipes (stream and packet modes), and eventfds.
In #3277 I moved the |
I resolved the conflict by merging instead of rebasing so that I would not lose the history. I will rebase it later. |
@stevenengler it's ready for your eyes |
Looks good! Just do a rebase, then I'll approve it, run the benchmark, and merge it. |
@stevenengler it's all done. Can you please add a milestone to this PR? |
No change to the tor benchmark. I don't think tor uses edge-triggered epoll, so this should be expected. |
Thanks @ppopth! |
EDITED: I have already implemented this feature for tcp sockets, udp sockets, unix domain sockets, pipes, eventfds.