Skip to content
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
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
18 changes: 17 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,22 @@ output/

# logs
*.log
*.json.log

# generated reports and traces
*.report.json
tmp-generated-*
**/collected_reports*/
**/sweep_reports*/
**/sweep_reports_micro*/
latest_collected_reports

# local build artifacts
/main

# Python caches
__pycache__/
*.pyc

.venv/
venv/
venv/
30 changes: 26 additions & 4 deletions api/builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,28 @@ package api
import "github.com/sarchlab/akita/v4/sim"

type defaultPortFactory struct {
incomingBufCap int
outgoingBufCap int
}

func (f defaultPortFactory) make(c sim.Component, name string) sim.Port {
return sim.NewPort(c, 1, 1, name)
incoming := f.incomingBufCap
if incoming <= 0 {
incoming = 1
}
outgoing := f.outgoingBufCap
if outgoing <= 0 {
outgoing = 1
}
return sim.NewPort(c, incoming, outgoing, name)
}

// DriverBuilder creates a new instance of Driver.
type DriverBuilder struct {
engine sim.Engine
freq sim.Freq
engine sim.Engine
freq sim.Freq
portIncomingBufferCap int
portOutgoingBufferCap int
}

// WithEngine sets the engine.
Expand All @@ -27,10 +39,20 @@ func (b DriverBuilder) WithFreq(freq sim.Freq) DriverBuilder {
return b
}

// WithPortBufferDepth configures driver boundary-port incoming/outgoing capacity.
func (b DriverBuilder) WithPortBufferDepth(incoming, outgoing int) DriverBuilder {
b.portIncomingBufferCap = incoming
b.portOutgoingBufferCap = outgoing
return b
}

// Build create a driver.
func (b DriverBuilder) Build(name string) Driver {
d := &driverImpl{
portFactory: defaultPortFactory{},
portFactory: defaultPortFactory{
incomingBufCap: b.portIncomingBufferCap,
outgoingBufCap: b.portOutgoingBufferCap,
},
}

d.TickingComponent = sim.NewTickingComponent(name, b.engine, b.freq, d)
Expand Down
29 changes: 29 additions & 0 deletions api/builder_microarch_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package api

import (
"testing"

"github.com/sarchlab/akita/v4/sim"
)

func TestDriverBuilderWithPortBufferDepth(t *testing.T) {
engine := sim.NewSerialEngine()
driver := DriverBuilder{}.
WithEngine(engine).
WithFreq(1*sim.GHz).
WithPortBufferDepth(3, 5).
Build("Driver")

impl, ok := driver.(*driverImpl)
if !ok {
t.Fatalf("expected *driverImpl, got %T", driver)
}

factory, ok := impl.portFactory.(defaultPortFactory)
if !ok {
t.Fatalf("expected defaultPortFactory, got %T", impl.portFactory)
}
if factory.incomingBufCap != 3 || factory.outgoingBufCap != 5 {
t.Fatalf("unexpected driver port caps: in=%d out=%d", factory.incomingBufCap, factory.outgoingBufCap)
}
}
3 changes: 2 additions & 1 deletion api/driver.go
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,8 @@ func (d *driverImpl) doOneFeedInTask(task *feedInTask) bool {
err := port.Send(msg)
//fmt.Println(msg)
if err != nil {
panic("CGRA cannot handle the data rate")
// Keep task pending when downstream is temporarily back-pressured.
continue
}

timeValue := float64(d.Engine.CurrentTime() * 1e9)
Expand Down
48 changes: 48 additions & 0 deletions api/feedin_backpressure_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package api

import (
"testing"

gomock "github.com/golang/mock/gomock"
"github.com/sarchlab/akita/v4/sim"
)

func TestDoOneFeedInTaskBackpressureDoesNotPanic(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()

engine := sim.NewSerialEngine()
d := &driverImpl{}
d.TickingComponent = sim.NewTickingComponent("Driver", engine, 1*sim.GHz, d)

port := NewMockPort(ctrl)
port.EXPECT().CanSend().Return(true).Times(2)
port.EXPECT().Name().Return("mock-port").AnyTimes()
port.EXPECT().AsRemote().Return(sim.RemotePort("driver-local")).AnyTimes()
port.EXPECT().Send(gomock.Any()).Return(sim.NewSendError()).Times(1)
port.EXPECT().Send(gomock.Any()).Return(nil).Times(1)

task := &feedInTask{
data: []uint32{7},
localPorts: []sim.Port{port},
remotePorts: []sim.RemotePort{sim.RemotePort("device-remote")},
stride: 1,
color: 0,
rounds: 1,
portRounds: []int{0},
}

if progressed := d.doOneFeedInTask(task); progressed {
t.Fatal("expected no progress when Send returns backpressure error")
}
if task.portRounds[0] != 0 {
t.Fatalf("expected round to stay 0 after backpressure, got %d", task.portRounds[0])
}

if progressed := d.doOneFeedInTask(task); !progressed {
t.Fatal("expected progress once backpressure clears")
}
if task.portRounds[0] != 1 {
t.Fatalf("expected round to advance to 1, got %d", task.portRounds[0])
}
}
14 changes: 14 additions & 0 deletions api/mock_cgra_test.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

27 changes: 26 additions & 1 deletion cgra/data.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,26 @@ func (d Data) First() uint32 {
return d.Data[0]
}

// LaneCount returns the number of lanes carried by this value.
func (d Data) LaneCount() int {
return len(d.Data)
}

// IsScalar reports whether the value is a single-lane scalar.
func (d Data) IsScalar() bool {
return len(d.Data) <= 1
}

// Clone returns a deep copy of the value container.
func (d Data) Clone() Data {
if len(d.Data) == 0 {
return Data{Pred: d.Pred}
}
cloned := make([]uint32, len(d.Data))
copy(cloned, d.Data)
return Data{Data: cloned, Pred: d.Pred}
}

// WithPred returns a copy with the given predicate flag.
func (d Data) WithPred(pred bool) Data {
d.Pred = pred
Expand All @@ -32,5 +52,10 @@ func (d Data) WithPred(pred bool) Data {

// FromSlice constructs a Data from a slice and optional predicate.
func FromSlice(vals []uint32, pred bool) Data {
return Data{Data: vals, Pred: pred}
if len(vals) == 0 {
return Data{Pred: pred}
}
cloned := make([]uint32, len(vals))
copy(cloned, vals)
return Data{Data: cloned, Pred: pred}
}
Loading
Loading