Up to Main Index                          Up to Journal for November, 2023

                    JOURNAL FOR FRIDAY 17TH NOVEMBER, 2023
______________________________________________________________________________

SUBJECT: Optimising math and constants + Mere embedded server demo
   DATE: Fri 17 Nov 20:56:48 GMT 2023

After my Covid and flu shots last Friday still feeling awful. As a bonus, I’m
now developing an annoying cough and the start of a cold.

I’ve continued toying around adding constants to Mere. Actually there are two
types of constants, optimised and non-optimised. Don’t worry, it’s all handled
for you automatically ;)

The optimised form is where the constant is a simple int, uint, float, string
or bool value:


    const i := 3
    const u := 3u
    const f := 3.3
    const s := "three"
    const b := true


When an optimised constant is referenced the constant variable is replaced by
its value. For example:


    println i // becomes "println 3"


This was mentioned in my previous post. I’ve added a new math optimisation
compile phase. The math optimisations simplify constant math expressions:


    println 3 + 7 // becomes "println 10"


Now if we take the constant and math optimisations together:


    const a := 3
    const b := a + 5 // a replaced with 3 "3+5", replaced by "8"
    println b        // becomes "println 8"

    // Equivalent code after optimisations
    const a := 3
    const b := 8
    println 8


Parenthesised expressions are also supported for math optimisations:


  const a := 1 + (2 * 3)
  const b := (1 + 2) * 3
  println a   // displays "7"
  println b   // displays "9"


The math optimisations apply to the program as a whole — not just constants.
However, only a subset of operators are simplified:


  int, uint, float: add ‘+’, subtract ‘-’, divide ‘/’, multiply ‘*’

         int, uint: bit-wise AND ‘&’, bit-wise OR ‘|’, bit-wise XOR ‘^’
                    bit-wise shift left ‘<<’, bit-wise shift right ‘>>’
                    modulus ‘%’,

              uint: bit-wise NOT ‘!’

            string: concatenation ‘+’, repetition ‘*’, extended string ‘~x’

           boolean: logical NOT ‘!’

     miscellaneous: open parentheses ‘(’, close parentheses ‘)’


I have all of the above working now in my development branch, just need to
finish the tests and documentation.

All optimisations happen at compile time. This improves runtime performance,
especially for something like a server where programs are compiled once and
are cached then execute multiple times.

Talking of servers using Mere, a colleague asked how easy it would be to embed
Mere into a server. So I knocked up a demo for them in 5 minutes:


    package main

    import (
      "log"
      "net/http"

      "code.wolfmud.org/mere.git/mere"
    )

    var code = map[string]mere.Export{}

    func main() {
      code["/hello1"] = mere.Compile("helllo1",
       `for x := 1; x <= 10; x++
          print x " "
        next
        println
        println (elapsed,string ["stampNano"])
      `)

      code["/hello2"] = mere.Compile("hello2",
       `for x := 10; x >= 1; x--
          print x " "
        next
        println
        println (elapsed,string ["stampNano"])
      `)

      http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        w.Write([]byte("<!DOCTYPE html><head><body><pre>"))
        if code, ok := code[r.URL.Path]; ok {
          inst := code.Copy()
          inst.Stdout = w
          inst.Execute()
        } else {
          w.Write([]byte("Not found " + r.URL.Path))
        }
        w.Write([]byte("</pre></body></html>"))
      })

      log.Fatal(http.ListenAndServe(":8080", nil))
    }


The server has two simple hard-coded programs. One counts from 1 to 10 and the
other from 10 to 1, both then print the elapsed time:


  >w3m -dump http://localhost:8080/hello1
  1 2 3 4 5 6 7 8 9 10
  0:00:00.000066795

  >w3m -dump http://localhost:8080/hello2
  10 9 8 7 6 5 4 3 2 1
  0:00:00.000047826


Hitting the server with the Apache benchmark tool gets about 51k pages/sec
with a concurrency of 5,000 connections over 100,000 requests. The Mere code
is compiled once and then executed for each request. Not too shabby, but it is
only HTTP not HTTPS. Running over HTTPS, loading files to compile at server
start-up and compressing output would be easy enough to add — this was just a
quick demo ;)

For something a bit more substantial than simple for-next loops I also threw
in the “times table” and “ASCII table” examples from Mere ICE. The first
managed 8k pages/sec and the second 22k pages/sec :|

This was without any network tuning or optimisation on my regular desktop…

--
Diddymus


  Up to Main Index                          Up to Journal for November, 2023