Live data from Hacker News

Comparison of C++17, Go, and Java for a next-generation sequencing tool

bmcbioinformatics.biomedcentral.com

61–70 of 190 posts

Re: Comparison of C++17, Go, and Java for a next-generation sequencing tool

#61
post #22

Earlier quoted context omitted.

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.

I think this applies to any kind of advanced software development or programming languages, not only C++. There may be many reasons why scientists who are not computer scientists feel more comfortable with Go than with C++, but performance is certainly not one of them.

The authors of that paper are computer scientists.

Re: Comparison of C++17, Go, and Java for a next-generation sequencing tool

#62
post #40

"We have not performed a detailed comparison against the original version of elPrep implemented in Common Lisp, but based on previous performance benchmarks, the Go implementation seems to perform close to the Common Lisp implementation." LMFAO.

If I understand correctly, new Go code was as fast as old Lisp code, with much less effort and much clearer code.

> Most existing Common Lisp implementations use stop-the-world, sequential garbage collectors. To achieve good performance, it was therefore necessary to explicitly control how often and when the garbage collector would run to avoid needless interruptions of the main program, especially during parallel phases. As a consequence, we also had to avoid unnecessary memory allocations, and reuse already allocated memory as far as possible, to reduce the number of garbage collector runs. However, our more recent attempts to add more functionality to elPrep (like optical duplicate marking, base quality score recalibration, and so on) required allocating additional memory for these new steps, and it became an even more complex task and a serious productivity bottleneck to keep memory allocation and garbage collection in check.

Re: Comparison of C++17, Go, and Java for a next-generation sequencing tool

#63
post #21
post #5

Earlier quoted context omitted.

Yeah, further down in the article they track down the gap between cpp and Go/Java to the ref-counting deallocation work. I'm not a cpp expert, but it seems surprising to me that GC would beat ref-counting in any scenario.

I guess I was wrong with this comment: https://news.ycombinator.com/item?id=22959600 1. Reference counting is a form of GC; you could implement a JVM that used reference counting (though in order to be general a small amount of additional work is needed) 2. Reference counting causes extra work every time a reference appears or disappears. Tracing GCs amortize that cost across many allocations. 2.b. This is particular…

> you could implement a JVM that used reference counting

It would leak memory - reference counting cannot collect cycles (you need tracing GC for that, defeating the purpose of refcounting).

Re: Comparison of C++17, Go, and Java for a next-generation sequencing tool

#64
post #60
post #6

I 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…

The problem starts with the design decision to stream the file into memory; if you map the file instead you can directly use the mapped data and only have to allocate supporting structures (if required). And anyway, the "Therefore" part does not follow from the "Phase 1" statement.

Re: Comparison of C++17, Go, and Java for a next-generation sequencing tool

#66
post #61
post #22

Earlier quoted context omitted.

I think this applies to any kind of advanced software development or programming languages, not only C++. There may be many reasons why scientists who are not computer scientists feel more comfortable with Go than with C++, but performance is certainly not one of them.

The authors of that paper are computer scientists.

But most life scientists using the library for their work are not; Go is a language they can master, as well as Python or Lua; if they're biophysicists they're likely to know Fortran and C as well, but I rarely meet scientists fluent in C++. Also not sure how much experience the authors have with such software projects.

Re: Comparison of C++17, Go, and Java for a next-generation sequencing tool

#67

No Rust smh

It was mentioned in the article and was not considered a candidate due to a specific API requirement: > Other mature programming languages with support for reference counting include Objective-C, Swift, and Rust [50]. However, in its algorithm for duplicate marking, elPrep requires an atomic compare-and-swap operation on reference-counted pointers, which does not exist in those languages, but exists in C++17.

So they need https://crates.io/crates/arc-swap ?

Re: Comparison of C++17, Go, and Java for a next-generation sequencing tool

#68
post #60
post #6

I 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…

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 shared? And why does the deque instance need to be heap allocated at all? It just contains a pointer to the actual allocation anyway, moving it around by value is super cheap?

It's like make_shared is the only way they know to allocate an object. They even put string inside of shared_ptr:

    class istream_wrapper {
        ...
 shared_ptr buffer;
It could be that it does need to be shared for some reason, but this looks like a pointer to a pointer for no obvious reason. Even ignoring the atomics that shared_ptr results in, the dependent data loads are going to be brutal.

EDIT: And they don't even seem to use std::move anywhere :/ There's a huge gap between this code and custom allocator territory.

Re: Comparison of C++17, Go, and Java for a next-generation sequencing tool

#69
After 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 forbid any? Why did they do that? What kind of abomination is this? Also from the context, it is the only possible type. they use:

  try { any_cast(data) ; }
  catch ( bad_any_cast ) { throw runtime_error(...) ; }
If you're so sure an object of any only hold exactly one type and everything else is unexpected error, you shouldn't use any at all!

They really like std::deque and use it everywhere even though the sizeof(T) is like a few dozen bytes at best so they should rather use std::vector. The data structure of deque is a list of array. while it can amortize the continious adding of the elements to front or back, since the element size is very small, they should rather use vector.

Speaking of data structure, they also use std::unordered_map. the unordered_map is very slow(it's a node based hash map, not suitable for the modern hardware) and the sizeof(int) + sizeof(any) is like 20 bytes(sizeof(int) + two pointers) so they got no benefit of using node based data structure here. They should rather use sorted vector and binary search it.

My conclusion, it's slow because they wrote C++ like a dynamic typed language and they choose the wrong data structures.

Re: Comparison of C++17, Go, and Java for a next-generation sequencing tool

#70

This is not surprising. Parallel GC will almost always be faster than refcounting. If you wrote a C or C++ program to accomplish this task after carefully planning out exactly when stuff needs to get manually malloced/freed, you could outperform any of their approaches And like another commenter mentioned, if you're writing a program which streams a lot of data sequentially from disk, and where throughput is importan…

That's a case where mmap isn't actually all that much faster than read, and due to the inter processor interrupts needed to synchronize the memory mappings across cores, it may end up much slower. You're grabbing large chunks and flushing the TLB a whole lot.

If you are seeking randomly and doing small reads, then mmap will help quite a bit: the data will be faulted in, and accessing it a second, third, or hundredth time will not cost much.

Post reply on HN