Add benchmark

This commit is contained in:
dalance 2019-10-07 17:46:26 +09:00
parent 030068f36f
commit 5ebaa7017c
4 changed files with 225 additions and 0 deletions

View File

@ -23,3 +23,8 @@ sv-parser-syntaxtree = {version = "0.1.0", path = "../sv-parser-syntaxtree"}
[dev-dependencies]
structopt = "0.3.2"
criterion = "0.3"
[[bench]]
name = "parse_sv"
harness = false

View File

@ -0,0 +1,52 @@
use criterion::{criterion_group, criterion_main, Criterion, Throughput};
use std::collections::HashMap;
use std::path::{Path, PathBuf};
use std::time::Duration;
use std::{env, fs};
use sv_parser::parse_sv;
fn get_path(s: &str) -> PathBuf {
PathBuf::from(format!(
"{}/testcases/{}",
env::var("CARGO_MANIFEST_DIR").unwrap(),
s
))
}
fn get_size(p: &Path) -> u64 {
let metadata = fs::metadata(p).unwrap();
metadata.len()
}
fn gen_benchmark_group(c: &mut Criterion, s: &str) {
let defines = HashMap::new();
let includes: Vec<PathBuf> = Vec::new();
let path = get_path(s);
let size = get_size(&path);
let mut group = c.benchmark_group(s);
group.throughput(Throughput::Bytes(size));
group.bench_function(s, |b| {
b.iter_with_large_drop(|| parse_sv(&path, &defines, &includes))
});
group.finish();
}
fn config() -> Criterion {
Criterion::default()
.sample_size(30)
.measurement_time(Duration::new(30, 0))
//Criterion::default().measurement_time(Duration::new(90, 0))
}
fn criterion_benchmark(c: &mut Criterion) {
gen_benchmark_group(c, "test1.sv");
gen_benchmark_group(c, "test2.sv");
}
criterion_group! {
name = benches;
config = config();
targets = criterion_benchmark
}
criterion_main!(benches);

View File

@ -0,0 +1,64 @@
module dimm(addr, ba, rasx, casx, csx, wex, cke, clk, dqm, data, dev_id);
parameter [31:0] MEM_WIDTH = 16, MEM_SIZE = 8; // in mbytes
input [10:0] addr;
input ba, rasx, casx, csx, wex, cke, clk;
input [ 7:0] dqm;
inout [63:0] data;
input [ 4:0] dev_id;
genvar i;
case ({MEM_SIZE, MEM_WIDTH})
{32'd8, 32'd16}: // 8Meg x 16 bits wide
begin: memory
for (i=0; i<4; i=i+1) begin:word16
sms_08b216t0 p(.clk(clk), .csb(csx), .cke(cke),.ba(ba),
.addr(addr), .rasb(rasx), .casb(casx),
.web(wex), .udqm(dqm[2*i+1]), .ldqm(dqm[2*i]),
.dqi(data[15+16*i:16*i]), .dev_id(dev_id));
// The hierarchical instance names are:
// memory.word16[3].p, memory.word16[2].p,
// memory.word16[1].p, memory.word16[0].p,
// and the task memory.read_mem
end
task read_mem;
input [31:0] address;
output [63:0] data;
begin // call read_mem in sms module
word16[3].p.read_mem(address, data[63:48]);
word16[2].p.read_mem(address, data[47:32]);
word16[1].p.read_mem(address, data[31:16]);
word16[0].p.read_mem(address, data[15: 0]);
end
endtask
end
{32'd16, 32'd8}: // 16Meg x 8 bits wide
begin: memory
for (i=0; i<8; i=i+1) begin:word8
sms_16b208t0 p(.clk(clk), .csb(csx), .cke(cke),.ba(ba),
.addr(addr), .rasb(rasx), .casb(casx),
.web(wex), .dqm(dqm[i]),
.dqi(data[7+8*i:8*i]), .dev_id(dev_id));
// The hierarchical instance names are
// memory.word8[7].p, memory.word8[6].p,
// ...
// memory.word8[1].p, memory.word8[0].p,
// and the task memory.read_mem
end
task read_mem;
input [31:0] address;
output [63:0] data;
begin // call read_mem in sms module
word8[7].p.read_mem(address, data[63:56]);
word8[6].p.read_mem(address, data[55:48]);
word8[5].p.read_mem(address, data[47:40]);
word8[4].p.read_mem(address, data[39:32]);
word8[3].p.read_mem(address, data[31:24]);
word8[2].p.read_mem(address, data[23:16]);
word8[1].p.read_mem(address, data[15: 8]);
word8[0].p.read_mem(address, data[ 7: 0]);
end
endtask
end
// Other memory cases ...
endcase
endmodule

View File

@ -0,0 +1,104 @@
interface simple_bus (input logic clk); // Define the interface
logic req, gnt;
logic [7:0] addr, data;
logic [1:0] mode;
logic start, rdy;
int slaves = 0;
// tasks executed concurrently as a fork-join block
extern forkjoin task countSlaves();
extern forkjoin task Read (input logic [7:0] raddr);
extern forkjoin task Write (input logic [7:0] waddr);
modport slave (input req,addr, mode, start, clk,
output gnt, rdy,
ref data, slaves,
export Read, Write, countSlaves);
// export from module that uses the modport
modport master ( input gnt, rdy, clk,
output req, addr, mode, start,
ref data,
import task Read(input logic [7:0] raddr),
task Write(input logic [7:0] waddr));
// import requires the full task prototype
initial begin
slaves = 0;
countSlaves;
$display ("number of slaves = %d", slaves);
end
endinterface: simple_bus
module memMod #(parameter int minaddr=0, maxaddr=0) (interface a);
logic avail = 1;
logic [7:0] mem[255:0];
task a.countSlaves();
a.slaves++;
endtask
task a.Read(input logic [7:0] raddr); // Read method
if (raddr >= minaddr && raddr <= maxaddr) begin
avail = 0;
#10 a.data = mem[raddr];
avail = 1;
end
endtask
task a.Write(input logic [7:0] waddr); // Write method
if (waddr >= minaddr && waddr <= maxaddr) begin
avail = 0;
#10 mem[waddr] = a.data;
avail = 1;
end
endtask
endmodule
module cpuMod(interface b);
typedef enum {read, write} instr;
instr inst;
logic [7:0] raddr;
integer seed;
always @(posedge b.clk) begin
inst = instr'($dist_uniform(seed, 0, 1));
raddr = $dist_uniform(seed, 0, 3);
if (inst == read) begin
$display("%t begin read %h @ %h", $time, b.data, raddr);
callr:b.Read(raddr);
$display("%t end read %h @ %h", $time, b.data, raddr);
end
else begin
$display("%t begin write %h @ %h", $time, b.data, raddr);
b.data = raddr;
callw:b.Write(raddr);
$display("%t end write %h @ %h", $time, b.data, raddr);
end
end
endmodule
module top;
logic clk = 0;
function void interrupt();
disable mem1.a.Read; // task via module instance
disable sb_intf.Write; // task via interface instance
if (mem1.avail == 0) $display ("mem1 was interrupted");
if (mem2.avail == 0) $display ("mem2 was interrupted");
endfunction
always #5 clk++;
initial begin
#28 interrupt();
#10 interrupt();
#100 $finish;
end
simple_bus sb_intf(clk);
memMod #(0, 127) mem1(sb_intf.slave);
memMod #(128, 255) mem2(sb_intf.slave);
cpuMod cpu(sb_intf.master);
endmodule