Skip to content

Commit

Permalink
Analyzer: Add SQLite support (#34)
Browse files Browse the repository at this point in the history
Analyzer: added SQLite support
  • Loading branch information
syifan authored Jun 24, 2023
1 parent 64c5e20 commit 734a8c6
Show file tree
Hide file tree
Showing 13 changed files with 730 additions and 712 deletions.
10 changes: 4 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,18 +1,15 @@
# Akita

[![Go Reference](https://pkg.go.dev/badge/github.com/sarchlab/akita/v3.svg)](https://pkg.go.dev/github.com/sarchlab/akita/v3)
[![Go Report Card](https://goreportcard.com/badge/github.com/sarchlab/akita/v3)](https://goreportcard.com/report/github.com/sarchlab/akita/v3)

![GitHub Discussions](https://img.shields.io/github/discussions/sarchlab/akita)


[![Go Reference](https://pkg.go.dev/badge/github.com/sarchlab/akita/v3.svg)](https://pkg.go.dev/github.com/sarchlab/akita/v3)
[![Go Report Card](https://goreportcard.com/badge/github.com/sarchlab/akita/v3)](https://goreportcard.com/report/github.com/sarchlab/akita/v3)
[![Akita Test](https://github.com/sarchlab/akita/actions/workflows/akita_test.yml/badge.svg)](https://github.com/sarchlab/akita/actions/workflows/akita_test.yml)

Akita is a computer architecture simulation engine. Like a game engine, a simulator engine is not a simulator, but rather a framework for building simulators. Akita is designed to be modular and extensible, allowing for easy experimentation with new computer architecture design ideas.

## Communication

[<img src="https://img.shields.io/badge/slack-Akita-blue.svg?logo=slack">](https://join.slack.com/t/projectakita/shared_invite/zt-adiqifj8-0h0oJnIX~cYxbdFwmDOQJg)
[<img src="https://img.shields.io/badge/reddit-MGPUSim-blue.svg?logo=redit">](https://www.reddit.com/r/mgpusim/)

## Sub-Projects

Expand All @@ -22,6 +19,7 @@ The simulator engine itself is located under the packages including:

* `github.com/sarchlab/akita/sim`
* `github.com/sarchlab/akita/pipelining`
* `gitlab.com/sarchlab/akita/analysis`

### AkitaRTM

Expand Down
147 changes: 0 additions & 147 deletions analysis/PerfAnalyzer.go

This file was deleted.

25 changes: 25 additions & 0 deletions analysis/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# Akita Performance Analysis Toolkit

Akita Performance Analysis Toolkit provides a set of tools for analyzing the performance of Akita-based simulators. The library mainly uses the hooking feature` of Akita to collect the performance metrics during simulation. The metrics will be recorded and stored in a file.

## `PerfAnalyzer`

The `PerfAnalyzer` is the facade of the performance analysis toolkit. Once a `PerfAnalyzer` is created, simulator developers can register components by calling the `RegisterComponent` method.

Currently, the `PerfAnalyzer` automatically discovers the ports and buffers used by the components. It will attach hooks to the ports and buffers to collect throughput and buffer level information, respectively.

It is optional the report values in periods. The throughput and buffer level information will be reported periodically. Each report is the metrics collected in the last period. The period is specified by the `WithPeriod` method of the `PerfAnalyzerBuilder`.

## Output

The output can either be stored a csv file or a sqlite database file. By default, the data is stored in a CSV file. To store the data in a sqlite database, call the `WithSQLiteBackend` method of the `PerfAnalyzerBuilder`. No matter the CSV backend of the SQLite backend is selected, the output file name can be specified by the `WithDBFilename` method of the `PerfAnalyzerBuilder`. Existing files will be overwritten.

The output format is the same for the CSV and SQLite backend. It is designed to be generic so that any type of data can be recorded. The output is organized in a table that includes the following columns:

- `start`: the start time of the period
- `end`: the end time of the period
- `where`: the name of the element that the data is collected from. This field is named as `where_` in SQLite to avoid conflict with the `where` keyword.
- `what`: the name of the metric
- `value`: the value of the metric
- `unit`: the unit of the metric

File renamed without changes.
138 changes: 109 additions & 29 deletions analysis/bufferanalyzer.go → analysis/buffer_analyzer.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,50 +4,36 @@ import (
"math"

"github.com/sarchlab/akita/v3/sim"
"github.com/tebeka/atexit"
)

// BufferAnalyzer can periodically record the buffer level of a buffer.
type BufferAnalyzer struct {
PerfLogger
timeTeller sim.TimeTeller
sim.TimeTeller

buf sim.Buffer
usePeriod bool
period sim.VTimeInSec

buf sim.Buffer
period sim.VTimeInSec
lastTime sim.VTimeInSec
lastBufLevel int
bufLevelToDuration map[int]sim.VTimeInSec
}

// NewBufferAnalyzer creates a buffer analyzer.
func NewBufferAnalyzer(
buffer sim.Buffer,
tt sim.TimeTeller,
perfLogger PerfLogger,
period sim.VTimeInSec,
) *BufferAnalyzer {
b := &BufferAnalyzer{
buf: buffer,
PerfLogger: perfLogger,
timeTeller: tt,
period: period,
lastTime: 0.0,
bufLevelToDuration: make(map[int]sim.VTimeInSec),
}

return b
}

// Func is a function that records buffer level change.
func (b *BufferAnalyzer) Func(ctx sim.HookCtx) {
now := b.timeTeller.CurrentTime()
now := b.CurrentTime()
buf := ctx.Domain.(sim.Buffer)
currLevel := buf.Size()

lastPeriodEndTime := b.periodEndTime(b.lastTime)
if b.usePeriod {
lastPeriodEndTime := b.periodEndTime(b.lastTime)

if now > lastPeriodEndTime {
b.summarize()
b.resetPeriod()
if now > lastPeriodEndTime {
b.summarize()
b.resetPeriod()
}
}

b.bufLevelToDuration[b.lastBufLevel] += now - b.lastTime
Expand All @@ -56,7 +42,13 @@ func (b *BufferAnalyzer) Func(ctx sim.HookCtx) {
}

func (b *BufferAnalyzer) summarize() {
now := b.timeTeller.CurrentTime()
now := b.CurrentTime()

if !b.usePeriod {
b.summarizePeriod(now, 0, now)
return
}

periodStartTime := b.periodStartTime(b.lastTime)
periodEndTime := b.periodEndTime(b.lastTime)

Expand Down Expand Up @@ -89,6 +81,10 @@ func (b *BufferAnalyzer) summarizePeriod(

avgLevel := sumLevel / sumDuration

if avgLevel == 0 {
return
}

b.PerfLogger.AddDataEntry(PerfAnalyzerEntry{
Start: periodStartTime,
End: periodEndTime,
Expand All @@ -100,7 +96,7 @@ func (b *BufferAnalyzer) summarizePeriod(
}

func (b *BufferAnalyzer) resetPeriod() {
now := b.timeTeller.CurrentTime()
now := b.CurrentTime()

b.bufLevelToDuration = make(map[int]sim.VTimeInSec)

Expand All @@ -122,3 +118,87 @@ func minTime(a, b sim.VTimeInSec) sim.VTimeInSec {

return b
}

// BufferAnalyzerBuilder can build a BufferAnalyzer.
type BufferAnalyzerBuilder struct {
perfLogger PerfLogger
timeTeller sim.TimeTeller
usePeriod bool
period sim.VTimeInSec
buffer sim.Buffer
}

// MakeBufferAnalyzerBuilder creates a BufferAnalyzerBuilder.
func MakeBufferAnalyzerBuilder() BufferAnalyzerBuilder {
return BufferAnalyzerBuilder{
perfLogger: nil,
timeTeller: nil,
usePeriod: false,
period: 0.0,
}
}

// WithPerfLogger sets the PerfLogger to use.
func (b BufferAnalyzerBuilder) WithPerfLogger(
perfLogger PerfLogger,
) BufferAnalyzerBuilder {
b.perfLogger = perfLogger
return b
}

// WithTimeTeller sets the TimeTeller to use.
func (b BufferAnalyzerBuilder) WithTimeTeller(
timeTeller sim.TimeTeller,
) BufferAnalyzerBuilder {
b.timeTeller = timeTeller
return b
}

// WithPeriod sets the period to use.
func (b BufferAnalyzerBuilder) WithPeriod(
period sim.VTimeInSec,
) BufferAnalyzerBuilder {
b.usePeriod = true
b.period = period
return b
}

// WithBuffer sets the buffer to use.
func (b BufferAnalyzerBuilder) WithBuffer(
buffer sim.Buffer,
) BufferAnalyzerBuilder {
b.buffer = buffer
return b
}

// Build creates a BufferAnalyzer.
func (b BufferAnalyzerBuilder) Build() *BufferAnalyzer {
if b.perfLogger == nil {
panic("perfLogger is not set")
}

if b.timeTeller == nil {
panic("timeTeller is not set")
}

if b.buffer == nil {
panic("buffer is not set")
}

analyzer := &BufferAnalyzer{
PerfLogger: b.perfLogger,
TimeTeller: b.timeTeller,
buf: b.buffer,
usePeriod: b.usePeriod,
period: b.period,
lastTime: 0.0,
lastBufLevel: 0,
bufLevelToDuration: make(map[int]sim.VTimeInSec),
}

atexit.Register(func() {
analyzer.summarize()
})

return analyzer
}
Loading

0 comments on commit 734a8c6

Please sign in to comment.