Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a tracer for the DMA #9

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
101 changes: 101 additions & 0 deletions src/include/idma/tracer.svh
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
// Copyright 2022 ETH Zurich and University of Bologna.
// Solderpad Hardware License, Version 0.51, see LICENSE for details.
// SPDX-License-Identifier: SHL-0.51
//
// Thomas Benz <[email protected]>

// Macro holding all the resources for the iDMA backend tracer
`ifndef IDMA_TRACER_SVH_
`define IDMA_TRACER_SVH_

// largest type to trace
`define IDMA_TRACER_MAX_TYPE_WIDTH 1024
`define IDMA_TRACER_MAX_TYPE logic [`IDMA_TRACER_MAX_TYPE_WIDTH-1:0]

// string assembly function
`define IDMA_TRACER_STR_ASSEMBLY(__dict, __cond) \
if(__cond) begin \
trace = $sformatf("%s'%s':{", trace, `"__dict`"); \
foreach(__dict``[key]) trace = $sformatf("%s'%s': 0x%0x,", trace, key, __dict``[key]); \
trace = $sformatf("%s},", trace); \
end

// helper to clear a condition
`define IDMA_TRACER_CLEAR_COND(__cond) \
if(__cond) begin \
__cond = ~__cond; \
end

// The tracer for the iDMA
`define IDMA_TRACER(__backend_inst, __out_f_name) \
`ifndef SYNTHESYS \
`ifndef VERILATOR \
initial begin : inital_tracer \
automatic bit first_iter = 1; \
automatic integer tf; \
automatic `IDMA_TRACER_MAX_TYPE cnst [string]; \
automatic `IDMA_TRACER_MAX_TYPE meta [string]; \
automatic `IDMA_TRACER_MAX_TYPE busy [string]; \
automatic `IDMA_TRACER_MAX_TYPE axib [string]; \
automatic string trace; \
#0; \
tf = $fopen(__out_f_name, "w"); \
$display("[Tracer] Logging iDMA backend %s to %s", `"__backend_inst`", __out_f_name); \
forever begin \
@(posedge __backend_inst``.clk_i); \
if(__backend_inst``.rst_ni & |__backend_inst``.busy_o) begin \
/* Trace */ \
trace = "{"; \
/* Constants */ \
cnst = '{ \
"inst" : `"__backend_inst`", \
"data_width" : __backend_inst``.DataWidth, \
"addr_width" : __backend_inst``.AddrWidth, \
"user_width" : __backend_inst``.UserWidth, \
"axi_id_width" : __backend_inst``.AxiIdWidth, \
"num_ax_in_flight" : __backend_inst``.NumAxInFlight, \
"buffer_depth" : __backend_inst``.BufferDepth, \
"tf_len_width" : __backend_inst``.TFLenWidth, \
"mem_sys_depth" : __backend_inst``.MemSysDepth, \
"rw_coupling_avail" : __backend_inst``.RAWCouplingAvail, \
"mask_invalid_data" : __backend_inst``.MaskInvalidData, \
"hardware_legalizer" : __backend_inst``.HardwareLegalizer, \
"reject_zero_transfers" : __backend_inst``.RejectZeroTransfers, \
"error_cap" : __backend_inst``.ErrorCap, \
"print_fifo_info" : __backend_inst``.PrintFifoInfo \
}; \
meta = '{ \
"time" : $time() \
}; \
busy = '{ \
"buffer" : __backend_inst``.busy_o.buffer_busy, \
"r_dp" : __backend_inst``.busy_o.r_dp_busy, \
"w_dp" : __backend_inst``.busy_o.w_dp_busy, \
"r_leg" : __backend_inst``.busy_o.r_leg_busy, \
"w_leg" : __backend_inst``.busy_o.w_leg_busy, \
"eh_fsm" : __backend_inst``.busy_o.eh_fsm_busy, \
"eh_cnt" : __backend_inst``.busy_o.eh_cnt_busy, \
"raw_coupler" : __backend_inst``.busy_o.raw_coupler_busy \
}; \
axib = '{ \
"w_valid" : __backend_inst``.axi_req_o.w_valid, \
"w_ready" : __backend_inst``.axi_rsp_i.w_ready, \
"w_strb" : __backend_inst``.axi_req_o.w.strb, \
"r_valid" : __backend_inst``.axi_rsp_i.r_valid, \
"r_ready" : __backend_inst``.axi_req_o.r_ready \
}; \
/* Assembly */ \
`IDMA_TRACER_STR_ASSEMBLY(cnst, first_iter); \
`IDMA_TRACER_STR_ASSEMBLY(meta, 1); \
`IDMA_TRACER_STR_ASSEMBLY(busy, 1); \
`IDMA_TRACER_STR_ASSEMBLY(axib, 1); \
`IDMA_TRACER_CLEAR_COND(first_iter); \
/* Commit */ \
$fwrite(tf, $sformatf("%s}\n", trace)); \
end \
end \
end \
`endif \
`endif

`endif
19 changes: 18 additions & 1 deletion test/tb_idma_backend.sv
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
`timescale 1ns/1ns
`include "axi/typedef.svh"
`include "idma/typedef.svh"
`include "idma/tracer.svh"

module tb_idma_backend import idma_pkg::*; #(
parameter int unsigned BufferDepth = 3,
Expand All @@ -25,7 +26,8 @@ module tb_idma_backend import idma_pkg::*; #(
parameter bit HardwareLegalizer = 1,
parameter bit RejectZeroTransfers = 1,
parameter bit ErrorHandling = 1,
parameter bit IdealMemory = 1
parameter bit IdealMemory = 1,
parameter bit DmaTracing = 0
);

// timing parameters
Expand Down Expand Up @@ -105,6 +107,21 @@ module tb_idma_backend import idma_pkg::*; #(
idma_busy_t busy;


//--------------------------------------
// DMA Tracer
//--------------------------------------
// only activate tracer if requested
if (DmaTracing) begin
// fetch the name of the trace file from CMD line
string trace_file;
initial begin
void'($value$plusargs("trace_file=%s", trace_file));
end
// attach the tracer
`IDMA_TRACER(i_idma_backend, trace_file);
end


//--------------------------------------
// DMA Driver
//--------------------------------------
Expand Down
19 changes: 18 additions & 1 deletion test/tb_idma_nd_backend.sv
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
`timescale 1ns/1ns
`include "axi/typedef.svh"
`include "idma/typedef.svh"
`include "idma/tracer.svh"

module tb_idma_nd_backend import idma_pkg::*; #(
parameter int unsigned BufferDepth = 3,
Expand All @@ -28,7 +29,8 @@ module tb_idma_nd_backend import idma_pkg::*; #(
parameter bit HardwareLegalizer = 1,
parameter bit RejectZeroTransfers = 1,
parameter bit ErrorHandling = 1,
parameter bit IdealMemory = 1
parameter bit IdealMemory = 1,
parameter bit DmaTracing = 0
);

// timing parameters
Expand Down Expand Up @@ -123,6 +125,21 @@ module tb_idma_nd_backend import idma_pkg::*; #(
idma_busy_t busy;


//--------------------------------------
// DMA Tracer
//--------------------------------------
// only activate tracer if requested
if (DmaTracing) begin
// fetch the name of the trace file from CMD line
string trace_file;
initial begin
void'($value$plusargs("trace_file=%s", trace_file));
end
// attach the tracer
`IDMA_TRACER(i_idma_backend, trace_file);
end


//--------------------------------------
// DMA Driver
//--------------------------------------
Expand Down
73 changes: 73 additions & 0 deletions util/trace.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
#!/usr/bin/env python3
# Copyright 2022 ETH Zurich and University of Bologna.
# Solderpad Hardware License, Version 0.51, see LICENSE for details.
# SPDX-License-Identifier: SHL-0.51

# Author: Thomas Benz <[email protected]>

"""Functions used to parse and evaluate iDMA trace files."""
import ast
import sys
from pprint import pprint as pp


def strb_to_bytes(strobe: int) -> int:
"""Returns the amount of valid bytes in a strobe value"""

res = 0

# iterate over strobe
for byte_en in str(bin(strobe))[2:]:
if byte_en == '1':
res += 1

return res


def read_trace (fn: str) -> list:
"""Reads a trace file and returns it as a list of dict objects"""

# resulting list of trace events
trace = []

# read and parse file
with open(fn, 'r', encoding='utf8') as tf:
for line in tf:
trace_dict = ast.literal_eval(line)
trace.append(trace_dict)

return trace


def extract_parameter (trace: list) -> dict:
"""Extracts the parameter of the DMA backend the run resulted from"""

return trace[0]['cnst']


def get_global_utilization (trace: list, data_width: int) -> list:
"""Calculates the global utilization [read, write] of the DMA"""

read_data = 0 # in bytes
write_data = 0 # in bytes

for ele in trace:
# add read contribution
if ele['axib']['r_ready'] and ele['axib']['r_valid']:
read_data += data_width // 8

# add write contribution
if ele['axib']['w_ready'] and ele['axib']['w_valid']:
write_data += strb_to_bytes(ele['axib']['w_strb'])

# calculate maximum possible amount of data
max_data = len(trace) * data_width // 8

return [read_data / max_data, write_data / max_data ]


if __name__ == '__main__':
_, filename = sys.argv
idma_trace = read_trace(filename)
idma_data_width = extract_parameter(idma_trace)['data_width']
pp(get_global_utilization(idma_trace, idma_data_width))