On Moldova


When I started this blog the intenetion was to stay off politcs, but some things are too important.

I cannot say I am really an expert on Moldova but I have been there many times and worked as a political consultant for good and bad people there. One person I worked for ended up in jail, another fled the country before he could be – he feared – imprisoned.

But two people I worked with, and have absolute confidence in, are Maia Sandu and Nicu Popescu. As Maia is now president and Nicu is deputy PM and foreign minister, that gives me great hope for the country’s future.

President Sandu’s election marked a decisive turning point in Moldovan politics because it signalled the end of Moldova’s 15 – 20 years of stumbling down the road of corruption as a way of life, with the state’s principal role as being a protector of rent seekers. She and her team (her party went on to win the parliamentary elections which is why Nicu Popescu is in government) have a long way to go, but knowing them as I do I am sure their determination is great.

Maia Sandu’s first job in government was as education minister, where her mission was to end the routine and all-but-open system of bribery to fix school examinations. It seems almost unbelievable that such a system existed – you basically paid the teachers and got told what the exam questions and answers would be – and even more ludicrous that it was accepted by so many as a good way to live, but as with many examples of corruption it was not just accepted but often actively promoted by those who made money from it. Minister Sandu faced a viscious campaign of smears and threats – often from politicians she was nominally in government with but who were the patrons of the bribers – when she ended it: but she didn’t back off and it, in fact, made her ever more determined to put Moldova back on track.

As of today the focus in the UK is on the idea of supplying Moldova’s armed forces with modern, NATO-standard, weapons. I’m not against this – if the Moldovans have asked for this, they should get them. But Moldova is not Ukraine. It’s tiny in comparison and it doesn’t have the experience of the Ukrainians in fighting the Russians and their proxies for the last eight years. In short – Moldova’s ability, certainly alone, to hold off a Russian attack would be very limited no matter what weapns it had.

Of course, if this happened Moldova would likely be fighting in alliance with Ukraine. But then the crucial thing would be, I’d hazard, that its military logistics, tactics and doctrines were as good as the Ukrainians’ obviously are. That suggests to me that training is far, far, more important than weapons right now. (Though ultimately this is for the Moldovans to decide).

I think, if invited, British and other NATO trainers could and should go into Moldova now and establish training bases. It’s not an escalation – because Moldova is at war with nobody – but it is a warning and a deterrent, and that’s not a bad thing.

But more generally we should also be mindful of Moldova’s history – the Russians are having to work quite hard to stoke up the flames of fear in Transnistria, the “breakaway” statelet created in eastern Moldova in the mess of the USSR’s breakup. The reason for that is that Transnistria’s break with the rest of Moldova has been very far from complete. The fact that the leading football team of the Moldovan league is from Transnistria helps tell the story.

The Transnistrian state’s continued existence is as much to do with the economic interests of its ruling elite (and of its people in the poorest corner of Europe) as with anything else. Crudely, they can make money out of being part of a zone beyond the reach of international law, and the prospect of foregoing that to become part of Moldova – hardly any less poor – is not a big attractor. The ethnic factors – as well as nostalgia for Soviet certainties – are the front-of-shop arguments for sure (and being from Northern Ireland I am always at least a little wary of saying economic factors can render them null), but they need not be fatal stumbling blocks.

Building Molodovan state capacity – turning it into an economic magnet for Transnistria and strengthening the rule of law and respect for human rights – rather than any prospect of military reconquest ought to be the way to solve the Transnistrian conflict and it has, essentially, been the approach used until the Russians attacked Ukraine and decided that they had to try to open a second front in Moldova by stoking up fear of a Moldovan invasion of Transnistria.

Whatever decision is taken by Britain and Moldova on weapons and military training, a parallel decision to actively assist the Moldovan state in meeting the requirements needed to achieve its aim of joining the European Union ought to also be a foreign policy priority for the UK.

It might seem odd to suggest that the one country that, in the whole history of the “European project”, has walked away from it should play this role – but why would it be? Moldova has made its sovereign decision to join the EU, the values of the EU about democracy, open markets and rule of law are (as UK politicians often argue) things the British state also stands for and the UK understands the rules of mechanisms of the EU better than any non-member state.

