Spracherkennung für: .go vermutete Sprache: Delphi {Delphi[50] ABAP[32] Fortran[28]} [Methode: maximale Elemente, drei 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 []Co
unter) {
t.writeEvent(&viewerEvent{
Name: name,
Phase: "C",
Time: time / 1000,
Pid: 0,
Tid: uint64(thread),
Arg: countersMarshaller(counters),
})
}