I do not use dmd -run
too often, but recently was checking out Nim language, and they also do have run option, plus pretty fast compiler, so checked it out.
Then, I was curious about trends of dmd -run
, and did some historical tracking.
The example is simple example from nim website, ported to Python and D. It imports writefln
, and std.array
(for split), defines a simple data only class, construct array of few objects, do some iterations, as well do some very small compile time generation, and generator (in I used foreach over delegate). It is very small program, with nothing interesting going on, so we are are mostly measuring compiler, linker, parsing few libraries we import, and startup times.
x | min wall time [ms] | Notes |
---|---|---|
Python 3.11.6 | 31.4 | |
Nim 2.0.0 (cached) | 139.4 | |
Nim 2.0.0 (uncached) | 711.4 | cached binary removed before each re-run |
gdc 13.2.0-7 | 1117.0 | |
dmd 2.106.0 | 728.1 | |
dmd 2.105.3 | 712.9 | |
dmd 2.104.2 | 728.2 | |
dmd 2.103.1 | 714.7 | |
dmd 2.102.2 | 714.0 | |
dmd 2.101.2 | 853.0 | |
dmd 2.100.2 | 842.9 | |
dmd 2.099.1 | 843.7 | |
dmd 2.098.1 | 898.1 | |
dmd 2.097.2 | 771.9 | |
dmd 2.096.1 | 729.7 | |
dmd 2.095.1 | 723.1 | |
dmd 2.094.2 | 1008 | |
dmd 2.093.1 | 1078 | |
dmd 2.092.1 | 1073 | |
dmd 2.091.1 | 790.6 | |
dmd 2.090.1 | 794.0 | |
dmd 2.089.1 | 771.1 | |
dmd 2.088.1 | 802.1 | |
dmd 2.087.1 | 790.6 | |
dmd 2.086.1 | 769.4 | |
dmd 2.085.1 | 822.6 | |
dmd 2.084.1 | 771.3 | |
dmd 2.083.1 | 784.0 | |
dmd 2.082.1 | 765.4 | |
dmd 2.081.2 | 693.0 | |
dmd 2.080.1 | 685.5 | |
dmd 2.079.1 | 650.4 | |
dmd 2.078.3 | 628.2 | |
dmd 2.077.1 | 626.3 | |
dmd 2.076.1 | 618.8 | |
dmd 2.075.1 | 589.9 | |
dmd 2.074.1 | 564.3 | |
dmd 2.073.2 | 574.3 | |
dmd 2.072.2 | 590.4 | |
dmd 2.071.2 | n/a | Linker issues |
dmd 2.070.2 | n/a | Linker issues |
dmd 2.069.2 | n/a | Linker issues |
dmd 2.065.0 | n/a | Linker issues |
dmd 2.064.0 | n/a | No std.array.split available |
Measurement error is <0.1%. (idle Linux system, performance governor, 240 or more repetitions, minimums taken).
So, not too bad, but not too good either.
We are not regressing too much, but things could be improved: Sizes of imports reduced, Compiler in general speed up, and for -run, some intermediate form cached on disk to speed up parsing, for various imports, or for the final binary.
Environment: Debian Linux amd64, Threadripper 2950X, all inputs and outputs in RAM on tmpfs (including compilers and libraries).
GNU ld (GNU Binutils for Debian) 2.41.50.20231202
Reference code:
#!/usr/bin/env -S dmd -run
struct Person {
string name;
int age;
}
auto people = [
Person("John", 45),
Person("Kate", 30),
];
void main() {
import std.stdio : writefln;
foreach (person; people) {
writefln("%s is %d years old", person.name, person.age);
}
static auto oddNumbers(T)(T[] a) {
return delegate int(int delegate(ref T) dg) {
foreach (x; a) {
if (x % 2 == 0) continue;
auto ret = dg(x);
if (ret != 0) return ret;
}
return 0;
};
}
foreach (odd; oddNumbers([3, 6, 9, 12, 15, 18])) {
writefln("%d", odd);
}
static auto toLookupTable(string data) {
import std.array : split;
bool[string] result;
foreach (w; data.split(';')) {
result[w] = true;
}
return result;
}
enum data = "mov;btc;cli;xor;afoo";
enum opcodes = toLookupTable(data);
foreach (o, k; opcodes) {
writefln("%s", o);
}
}
#!/usr/bin/env python3
import dataclasses
@dataclasses.dataclass
class Person:
name: str
age: int
people = [
Person(name="John", age=45),
Person(name="Kate", age=30),
]
for person in people:
print(f"{person.name} is {person.age} years old")
def oddNumbers(a):
for x in a:
if x % 2 == 1:
yield x
for odd in oddNumbers([3, 6, 9, 12, 15, 18]):
print(odd)
def toLookupTable(data):
result = set()
for w in data.split(";"):
result.add(w)
return result
data = "mov;btc;cli;xor;afoo"
opcodes = toLookupTable(data)
for o in opcodes:
print(o)
#!/usr/bin/env -S /home/user/nim-2.0.0/bin/nim r --warnings:off --hints:off
import std/strformat
type Person = object
name: string
age: Natural # Ensures the age is positive
let people = [
Person(name: "John", age: 45),
Person(name: "Kate", age: 30),
]
for person in people:
echo(fmt"{person.name} is {person.age} years old")
iterator oddNumbers[Idx, T](a: array[Idx, T]): T =
for x in a:
if x mod 2 == 1:
yield x
for odd in oddNumbers([3, 6, 9, 12, 15, 18]):
echo odd
import macros, strutils
macro toLookupTable(data: static[string]): untyped =
result = newTree(nnkBracket)
for w in data.split(';'):
result.add newLit(w)
const
data = "mov;btc;cli;xor;afoo"
opcodes = toLookupTable(data)
for o in opcodes:
echo o