That is might also help soothe UK-EU relations would be an added (and big) bonus.

How I actually extended Riscyforth


Before I suggested I was going to add dynamic linking by rolling on object files but that turned out to be pretty inflexible.

Then I thought I could pass needed initialisation values via use of the gp register (using it as a stack pointer). That actually seemed to work but it was pointed out to me that I could be taking a big gamble on what might happens when interrupts were called and I had a bogus value in that register.

The solution turned out to be quite simple – a very small shared library that is linked to both to the main executable and to the modules – I can even make it easy on myself and write it in C:

/** RISCYLIB                                            **/
/** Common code for Riscyforth and Riscyforth modules   **/
/** Copyright (C) Adrian McMenamin, 2022                **/
/** Licenced for reuse under the terms of v2 of GNU GPL **/

unsigned long nextAddress = 0;
unsigned long dictionaryAddress = 0;

unsigned long getNextAddress(void)
{
	return nextAddress;
}

void setNextAddress(unsigned long addressIn)
{
	nextAddress = addressIn;
}

unsigned long getDictionaryAddress(void)
{
	return dictionaryAddress;
}

void setDictionaryAddress(unsigned long addressIn)
{
	dictionaryAddress = addressIn;
}

This just providers getters and setters for two variables which are used to provide the address of the NEXT function (called by every Forth word at the end of execution) and to manage to end end of the dictionary (as we load modules we add their word definitions to the end of the dictionary).

Midnite Commander gives us some more information about the compiled libriscy.so:

Here dictionaryAddress and nextAddress symbols are marked as ‘B’ – ie in the BSS section, while the get and set functions/sysmpols are marked as T – ie in the “text”, or executable, section of the library.

Managed or unmanaged: funds and football


Some people are making a lot of money in the City of London and elsewhere by proactively managing investment funds (such as pensions) and charging a fee for their expertise? Are they worth it: the evidence doesn’t seem to be very clear.

I am reminded of this by the consistent failure of my efforts to manage my fantasy football team – looking out repeatedly for the bargain buys and the clever ways to game the system. And failing.

Someone should actually take the data and calculate whether a managed strategy – actively looking for hidden gems (perhaps by averaging the performance of the teams that most regularly transfer players), or simply algorithmically picking the best available team at the start of the season (based on the previous year’s performance) and leaving it be, would give the better results.

Adding dynamic linking to Riscyforth


This is one of those blogs one writes to clarify inchoate thoughts, so it’s sorry-not-sorry if it starts to wander around…

Last week I got to an important point with Riscyforth, my Forth for RISC-V single board computers: I tagged my first release (v0.1).

I did that because I had, finally, managed to cover all of the core and extended core code of the Forth 2012 standard. Essentially that means something written using words from the core of the language should compile and run (and give correct results).

But merely covering the core definitions doesn’t deliver a system that many real-world users will want to play with except out of curiosity. No floating points maths, no control over screen output beyond, essentially, printing line by line (though there are a few additions here like coloured output) and certainly no graphics.

But I also don’t want to build an ever-larger monolithic system. Users should be able to pick and choose which parts of the extended language they get (as well, of course, being free to extend it in Forth itself).

That is going to require some form of dynamic loading and linking. Whilst all the tools are now available for anyone (with a screw-loose) to write their own extended floating point words using the integer primitives, it’s much more sensible to provide words (written in assembly) that call the library code provided by the operating system.

My initial thought was that there should be a riscyforth.conf file in the Riscyforth distribution that would list what modules are loaded on startup. But I now think a more flexible way is to provide a new Forth word – LOADMODULE ("<name>" -- flag) say – that would specify a module that could be loaded. This word could be used at anytime, but if we put it in a short Forth file/program – eg startup.fth – then Riscyforth could be made to execute this at start-up time and so users would edit that program/file to fix what they started with.

