Skip to content

Commit

Permalink
Merge pull request #2 from CTSRD-CHERI/scratch-jf613-performance-monitor
Browse files Browse the repository at this point in the history
Add performance monitor module
  • Loading branch information
gameboo authored Sep 21, 2020
2 parents 0b9d07b + 49b6104 commit 69727db
Show file tree
Hide file tree
Showing 4 changed files with 341 additions and 0 deletions.
19 changes: 19 additions & 0 deletions AXI/AXI4_Types.bsv
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@ import MasterSlave :: *;

import AXI4_AXI4Lite_Types :: *;

`ifdef PERFORMANCE_MONITORING
import PerformanceMonitor :: *;
`endif

//////////////////
// helper types //
////////////////////////////////////////////////////////////////////////////////
Expand Down Expand Up @@ -879,6 +883,21 @@ interface AXI4_Shim_Synth#(
) slave;
endinterface

`ifdef PERFORMANCE_MONITORING
typedef struct {
Bool evt_AR_FLIT;
Bool evt_AW_FLIT;
Bool evt_W_FLIT;
Bool evt_R_FLIT;
Bool evt_R_FLIT_FINAL;
Bool evt_B_FLIT;
} EventsAXI4 deriving (Bits, FShow);

instance BitVectorable#(EventsAXI4, 1, n) provisos (Bits#(EventsAXI4, n));
function to_vector = struct_to_vector;
endinstance
`endif

////////////////////////////////
// AXI4 Connectable instances //
////////////////////////////////////////////////////////////////////////////////
Expand Down
69 changes: 69 additions & 0 deletions AXI/AXI4_Utils.bsv
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,9 @@ import AXI4_R_Utils :: *;

// BlueStuff import
import Routable :: *;
`ifdef PERFORMANCE_MONITORING
import MonitorWrapper :: *;
`endif
// BlueBasics import
import SourceSink :: *;
import MasterSlave :: *;
Expand Down Expand Up @@ -610,6 +613,72 @@ module mkAXI4DebugShim #(String debugTag) (AXI4_Shim#(a,b,c,d,e,f,g,h));
interface clear = shim.clear;
endmodule

//////////////////////////////
// AXI4 Performance monitor utils //
////////////////////////////////////////////////////////////////////////////////

`ifdef PERFORMANCE_MONITORING
module monitorAXI4_Shim #(AXI4_Shim#(a, b, c, d, e, f, g, h) shim)
(Monitored#(AXI4_Shim#(a, b, c, d, e, f, g, h), Tuple2#(EventsAXI4, EventsAXI4)));
let masterMonitor <- monitorAXI4_Master(shim.master);
let slaveMonitor <- monitorAXI4_Slave(shim.slave);
interface ifc = interface AXI4_Shim;
interface clear = shim.clear;
interface master = masterMonitor.ifc;
interface slave = slaveMonitor.ifc;
endinterface;
method events = tuple2(masterMonitor.events, slaveMonitor.events);
endmodule

module monitorAXI4_Master #(AXI4_Master#(a, b, c, d, e, f, g, h) master)
(Monitored#(AXI4_Master#(a, b, c, d, e, f, g, h), EventsAXI4));
let awMonitor <- monitorSource(master.aw);
let wMonitor <- monitorSource(master.w);
let bMonitor <- monitorSink(master.b);
let arMonitor <- monitorSource(master.ar);
let rMonitor <- monitorLastSink(master.r);
interface ifc = interface AXI4_Master;
interface aw = awMonitor.ifc;
interface w = wMonitor.ifc;
interface b = bMonitor.ifc;
interface ar = arMonitor.ifc;
interface r = rMonitor.ifc;
endinterface;
method events = EventsAXI4 {
evt_AR_FLIT : unpack(arMonitor.events),
evt_AW_FLIT : unpack(awMonitor.events),
evt_W_FLIT : unpack(wMonitor.events),
evt_R_FLIT : unpack(rMonitor.events[0]),
evt_R_FLIT_FINAL : unpack(rMonitor.events[1]),
evt_B_FLIT : unpack(bMonitor.events)
};
endmodule

module monitorAXI4_Slave #(AXI4_Slave#(a, b, c, d, e, f, g, h) slave)
(Monitored#(AXI4_Slave#(a, b, c, d, e, f, g, h), EventsAXI4));
let awMonitor <- monitorSink(slave.aw);
let wMonitor <- monitorSink(slave.w);
let bMonitor <- monitorSource(slave.b);
let arMonitor <- monitorSink(slave.ar);
let rMonitor <- monitorLastSource(slave.r);
interface ifc = interface AXI4_Slave;
interface aw = awMonitor.ifc;
interface w = wMonitor.ifc;
interface b = bMonitor.ifc;
interface ar = arMonitor.ifc;
interface r = rMonitor.ifc;
endinterface;
method events = EventsAXI4 {
evt_AR_FLIT : unpack(arMonitor.events),
evt_AW_FLIT : unpack(awMonitor.events),
evt_W_FLIT : unpack(wMonitor.events),
evt_R_FLIT : unpack(rMonitor.events[0]),
evt_R_FLIT_FINAL : unpack(rMonitor.events[1]),
evt_B_FLIT : unpack(bMonitor.events)
};
endmodule
`endif

