aboutsummaryrefslogtreecommitdiff
path: root/examples/actors_demo.zc
blob: 656e131174107dfcbcd35082782cbcd619cb307c (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
namespace;
include rt, actor;
typecheck on;

// actors demo: a ring of isolated worker processes passes a token around,
// then a fan-out of workers crunches collatz ranges in parallel.
// run: build/bin/zy < examples/actors_demo.zc

const N = 6, LAPS = 3, W = 4;

void color(int c) { rt.put_c(27); rt.put_s("[1;"); rt.put_n(30 + c); rt.put_c('m'); return; }
void plain() { rt.put_c(27); rt.put_s("[0m"); return; }
void bar(int n, int c) { color(c); for (int i = 0; i < n; i++) rt.put_s("#"); plain(); return; }

// one stage of the ring: mixes the token and counts its own hops.
// `seen` lives in the worker, so the caller's copy stays 0.
actor Hop {
    int seen;
    int handle(int tok) {
        this.seen += 1;
        return (tok * 31 + this.seen * 7) % 9973;
    }
}

// a cruncher: longest collatz chain that starts in [lo, lo + 20000)
actor Crunch {
    int handle(int lo) {
        int best = 0;
        for (int s = lo; s < lo + 20000; s++) {
            int n = s, k = 0;
            while (n != 1) { if (n % 2) n = 3 * n + 1; else n = n / 2; k++; }
            if (k > best) best = k;
        }
        return best;
    }
}

fn main() {
    color(5); rt.put_s("== tinyvm actors: isolated workers, typed channels ==\n"); plain();

    // the ring: the receive callback of stage i forwards to stage i + 1
    Hop*[6] ring;
    for (int i = 0; i < N; i++) { ring[i] = rt.new(Hop); ring[i].spawn(); }
    Hop** rp = &ring[0]; // closures capture a pointer, not the array
    let hops = 0, last = 0, done = 0;
    for (int i = 0; i < N; i++) {
        let me = i;
        ring[i].recv(fn(int v) {
            hops++; last = v;
            color(1 + me % 6); rt.put_s("  stage "); rt.put_n(me); plain();
            rt.put_s(" -> token "); rt.put_n(v); rt.put_c(' ');
            bar(v % 40 + 1, 1 + me % 6); rt.put_c(10);
            if (hops < N * LAPS) {
                if (me == N - 1) { color(3); rt.put_s("  -- lap "); rt.put_n(hops / N); rt.put_s(" done --\n"); plain(); }
                rp[(me + 1) % N].send(v);
            } else done = 1;
            return 0;
        });
    }
    color(2); rt.put_s("ring of "); rt.put_n(N); rt.put_s(" actors, "); rt.put_n(LAPS); rt.put_s(" laps, seed 42\n"); plain();
    ring[0].send(42);
    while (!done) for (int i = 0; i < N; i++) ring[i].poll();
    for (int i = 0; i < N; i++) ring[i].close();

    // fan-out: W workers in parallel, results arrive as they finish
    color(2); rt.put_s("\nfan-out: "); rt.put_n(W); rt.put_s(" crunchers, collatz over 80000 starts\n"); plain();
    Crunch*[4] pool;
    let answers = 0, best = 0;
    for (int i = 0; i < W; i++) {
        pool[i] = rt.new(Crunch); pool[i].spawn();
        let me = i;
        pool[i].recv(fn(int k) {
            answers++; if (k > best) best = k;
            color(4); rt.put_s("  worker "); rt.put_n(me); plain();
            rt.put_s(" ["); rt.put_n(me * 20000 + 1); rt.put_s(".."); rt.put_n(me * 20000 + 20000); rt.put_s("] longest chain ");
            color(6); rt.put_n(k); plain(); rt.put_c(' '); bar(k / 8, 4 + me % 3); rt.put_c(10);
            return 0;
        });
        pool[i].send(i * 20000 + 1);
    }
    for (int i = 0; i < W; i++) pool[i].await();
    for (int i = 0; i < W; i++) pool[i].close();

    color(5); rt.put_s("\n== summary ==\n"); plain();
    rt.put_s("  ring hops:     "); color(3); rt.put_n(hops); plain(); rt.put_c(10);
    rt.put_s("  final token:   "); color(3); rt.put_n(last); plain(); rt.put_c(10);
    rt.put_s("  worker replies: "); color(3); rt.put_n(answers); plain(); rt.put_c(10);
    rt.put_s("  longest chain: "); color(3); rt.put_n(best); plain(); rt.put_c(10);
    rt.put_s("  caller's ring[0].seen: "); color(3); rt.put_n(ring[0].seen); plain();
    rt.put_s(" (state stayed in the worker)\n");
    return 0;
}