Live data from Hacker News

How is Ultrassembler so fast?

jghuff.com

21–30 of 53 posts

Re: How is Ultrassembler so fast?

#21
post #3

Hi everyone, I'm the author of this article. Feel free to ask me any questions to break the radio silence!

Nice work and good writeup. I think most of that is very sound practice. The codegen switch with the offsets is in everything, first time I saw it was in the Rhino JS bytecode compiler in maybe 2006, written it a dozen times since. Still clever you worked it out from first principles. There are some modern C++ libraries that do frightening things with SIMD that might give your bytestring stuff a lift on modern stupid…

FWIW, this is basically an implementation of perfect hashing, and there's a myriad of different strategies. Sometimes “switch on length + well-chosen characters” are good, sometimes you can do better (e.g. just looking up in a table instead of a long if chain).

The “value speculation” thing looks completely weird to me, especially with the “volatile” that doesn't do anything at all (volatile is generally a pointer qualifier in C++). If it works, I'm not really convinced it works for the reason the author thinks it works (especially since it refers to an article talking about a CPU from the relative stone age).

Re: How is Ultrassembler so fast?

#22
post #3

Hi everyone, I'm the author of this article. Feel free to ask me any questions to break the radio silence!

You might look into using memory mapped IO for reading input and writing your output files. This can save some memory allocations and file read and write times. I did this with a project where I got more than 10x speed up. For many cases file IO is going to be your bottleneck.

mmap-based I/O still needs to go through the kernel, including memory allocation (in the page cache) and all. If you've got 10x speedup from mmap, it is usually because your explicit I/O was very inefficient; there are situations where mmap is useful, but it's rarely a high-performance strategy, as it's really hard for it to guess what your intended I/O patterns are just from the page faults it's seeing.

Re: How is Ultrassembler so fast?

#23

I wonder if you thought about perfect hashing instead of that comparison tree. Also, flex (as in flex and bison) can generate what amounts to trees like that, I believe. I haven't benchmarked it compared to a really careful explicit tree though.

You're probably thinking of gperf, not flex and bison.

Re: How is Ultrassembler so fast?

#24
post #2

Neat, but it's not like assembly is really a bottleneck in any but the most extreme cases. LLVM and GAS are already very fast. I feel like this might mostly be useful as a reference, because currently RISC-V assembly's specification is mostly "what do GCC/Clang do?"

Exactly. I don’t know too many assembly language programmer's who are griping about slow tools, particularly on today’s hardware. Yea, Orca/M on my old Apple II with 64k RAM and floppy drives was pretty slow, but since then not so much. But sure, as a fun challenge to see how fast you can make it run, go for it.

Re: How is Ultrassembler so fast?

#25
post #20

Exceptions in C++ are never zero-overhead. There is a time-space tradeoff for performance of uncaught exceptions, and G++ picks space over time.

> G++ picks space over time

By definition, that's zero-overhead because Ultrassembler doesn't care about space.

Re: How is Ultrassembler so fast?

#26
post #16

Earlier quoted context omitted.

Ditto. Perfect hashing strings smaller than 8 bytes has been the fastest lookup method in my experience.

Problem is, there are a lot of RISC-V instruction way longer than that (like th.vslide1down.vx) so hashing is going to be slow.

You could copy the instruction to a 16 byte sized buffer and hash the one/two int64s. Looking at the code sample in the article, there wasn't a single instruction longer than 5 characters, and I suspect that in general instructions with short names are more common than those with long names.

This last fact might actually support the current model, as it grows linearly-ish in the size of the instruction, instead of being constant like hash.

Re: How is Ultrassembler so fast?

#27
post #20

Exceptions in C++ are never zero-overhead. There is a time-space tradeoff for performance of uncaught exceptions, and G++ picks space over time.

> G++ picks space over time By definition, that's zero-overhead because Ultrassembler doesn't care about space.

Okay, than a traditional setjmp/longjmp implementation is zero-overhead because I don't care about space or time!

Re: How is Ultrassembler so fast?

#28
post #23

I wonder if you thought about perfect hashing instead of that comparison tree. Also, flex (as in flex and bison) can generate what amounts to trees like that, I believe. I haven't benchmarked it compared to a really careful explicit tree though.

You're probably thinking of gperf, not flex and bison.

Oh, I remember I did a plain and simple C port of an old gperf, cgperf https://www.rocketgit.com/user/sylware/cgperf

Ofc, I did add my own bugs.

Re: How is Ultrassembler so fast?

#29
post #7

Earlier quoted context omitted.

Overall, this is a fantastic dive into some of RISC-V's architecture and how to use it. But I do have some comments: > However, in Chata's case, it needs to access a RISC-V assembler from within its C++ code. The alternative is to use some ugly C function like system() to run external software as if it were a human or script running a command in a terminal. Have you tried LLVM's C++ API [0]? To be fair, I do think th…

> LLVM's C++ API I think I read something about this but couldn't figure out how to use it because the documentation is horrible. So, I found it easier to implement my own, and as it turns out, there are a few HORRIBLE bugs in the LLVM assembler (from cross reference testing) probably because nobody is using the C++ API. > There are plenty of cppcon presentations [1] about exceptions, performance, caveats, blah blah.…

> I think I read something about this but couldn't figure out how to use it because the documentation is horrible.

Fair enough.

> So, I found it easier to implement my own, and as it turns out, there are a few HORRIBLE bugs in the LLVM assembler (from cross reference testing)

Interesting claim, do you have any examples?

Re: How is Ultrassembler so fast?

#30
post #2

Neat, but it's not like assembly is really a bottleneck in any but the most extreme cases. LLVM and GAS are already very fast. I feel like this might mostly be useful as a reference, because currently RISC-V assembly's specification is mostly "what do GCC/Clang do?"

ASM should compile at hundreds of MB/s. All the ASM you could write in your entire life will compile instantly. There is no one in decades that has thought their assembler is too slow.
Post reply on HN