Category: Techniques

How much faster is C code compiled with fastcall?

How much faster is C code compiled with fastcall?

Setting fastcall in VS 2019Something I read about the other day was the __fastcall convention. In Visual Studio you enable this with the /Gr flag and in gcc (it’s __attribute__((fastcall)). For clang it’s fastcall but see this.

So what does fastcall do? It changes the calling convention, so instead of pushing parameters to a function on the stack, it passes them in the registers starting with ECX then EDX and so on.  Let’s look at an example.

#include <stdio.h>

int add(int a, int b, int c) {
	return a + b * 2 + c * 3;
}

int main() {
	printf("Add(4,5,6)=%d\n", add(4, 5, 6));
}

This is the disassembly code from VS 2019. I pressed F10 to start debugging then Debug => Windows => Disassembly to get the listing. Note thei is x86, ie 32-bit.

005B18DC  lea         edi,[ebp-0C0h]  
005B18E2  mov         ecx,30h  
005B18E7  mov         eax,0CCCCCCCCh  
005B18EC  rep stos    dword ptr es:[edi]  
005B18EE  mov         ecx,offset _9831A1D6_test@c (05BC003h)  
005B18F3  call        @__CheckForDebuggerJustMyCode@4 (05B131Bh)  
	printf("Add(4,5,6)=%d\n", add(4, 5, 6));
005B18F8  push        6  
005B18FA  push        5  
005B18FC  push        4  
005B18FE  call        _add (05B1023h)  
005B1903  add         esp,0Ch  
005B1906  push        eax  
005B1907  push        offset string "Add(4,5,6)=%d\n" (05B7B30h)  
005B190C  call        _printf (05B10D2h)  

Now if I build it after setting the /Gr flag. In Vs 2019, on the project property pages, click advanced then the Calling Convention and switch from cdecl (/Gd) to –fastcall (/Gr).

008118EC  lea         edi,[ebp-0C0h]  
008118F2  mov         ecx,30h  
008118F7  mov         eax,0CCCCCCCCh  
008118FC  rep stos    dword ptr es:[edi]  
008118FE  mov         ecx,offset _9831A1D6_test@c (081C003h)  
00811903  call        @__CheckForDebuggerJustMyCode@4 (081131Bh)  
	printf("Add(4,5,6)=%d\n", add(4, 5, 6));
00811908  push        6  
0081190A  mov         edx,5  
0081190F  mov         ecx,4  
00811914  call        @add@12 (0811276h)  
00811919  push        eax  
0081191A  push        offset string "Add(4,5,6)=%d\n" (0817B30h)  
0081191F  call        _printf (08110CDh) 

I’ve highlighted the differences in bold. However the function Add is also different as the fastcall version doesn’t have to pop parameters off the stack.

Note, to get this to compile I had to prefix main with __cdecl. Using /Gr means that every function in the program uses registers and that’s not allowed with main as it’s called from Windows end must use the cdecl (default stack passing) convention.

This is what main looks like now.

int __cdecl main() {

Notes

This is only for 32-bit. 64-bit code is done somewhat differently so possibly wouldn’t be that different. Next I have to write a program that does lots of function calls and use high precision timing to see how much of a difference it makes. To be continued.

An intriguing Matchbox based learning machine

An intriguing Matchbox based learning machine

Matchbox
Image by Horst Winkler from Pixabay

I mentioned Menace the other day. This was a “Learning Machine” implemented entirely with Matchboxes. This was back in the 1960s. The idea is that a simple game like noughts and crosses (aka Tic-tac-toe) can be played by a crude form of learning computer.

You need enough matchboxes for every possible position in the game. That’s 304 matchboxes and you start but putting four coloured beads into each box for every possible turn. These represent the possible moves. To make a move, you pick the box corresponding to the position shake it and draw a bead out and play that move.

And so on until the game is finished. Then if Menace (as it was called- Machine Educable Noughts And Crosses Engine) won, you add three beads to each winning Matchbox, put one back in if its a draw and remove all of that colour if it lost.  Gradually it becomes better at winning.

There’s a far detailed write up here. It’s an intriguing technique though possibly not the easiest to apply as it requires you to have a matchbox for every position in a game. Fine with noughts and crosses but impossible with chess. Instead of Matchboxes, it could be done way faster in software.

It needs games with determinate moves and not too many, though I suppose with RAM in modern PCs, a few million moves would be manageable. One possibility would be the L game. I’ve never heard of anyone doing that, and it would make for an interesting project. I’ll add it to my list of future projects. Now I wonder how many possible moves there are in a L- Game? It’s made more complex because you can optionally move one of the single pieces as well as the L-Shape which can be rotated and flipped and it’s a 4 x 4 board not 3 x 3 as in noughts and crosses. .

Doing 3D Math(s) in C

Doing 3D Math(s) in C

Donuts.cIf you’re interested in seeing how 3D math(s) are done, this article by ex Googler Andy Sloane is about a program he wrote called donut.c. The name is doubly appropriate as not only is the source code shaped like a Donut (doughnut for us Brits), when run on Linux, it outputs an animated 3D donut. This was an attempt at obfuscated C back in 2006.

Now 15 years later he’s updated it to work without using the math library. Interesting is the explanation of how he did all the mathematics without using sin and cos directly. Also it includes a version that uses 10 bit integer arithmetic; no floats at all. If you’re interested in understanding how Donuts.c works, read this post from 2011.

I like articles like this- they’re a bit different and add to programming knowledge. and you can never get enough of that

 

 

 

How to read a text file into memory in C

How to read a text file into memory in C

Words readAs part of the crossword grid packing utility, the first stage is building the list of words in a structure in RAM. To keep thing simple I’m going to use an array of char * pointers. The array is limited to a maximum 20 words. If any more are read then they will be discarded.

Just to prove that it worked, I wrote this in Visual Studio and ran it in the debugger. You can see elements 0-9 in the screenshot with the source code in the background.

This is the listing of the program. Note, it doesn’t have a function to free up the memory dynamically allocated for each of the words.

You might wonder about these lines (25 and 26).

	if (line[len-1] == '\n')
		line[--len] = '
	if (line[len-1] == '\n')
line[--len] = '\0';
';

This is needed because when you use fgets to read a line of text it includes a line feed at the end. So the first line in the file Engine is actually 7 characters long with a terminating \n. The malloc on line 27 allocated enough RAM for len + 1 to allow for the terminating 0 at the end of each string. In line 33, if you are on Linux replace strcpy_s with strncpy. Both are safe versions of strcpy. Here’s the full listing.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

#define MAXWORDS 20
#define MAXWORDLENGTH 32

typedef char* pWord;
pWord allwords[MAXWORDS];

int ReadWords(char * filename) {
	memset(allwords, 0, sizeof(allwords)); // clear it
	char line[MAXWORDLENGTH*2]; // double max size just in case
	FILE* fwords;
	int errnum = fopen_s(&fwords,filename, "rt");
	if (!fwords) {
		printf("Missing word file %s", filename);
	}
	int wordIndex = 0;
	while (fgets(line, MAXWORDLENGTH, fwords)) {
		int len = strlen(line);
		if (!len)
			break;
		if (line[len-1] == '\n')
			line[--len] = '
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#define MAXWORDS 20
#define MAXWORDLENGTH 32
typedef char* pWord;
pWord allwords[MAXWORDS];
int ReadWords(char * filename) {
memset(allwords, 0, sizeof(allwords)); // clear it
char line[MAXWORDLENGTH*2]; // double max size just in case
FILE* fwords;
int errnum = fopen_s(&fwords,filename, "rt");
if (!fwords) {
printf("Missing word file %s", filename);
}
int wordIndex = 0;
while (fgets(line, MAXWORDLENGTH, fwords)) {
int len = strlen(line);
if (!len)
break;
if (line[len-1] == '\n')
line[--len] = '\0';
pWord pNewWord = (pWord)malloc(len + 1);    // line 27
if (!pNewWord) {
printf("Error allocating memory");
break;
}
if (wordIndex < MAXWORDS) { // can add to list
strcpy_s(pNewWord, len+1, line);  // line 33
allwords[wordIndex++] = pNewWord;
}
}
fclose(fwords);
return wordIndex; // = Count of words
}
int main() {
int numWordsread = ReadWords("words.txt");
}
'; pWord pNewWord = (pWord)malloc(len + 1); // line 27 if (!pNewWord) { printf("Error allocating memory"); break; } if (wordIndex < MAXWORDS) { // can add to list strcpy_s(pNewWord, len+1, line); // line 33 allwords[wordIndex++] = pNewWord; } } fclose(fwords); return wordIndex; // = Count of words } int main() { int numWordsread = ReadWords("words.txt"); }
Fun with optimisation in C

Fun with optimisation in C

Inner cogs
Image by ar130405 from Pixabay

Bit twiddling with C is quite a common thing but sometimes it can be hard to understand something quite simple.  Here’s a line of code. Can you say what it does? Note that a,b and c are all ints.

c = b ^ ((a ^ b) & -(a < b));

Or how about this which looks quite similar

c = a ^ ((a ^ b) & -(a < b));

The first line puts the minimum of a and b into c, while the second line puts the max of a and b. Both came from a page of bit twiddling hacks by Sean Eron Anderson at Stanford university. The significant thing about these is not that they provide two clever if incomprehensible ways of calculating min and max but they do it without branches.

If you look at the source of min and max in stdlib.h they are defined like this:

#define max(a,b) (((a) > (b)) ? (a) : (b))
#define min(a,b) (((a) < (b)) ? (a) : (b))

Because modern CPUs use instruction caches (pipelines), they try to keep them full through a technique called branch prediction. If a branch happens then the CPU has to read instructions from the wherever the branch goes to and this causes a pipeline stall which slightly slows down processing. So branchless min and max should run faster than branching code, at least in theory.

I tried it on Windows using a small Visual C++ (Well C) program doing the four in a loop 10 million times. I also ran it in 32-bit and 64-bit.  All runs were done in release mode which lets the compiler optimise.

Curiously the 32-bit took almost no time at all while the 64-bit took a lot lot longer. There wasn’t much difference between branchless and branch. Possibly the code is too small and the benefits of branchless are less significant because the instructions fall inside the instruction cache for 32-bit while 64-bit may be too big and so is affected by instruction cache misses.

This is the 32-bit time.

fastMin 0.0000000
fastMax 0.1000000
Min 0.1000000
Max 0.1000000

And this is the 64-bit. Quite a lot of difference!

fastMin 1757.6000000
fastMax 1677.9000000
Min 2039.4000000
Max 2134.4000000

This is the code which compiles in Visual C++. You can get the hr_time timing code (for WIndows) from the sdlttf.zip file. I increment and decrement a and b to stop the compiler possibly spotting that the values would be invariant otherwise and doing too-clever optimisation stuff.

#include <math.h>
#include <stdio.h>
#include "hr_time.h"

#define NUMLOOPS 10000000
	int a = 1000;
	int b = 67;
	int c;
	double t;
	stopWatch s;

int main() {

	startTimer(&s);
	for (int i = 0; i < NUMLOOPS; i++) {
		a++;
		b++;
		c = b ^ ((a ^ b) & -(a < b));
	}
	stopTimer(&s);
	t = getElapsedTime(&s) * 1000000.0;
	printf( "fastMin %8.7f\n", t);
	startTimer(&s);
	for (int i = 0; i < NUMLOOPS; i++) {
		a--;
		b--;
		c = a ^ ((a ^ b) & -(a < b));
	}
	stopTimer(&s);
	t = getElapsedTime(&s) * 1000000.0;
	printf("fastMax %8.7f\n", t);
	startTimer(&s);
	for (int i = 0; i < NUMLOOPS; i++) {
		a++;
		b++;
		c = min(a, b);
	}
	stopTimer(&s);
	t = getElapsedTime(&s) * 1000000.0;
	printf("Min %8.7f\n", t);
	startTimer(&s);
	for (int i = 0; i < NUMLOOPS; i++) {
		a--;
		b--;
		c = max(a, b);
	}
	stopTimer(&s);
	t = getElapsedTime(&s) * 1000000.0;
	printf("Max %8.7f\n", t);
}

Learning C and SDL

Learning C and SDL

Learning
Image by Gerd Altmann from Pixabay

I frequent the Reddit C subreddit and Quora.com and quite often see people asking what they should learn first. So I’ve updated the C tutorials page (link at top) with details of future tutorials as well as a new one on functions. This includes the entire course (though some are not yet written).  It has more details about each lesson and shows the whole course,

There’s considerable overlap with material in my first EBook though that was for Windows only and this is for Windows, Linux and Raspberry Pi. The Pi of course is Linux with some hardware specific stuff and I’ll include links back to previous blog entries which have explained how to get and display the Pi’s temperature in a C program or use game pads.

Unlike other C courses it will include SDL2 code and how to use it. I think C + SDL2 is a great way to make 2D games, and is probably the easiest and simplest to learn.

 

The joys of SSL certs

The joys of SSL certs

Certificate ass u meThere’s a saying “Don’t assume- it makes an ass of U and me“, and I er fell foul of this a month ago. A couple of months ago I setup a cheap VPS. It was one of those that you pay every month. What I didn’t realise was you are explicitly meant to renew the hosting every month and they send you an email with a link. Of course what did I do?, I er forgot to renew it. Annoyingly, I’d installed Virtualmin, redirected a domain and bought a cheap SSL certificate. All lost.

Now I actually did something right and there’s a lesson here. When you setup a SSL certificate, you create a CSR (Certificate Signing Request) and a Private key. You upload the CSR, pay your money (£20 for four years) and get a certificate back. The hosting companies I’ve used provide a SCR creation facility and somewhere to paste the private key and certificate when you get it. Then you click a button and your website now has a working SSL. It couldn’t be easier.

So luckily for me I had made a backup copy of my private key and was able to download the certificate. I’ve setup a completely new VPS, redirected the domain and very nervously pasted in the cert and private key. It worked. I had been bothered that the CSR was generated on a different server but it doesn’t seem to matter. So long as you have the private key the certificate works on a different server.

 

Hyper-V VMs are not all the same

Hyper-V VMs are not all the same

Hyper-V Ubuntu installOne of the big problems with Hyper-V and Ubuntu in particular is the clipboard or lack of it. I had 18.04 LTS installed with an X Org RDP login. This worked perfectly and I could have a full screen in my Monitor and could copy/paste.  Don’t underestimate copy/paste.

It’s a real PITA if you have to use say WinSCP to copy files over. I think WinSCP is excellent BTW but the amount of labour saving that copy/paste has done since some genius thought it up is immeasurable. That and allowing the full screen of the monitor are two highly important things.

Sadly the 20.04 LTS didn’t seem to allow it. Copy/paste didn’t work between my Windows PC (host) and Ubuntu (guest). There’s nothing worse than losing a feature you’ve grown fond of.

If you follow these instructions for creating a Hyper-V 18.04, you get the screen size popup but not with 20.04 LTS. For that you have to follow these instructions!

It’s things like this that suggest why Linux Desktop has never been that successful. You can waste many hours getting simple things working and sometimes like Copy/Paste they break between versions. And this is with Ubuntu, probably the biggest and best known and supported Distro.

 

Interesting looking Game Handheld device- Odroid-Go

Interesting looking Game Handheld device- Odroid-Go

Odroid-GoThe Odroid-go Game kit looks like a gameboy. It has a LCD, game controllers and the case. It has a CPU that runs between 80 and 240 MHZ, 4MB RAM, WiFi, Bluetooh, a Micro-SD slot, a rechargeable battery – charged through a Micro USB, a built-in speaker and a 320 x 240 LCD. That may not sound very much but all the CBM-64 games ran on that size of screen and it only had 64 KB of RAM.

There’s more information on the manufacturers website (it’s in English though it is Chinese made) and all the useful information is on a Wiki with info on emulators, downloadable games and how to write programs for it using the Arduino programming language which is very much like C/C++. You have to install Arduino for ESP32 first on a Pc (Windows, Linux or Mac) then can you write programs and run them on your Odroid-Go.

There’s a bit of assembling but the website includes instructions with photos. A quick search on Youtube found a video showing how to assemble it.

This is an example of Arduino code, taken from their online reference manual. The Ardunio has been around for several years so there is a lot of code around for it.

// the setup function runs once when you press reset or power the board
void setup() {
  // initialize digital pin LED_BUILTIN as an output.
  pinMode(LED_BUILTIN, OUTPUT);
}

// the loop function runs over and over again forever
void loop() {
  digitalWrite(LED_BUILTIN, HIGH);   // turn the LED on (HIGH is the voltage level)
  delay(1000);                       // wait for a second
  digitalWrite(LED_BUILTIN, LOW);    // turn the LED off by making the voltage LOW
  delay(1000);                       // wait for a second
}
To brace or not to brace

To brace or not to brace

Abstract programming picture
Image by Gerd Altmann from Pixabay

This isn’t exactly confined to C, in fact it applies to many programming languages where braces or curly brackets {like this} are optional after an if. It even applies to Pascal with Begin ends which are optional after an if.

You can have the first or the second as shown below.

if (expressions) 
  DoSomething;

if (expression {
  DoSomething;
}

I saw a recent example where the DoSomething was a logging expression which the compiler optimised away so the if, which lacked braces applied to the next statement. As the if was only true on rare occasions. It meant that that statement which should have been run every time was only run on those rare occasions.

So the prevailing wisdom and one that I entirely agree with is that you should always use braces. If you don’t you risk accidentally introducing bugs like this.

Note. that link is to a discussion on the C programming Subreddit (on Reddit.com).

.