LibPhenom, a high-performance C eventing framework from Facebook
facebook.github.io
facebook.github.io
libevent/libev are easier to retrofit into existing applications. This looks like something you'd start a new application with. libuv is somewhere in the middle.
The `tests/bench/iopipes.t` "test" allows you to play with some concurrency parameters to try this for yourself on your hardware.
We haven't compared against libev.
We've added some more APIs (buffers and sockets) since those benchmarks were done and we don't have numbers to share around those yet.
One key difference between libevent, libev and libuv is that libphenom is inherently multithreaded in its IO dispatcher and timeout implementation.
If you're dispatching purely CPU bound jobs, we get very close to linear scaling with the number of cores: https://github.com/facebook/libphenom/commit/c2753c2154a0cff...
Contrast with the libevent approach of using an application specific scheme to assign descriptors to an event base associated with a thread (strong thread affinity).
This makes more of a difference if you have chatty protocols and/or long lived sessions and no way to rebalance your fd -> event_base mapping.
- printf calls malloc
- printf calls FPU emulator
- platforms differ over whether %p's output includes a leading 0x
- platforms differ over how you print int64_t/uint64_t
- platforms differ over how you print size_t
- some platforms have almost-ISO-but-not-quite semantics
Additionally, on top of the difficulty of adding extra types in a cross-platform fashion, the printf system is tied to the FILE . FILE s are usually not extensible, and on Windows don't work with sockets.
This is daft, and surprisingly shortsighted (perhaps it's the word "FILE" that causes people to come over all unimaginative?), because you could provide some system like Mac OS X's funopen, and then use fprintf for everything - maybe even replacing snprintf with it! - but functionality like this isn't as widely available as it should be.
Anyway, if you write your own printf, you can fix all of this.
Another fun one: FILE on Solaris can only be used with file descriptors whose value fits in 8 bits due to an astonishing degree of backwards ABI compatibility. Also on Solaris, printf("%s", NULL) -> crash but on other systems will print "(null)".
In our implementation we couldn't solve the frustrating size_t uint64_t stuff without disabling the compile time parameter checking that gcc provides; I value that more than the slight annoyance of PRIu64.
The platform was the Playstation2 and the issue was (as I recall) that the system's FPU supported floats but not doubles, and the supplied libc wasn't fully compatible with the compiler flag that effectively did a typedef float double. (I assume printf was affected because of the traditional varargs promotion rules.)
I suspect it was easier to write a new printf than figure out how to rebuild libc, assuming you were even allowed to link the final game to your own libc in the first place...
(As for the rest being simply differences between one platform and the next, that's quite true. (And you can usually work around to one degree or another - believe it or not I've worked on a number of multi-platform projects that didn't rewrite printf, though funnily enough every single one had to wrap it.) But then, for what reason does one do this sort of thing, except to remove these differences? You might as well rail against #define stricmp strcasecmp and the like - writing your own printf is just a difference of degree.)
I pick on printf in particular because most seasoned programmers consider copying and pasting code a smell, but is accepted for printf and friends.
In addition to reducing boilerplate and aiding portability, having our own printf implementation aids in consistent behavior across platforms, and allows for a deeper integration with our streams and buffers so that we don't need to make a series of clunky calls to measure how much storage is needed before passing the formatted data into the lower layers.
1) block at the caller, ever
2) have its data parameters pushed onto the stack
3) print all or nothing to a single buffer
4) identify the data type or modifier by the first letter of its English name (int, long, etc)
5) have its core modified to add functionality
Traditional eventing frameworks focused on non-blocking I/O on a single thread on the basis that you don't need so many resources to scale up to a large number of clients when compared to a simple one-thread-per-client model.
There's lot of good material discussing this at http://www.kegel.com/c10k.html
libphenom is a bit more than just an eventing framework though; we have a number of APIs that help with putting together the whole application. And we blur the lines a bit: we also have thread pooling and dispatch support for cases where your can't build 100% of your application in a non-blocking fashion.
We hope we do well here; we've had some nice results: https://github.com/facebook/libphenom/commit/c2753c2154a0cff...
I used libdispatch to prototype a server and would be great to compare with other libraries before starting the project.
libPhenom seems to have much more features, maybe even more than I need, but the documentation seems good. I will try to make another prototype with your lib.
Thanks.
I can't comment on performance.
http://stackoverflow.com/questions/5907071/clang-block-in-li...
Regarding roadmap, we'll try to keep the issue tracker on Github sync'd up with the broad goals and milestones, and we welcome feedback there too; they're a bit more dynamic and easier to update in real time than the docs and website materials.
Do you know of anything else that's using it?