But how to implement? The best way seems to be to supply object files (along with the source, this is a GPL-licenced project) and have mmap load them into memory. My code already uses mmap to create the space where new words can be written, so the theory seems sound enough and I have found this on the web which says it can be done. But it might also be a bit of a challenge – but then again, it wouldn’t be any fun if it wasn’t.

Getting Covid


The Government won’t tell you this – so I will – it wants (most) of us to catch Covid. And this week I complied.

The Government aren’t out to get most of us infected because they are evil and want people to die. Instead they (I assume) see something like the following as good reasons not to be unduly worried about the fact we now have record infection rates in the UK:

  1. Infection, in general, boosts immunity to future infections and for most people (this includes me) who have been vaccinated, the current variant doing the rounds is likely to be less severe than previous variants, so it’s better to acquire additional immunity from this variant than from what might be coming next (more on this below).
  2. We are now in the Spring and generally this leads to lower demands on the health service anyway, so if people are going to get infected it’s better that it happens now and not in the winter.
  3. Most adults have now had three doses of vaccine in the space of 12 months – if the effect of vaccinations fades over time (making it more likely that those infected will face serious problems) and newer variants are more likely to evade vaccines, then – the argument runs – better to get it now and boost acquired immunity.

None of these arguments are foolproof – and Christina Pagel cuts through a lot of the complacency like a knife through butter. And, of course, there is the basic trust-weakening dishonesty about the whole thing: but nor are they scientific mumbo-jumbo.

Pagel’s most salient point (which goes to 1 on the list above) is that we can have no certainty that any future variants will be less severe than any we have seen in the past. They are just as likely to be more severe – as severity and transmission are not evolutionarily linked for the Sars-CoV-2 virus.

The current approach of pretending the pandemic is over is likely to severely weaken public trust in future health measures, if required,

Her point that there is not much more we can do with the current vaccines is also one that should be taken seriously: despite the promise that mRNA vaccines offered the ability to relatively quickly reconfigure what was on offer there has been little done on that front. Partly, I’m sure, because the commercial risk is high: that is where governments could and should intervene to share the risk.

As for me: so far it hasn’t been worse than a bad cold – the mornings are worse than the afternoons for some reason: sleep can be poor because of a sore throat and it’s often very sore first thing, though gets better quickly after that.

Getting the POSTPONE word to work in Forth

RISCYFORTH in action

I have struggled with this issue for several weeks now and I didn’t find the explanations in Starting Forth or the 2012 Forth standard or even the GForth documentation particularly enlightening, so I wanted to write this to – hopefully – add some clarity to anyone else trying to get this right in their own Forth implementation.

The standard says this of POSTPONE:

Compilation:

“<spaces>name” — )

Skip leading space delimiters. Parse name delimited by a space. Find name. Append the compilation semantics of name to the current definition. An ambiguous condition exists if name is not found.

But what does that actually mean? I think there are three rules you need to apply (of which more later), but first you need to think about where they are applied. Typically you might have something like this:

: ENDIF POSTPONE THEN ; IMMEDIATE

: EXAMPLE IF ." Say something" ELSE ." Say something different" ENDIF ;

ENDIF here replacing the modern standard THEN (some older Forth code may contain the ENDIF word, and our ENDIF should be a perfect replacement).

Now, we have defined ENDIF in its own word but we want it to act inside the word EXAMPLE – in this case we want it to ensure that what we might call the contractual obligations of THEN (in this case to inform ELSE clause where code following the ‘true’ path should jump to when it hits ELSE).

Now, defining our ENDIF word as IMMEDIATE ensures it is activated when we are compiling EXAMPLE, but it all it did was call itself then it would do literally nothing (as in Riscyforth, in any case, THEN in execution is a NOP).

What we actually want to see happen is that compilation actions of THEN are activated and that their effects are seen in EXAMPLE.

In this case that means calculating and inserting the jump-to address for the ELSE. Exactly what a THEN would do if it were there in EXAMPLE.

(The badging of ENDIF as IMMEDIATE then gives us a second boost – because that labelling means it doesn’t get called when EXAMPLE is executed, so we don’t have to worry about it trying to compile in those actions every time EXAMPLE is called.)

