Last active
September 23, 2018 22:18
-
-
Save mmcloughlin/0eda5b70fc095723ab695122d34bd3c2 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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