Skip to content

Instantly share code, notes, and snippets.

@mmcloughlin
Last active September 23, 2018 22:18
Show Gist options
  • Select an option

  • Save mmcloughlin/0eda5b70fc095723ab695122d34bd3c2 to your computer and use it in GitHub Desktop.

Select an option

Save mmcloughlin/0eda5b70fc095723ab695122d34bd3c2 to your computer and use it in GitHub Desktop.
package main
import (
"bufio"
"errors"
"fmt"
"io"
"log"
"os"
"regexp"
"strconv"
"strings"
)
type FragmentType string
const (
FragmentTypeUnknown FragmentType = ""
FragmentTypeLoad FragmentType = "TYPE_LOAD"
FragmentTypeOp FragmentType = "TYPE_OP"
FragmentTypeStoreData FragmentType = "TYPE_STOREDATA"
FragmentTypeStoreAddress FragmentType = "TYPE_STOREADDRESS"
)
var fragmentTypeSet = map[string]bool{
string(FragmentTypeLoad): true,
string(FragmentTypeOp): true,
string(FragmentTypeStoreData): true,
string(FragmentTypeStoreAddress): true,
}
func IsFragmentType(t string) bool {
_, ok := fragmentTypeSet[t]
return ok
}
func ParseFragment(s string) (FragmentType, int, error) {
re := regexp.MustCompile(`([A-Z_]+) \((\d+) uops\)`)
matches := re.FindStringSubmatch(s)
if matches == nil {
return FragmentTypeUnknown, 0, errors.New("unexpected fragment format")
}
if !IsFragmentType(matches[1]) {
return FragmentTypeUnknown, 0, errors.New("unknown fragment type")
}
uops, err := strconv.Atoi(matches[2])
if err != nil {
return FragmentTypeUnknown, 0, err
}
return FragmentType(matches[1]), uops, nil
}
type Stage byte
const (
StageNone Stage = ' '
StageAllocated Stage = 'A'
StageSourcesReady Stage = 's'
StagePortConflict Stage = 'c'
StageDispatched Stage = 'd'
StageExecute Stage = 'e'
StageWriteback Stage = 'w'
StageRetired Stage = 'R'
StagePostRetire Stage = 'p'
StagePending Stage = '-'
StageStalled Stage = '_'
)
var stageSet = map[byte]bool{
byte(StageNone): true,
byte(StageAllocated): true,
byte(StageSourcesReady): true,
byte(StagePortConflict): true,
byte(StageDispatched): true,
byte(StageExecute): true,
byte(StageWriteback): true,
byte(StageRetired): true,
byte(StagePostRetire): true,
byte(StagePending): true,
byte(StageStalled): true,
}
func IsStage(s byte) bool {
_, ok := stageSet[s]
return ok
}
func ParseTimeline(t []byte) ([]Stage, error) {
var timeline []Stage
for _, b := range t {
var s Stage
switch {
case IsStage(b):
s = Stage(b)
case b == '|':
s = StageNone
default:
return nil, errors.New("bad character in timeline")
}
timeline = append(timeline, s)
}
return timeline, nil
}
type Execution struct {
Iteration int
Instruction int
Dissasembly string
Type FragmentType
Uops int
Timeline []Stage
}
type Trace struct {
Executions []Execution
}
func Parse(r io.Reader) (*Trace, error) {
t := &Trace{}
cur := -1
dis := ""
s := bufio.NewScanner(r)
for s.Scan() {
parts := strings.Split(s.Text(), ":")
if len(parts) != 2 {
break
}
meta := parts[0]
timeline := parts[1]
fields := strings.Split(meta, "|")
if len(fields) != 3 {
break
}
// Skip heading line.
if fields[0] == "it" {
continue
}
// Parse iteration number.
it, err := strconv.Atoi(strings.TrimSpace(fields[0]))
if err != nil {
return nil, err
}
// Parse instruction number.
in, err := strconv.Atoi(strings.TrimSpace(fields[1]))
if err != nil {
return nil, err
}
fragment := strings.TrimSpace(fields[2])
// Skip the "macro instruction" line.
if in != cur {
cur = in
dis = fragment
continue
}
f, uops, err := ParseFragment(fragment)
if err != nil {
return nil, err
}
stages, err := ParseTimeline([]byte(timeline))
if err != nil {
return nil, err
}
t.Executions = append(t.Executions, Execution{
Iteration: it,
Instruction: in,
Dissasembly: dis,
Type: f,
Uops: uops,
Timeline: stages,
})
}
if err := s.Err(); err != nil {
return nil, err
}
return t, nil
}
func (t *Trace) ExecutionsByCycle() [][]*Execution {
if len(t.Executions) == 0 {
return nil
}
n := len(t.Executions[0].Timeline)
cycles := make([][]*Execution, n)
for i, e := range t.Executions {
for c, stage := range e.Timeline {
if stage == StageExecute || stage == StageWriteback {
cycles[c] = append(cycles[c], &t.Executions[i])
}
}
}
return cycles
}
func main() {
t, err := Parse(os.Stdin)
if err != nil {
log.Fatal(err)
}
for i, cycle := range t.ExecutionsByCycle() {
fmt.Printf("%03d:\n", i)
for _, e := range cycle {
fmt.Printf("\t%s\n", e.Dissasembly)
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment