fruneau
IMHO, the main benefit lost by using bleeding-edge extensions is portability, which may or may not be an issue.
First, we originally chose the C language because it is much much simpler. One can master the language without too much pain, and you end up having much more control on what you are actually doing (there's little chance a line of code does not do what you read from it... while in C++ you may have hidden behavior behind even the simpler operation such a + or *).
Secondly, and this is probably a matter of taste, C++11's lambdas are just awfully designed. Their syntax overloads, with a totally different meaning, some tokens such as []. As in many situations, C++ design committee tends to chose the most complicate possible design, without taking readability into account (maybe conciseness is the main goal of their syntax choices?). On the other, the blocks syntax makes is very clear you are dealing with a function-like object with very similar syntax. The choice was made to have a clean and readable syntax.
Third point, C++11 just didn't exist in 2009. There were drafts but support from compilers was just nascent. RHEL in 2009 was at version 6 (very young release) which ships with GCC 4.4 (and GCC 4.7 as an experimental toolchain). The most common RHEL was version 5 with GCC 4.1. RHEL officially supports C++11 since RHEL 7 which ships with GCC 4.8 and was release on June 2014.
I'm not aware of any attempt that successfully reached the upstream. GCC could have simply imported Apple patches if there were no licensing issues.
Block rewriting with Clang
That's exactly when you realise that you can get rid of that frustration if you introduce some complex caching, object pools or more complex structures. But the more complex it gets, the more frustrated you become (again). Finally, you end up writing something simple and efficient: a memory allocator that matches the exact allocation pattern of your use case... and you want to allocator to be as efficient as possible.
Memory – Part 6: Optimizing the FIFO and Stack allocators
What Are Your GCC Flags?
Memory locality
Mosh: remote shell that allows roaming
Only the runtime part is considered to be less feature-complete that valgrind (because the runtime part of ASan only keeps information about allocated memory, not about memory initialization). It is compile-time instrumentation that make it possible to detect stack and global oob.
Debugging Memory on Linux
The second drawback is that alloca allocates on the stack, as a consequence it is limited by the size of the stack (a few megabytes on recent linux distribution, and the actual size of remaining stack depends on the callstack, since each frame consumes some stack and may have put huge buffers/alloca on it already). The t_stack has no hard-limit.
Additionally, by being totally separated from the stack, the t_stack provides a flexible alternative to the stack: you have finer-grained control on allocation/deallocation patterns.
As said in another comment, the drawbacks of alloca are explained in the previous article of the series.
A use case for such pattern is a message-posting with workers: you queue some messages that are later unqueued and processed by a different thread. This is an increasingly common pattern in modern programs. In that pattern the message is allocated in one thread (let say the main one) and processed then deallocated by another thread.
If your implementation of message allocation is malloc-based, then you will stress the exact same code paths the benchmark is stressing.
Nowadays there is so little intelligence in the PHP that we only consider it as a pass-through layer.
Also, the choice of lot of allocations + lot of deallocations pattern was chosen because this is an issue we ran into quite recently: we allocated a huge tree structure progressively and sometimes we flushed it to disk. The flush was quite efficient, but the deallocation blocked the program during approximatively 30s. As a quick fix, we put the deallocation in background, but this slowed the tree construction down by approximatively 50% because of the contention of the allocator. Even if the size of the chunks in the article were not realistic, the results were near-realistic enough to be considered publishable.
I provided (in a separate comment) the result of the benchmarks with a 32-bytes payload (in that benchmark, all the allocators had the same 12% overhead in term of memory, but we clearly see the same performance pattern as with the 8-bytes payload).
Non-Contented test:
* ptmalloc: alloc 39M/s, free 49M/s
* tcmalloc: alloc 42M/s, free 40M/s
* jemalloc: alloc 21M/s, free 21M/s
* t_stack: alloc 110M/s
Contended test:
* ptmalloc: alloc 6.1M/s, free 6.4M/s
* tcmalloc: alloc 25M/s, free 11M/s
* jemalloc: alloc 18M/s, free 6.5M/s
Note that the results are less accurate that those provided in the article since the number of allocations per batch is smaller (due to the limited amount of RAM available on my desktop).
That's said, the article does not pretend benching realistic patterns.