https://core.tcl-lang.org/akupries/aktive/doc/trunk/doc/presentations/eurotcl-2025-bologna.pdf
https://core.tcl-lang.org/akupries/aktive/doc/trunk/doc/presentations/eurotcl-2025-bologna.zip
https://learn.wu.ac.at/eurotcl2025/lecturecasts/753988258?m=delivery
https://learn.wu.ac.at/eurotcl2025/lecturecasts/?page=1
aktive format as d2 $image aktive format as markdown $image aktive format as tclscript $image
set file1 [aktive read from netpbm file path ...];# FO(2): tmp2,tmp4
set tmp2 [aktive op view $file1 port {-1 -1 382 252}]
set tmp3 [aktive op tile max $tmp2 radius 1]
set tmp4 [aktive op view $file1 port {-1 -1 382 252}]
set tmp5 [aktive op tile min $tmp4 radius 1]
set tmp6 [aktive op math sub $tmp3 $tmp5]
set tmp7 [aktive op math1 invert $tmp6]
set tmp8 [aktive op math1 gamma expand $tmp7]
set tmp9 [aktive op color scRGB to Grey $tmp8]
set result [aktive op math1 scale $tmp9 factor 0.01]
aktive format as d2 $image aktive format as markdown $image aktive format as tclscript $image
Charcoal effect
Shoutout: Pikchr @ https://pikchr.org
Types and Parameters
Content and Meta
C Types
Coordination ?
Unordered
Sequential
op-bench {
aktive image from value // width %W height %H depth 1 value 0.5
}
foreach sink {
null
null-s
} {
# varying concurrency ... unthreaded, ...
# ... threads up to num cpu cores, ...
# ... then overcommitted cpu ...
foreach cores {
-1 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
} {
# varying sizes ... small to large
foreach size {
1 10 100 1000 10000 100000 1000000 10000000
} { ;# 1K 10K 100K 1M 10M
# varying shapes of the same size ... tall to wide
for { set h $size ; set w 1 } { $h > 0 } {
set w [expr {$w*10}] ; set h [expr {$h/10}]
} { ...
Unordered vs. Sequential
Unordered vs. Sequential
Function specification
set unary0 {
acos { scalar { v = acos (v); } }
[...]
}
set unary1 {
[...]
shift {
scalar { v = v + a; }
highway { v = Add (v, a); }
}
[...]
}
Templating
set u4_unary0_vdecl {
extern void aktive_vector4_unary_@name@ (
double* d, double* s, aktive_uint n);
}
set u4_unary0_vdef {
void aktive_vector4_unary_@name@ (double* d, double* s, aktive_uint n) {
// 4-unroll
for (; n > 3; n -= 4, d += 4, s += 4) {
double v0 = s[0]; // v1, v2, v3 = s[1,2,3]
#define v v0 // ... v1 v2 v3
@opcode@
#undef v
d[0] = v0; // d[1,2,3] = v1, v2, v3
}
// 2-unroll,
for (; n > 1; n -= 2, d += 2, s += 2) { ... }
// remainder
for (; n > 0; n--, d++, s++) { ... }
}
}
Templating
set u1_unary0_hdecl {
void aktive_highway1_unary_@name@ (
double* d, double* s, aktive_uint n);}
set u1_unary0_hdef {
HWY_ATTR void aktive_highway1_unary_@name@ (
double* d, double* s, aktive_uint n) {
const int32_t N = Lanes(f64);
@decls@
if (n < N) { // not a full block - do a masked partial op
auto mask = FirstN(f64, n);
auto v = MaskedLoad(mask, f64, s);
@opcode@
BlendedStore (v, mask, f64, d); return;
}
aktive_uint k, border = n - N; // lane-sized blocks
for (k = 0; k < n; k += N) {
aktive_uint at = HWY_MIN (k, border);
auto v = LoadU (f64, s + at);
@opcode@
StoreU (v, f64, d + at);
}
}
}
Templating
set u1_unary0_hdecl {
void aktive_highway1_unary_@name@ (
double* d, double* s, aktive_uint n);}
set u1_unary0_hdef {
HWY_ATTR void aktive_highway1_unary_@name@ (
double* d, double* s, aktive_uint n) {
const int32_t N = Lanes(f64);
@decls@
if (n < N) { // not a full block - do a masked partial op
auto mask = FirstN(f64, n);
auto v = MaskedLoad(mask, f64, s);
@opcode@
BlendedStore (v, mask, f64, d); return;
}
aktive_uint k, border = n - N; // lane-sized blocks
for (k = 0; k < n; k += N) {
aktive_uint at = HWY_MIN (k, border);
auto v = LoadU (f64, s + at);
@opcode@
StoreU (v, f64, d + at);
}
}
}
Loop Unrolling (1x, 2x, 4x) -- acos
Loop Unrolling (1x, 2x, 4x) -- shift
Loop Unrolling 4x vs Highway -- shift
https://core.tcl-lang.org/akupries/aktive/doc/highway-simd-experiment/bench/plots/simd/README.md
https://core.tcl-lang.org/akupries/aktive/timeline?r=highway-simd-experiment
https://core.tcl-lang.org/akupries/aktive/doc/trunk/bench/plots/README.md
https://core.tcl-lang.org/akupries/aktive/doc/highway-simd-experiment/bench/plots/README.md