DSLX: bug: bytecode interpreter is very slow and quickly runs out of memory when using RamModel in tests
- Dominant language
- C++
- Stars
- 1.9k
- Forks
- 283
- Avg merge
- 2d 10h
- Merged PRs (30d)
- 135
Description
To implement #995, DSLX procs need to use RAM blocks, each with size in range 8 - 128 KBytes.
When running bytecode interpreter-based tests that make use of RAM blocks (using `xls_dslx_test` Bazel rule with `compare: none`) I've noticed that the progression of the test is extremely slow - it literally executes 1 or 2 iterations of `next()` of my _test_proc_ per second. In addition to that, after running the test for ~180 seconds my PC runs out of RAM and the interpreter is killed by Linux kernel OOM. I've confirmed that the RAM consumption comes from `interpreter_main` executable of XLS, I have 32G RAM + 32G swap and the interpreter consumes around 55G at the moment when it is killed.
@proppy @cdleary Do you perhaps have some idea why this may be happening and whether there is some workaround? Currently it's a blocker as it prevents us from testing code that uses RAMs.
I can reproduce the behavior using following minimalistic _test_proc_. It fills 64KByte RAM with zero bytes starting from address 0 and incrementing it by 1 till the full RAM is filled. It writes one byte each 10 iterations of `next()`.
```
import xls.examples.ram as ram
type RamWriteReq = ram::WriteReq;
type RamWriteResp = ram::WriteResp;
type RamReadReq = ram::ReadReq;
type RamReadResp = ram::ReadResp;
#[test_proc]
proc tst_ram {
o_term: chan out;
o_write_req: chan> out;
i_write_resp: chan in;
o_read_req: chan> out;
i_read_resp: chan> in;
init {(u32:0, u16:0)}
config(o_term: chan out) {
let (o_write_req, i_write_req) = chan>;
let (o_write_resp, i_write_resp) = chan;
let (o_read_req, i_read_req) = chan>;
let (o_read_resp, i_read_resp) = chan>;
spawn ram::RamModel
(i_read_req, o_read_resp, i_write_req, o_write_resp);
(
o_term,
o_write_req, i_write_resp,
o_read_req, i_read_resp
)
}
next (tok: token, state: (u32, u16)) {
let (delay, addr) = state;
let do_write = delay == u32:0;
if do_write {
trace_fmt!("writing addr:{}", addr);
} else {()};
let tok = send_if(tok, o_write_req, do_write, ram::WriteWordReq(addr, u8:0));
let (tok, _) = recv_if(tok, i_write_resp, do_write, RamWriteResp{});
let addr = if do_write {
addr + u16:1
} else {
addr
};
let delay = if do_write {
u32:9
} else {
delay - u32:1
};
send_if(tok, o_term, addr == u16:0, true);
(delay, addr)
}
}
```
Contributor guide
Assessment
This issue has not been assessed yet.