Eine aufbereitete Darstellung der Quelle

 
     
 
 
Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 

Benutzer

Quelle  tracer.go   Sprache: unbekannt

 
Spracherkennung für: .go vermutete Sprache: Unknown {[0] [0] [0]} [Methode: Schwerpunktbildung, einfache Gewichte, sechs Dimensionen]

// Copyright 2017 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// This package implements a trace file writer, whose files can be opened in
// chrome://tracing.
//
// It implements the JSON Array Format defined here:
// https://docs.google.com/document/d/1CvAClvFfyA5R-PhYUmn5OOQtYMH4h6I0nSsKchNAySU/edit
package tracer

import (
 "bytes"
 "compress/gzip"
 "encoding/json"
 "fmt"
 "io"
 "os"
 "strings"
 "sync"
 "time"

 "android/soong/ui/logger"
 "android/soong/ui/status"
)

type Thread uint64

const (
 MainThread     = Thread(iota)
 MaxInitThreads = Thread(iota)
)

type Tracer interface {
 Begin(name string, thread Thread)
 End(thread Thread)
 Complete(name string, thread Thread, begin, end uint64)

 CountersAtTime(name string, thread Thread, time uint64, counters []Counter)

 ImportMicrofactoryLog(filename string)

 StatusTracer() status.StatusOutput

 NewThread(name string) Thread
}

type tracerImpl struct {
 lock sync.Mutex
 log  logger.Logger

 buf  bytes.Buffer
 file *os.File
 w    io.WriteCloser

 firstEvent bool
 nextTid    uint64
}

var _ Tracer = &tracerImpl{}

type viewerEvent struct {
 Name  string      `json:"name,omitempty"`
 Phase string      `json:"ph"`
 Scope string      `json:"s,omitempty"`
 Time  uint64      `json:"ts"`
 Dur   uint64      `json:"dur,omitempty"`
 Pid   uint64      `json:"pid"`
 Tid   uint64      `json:"tid"`
 ID    uint64      `json:"id,omitempty"`
 Arg   interface{} `json:"args,omitempty"`
}

type nameArg struct {
 Name string `json:"name"`
}

type nopCloser struct{ io.Writer }

func (nopCloser) Close() error { return nil }

// New creates a new Tracer, storing log in order to log errors later.
// Events are buffered in memory until SetOutput is called.
func New(log logger.Logger) *tracerImpl {
 ret := &tracerImpl{
  log: log,

  firstEvent: true,
  nextTid:    uint64(MaxInitThreads),
 }
 ret.startBuffer()

 return ret
}

func (t *tracerImpl) startBuffer() {
 t.w = nopCloser{&t.buf}
 fmt.Fprintln(t.w, "[")

 t.defineThread(MainThread, "main")
}

func (t *tracerImpl) close() {
 if t.file != nil {
  fmt.Fprintln(t.w, "]")

  if err := t.w.Close(); err != nil {
   t.log.Println("Error closing trace writer:", err)
  }

  if err := t.file.Close(); err != nil {
   t.log.Println("Error closing trace file:", err)
  }
  t.file = nil
  t.startBuffer()
 }
}

// SetOutput creates the output file (rotating old files).
func (t *tracerImpl) SetOutput(filename string) {
 t.lock.Lock()
 defer t.lock.Unlock()

 t.close()

 // chrome://tracing requires that compressed trace files end in .gz
 if !strings.HasSuffix(filename, ".gz") {
  filename += ".gz"
 }

 f, err := logger.CreateFileWithRotation(filename, 5)
 if err != nil {
  t.log.Println("Failed to create trace file:", err)
  return
 }
 // Save the file, since closing the gzip Writer doesn't close the
 // underlying file.
 t.file = f
 t.w = gzip.NewWriter(f)

 // Write out everything that happened since the start
 if _, err := io.Copy(t.w, &t.buf); err != nil {
  t.log.Println("Failed to write trace buffer to file:", err)
 }
 t.buf = bytes.Buffer{}
}

