diff options
| author | 2023-04-28 01:36:55 +0800 | |
|---|---|---|
| committer | 2023-04-28 01:36:55 +0800 | |
| commit | fc8c5fdce62fb229202659408798a7b6c98f6e8b (patch) | |
| tree | 7554f80e50de4af6fd255afa7c21bcdd58a7af34 /cli/internal/chrometracing | |
| parent | dd84b9d64fb98746a230cd24233ff50a562c39c9 (diff) | |
| download | HydroRoll-fc8c5fdce62fb229202659408798a7b6c98f6e8b.tar.gz HydroRoll-fc8c5fdce62fb229202659408798a7b6c98f6e8b.zip | |
Diffstat (limited to 'cli/internal/chrometracing')
| -rw-r--r-- | cli/internal/chrometracing/chrometracing.go | 227 | ||||
| -rw-r--r-- | cli/internal/chrometracing/chrometracing_close.go | 26 |
2 files changed, 0 insertions, 253 deletions
diff --git a/cli/internal/chrometracing/chrometracing.go b/cli/internal/chrometracing/chrometracing.go deleted file mode 100644 index d9325fd..0000000 --- a/cli/internal/chrometracing/chrometracing.go +++ /dev/null @@ -1,227 +0,0 @@ -// Copyright 2020 Google LLC -// -// 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 -// -// https://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. - -// Package chrometracing writes per-process Chrome trace_event files that can be -// loaded into chrome://tracing. -package chrometracing - -import ( - "encoding/json" - "fmt" - "os" - "path/filepath" - "strings" - "sync" - "time" - - "github.com/google/chrometracing/traceinternal" -) - -var trace = struct { - start time.Time - pid uint64 - - fileMu sync.Mutex - file *os.File -}{ - pid: uint64(os.Getpid()), -} - -var out = setup(false) - -// Path returns the full path of the chrome://tracing trace_event file for -// display in log messages. -func Path() string { return out } - -// EnableTracing turns on tracing, regardless of running in a test or -// not. Tracing is enabled by default if the CHROMETRACING_DIR environment -// variable is present and non-empty. -func EnableTracing() { - trace.fileMu.Lock() - alreadyEnabled := trace.file != nil - trace.fileMu.Unlock() - if alreadyEnabled { - return - } - out = setup(true) -} - -func setup(overrideEnable bool) string { - inTest := os.Getenv("TEST_TMPDIR") != "" - explicitlyEnabled := os.Getenv("CHROMETRACING_DIR") != "" - enableTracing := inTest || explicitlyEnabled || overrideEnable - if !enableTracing { - return "" - } - - var err error - dir := os.Getenv("TEST_UNDECLARED_OUTPUTS_DIR") - if dir == "" { - dir = os.Getenv("CHROMETRACING_DIR") - } - if dir == "" { - dir = os.TempDir() - } - fn := filepath.Join(dir, fmt.Sprintf("%s.%d.trace", filepath.Base(os.Args[0]), trace.pid)) - trace.file, err = os.OpenFile(fn, os.O_WRONLY|os.O_CREATE|os.O_TRUNC|os.O_EXCL, 0644) - if err != nil { - // Using the log package from func init results in an error message - // being printed. - fmt.Fprintf(os.Stderr, "continuing without tracing: %v\n", err) - return "" - } - - // We only ever open a JSON array. Ending the array is optional as per - // go/trace_event so that not cleanly finished traces can still be read. - trace.file.Write([]byte{'['}) - trace.start = time.Now() - - writeEvent(&traceinternal.ViewerEvent{ - Name: "process_name", - Phase: "M", // Metadata Event - Pid: trace.pid, - Tid: trace.pid, - Arg: struct { - Name string `json:"name"` - }{ - Name: strings.Join(os.Args, " "), - }, - }) - return fn -} - -func writeEvent(ev *traceinternal.ViewerEvent) { - b, err := json.Marshal(&ev) - if err != nil { - fmt.Fprintf(os.Stderr, "%v\n", err) - return - } - trace.fileMu.Lock() - defer trace.fileMu.Unlock() - if _, err = trace.file.Write(b); err != nil { - fmt.Fprintf(os.Stderr, "%v\n", err) - return - } - if _, err = trace.file.Write([]byte{',', '\n'}); err != nil { - fmt.Fprintf(os.Stderr, "%v\n", err) - return - } -} - -const ( - begin = "B" - end = "E" -) - -// A PendingEvent represents an ongoing unit of work. The begin trace event has -// already been written, and calling Done will write the end trace event. -type PendingEvent struct { - name string - tid uint64 -} - -// Done writes the end trace event for this unit of work. -func (pe *PendingEvent) Done() { - if pe == nil || pe.name == "" || trace.file == nil { - return - } - writeEvent(&traceinternal.ViewerEvent{ - Name: pe.name, - Phase: end, - Pid: trace.pid, - Tid: pe.tid, - Time: float64(time.Since(trace.start).Microseconds()), - }) - releaseTid(pe.tid) -} - -// Event logs a unit of work. To instrument a Go function, use e.g.: -// -// func calcPi() { -// defer chrometracing.Event("calculate pi").Done() -// // … -// } -// -// For more finely-granular traces, use e.g.: -// -// for _, cmd := range commands { -// ev := chrometracing.Event("initialize " + cmd.Name) -// cmd.Init() -// ev.Done() -// } -func Event(name string) *PendingEvent { - if trace.file == nil { - return &PendingEvent{} - } - tid := tid() - writeEvent(&traceinternal.ViewerEvent{ - Name: name, - Phase: begin, - Pid: trace.pid, - Tid: tid, - Time: float64(time.Since(trace.start).Microseconds()), - }) - return &PendingEvent{ - name: name, - tid: tid, - } -} - -// tids is a chrome://tracing thread id pool. Go does not permit accessing the -// goroutine id, so we need to maintain our own identifier. The chrome://tracing -// file format requires a numeric thread id, so we just increment whenever we -// need a thread id, and reuse the ones no longer in use. -// -// In practice, parallelized sections of the code (many goroutines) end up using -// only as few thread ids as are concurrently in use, and the rest of the events -// mirror the code call stack nicely. See e.g. http://screen/7MPcAcvXQNUE3JZ -var tids struct { - sync.Mutex - - // We allocate chrome://tracing thread ids based on the index of the - // corresponding entry in the used slice. - used []bool - - // next points to the earliest unused tid to consider for the next tid to - // hand out. This is purely a performance optimization to avoid O(n) slice - // iteration. - next int -} - -func tid() uint64 { - tids.Lock() - defer tids.Unlock() - // re-use released tids if any - for t := tids.next; t < len(tids.used); t++ { - if !tids.used[t] { - tids.used[t] = true - tids.next = t + 1 - return uint64(t) - } - } - // allocate a new tid - t := len(tids.used) - tids.used = append(tids.used, true) - tids.next = t + 1 - return uint64(t) -} - -func releaseTid(t uint64) { - tids.Lock() - defer tids.Unlock() - tids.used[int(t)] = false - if tids.next > int(t) { - tids.next = int(t) - } -} diff --git a/cli/internal/chrometracing/chrometracing_close.go b/cli/internal/chrometracing/chrometracing_close.go deleted file mode 100644 index 1b3a7b9..0000000 --- a/cli/internal/chrometracing/chrometracing_close.go +++ /dev/null @@ -1,26 +0,0 @@ -package chrometracing - -// Close overwrites the trailing (,\n) with (]\n) and closes the trace file. -// Close is implemented in a separate file to keep a separation between custom -// code and upstream from github.com/google/chrometracing. Additionally, we can -// enable linting for code we author, while leaving upstream code alone. -func Close() error { - trace.fileMu.Lock() - defer trace.fileMu.Unlock() - // Seek backwards two bytes (,\n) - if _, err := trace.file.Seek(-2, 1); err != nil { - return err - } - // Write 1 byte, ']', leaving the trailing '\n' in place - if _, err := trace.file.Write([]byte{']'}); err != nil { - return err - } - // Force the filesystem to write to disk - if err := trace.file.Sync(); err != nil { - return err - } - if err := trace.file.Close(); err != nil { - return err - } - return nil -} |