In Riscyforth there are a number of words – currently LITERAL, DOES>, ABORT”, .”, S”, , [‘], COMPILE,, IS, TO, [CHAR], ACTION-OF, AGAIN, UNTIL, DO, ?DO, LOOP, +LOOP, -LOOP, UNLOOP, LEAVE, RECURSE, I, J, EXIT, IF, ELSE, THEN, OF, WHILE, REPEAT, and ; (though others will probably need to be added as the code is matured) – that need special handling on compilation and that has to be reflected if they are POSTPONE’d with those special handling routines compiled into the colon word being worked – for the other, “ordinary”, words what has to happen is that a reference to them is what gets compiled in – here’s another example:

: -IF POSTPONE 0= POSTPONE IF ; IMMEDIATE

In this case we’ve defined a new word -IF which works in the opposite sense (Boolean-wise) to the standard IF, i.e, what was FALSE on IF is treated as TRUE in -IF and so on. The key here is that, for example:

: WASFALSE -IF ." Result was FALSE " ELSE ." Result was TRUE " THEN ;

That the 0= gets compiled into the definition of WASFALSE and not left to languish inside -IF. Because – again – -IF, being marked as IMMEDIATE, never gets called again after the initial invocation on compilation – what it leaves behind is what gets called.

So – those three rules:

  1. If a word is marked as IMMEDIATE then POSTPONE strips it of that character and it becomes JAW – just another word. These words are not compiled into a new definition, they are simply executed when they are reached.
  2. If a word requires special handling on compilation that special handling should be repeated when it is POSTPONE’d.
  3. All POSTPONE’d words that are not immediate should be compiled into the current colon definition being worked on (that phrase “the current definition” from the standard is extremely confusing).





Mo Salah, penalties and artificial intelligence


Last night, as Leicester City played Liverpool, Mo Salah, current top scorer in the English Premiership, was taken down in the penalty box and then stepped up to take the (correctly-awarded) penalty.

Salah hardly ever misses a penalty. It’s about as nailed on as you can get that he will score. Except last night he didn’t. Something – a badly placed kick, a goalkeeper at the top of his game, a momentary lack of concentration, who knows – meant he kicked the ball into the keepers hands (and then failed to score on the rebound).

Well, it happens. Form is temporary, class is permanent as the saying goes. But what struck me was I knew, I just knew, he was going to miss. Something in the few seconds before he struck the ball made me think he wasn’t going to do it.

To be honest, this is quite a common feeling (for me, anyway). But not all the time. David O’Leary’s famous “the nation holds its breath” penalty never bothered me at all. Never in doubt.

But the thing that interests me here is that I am sure I am the only one who feels this way about penalties and furthermore my belief – untested – is that when I feel that someone is going to miss I am right more times than I am wrong.

An unverified search on the internet says that 70% of penalties awarded in the English top flight are scored, so testing for people’s ability to predict a miss ought not to be too hard – (at these odds a random miss predictor would be relatively easy to spot).

If people can do it through some sort of split-second multiply parallel assessment of the factors – the morale of the team, the state of the game, the look of the keeper and, I think above all, the look and feel of the man taking the kick – the question is then whether we could build a machine that did this too.

What would be the point of that? Well, part from the “it’s interesting” factor there is presumably an arbitrage opportunity out there somewhere that would allow those informed by the machine to bet on the outcome. That, of course, would be of no net social benefit to humanity as a whole and probably isn’t something to be encouraged, but still I do think it’s fascinating.

Winning the evolutionary war?


Earlier this week I wrote that there appeared to be no evolutionary biological reason to think the corona virus would evolve at present to be less deadly. It’s starting to look like I was wrong.

In fact it looks as though the vaccines have driven selection of changes in the virus’s spike (to evade vaccination-driven antibodies) that make it less likely to be able to inflict serious harm on humans. If so it’s an unexpected bonus from what is already the great scientific achievement of the century. Anti-vaxxers should (but are unlikely to) note that those of us who did our duty to society by being vaccinated have delivered this, not them.

