How fast is Assembly? How slow are C and Go?

TL/DC Jump to the Test Results

I started my tech life working with FoxPro and the BASIC language... I wrote in SuperBase, Visual Basic, Perl, Ruby and Shell Scripts. All very high level languages. I always wanted to learn what was truly happening inside of the machine, but I was either too intimidated or too busy to learn low level languages. I moved into management, sales and business, and would code a bit over the years, but I had become a generalist.

A few years back I started getting back into writing software again. I looked at Perl 6. That's interesting, but why? I looked at some of the newer JavaScript and TypeScript, but none of it satisfied my curiosity. I wanted to know what's really going on. Something lower level and faster!

I started writing a fair amount of Go. It's a pretty nice language. Very easy. If I were writing a large app with several developers, I think Go may be a good choice. Everything is simple, compact, and standard. The more I got deeper into Go, the more I would see that I still didn't understand what's happening in the machine. I was reading something like "Advanced Go" that was talking about how to connect Go to C and I though, why am I doing this instead of just writing in C?

I had written a little bit of C in school, but never got very good at it. At that time, the money I could make solving other people's problems in high level languages was more interesting to me than understanding what was actually happening inside the machine.
Head First C - Chinese Edition... I actually read the English version, though this one might be more fun

I found a great C book... Head First C. I wish my college had used this as the C textbook instead of the dry, sleep inducing tome the professors chose. I started writing C and enjoying it, but I had a lot of problems solving some of the memory errors, especially at first. You could say that I hit these problems because I didn't have very much experience in C. I would say I hit them because I had finally gotten closer to the processor, but I still didn't know what's going on.

So I thought to myself, a simple C introduction wasn't difficult at all. It was fun and enjoyable. What if there's something similar for Assembler?
Assembly Language Step-By-Step

So I found Assembly Language: Step-By-Step. The author's idea is to teach Assembly Language as a first programming language. It's an interesting idea.


The blog post title... How fast is Assembly, and how slow are Go and C? The thing to remember with ASM is that each line of your assembly code corresponds to object code that you'll feed the processor.

SECTION .data			; init data

	HelloMsg: db "Hello world!",10 ;
	HelloLen: equ $-HelloMsg ;

SECTION .text			; code section

global _start  ; link needs this to find the entry point

	mov eax, 4        ; sys_write syscall
	mov ebx, 1        ; stdout (file 1)
	mov ecx,HelloMsg  ; pass offset of message
	mov edx,HelloLen  ; pass length of message
	int 80H           ; syscall

	mov eax, 1        ; exit syscall
	mov ebx, 0        ; return 0
	int 80H           ; syscall 

Assuming code is in a file named asm-hello.asm, run the following to build and test (assuming you're on a 64 bit machine)

nasm -f elf64 asm-hello.asm && \
ld -o asm-hello asm-hello.o && \

If you've never written assembler before, and you're not quite sure what any of that means... eax ebx ecx and edx are registers. You trigger the syscall with interrupt 80H (code 128). If you want a better explanation of how and why it works, read the book linked above.

Performance Testing with perf

The interesting thing about this, is that I don't think you could make a hello world program significantly shorter.

sudo perf stat -r 1000 -d ./asm-hello

For this tiny asm example, you can see it took 0.00029 seconds to execute.

Total execution time: 0.000296 seconds

For the C version, I set -Ofast for maximum optimization. On such a simple program I don't think the optimization made any difference.

C version with -Ofast, Total execution time: 0.000498 seconds
Go version, Total execution time: 0.000984 seconds
Perl version, Total execution time: 0.00135

Of course it's very possible that you could write awful ASM and either never get it to work or get it to work so bad that it's even slower than any of the other options. It's just interesting to see how much different the speed can be. If you do have a part of a Go program that's too slow, it makes a lot of sense to move that part to C. If you have part of a C program that's too slow, it makes a lot of sense to move that part to ASM.

This clarifies for my why old programs on old hardware were so fast! Because RAM and CPU were both extremely expensive, lots of things were written in ASM.

Now that RAM and CPU prices are so low, most RAM segments and CPU cycles are thrown away on things like Electron...