/////////////////////////////////////
// to/from "Synth" interface utils //
////////////////////////////////////////////////////////////////////////////////
Expand Down
98 changes: 98 additions & 0 deletions MonitorWrapper.bsv
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
/*-
* Copyright (c) 2020 Jonas Fiala
* All rights reserved.
*
* This software was developed by SRI International and the University of
* Cambridge Computer Laboratory (Department of Computer Science and
* Technology) under DARPA contract HR0011-18-C-0016 ("ECATS"), as part of the
* DARPA SSITH research programme.
*
* @BERI_LICENSE_HEADER_START@
*
* Licensed to BERI Open Systems C.I.C. (BERI) under one or more contributor
* license agreements. See the NOTICE file distributed with this work for
* additional information regarding copyright ownership. BERI licenses this
* file to you under the BERI Hardware-Software License, Version 1.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at:
*
* http://www.beri-open-systems.org/legal/license-1-0.txt
*
* Unless required by applicable law or agreed to in writing, Work distributed
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
* @BERI_LICENSE_HEADER_END@
*/

package MonitorWrapper;

import Vector :: *;

import SourceSink :: *;

import Routable :: *;
import PerformanceMonitor :: *;


// Wrapper interface for reporting events of a given interface
interface Monitored#(type original_module, type bitvec);
interface original_module ifc;
method bitvec events provisos (BitVectorable#(bitvec, n, m));
endinterface


// Count drop events
module monitorSource #(Source#(t) s) (Monitored#(Source#(t), Bit#(1)));
Wire#(Bit#(1)) evt <- mkDWire(0);
interface ifc = interface Source;
method canPeek = s.canPeek;
method peek = s.peek;
method drop = action
s.drop;
evt <= 1;
endaction;
endinterface;
method events = evt;
endmodule
// Count put events
module monitorSink #(Sink#(t) s) (Monitored#(Sink#(t), Bit#(1)));
Wire#(Bit#(1)) evt <- mkDWire(0);
interface ifc = interface Sink;
method canPut = s.canPut;
method put (x) = action
s.put(x);
evt <= 1;
endaction;
endinterface;
method events = evt;
endmodule
// Count drop (at events[0]) and drop last (at events[1])
module monitorLastSource #(Source#(t) s) (Monitored#(Source#(t), Bit#(2)))
provisos (DetectLast#(t));
Wire#(Bit#(2)) evt <- mkDWire(0);
interface ifc = interface Source;
method canPeek = s.canPeek;
method peek = s.peek;
method drop = action
s.drop;
evt <= {pack(detectLast(s.peek)), 1};
endaction;
endinterface;
method events = evt;
endmodule
// Count put (at events[0]) and put last (at events[1])
module monitorLastSink #(Sink#(t) s) (Monitored#(Sink#(t), Bit#(2)))
provisos (DetectLast#(t));
Wire#(Bit#(2)) evt <- mkDWire(0);
interface ifc = interface Sink;
method canPut = s.canPut;
method put (x) = action
s.put(x);
evt <= {pack(detectLast(x)), 1};
endaction;
endinterface;
method events = evt;
endmodule
endpackage
155 changes: 155 additions & 0 deletions PerformanceMonitor.bsv
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
/*-
* Copyright (c) 2020 Jonas Fiala
* All rights reserved.
*
* This software was developed by SRI International and the University of
* Cambridge Computer Laboratory (Department of Computer Science and
* Technology) under DARPA contract HR0011-18-C-0016 ("ECATS"), as part of the
* DARPA SSITH research programme.
*
* @BERI_LICENSE_HEADER_START@
*
* Licensed to BERI Open Systems C.I.C. (BERI) under one or more contributor
* license agreements. See the NOTICE file distributed with this work for
* additional information regarding copyright ownership. BERI licenses this
* file to you under the BERI Hardware-Software License, Version 1.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at:
*
* http://www.beri-open-systems.org/legal/license-1-0.txt
*
* Unless required by applicable law or agreed to in writing, Work distributed
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
* @BERI_LICENSE_HEADER_END@
*/

package PerformanceMonitor;

import Vector :: *;

// A module which wants to count events must return some vector of events
// However it is easier to count the events as a Struct within a module
// So if the Struct is an instance of this class it can be returned as is
typeclass BitVectorable#(type from, numeric type n, numeric type m) dependencies (from determines (n, m));
function Vector#(m, Bit#(n)) to_vector (from e);
endtypeclass

instance BitVectorable#(Vector#(m, Bit#(n)), n, m);
function to_vector = id;
endinstance

// A Bit#(n) will be converted to a 1 element vector
instance BitVectorable#(Bit#(n), n, 1);
function to_vector = replicate;
endinstance


function Vector#(mm, Bit#(nn)) to_large_vector (from e)
provisos (BitVectorable#(from, n, m), Add#(a__, n, nn), Add#(b__, m, mm));
return append(map(zeroExtend, to_vector(e)), replicate(0));
endfunction

// Use to_vector = struct_to_vector
// with BitVectorable instances for structs of events
// The struct must only contain Bools (or Bit#(1)) for this fn to be reasonable
function Vector#(m, Bit#(1)) struct_to_vector (from e) provisos (Bits#(from, m));
return reverse(unpack(pack(e)));
endfunction


// Write is exposed to only one counter per cycle
// Could change write_* methods to return WriteOnly Vector if needed
interface PerfCounters_IFC#(numeric type ctrs, numeric type ctrW, numeric type evts);
(* always_ready, always_enabled *)
method Action send_performance_events (Vector#(evts, Bit#(ctrW)) evts);

(* always_ready *)
method Vector#(ctrs, ReadOnly#(Bit#(ctrW))) read_counters;
(* always_ready *)
method Vector#(ctrs, ReadOnly#(Bit#(TLog#(evts)))) read_ctr_sels;
(* always_ready *)
method ReadOnly#(Bit#(ctrs)) read_ctr_inhibit;
(* always_ready *)
method ReadOnly#(Bit#(ctrs)) read_ctr_overflow;

(* always_ready *)
method Action write_counter (Bit#(TLog#(ctrs)) idx, Bit#(ctrW) val);
(* always_ready *)
method Action write_ctr_sel (Bit#(TLog#(ctrs)) idx, Bit#(TLog#(evts)) val);
(* always_ready *)
method Action write_ctr_inhibit (Bit#(ctrs) val);
endinterface


module mkPerfCounters (PerfCounters_IFC#(ctrs, ctrW, evts));
let ctrs = valueOf(ctrs);
let ctrW = valueOf(ctrW);
let evts = valueOf(evts);

// Event counters
Vector#(ctrs, Array#(Reg#(Bit#(ctrW))))
vec_rg_counter <- replicateM(mkCRegU(2));
// Which event the corresponding counter will count
Vector#(ctrs, Reg#(Bit#(TLog#(evts))))
vec_rg_event_sel <- replicateM(mkRegU);

Reg#(Bit#(ctrs)) rg_ctr_inhibit <- mkReg(0);
Wire#(Bit#(ctrs)) wr_overflow <- mkDWire(0);

// Since [i] is not a function, cannot map it to a Vector
function a_type sel_snd_port (Array#(a_type) arr) = arr[1];

// Should be called every cycle with vector of how many times each event
// occured in the given cycle. The maximum is 2^ctrW, but an event 'should'
// never happen so many times in a cycle:
// So map zeroExtend to the vector before passing it to this method
method Action send_performance_events (Vector#(evts, Bit#(ctrW)) events);
Bit#(ctrs) overflow = 0;
for (Integer i = 0; i < ctrs; i = i + 1) begin
// Get the number of times the selected event fired this cycle
Bit#(ctrW) event_count = 0;
if (vec_rg_event_sel[i] <= fromInteger(evts - 1))
event_count = events[vec_rg_event_sel[i]];

// Check that the given counter is not inhibited
Bool inhibit = unpack(rg_ctr_inhibit[i]);
// Count event
if (!inhibit) begin
Bit#(TAdd#(ctrW, 1)) count_sum = zeroExtend(vec_rg_counter[i][0])
+ zeroExtend(event_count);
vec_rg_counter[i][0] <= truncate(count_sum);
overflow[i] = truncateLSB(count_sum);
end

// $display("<time %0t, StatCounters> Counter #%2d Counting event %0d: Adding %0d to %0d (Inhibit %0d)",
// $time, i, vec_rg_event_sel[i], event_count, vec_rg_counter[i][0], inhibit);
end
wr_overflow <= overflow;
// $display("-------------------------CLK-------------------------");
endmethod

method Vector#(ctrs, ReadOnly#(Bit#(ctrW))) read_counters =
map(compose(regToReadOnly, sel_snd_port), vec_rg_counter);

method Vector#(ctrs, ReadOnly#(Bit#(TLog#(evts)))) read_ctr_sels =
map(regToReadOnly, vec_rg_event_sel);

method ReadOnly#(Bit#(ctrs)) read_ctr_inhibit =
regToReadOnly(rg_ctr_inhibit);

method ReadOnly#(Bit#(ctrs)) read_ctr_overflow =
regToReadOnly(wr_overflow);


method write_counter (Bit#(TLog#(ctrs)) idx) =
vec_rg_counter[idx][1]._write;

method write_ctr_sel (Bit#(TLog#(ctrs)) idx) =
vec_rg_event_sel[idx]._write;

method write_ctr_inhibit = rg_ctr_inhibit._write;
endmodule
endpackage

0 comments on commit 69727db

Please sign in to comment.