But, of course, it’s all far from good news. The Omicron variant is clearly much more transmissible and is still a killer. Those who have not been vaccinated are at particular risk. If numbers hospitalised keep rising at the anything like the current rate then the health system could still be swamped even if the risks to any individual are lower.

If you can, get vaccinated and help give us the tools to finish the job.

More on the Riscyforth versus Gforth shootout


This is a further post about optimising Riscyforth, my Forth language for RISC-V single board computers.

Riscyforth is a 64-bit Forth which runs on top of Linux – my test system is the Sipeed Nezha SBC – which runs a 1 GHz single core CPU (so 1 cycle is one nano-second). I’m testing it against GForth, the GNU Project’s Forth.

Whilst Riscyforth is written in RISC-V assembly, GForth is mainly Forth on top of C. For those familiar with Forth techniques – Riscyforth is a very traditional indirect threaded implementation, GForth uses a mixture of this and (faster) direct threaded code.

GForth also sticks to the Forth standard of 32-bit numbers as the default, Riscyforth uses 64 bit numbers throughout.

GForth is a much more sophisticated (and portable) environment than Riscyforth – and certainly my suggestion/intention has never been to claim I will write a better Forth than GForth – the GForth effort goes back to the 1990s, Riscyforth goes back to 28 December 2020!

The two key posts before this are:

The quick summary of the material those two posts is that I could make significant timing savings in my code with some optimisation steps that replaced correct but long-winded compile-time generated code that loaded registers with fixed (at compile-time) numbers via a sequence of adds and bit shifts, with code that loaded those values from a known memory location.. However those optimisations were not enough to close the gap on performance with the GNU Project’s GForth – which runs matrix.fth about 12% faster.

My code started out at taking about 9.5 seconds and I have got that down to about 8.5 seconds, whilst GForth is taking about 7.5 seconds.

Not satisfied with leaving it there I wrote some code to count cycles taken in executing Forth words or groups of words, and looked closer at what might be fixable.

		CODEHEADER DEBUGIN, Q, 0x0
		#(--)
		#debug word
		la t0, CYCLESTART
		rdcycle t1
		sd t1, 0(t0)
		tail NEXT
		
		CODEHEADER DEBUGOUT, DEBUGIN, 0x0
		#(--)
		#debug word
		rdcycle t0
		la t1, CYCLESTART
		ld t2, 0(t1)
		bgt t0, t2, debugout_normal
		li t3, -1
		sub t4, t3, t2
		add t4, t4, t0
		j debugout_sum
  debugout_normal:
		sub t4, t0, t2
  debugout_sum:
		la t5, CYCLECOUNT
		ld t0, 0(t5)
		add t1, t0, t4
		sd t1, 0(t5)
		la t6, CYCLEPINGS
		ld t2, 0(t6)
		addi t2, t2, 1
		sd t2, 0(t6)
		tail NEXT

		CODEHEADER DEBUGRESULTS, DEBUGOUT, 0x0
		#(-- n n n)
		la t0, CYCLECOUNT
		la t1, CYCLEPINGS
		ld t2, 0(t0)
		ld t3, 0(t1)
		div t4, t2, t3
		addi sp, sp, -24
		sd t2, 0(sp)
		sd t3, 8(sp)
		sd t4, 16(sp)
		sd zero, 0(t0)
		sd zero, 0(t1)
		la t2, CYCLESTART
		sd zero, 0(t2)
		tail NEXT

DEBUGIN records the cycle count at the start of some block of code, whilst DEBUGOUT calculates the time since the previous call to DEBUGIN, adds that to a total of elapsed times and increments a counter. DEBUGRESULTS then places, on the stack, the average time per IN – OUT cycle, the total number of samples and the total elapsed cycles.

Looking at the Forth code, the main word is what we call to run the program:

It initialises two 300 x 300 matrices (each initialisation taking about 53 million cycles) and then executes a loop and a nested loop: each loop runs 300 times, so the inner loop is executed 90000 times. The outer loop is recorded as taking just over 26 million cycles per execution whilst each inner loop takes about 87000 cycles per iteration.

The code to measure the cycles has an effect on the measurement so we can only be approximate here – eg while the inner loop is measured as taking 87000 cycles per iteration, each execution of innerproduct is measured as requiring around 88000 cycles (ie, longer than the code that calls it – an obvious contradiction). The test code itself is measured as taking about 15 cycles per execution – not much in itself, but rising to 409 million total cycles when called 27 million times inside innerproduct.

: innerproduct ( a[row][*] b[*][column] -- int)
  0 row-size 0 do
    >r over @ over @ * r> + >r
    swap cell+ swap row-byte-size +
    r>
  loop
  >r 2drop r>
;

In any case it is clear that innerproduct is where the real work is done:

Inside innerproduct lurks another loop, again called 300 times, meaning that the code inside this loop gets called 300 x 300 x 300 – 27 million – times: the graphic above shows the approximate (having accounted for the cost of calling the instrumentation code) total cycle count for each line of that loop.

Right at the start of this (see the first post linked above), the big cycle burner was the constant code: row-byte-size here, so it’s good that no longer seems to be the case.

It’s hard to be precise about this (a test of the row-size constant in main suggested, accounting for the cost of the instrumentation code, that it took about 269 cycles per execution but that looks to be a significant over-estimate as that would imply, if row-byte-size took the same time as the other constant (as it should) that 27 million executions of it alone should take about 7 billion cycles. A better guide seems to be that the nine words of the first line take a little bit less than twice the cycles/time of the five words of the second line – suggesting that each word takes on average a roughly similar time.

The final line in innerproduct is not inside the innermost loop and so is only called 90,000 times and takes, roughly, 8 million cycles.

It’s not possible to measure the cost of the loop control code using my simple instrumentation (as execution is not linear – all the work after the loop initialisation is done at the loop word) but as the total execution time of innerproduct (as measured inside innerproduct itself) is estimated at 7.6 billion cycles it seems unlikely the do ... loop code is particularly expensive.

This is all good news at one level: there appear to be no bits of code here chewing up cycles outrageously (each of the 14 words of the first two lines take roughly 19 cycles to execute, including the time taken to move from one word to another via the Forth threading).

But at level another it represents a bit of a dead end for efforts to optimise the code. All the words being executed here are pared down to the minimum and there is no room to squeeze anything out of them.

I covered that before in the initial posts but here’s a quick reminder/example:

		CODEHEADERZ TOR, >R, TOR2, 0x01 #>R
		POP t0
		addi s9, s9, -STACKOFFSET
		sd t0, 0(s9)
		tail NEXT

		CODEHEADERZ RFROM, R>, TOR, 0x01 #R>
		ld t0, 0(s9)
		PUSH t0
		addi s9, s9, STACKOFFSET
		tail NEXT

The >R and R> words are called repeatedly in the loop. They use the POP and PUSH macros which add or remove a 64 bit register from the stack:

.macro PUSH register
        addi sp, sp, -8
        sd  \register, 0(sp)
.endm

.macro POP register
        ld \register, 0(sp)
        addi sp, sp, 8
.endm

While the s9 register is used to manage the return stack (ie as a stack pointer to that stack) – so you can see these words just transfer a 64 bit value to and from two different stacks and there is just nothing that can be done to save cycles here (or if there is, I’d very much welcome being told about it).

So, it seems, GForth is the winner here – a Forth based on optimised C is not just portable but would appear to be faster too.

But, actually, I have some counter evidence.

The Forth program factoriel.f calculates the numerals of factorials. In Riscyforth I can calculate the factorial of 10000 (ie, 10000!) in about 26 seconds:

But GForth cannot manage it at all – though if I double the number of cells allocated in GForth (which means both systems have the same amount of resources due to the difference between 64 and 32 bits) it will work – but it takes around 36 seconds.

GForth will calculate the factorial of smaller numbers faster than Riscyforth though: if we try 3200! (close to the limit GForth can manage with the original settings for cell numbers) then GForth takes about 7 seconds and Riscyforth takes about 8 seconds.

Taken together these results suggest to me that at least there is nothing broken in Riscyforth. It’s about as fast as it could be with 64 bit arithmetic and the indirect threaded model.