github.com/westcoastroms/westcoastroms-build@v0.0.0-20190928114312-2350e5a73030/build/soong/ui/tracer/ninja.go (about) 1 // Copyright 2016 Google Inc. All rights reserved. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package tracer 16 17 import ( 18 "bufio" 19 "os" 20 "sort" 21 "strconv" 22 "strings" 23 "time" 24 ) 25 26 type eventEntry struct { 27 Name string 28 Begin uint64 29 End uint64 30 } 31 32 func (t *tracerImpl) importEvents(entries []*eventEntry) { 33 sort.Slice(entries, func(i, j int) bool { 34 return entries[i].Begin < entries[j].Begin 35 }) 36 37 cpus := []uint64{} 38 for _, entry := range entries { 39 tid := -1 40 for cpu, endTime := range cpus { 41 if endTime <= entry.Begin { 42 tid = cpu 43 cpus[cpu] = entry.End 44 break 45 } 46 } 47 if tid == -1 { 48 tid = len(cpus) 49 cpus = append(cpus, entry.End) 50 } 51 52 t.writeEvent(&viewerEvent{ 53 Name: entry.Name, 54 Phase: "X", 55 Time: entry.Begin, 56 Dur: entry.End - entry.Begin, 57 Pid: 1, 58 Tid: uint64(tid), 59 }) 60 } 61 } 62 63 // ImportNinjaLog reads a .ninja_log file from ninja and writes the events out 64 // to the trace. 65 // 66 // startOffset is when the ninja process started, and is used to position the 67 // relative times from the ninja log into the trace. It's also used to skip 68 // reading the ninja log if nothing was run. 69 func (t *tracerImpl) ImportNinjaLog(thread Thread, filename string, startOffset time.Time) { 70 t.Begin("ninja log import", thread) 71 defer t.End(thread) 72 73 if stat, err := os.Stat(filename); err != nil { 74 t.log.Println("Missing ninja log:", err) 75 return 76 } else if stat.ModTime().Before(startOffset) { 77 t.log.Verboseln("Ninja log not modified, not importing any entries.") 78 return 79 } 80 81 f, err := os.Open(filename) 82 if err != nil { 83 t.log.Println("Error opening ninja log:", err) 84 return 85 } 86 defer f.Close() 87 88 s := bufio.NewScanner(f) 89 header := true 90 entries := []*eventEntry{} 91 prevEnd := 0 92 offset := uint64(startOffset.UnixNano()) / 1000 93 for s.Scan() { 94 if header { 95 hdr := s.Text() 96 if hdr != "# ninja log v5" { 97 t.log.Printf("Unknown ninja log header: %q", hdr) 98 return 99 } 100 header = false 101 continue 102 } 103 104 fields := strings.Split(s.Text(), "\t") 105 begin, err := strconv.Atoi(fields[0]) 106 if err != nil { 107 t.log.Printf("Unable to parse ninja entry %q: %v", s.Text(), err) 108 return 109 } 110 end, err := strconv.Atoi(fields[1]) 111 if err != nil { 112 t.log.Printf("Unable to parse ninja entry %q: %v", s.Text(), err) 113 return 114 } 115 if end < prevEnd { 116 entries = nil 117 } 118 prevEnd = end 119 entries = append(entries, &eventEntry{ 120 Name: fields[3], 121 Begin: offset + uint64(begin)*1000, 122 End: offset + uint64(end)*1000, 123 }) 124 } 125 if err := s.Err(); err != nil { 126 t.log.Println("Unable to parse ninja log:", err) 127 return 128 } 129 130 t.importEvents(entries) 131 }