Earlier quoted context omitted.
They address that somewhat in the discussion section: > C++ provides many features for more explicit memory management than is possible with reference counting. For example, it provides allocators [35] to decouple memory management from handling of objects in containers. In principle, this may make it possible to use such an allocator to allocate temporary objects that are known to become obsolete during the dealloca…
Of course you can use better allocators; but it's faster to avoid dynamic allocation (e.g. by pointing to memory mapped from the input file by the OS) altogether. If they allocate memory for each flyspeck of a 200 GB file and also create and change a reference counter for it, nobody should be surprised about the low performance. Have a look what e.g. shared_ptr does behind the scenes.
Comparison of C++17, Go, and Java for a next-generation sequencing tool
91–100 of 190 posts
Re: Comparison of C++17, Go, and Java for a next-generation sequencing tool
#92Earlier quoted context omitted.
> elPrep is an open-ended software framework that allows for arbitrary combinations of different functional steps in a pipeline, like duplicate marking, sorting reads, replacing read groups, and so on; additionally, elPrep also accommodates functional steps provided by third-party tool writers. This openness makes it difficult to precisely determine the lifetime of allocated objects during a program run > Phase 1 all…
Well, one thing that jumps out immediately to me is that everything appears to be using shared_ptr. And by that I mean everything. Why is everything shared? What does it even mean to have a shared_ptr ? Arbitrary mixed writes to a string seems like a bad idea, so shouldn't that be unique_ptr? Or like this: auto alns = make_shared >>(); A shared_ptr to a deque of shared_ptrs? deque isn't thread-safe, why would it be s…
Re: Comparison of C++17, Go, and Java for a next-generation sequencing tool
#93Earlier quoted context omitted.
If either of those affects performance there are WAY too many memory allocations happening.
Sure, but I guess that's the point --- the GCs in Java and Go can handle any allocation pattern you throw at them reasonably well, but there's not, as far as I know, such a "one-size-fits-all" solution in C++ (not that it needs one.)
Re: Comparison of C++17, Go, and Java for a next-generation sequencing tool
#94I had a quick look at the C++ source code provided at https://github.com/ExaScience/elprep-bench/tree/master/cpp . As suspected, everything is dynamically allocated and no memory mapping (see e.g. http://man7.org/linux/man-pages/man2/mmap.2.html ) is used. No wonder this is slow and eats a lot of memory. At the moment I have no information about why this design was chosen, if there is a justification for it, or if th…
> elPrep is an open-ended software framework that allows for arbitrary combinations of different functional steps in a pipeline, like duplicate marking, sorting reads, replacing read groups, and so on; additionally, elPrep also accommodates functional steps provided by third-party tool writers. This openness makes it difficult to precisely determine the lifetime of allocated objects during a program run > Phase 1 all…
I would use std::monotonic_buffer_resource added in C++17. It's implementation is consists of just a pointer point to large contagious memory. You want a n bytes of memory? return the pointer while adding ptr += n. Deallocation do nothing. Destructing std::monotonic_buffer_resource object deallocate the memory. If the objects has trivial destructor, as that is the case based on glancing the code, this is very efficient.
Re: Comparison of C++17, Go, and Java for a next-generation sequencing tool
#95Earlier quoted context omitted.
Of course you can use better allocators; but it's faster to avoid dynamic allocation (e.g. by pointing to memory mapped from the input file by the OS) altogether. If they allocate memory for each flyspeck of a 200 GB file and also create and change a reference counter for it, nobody should be surprised about the low performance. Have a look what e.g. shared_ptr does behind the scenes.
Unless you're streaming, in which case mmap'ed access on Linux is generally slower than read/write. At least it was the last time we checked for the Ardour project (probably about 3 years ago).
Re: Comparison of C++17, Go, and Java for a next-generation sequencing tool
#96After quickly glancing the code, I concluded that they wrote C++ like there is no static type. It seems they faithfully ported the very dynamic nature of their existing code to C++ without thinking. Like what is this? https://github.com/ExaScience/elprep-bench/blob/master/cpp/f... auto alns = any_cast >>>(data); So the data is sam_alignment type inside shared_ptr inside deque inside another share_ptr inside god forbi…
Are you saying that access patterns (push/pop front/back) never matter and std::vector is always better than std::deque if the element size is very small? I don't think that this is true in this generality.
Re: Comparison of C++17, Go, and Java for a next-generation sequencing tool
#97I had a quick look at the C++ source code provided at https://github.com/ExaScience/elprep-bench/tree/master/cpp . As suspected, everything is dynamically allocated and no memory mapping (see e.g. http://man7.org/linux/man-pages/man2/mmap.2.html ) is used. No wonder this is slow and eats a lot of memory. At the moment I have no information about why this design was chosen, if there is a justification for it, or if th…
The problem with C++, for a lot of people, is not that it's impossible to do it right, but that it's easy to do it wrong.
Re: Comparison of C++17, Go, and Java for a next-generation sequencing tool
#98Earlier quoted context omitted.
Except that this "atomic" operation over shared_ptr's in the C++ standard isn't actually required to be lock free, and is in fact not lock free in common stdlib implementations. So they're not actually gaining anything over, e.g. RwLock >> in Rust.
They are atomic in the sense that it is not possible to observe the intermediate states and they are not data races. It is extremely hard though to implement them in a lock-free way without a true DCAS (which pretty much no architecture implements). I think all implementations use spinlock pools. I guess transactional hardware could be used. This is one of the reasons why GC does make it easier to implement some lock…
Does x86-64's cmpxchg16b not qualify?
Re: Comparison of C++17, Go, and Java for a next-generation sequencing tool
#99Earlier quoted context omitted.
It's implementation is buckets divided node based hash map. Theoretically, its order is good, but not that efficient in modern hardware where the memory access is heavily cached so the data locality is more important than saving the memory copy or memory size. Using the linked list to save some memory copy doesn't benefit at all and the overhead is far greater than simply copying the contagious large chunk of memory.…
> contagious normally I wouldn't point out an obvious autocorrect mistake, but this is really season-appropriate (or, better, inappropriate) :).
Re: Comparison of C++17, Go, and Java for a next-generation sequencing tool
#100Why? This is a batch program, interruptions don't matter, only the end-to-end time does.
> The goal of elPrep is to simultaneously keep both the runtime and the memory use low.
Why? Keeping runtime low lets you get more work done. Keeping memory use low means what? They are using a machine with 384 GB RAM, make use of it.
Worth noting also that they used GCC 7.2.1, Go 1.9.5, and Java 10. That's a pretty old GCC.
They don't seem to explicitly select a GC with Java, so they'll be using G1. G1 is still not entirely mature. It got much faster between 9 and 10, and somewhat faster from 10 to 11. For a batch process like this, though, the parallel collector is still probably a better choice. Using a newer JDK and a different collector should give better performance - but admittedly, probably won't reduce heap usage.