// Close closes the output file. Any future events will be buffered until the
// next call to SetOutput.
func (t *tracerImpl) Close() {
 t.lock.Lock()
 defer t.lock.Unlock()

 t.close()
}

func (t *tracerImpl) writeEvent(event *viewerEvent) {
 t.lock.Lock()
 defer t.lock.Unlock()

 t.writeEventLocked(event)
}

func (t *tracerImpl) writeEventLocked(event *viewerEvent) {
 bytes, err := json.Marshal(event)
 if err != nil {
  t.log.Println("Failed to marshal event:", err)
  t.log.Verbosef("Event: %#v", event)
  return
 }

 if !t.firstEvent {
  fmt.Fprintln(t.w, ",")
 } else {
  t.firstEvent = false
 }

 if _, err = t.w.Write(bytes); err != nil {
  t.log.Println("Trace write error:", err)
 }
}

func (t *tracerImpl) defineThread(thread Thread, name string) {
 t.writeEventLocked(&viewerEvent{
  Name:  "thread_name",
  Phase: "M",
  Pid:   0,
  Tid:   uint64(thread),
  Arg: &nameArg{
   Name: name,
  },
 })
}

// NewThread returns a new Thread with an unused tid, writing the name out to
// the trace file.
func (t *tracerImpl) NewThread(name string) Thread {
 t.lock.Lock()
 defer t.lock.Unlock()

 ret := Thread(t.nextTid)
 t.nextTid += 1

 t.defineThread(ret, name)
 return ret
}

// Begin starts a new Duration Event. More than one Duration Event may be active
// at a time on each Thread, but they're nested.
func (t *tracerImpl) Begin(name string, thread Thread) {
 t.writeEvent(&viewerEvent{
  Name:  name,
  Phase: "B",
  Time:  uint64(time.Now().UnixNano()) / 1000,
  Pid:   0,
  Tid:   uint64(thread),
 })
}

// End finishes the most recent active Duration Event on the thread.
func (t *tracerImpl) End(thread Thread) {
 t.writeEvent(&viewerEvent{
  Phase: "E",
  Time:  uint64(time.Now().UnixNano()) / 1000,
  Pid:   0,
  Tid:   uint64(thread),
 })
}

// Complete writes a Complete Event, which are like Duration Events, but include
// a begin and end timestamp in the same event.
func (t *tracerImpl) Complete(name string, thread Thread, begin, end uint64) {
 t.writeEvent(&viewerEvent{
  Name:  name,
  Phase: "X",
  Time:  begin / 1000,
  Dur:   (end - begin) / 1000,
  Pid:   0,
  Tid:   uint64(thread),
 })
}

type Counter struct {
 Name  string
 Value int64
}

type countersMarshaller []Counter

var _ json.Marshaler = countersMarshaller(nil)

func (counters countersMarshaller) MarshalJSON() ([]byte, error) {
 // This produces similar output to a map[string]int64, but maintains the order of the slice.
 buf := bytes.Buffer{}
 buf.WriteRune('{')
 for i, counter := range counters {
  name, err := json.Marshal(counter.Name)
  if err != nil {
   return nil, err
  }
  buf.Write(name)
  buf.WriteByte(':')
  value, err := json.Marshal(counter.Value)
  if err != nil {
   return nil, err
  }
  buf.Write(value)
  if i != len(counters)-1 {
   buf.WriteRune(',')
  }
 }
 buf.WriteRune('}')
 return buf.Bytes(), nil
}

// CountersAtTime writes a Counter event at the given timestamp in nanoseconds.
func (t *tracerImpl) CountersAtTime(name string, thread Thread, time uint64, counters []Counter) {
 t.writeEvent(&viewerEvent{
  Name:  name,
  Phase: "C",
  Time:  time / 1000,
  Pid:   0,
  Tid:   uint64(thread),
  Arg:   countersMarshaller(counters),
 })
}

[Dauer der Verarbeitung: 0.3 Sekunden, vorverarbeitet 2026-06-28]

                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Quellcodebibliothek
     Eigene Quellcodes
     Fremde Quellcodes
     Suchen

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik