16 ms·
I don't mean this as a slight because I love the project and other light fast OSes... but with modern compilers, what does assembly get you over just using C or
by mysterydip 7y ago
I don't mean this as a slight because I love the project and other light fast OSes... but with modern compilers, what does assembly get you over just using C or another language and having it handle the translation? I was under the impression compilers nowadays have lots of optimizations that would take a lot of work for a human to do by hand, as well as creating less readable/maintainable code.
- haolez 7y agoIt gives you a very close understanding of your CPU's instruction set and features. It's not necessary to write performant code, since compilers can do this very well.
- abnry 7y ago"We choose to write an OS in asm, not because it is easy, but because it is hard"
- MR4D 7y agoMake Assembly Great Again! LOL!!
- pjmlp 7y agoWell, C still doesn't offer the same macro capabilities as 90's macro assemblers were capable of. Thankfully in C++ we have constexpr for that.
- higerordermap 7y agoCan you elaborate which capabilities to those of us interested to know?
- pjmlp 7y agoYes, here is the manual for MASM. https://docs.microsoft.com/en-us/cpp/assembler/masm/directives-reference?view=vs-2019 https://docs.microsoft.com/en-us/cpp/assembler/masm/directiv... Basically already back in the Amiga/MS-DOS days, you could define: - procedures and functions like higher level languages - structures - make use of looping constructs (repeat/while) and conditional logic (if/else) - create hygienic labels for variables and jump targets TASM and the FOSS clones, yasm and fasm do support similar macro capabilities. On the Amiga side, Devpac was the goto Macro Assembler, https://www.amigagamedev.com/Downloads/DevPac_v3.00.Manual.pdf https://www.amigagamedev.com/Downloads/DevPac_v3.00.Manual.p... Only the UNIX Assemblers have been traditionally quite poor in macro capabilities, as they have been mostly used as yet another stage for generating code from C compilers. A good example how to take advantage of such macros is to implement a poor man's compiler, or the first stage of a bootstraped compiler. Generate bytecodes that can be easily mapped into macros, and then just by having your macro library for the target platform you get the compiler very quickly up and running.
- unwind 7y agoIn the Amiga demo scene, I would dare say that ASM-One [1] was the default assembler. [1] https://en.m.wikipedia.org/wiki/ASM-One_Macro_Assembler https://en.m.wikipedia.org/wiki/ASM-One_Macro_Assembler
- pjmlp 7y agoI was into portuguese demoscene Amiga/PC and never heard of it, then again it was back in the days when we exchanged floppies via the post.
- snvzz 7y agoAsmTwo[0] is a decent currently maintained fork of that. [0]: http://coppershade.org/articles/Code/Tools/AsmTwo/ http://coppershade.org/articles/Code/Tools/AsmTwo/
- DarkWiiPlayer 7y ago> Thankfully in C++ we have constexpr for that. The only C++ feature I'm thankful for is the option of not using it
- pjmlp 7y agoI on the other hand appreciate that since 1993, C++ has allowed me avoid C as much as possible.
- nibles_and_bits 7y agoThe greater our knowledge increases, the greater our ignorance unfolds.
- gilgoomesh 7y agoAssembly gives you minimal resource use by default. Some higher level languages make it possible as an edge case. Generally, higher level languages are usually built upon non-zero-cost abstraction overheads, library bindings, memory management and runtimes.
- saagarjha 7y agoNot always. Sometimes it’s annoying to do something performant in assembly but trivial in a higher-level language: hashmaps, for example.
- userbinator 7y agoThe main advantage of Asm is the tiny constant factor. A linear or quadratic algorithm can beat a logarithmic or even (amortised) constant-time one on the sizes of data used, if the latter has a much larger constant factor. Just like in a HLL, if you really need it you can still write reusable data structure libraries, but Asm's really tiny constant factor and effort involved in adding complexity forces you to think about whether you really need it first. In other words: in the amount of cycles spent initialising a hashmap and inserting a few dozen or hundred items (perhaps involving memory allocations, etc.) just so you can get (once again, a relatively large factor each time) asymptotically constant-time lookup in an HLL, you could've gone through the whole set many times already in a tight loop of less than a dozen instructions, that entirely fits in the L1 cache along with the data too.
- ajxs 7y agoWhat are you talking about? You're talking about implementation. This has nothing to do with assembly at all. Assembly is not a magic language that offers instant efficiency. 'Constant factor' is entirely irrelevant to this discussion. There's nothing stopping an engineer from implementing equally inefficient data structures/algorithms in assembler as they would in a higher-level language. It is true that if the engineer understands the problem domain very well, and the project requirements are amenable, the possibility certainly exists for them to solve the problem with highly efficient assembly. This is true for almost anything. However, it exists at the cost of extra development effort with no real guaranteed benefit.
- amedvednikov 7y agoFrom my experience in this area, it's still possible to produce a lot more efficient and compact machine code in ASM.
- userbinator 7y agoExactly. Compile a C or C++ application with -Os and the highest size optimisation settings, and you'll almost certainly still end up with a binary that's several multiples if not an order of magnitude or more larger than if you had written it in Asm with the equivalent functionality. Compilers can do SIMD tricks and such to get close in speed, but they are still pretty horrible at size optimisation. You could try to "decompile"(!) this project into a higher level language and compile the result if you were really curious and wanted to try this exercise in the opposite direction. I suspect a lot of the things done in this code aren't even representable in a HLL or something a C compiler could be coerced to generate (without cheating and using inline Asm.)
- ajxs 7y agoI disagree with almost every aspect of this post. I've never seen any evidence of your claim about binary size being the case. It's a spurious claim. There's always the possibility that a user could write slightly more efficient assembler by hand, but orders of magnitude? Maybe in the 80s this could have been correct. Your claim about compilers using "SIMD tricks" to "get close in speed" makes no sense either. If the HLL is using SIMD instructions and this magic assembler that you're talking about isn't, how would their performance ever be equivalent?
- ftvy 7y agoHow much of an effect would linking shared / static libraries have on binary size? Would someone writing assembly tend to avoid using external libraries unlike with HLL?
- ajxs 7y agoLinking a static library into your program will increase your binary size, linking to a shared library will not. Smaller binary size is one of the benefits that shared libraries offer. That decision is entirely up to the developer and the project requirements. If you're not writing a bare-metal program there's no reason why not to use external libraries. It's still perfectly possible.
- ajxs 7y agoWhy is this getting downvoted? Writing programs in pure assembly does offer the possibility of implementing very fine-grained optimisations. However, assembly is not a magic bullet. Modern optimising compilers are extremely efficient. The most efficient assembly is quite often not the most legible or maintainable assembly. I've written lots of bare-metal assembly and if I'm given the choice between writing more efficient assembly and writing straightforward assembly, I'll pick the latter every time. Edit: I have a little bit of experience in the area of operating-system development in assembly. This is purely a hobby project that I work on half-heartedly. Nevertheless, it does demonstrate what I know about bare-metal x86 assembler. https://github.com/ajxs/hxos https://github.com/ajxs/hxos
- projektfu 7y agoThe biggest benefit is usually that you can forgo calling conventions in your own code because everything is visible to you. Of course the code starts looking like spaghetti.
- ajxs 7y agoThis is correct. You can forego all aspects of your platform's calling conventions if you so desire. Omitting setting up stack frames is a really simple optimisation that can be done in hand-written assembly. You've already touched on what the stakes of doing such things are.
- jfkebwjsbx 7y agoCompilers are able to do the same since a few years.
- projektfu 7y agoYes, but they rarely take a whole-program approach. Reducing a complicated sequence of function calls to a few goto’s is not an easy task. Probably NP-hard?
- 7y ago
- deleted 7y ago[deleted]
- rustybolt 7y agoI suspect a big win is that usually, programs from hand-written assembly will be smaller than compiler-generated binaries. For example, see [1], where a 32-bit GCC-generated binary (2.6 KB) is compared with a hand-written assembly program (45 bytes, although this is not representative). For reference, when I compile an empty program with GCC 8.3 on my 64-bit system, I get a 16KB binary. [1] https://www.muppetlabs.com/~breadbox/software/tiny/teensy.html https://www.muppetlabs.com/~breadbox/software/tiny/teensy.ht...
- adrianN 7y agoThe constant overhead for compiler generated binaries is larger because the compiler doesn't optimize for the case of nearly empty programs. I'm not so sure that the benefits are that large once you have a decently sized piece of code.
- rustybolt 7y agoThat's true. The overhead on relatively small systems with lot of simple binaries might stil be considerable. But it's probably not the main reason for the difference in snappiness.
- WheelsAtLarge 7y agoI love the idea and I'm glad someone was able to create it but long term maintenance is the problem with assembler. Few people have the know-how to help. Even if there were a large number of programmers that could maintain it, it's better to write the OS in a high-level language and use assembler to optimize it. Nice job anyhow...
- metroholografix 7y agoAssembly doesn't have undefined behavior.
- jdsully 7y agoActually it does. BSF (Bit Scan Forward) is the most famous which returns an undefined result if your operand is 0. Many instructions leave the state of bits in the FLAGs register undefined. E.g. AAA will leave SF,ZF, and PF undefined. Then of course there is the “reserved bits” but those are easier to avoid.
- monocasa 7y agoHere's a 6502 instruction that has undefined behavior, because the microsequence connects circuits together in an invalid way causing analog effects that can change even run to run of the same processor. http://visual6502.org/wiki/index.php?title=6502_Opcode_8B_%28XAA,_ANE%29 http://visual6502.org/wiki/index.php?title=6502_Opcode_8B_%2...
- deleted 7y ago[deleted]
- dan_hawkins 7y ago"Of all the unsupported opcodes" - I'm not sure it's a good example.
- dkersten 7y agoIt looks like that’s not undefined behaviour, but using a non-existent and undefined opcode, which happens to “do something” because the cpu attempts to execute the bits anyway (it doesn’t mask the unused opcodes into no ops or errors). Later variants of the 6502, like the WDC 65C816, did away with this (I believe, either using the opcodes for something defined, or making them no ops, although I’m unsure)
- JohnBooty 7y agoIt sure does. Some is inherent to the ISA itself. And some undefined behavior is errata that differs from CPU to CPU. Check out the errata documentation for any processor released in the last few decades. For example, x86. You can trigger things that happen on one x86 CPU that won't happen on another.
- khazhoux 7y agoWhy do mimes not speak? Some things, one should just accept.
- jbk 7y ago> but with modern compilers, what does assembly get you over just using C or another language [...] I was under the impression compilers nowadays have lots of optimizations that would take a lot of work for a human to do by hand dav1d, the open source AV1 decoder, has now more asm than C code. It's one of the most recent open source projects with significant asm work ongoing. The asm version outperforms the C version (full optimizations enabled) by 4,5x on AVX2. We have similar results in SSSE3 (3,5x) and ARM64 (4x). We're not talking about a few percents, we're talking about multiple times faster. And AV1 is a standard, so there are no algo shortcuts that can be made: it is either compliant or it is not. Sure, in most cases, it is not needed to write asm; but there are cases, notably for multimedia, where writing asm by hand is a lot faster, and that includes codecs and game engines.
- wiz21c 7y agoWell, video decoding is very adapted to ASM, I'd say. You can use vectorisation, you can optimize pipelined executions, etc. Things were compiler may not be so good (my experience is a bit dated). You also optimize a few tight loops, so you can really invest time in them with good ROI. I'm not sure that operating systems are so suited to ASM optimization (in the sense that you may not reap so many benefits). Maybe one could optimize for size (so you can make super tiny OS) ?
- JohnBooty 7y agoMaybe one could optimize for size (so you can make super tiny OS) ? Yes, and remember... optimizing for code size is optimizing for speed. =) Smaller code and data = more CPU cache hits, which are orders of magnitude faster than fetching from RAM. So even if "all" you do is make code smaller, you can get more speed...
- fractalb 7y ago> Yes, and remember... optimizing for code size is optimizing for speed. =) Not always. I think loop-unrolling is a common perf-optimisation technique. Even if the perf-gain is positive in this case, I highly suspect that it doesn't outweigh the cost of maintaining asm code(vs C/other higher level code). edit: formatting
- pjmlp 7y agoSIMD like code, auto-vectorization has come a good way, but it still isn't as fast as doing it by hand. IoT devices with memory measured in single digits KB. Plus, someone needs to write the Assembly that those compilers generate.
- p0nce 7y agoIt depends. If your target is x86/x86_64 and the compiler has a LLVM or Intel backend, I've found that beating the compiler is almost impossible and largely futile. I took a long time to accept this since I know asm and the x86 instructions well.
- pjmlp 7y agoThat is my point of view as well, but then again the kind of code I write also does quite well with bounds checking enabled. So I never had to deep dive into stuff like writing AVX by hand, just basing my remark on some comments that occasionally read about.
- saagarjha 7y agoCompiler auto-vectorization is fairly easy to beat as it won’t even try when loop invariants are mildly complicated.
- strategarius 7y agoAs noticed above, creators admitted that creating OS written in Assembly was a challenge for them. However, I totally agree about optimizing capabilities of modern compilers. Interesting fact on the topic, my friend, Principal Developer of well-known tech giant has a practice of picking up candidates, who mentioned "fluent Assembly" skill in their CV, and challenge them by suggesting to create a small, highly optimized application. After that he compiles the same application in C++ with maximum optimization, and in 90% of cases generated code is more optimal, that written manually. However, before becoming all sceptical about obsolete skills of learning Assembly, I would point out on the rest 10% of his candidates.
- z3phyr 7y agoDo they mention fluent x86-64 or arm assembly? Because there are many ISAs where no C++ compiler will be able to generate better code than hand optimal code by a fluent programmer.
- fluffything 7y agoExactly, when the only compiler available for an ISA is gcc 2.9... manually writing the assembly doesn't sound that bad anymore. C++11? There isn't even a C++03 compiler for those..
- strategarius 7y agoI think, sinse he's working on internet search and knows targer architecture in advance, he meant x86_64 assembly, used probably for platform-specific fine-tuning
- qwerty456127 7y ago> compilers nowadays have lots of optimizations Whatever, the Kolibri ISO is 64 MB. Nuff said.
- DagAgren 7y ago64 MB is absolutely gigantic if we are talking about assembly code. So that is not "nuff said" by any measure, it is a completely irrelevant factoid that tells us nothing at all?
- snvzz 7y ago>64 MB is absolutely gigantic if we are talking about assembly code. Likely due to the inclusion of source code and some non-core stuff actually written in c.
- BenjiWiebe 7y ago64MB is gigantic, period. TinyCore Linux is what, 11MB?
- qwerty456127 7y agoDoes that include a window manager?
- abainbridge 7y agoHere's someone who wrote a load library routines in asm and claimed they were faster. https://old.reddit.com/r/programming/comments/dygsvm/heavything_x86_64_assembler_library_includes_tls/ https://old.reddit.com/r/programming/comments/dygsvm/heavyth... I was skeptical, so I looked into his zlib implementation. It was 18% faster than gzip v1.6. The author said, "all I did was hand-compile the reference implementation, an 18% reduction in user-space time is a big advantage IMO." I am not skeptical any more! More details of the benchmarking are in the linked thread.
- ascar 7y agoAs part of a university project we optimized a simple string to uppercase function via assembler analysis and asm. Directly optimizing the C code to produce more optimized assembly (notably removing branching) was nearly an order of magnitude faster. // uppercase without if *c -= (*c-'a'<26U)<<5; Adding loop unrolling to that C-optimized version via asm provided another 20% performance boost. And I didn't even add vectorization using AVX. While compilers provide a lot of optimization directly, there are huge performance gains in simple functionality by helping the compiler with easier to optimize code or by using asm directly. Also notably the highest GCC optimization level I tested (-O3) reverted the optimization of the optimized C code, while -O2 kept them, resulting in -O2 being much faster. So only using asm guaranteed the performance gain.
- jksmith 7y agoBeen 30 years since I've written assembler but back in the day I considered myself part of Abrash's army. What we tend to forget about writing in assembler is each typical formatted line has a one-to-one mapping to a machine instruction unless you're using macros. It really is the most wysiwyg programming experience you can have, so it's simply not possible to get the same optimization and space usage with a higher level language because your only choice for optimizing higher level is via groups of instructions. So C optimizers are inlining groups of instructions and making best assumptions about execution flows for you while maintaining intent. So if you want to enjoy the abstractions of higher languages, and the speed at which you can develop, the only obvious run-time optimization is faster hardware to compensate for abstractions that might decompile to massive amounts of machine instructions. Oh yeah and I'd just like to mention as an aside that assembler statements make more sense to me than bootstrap css codes - a sad statement to the art of reasonable brevity.
- kazinator 7y agoAssembly language gets you a detailed definition of behavior that isn't a moving target.
- api 7y agoModern compilers are pretty good, but it's still quite possible for a good human coder to exceed their performance even for normal code. For really tight algorithms I've still seen humans beat compilers by a lot, though it takes a lot of skill and some domain knowledge of the CPU. For code that benefits a lot from vectorization, human coders still beat the crap out of compilers. I am not aware of any vectorizing compiler or JIT that can even approach what a human coder can do with SSE, AVX, or NEON (ARM's equivalent). I think these CPU extensions are just too complex for current generation compilers to effectively deal with. They require too much abstract understanding of what's actually happening in the code and the CPU to use really effectively. I'm a bit surprised that there's been so little attention paid to the opportunities for applying deep learning and other advanced techniques to compiler optimization. It seems like this area is ripe for a new wave of innovation, but it's not happening. I do believe that many companies would pay for an advanced compiler capable of generating code that was significantly faster than stock compilers, but the speedup would have to be more than a few percent to justify spending money on it.