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  }