aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/compile/internal/base
diff options
context:
space:
mode:
authorRuss Cox <rsc@golang.org>2020-12-23 01:43:22 -0500
committerRuss Cox <rsc@golang.org>2020-12-23 01:43:22 -0500
commitd99dd178277c32c982ac2393446e503e76b9f56d (patch)
tree1bc6bdf9cc3cacfc62580c0cde22a0f7e2d83465 /src/cmd/compile/internal/base
parent8b1fbd8215699a864ed315e3306e118558c8e243 (diff)
parent37f138df6bcd7bb7cf62148cd8388f3916388ab6 (diff)
downloadgo-d99dd178277c32c982ac2393446e503e76b9f56d.tar.gz
go-d99dd178277c32c982ac2393446e503e76b9f56d.zip
[dev.typeparams] all: merge dev.regabi (37f138d) into dev.typeparams
Conflicts: * src/cmd/compile/fmtmap_test.go * src/cmd/compile/internal/gc/go.go * src/cmd/compile/internal/gc/main.go * src/cmd/compile/internal/noder/noder.go Merge List: * 2020-12-23 37f138df6b [dev.regabi] cmd/compile: split out package test [generated] * 2020-12-23 3d8a3cb06b [dev.regabi] cmd/compile: split out package pkginit [generated] * 2020-12-23 3f04d964ab [dev.regabi] cmd/compile: split up walkexpr1, walkstmt [generated] * 2020-12-23 e4895ab4c0 [dev.regabi] cmd/compile: split out package walk [generated] * 2020-12-23 01fd2d05c8 [dev.regabi] cmd/compile: split out package dwarfgen [generated] * 2020-12-23 6c34d2f420 [dev.regabi] cmd/compile: split out package ssagen [generated] * 2020-12-23 de65151e50 [dev.regabi] cmd/compile: split out package reflectdata [generated] * 2020-12-23 4dfb5d91a8 [dev.regabi] cmd/compile: split out package staticdata [generated] * 2020-12-23 fbc82f03b1 [dev.regabi] cmd/compile: split out package noder [generated] * 2020-12-23 de454eef5f [dev.regabi] cmd/compile: split out package escape [generated] * 2020-12-23 071ab0a14c [dev.regabi] cmd/compile: split out package liveness [generated] * 2020-12-23 0ced54062e [dev.regabi] cmd/compile: split out package objw [generated] * 2020-12-23 575fd6ff0a [dev.regabi] cmd/compile: split out package inline [generated] * 2020-12-23 0256ba99a8 [dev.regabi] cmd/compile: split up typecheck1 [generated] * 2020-12-23 b9693d7627 [dev.regabi] cmd/compile: split out package typecheck [generated] * 2020-12-23 dac0de3748 [dev.regabi] cmd/compile: move type size calculations into package types [generated] * 2020-12-23 527a1895d6 [dev.regabi] cmd/compile: move helpers into package ir [generated] * 2020-12-23 65c4c6dfb2 [dev.regabi] cmd/compile: group known symbols, packages, names [generated] * 2020-12-23 9ee309255a [dev.regabi] cmd/compile: move helpers into package types [generated] * 2020-12-23 ead4957892 [dev.regabi] cmd/compile: move helpers into package base [generated] * 2020-12-23 440308ffd7 [dev.regabi] cmd/compile: simplify Nodes usage [generated] * 2020-12-23 f9d373720e [dev.regabi] cmd/compile: remove Left, Right etc methods [generated] * 2020-12-23 14d667341f [dev.regabi] cmd/compile: remove Node.Left etc [generated] * 2020-12-23 6f27d29be0 [dev.regabi] cmd/compile: remove ir.Nod [generated] * 2020-12-23 69cf39089f [dev.regabi] cmd/compile: do not die in early base.FlushErrors Change-Id: Ic4686e77c6ee38b3cd7d37fc7f3e93aaa9017b7a
Diffstat (limited to 'src/cmd/compile/internal/base')
-rw-r--r--src/cmd/compile/internal/base/base.go51
-rw-r--r--src/cmd/compile/internal/base/flag.go3
-rw-r--r--src/cmd/compile/internal/base/print.go6
-rw-r--r--src/cmd/compile/internal/base/timings.go237
4 files changed, 296 insertions, 1 deletions
diff --git a/src/cmd/compile/internal/base/base.go b/src/cmd/compile/internal/base/base.go
index e26b378472..5a30fa6a33 100644
--- a/src/cmd/compile/internal/base/base.go
+++ b/src/cmd/compile/internal/base/base.go
@@ -26,3 +26,54 @@ func Exit(code int) {
}
os.Exit(code)
}
+
+// To enable tracing support (-t flag), set EnableTrace to true.
+const EnableTrace = false
+
+func Compiling(pkgs []string) bool {
+ if Ctxt.Pkgpath != "" {
+ for _, p := range pkgs {
+ if Ctxt.Pkgpath == p {
+ return true
+ }
+ }
+ }
+
+ return false
+}
+
+// The racewalk pass is currently handled in three parts.
+//
+// First, for flag_race, it inserts calls to racefuncenter and
+// racefuncexit at the start and end (respectively) of each
+// function. This is handled below.
+//
+// Second, during buildssa, it inserts appropriate instrumentation
+// calls immediately before each memory load or store. This is handled
+// by the (*state).instrument method in ssa.go, so here we just set
+// the Func.InstrumentBody flag as needed. For background on why this
+// is done during SSA construction rather than a separate SSA pass,
+// see issue #19054.
+//
+// Third we remove calls to racefuncenter and racefuncexit, for leaf
+// functions without instrumented operations. This is done as part of
+// ssa opt pass via special rule.
+
+// TODO(dvyukov): do not instrument initialization as writes:
+// a := make([]int, 10)
+
+// Do not instrument the following packages at all,
+// at best instrumentation would cause infinite recursion.
+var NoInstrumentPkgs = []string{
+ "runtime/internal/atomic",
+ "runtime/internal/sys",
+ "runtime/internal/math",
+ "runtime",
+ "runtime/race",
+ "runtime/msan",
+ "internal/cpu",
+}
+
+// Don't insert racefuncenterfp/racefuncexit into the following packages.
+// Memory accesses in the packages are either uninteresting or will cause false positives.
+var NoRacePkgs = []string{"sync", "sync/atomic"}
diff --git a/src/cmd/compile/internal/base/flag.go b/src/cmd/compile/internal/base/flag.go
index 898cb5470b..3602fb947d 100644
--- a/src/cmd/compile/internal/base/flag.go
+++ b/src/cmd/compile/internal/base/flag.go
@@ -131,6 +131,9 @@ type CmdFlags struct {
ImportMap map[string]string // set by -importmap OR -importcfg
PackageFile map[string]string // set by -importcfg; nil means not in use
SpectreIndex bool // set by -spectre=index or -spectre=all
+ // Whether we are adding any sort of code instrumentation, such as
+ // when the race detector is enabled.
+ Instrumenting bool
}
}
diff --git a/src/cmd/compile/internal/base/print.go b/src/cmd/compile/internal/base/print.go
index 6831b3ada3..9855dfdad0 100644
--- a/src/cmd/compile/internal/base/print.go
+++ b/src/cmd/compile/internal/base/print.go
@@ -73,7 +73,9 @@ func (x byPos) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
// FlushErrors sorts errors seen so far by line number, prints them to stdout,
// and empties the errors array.
func FlushErrors() {
- Ctxt.Bso.Flush()
+ if Ctxt != nil && Ctxt.Bso != nil {
+ Ctxt.Bso.Flush()
+ }
if len(errorMsgs) == 0 {
return
}
@@ -258,3 +260,5 @@ func ExitIfErrors() {
ErrorExit()
}
}
+
+var AutogeneratedPos src.XPos
diff --git a/src/cmd/compile/internal/base/timings.go b/src/cmd/compile/internal/base/timings.go
new file mode 100644
index 0000000000..f599f4e05f
--- /dev/null
+++ b/src/cmd/compile/internal/base/timings.go
@@ -0,0 +1,237 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package base
+
+import (
+ "fmt"
+ "io"
+ "strings"
+ "time"
+)
+
+var Timer Timings
+
+// Timings collects the execution times of labeled phases
+// which are added trough a sequence of Start/Stop calls.
+// Events may be associated with each phase via AddEvent.
+type Timings struct {
+ list []timestamp
+ events map[int][]*event // lazily allocated
+}
+
+type timestamp struct {
+ time time.Time
+ label string
+ start bool
+}
+
+type event struct {
+ size int64 // count or amount of data processed (allocations, data size, lines, funcs, ...)
+ unit string // unit of size measure (count, MB, lines, funcs, ...)
+}
+
+func (t *Timings) append(labels []string, start bool) {
+ t.list = append(t.list, timestamp{time.Now(), strings.Join(labels, ":"), start})
+}
+
+// Start marks the beginning of a new phase and implicitly stops the previous phase.
+// The phase name is the colon-separated concatenation of the labels.
+func (t *Timings) Start(labels ...string) {
+ t.append(labels, true)
+}
+
+// Stop marks the end of a phase and implicitly starts a new phase.
+// The labels are added to the labels of the ended phase.
+func (t *Timings) Stop(labels ...string) {
+ t.append(labels, false)
+}
+
+// AddEvent associates an event, i.e., a count, or an amount of data,
+// with the most recently started or stopped phase; or the very first
+// phase if Start or Stop hasn't been called yet. The unit specifies
+// the unit of measurement (e.g., MB, lines, no. of funcs, etc.).
+func (t *Timings) AddEvent(size int64, unit string) {
+ m := t.events
+ if m == nil {
+ m = make(map[int][]*event)
+ t.events = m
+ }
+ i := len(t.list)
+ if i > 0 {
+ i--
+ }
+ m[i] = append(m[i], &event{size, unit})
+}
+
+// Write prints the phase times to w.
+// The prefix is printed at the start of each line.
+func (t *Timings) Write(w io.Writer, prefix string) {
+ if len(t.list) > 0 {
+ var lines lines
+
+ // group of phases with shared non-empty label prefix
+ var group struct {
+ label string // label prefix
+ tot time.Duration // accumulated phase time
+ size int // number of phases collected in group
+ }
+
+ // accumulated time between Stop/Start timestamps
+ var unaccounted time.Duration
+
+ // process Start/Stop timestamps
+ pt := &t.list[0] // previous timestamp
+ tot := t.list[len(t.list)-1].time.Sub(pt.time)
+ for i := 1; i < len(t.list); i++ {
+ qt := &t.list[i] // current timestamp
+ dt := qt.time.Sub(pt.time)
+
+ var label string
+ var events []*event
+ if pt.start {
+ // previous phase started
+ label = pt.label
+ events = t.events[i-1]
+ if qt.start {
+ // start implicitly ended previous phase; nothing to do
+ } else {
+ // stop ended previous phase; append stop labels, if any
+ if qt.label != "" {
+ label += ":" + qt.label
+ }
+ // events associated with stop replace prior events
+ if e := t.events[i]; e != nil {
+ events = e
+ }
+ }
+ } else {
+ // previous phase stopped
+ if qt.start {
+ // between a stopped and started phase; unaccounted time
+ unaccounted += dt
+ } else {
+ // previous stop implicitly started current phase
+ label = qt.label
+ events = t.events[i]
+ }
+ }
+ if label != "" {
+ // add phase to existing group, or start a new group
+ l := commonPrefix(group.label, label)
+ if group.size == 1 && l != "" || group.size > 1 && l == group.label {
+ // add to existing group
+ group.label = l
+ group.tot += dt
+ group.size++
+ } else {
+ // start a new group
+ if group.size > 1 {
+ lines.add(prefix+group.label+"subtotal", 1, group.tot, tot, nil)
+ }
+ group.label = label
+ group.tot = dt
+ group.size = 1
+ }
+
+ // write phase
+ lines.add(prefix+label, 1, dt, tot, events)
+ }
+
+ pt = qt
+ }
+
+ if group.size > 1 {
+ lines.add(prefix+group.label+"subtotal", 1, group.tot, tot, nil)
+ }
+
+ if unaccounted != 0 {
+ lines.add(prefix+"unaccounted", 1, unaccounted, tot, nil)
+ }
+
+ lines.add(prefix+"total", 1, tot, tot, nil)
+
+ lines.write(w)
+ }
+}
+
+func commonPrefix(a, b string) string {
+ i := 0
+ for i < len(a) && i < len(b) && a[i] == b[i] {
+ i++
+ }
+ return a[:i]
+}
+
+type lines [][]string
+
+func (lines *lines) add(label string, n int, dt, tot time.Duration, events []*event) {
+ var line []string
+ add := func(format string, args ...interface{}) {
+ line = append(line, fmt.Sprintf(format, args...))
+ }
+
+ add("%s", label)
+ add(" %d", n)
+ add(" %d ns/op", dt)
+ add(" %.2f %%", float64(dt)/float64(tot)*100)
+
+ for _, e := range events {
+ add(" %d", e.size)
+ add(" %s", e.unit)
+ add(" %d", int64(float64(e.size)/dt.Seconds()+0.5))
+ add(" %s/s", e.unit)
+ }
+
+ *lines = append(*lines, line)
+}
+
+func (lines lines) write(w io.Writer) {
+ // determine column widths and contents
+ var widths []int
+ var number []bool
+ for _, line := range lines {
+ for i, col := range line {
+ if i < len(widths) {
+ if len(col) > widths[i] {
+ widths[i] = len(col)
+ }
+ } else {
+ widths = append(widths, len(col))
+ number = append(number, isnumber(col)) // first line determines column contents
+ }
+ }
+ }
+
+ // make column widths a multiple of align for more stable output
+ const align = 1 // set to a value > 1 to enable
+ if align > 1 {
+ for i, w := range widths {
+ w += align - 1
+ widths[i] = w - w%align
+ }
+ }
+
+ // print lines taking column widths and contents into account
+ for _, line := range lines {
+ for i, col := range line {
+ format := "%-*s"
+ if number[i] {
+ format = "%*s" // numbers are right-aligned
+ }
+ fmt.Fprintf(w, format, widths[i], col)
+ }
+ fmt.Fprintln(w)
+ }
+}
+
+func isnumber(s string) bool {
+ for _, ch := range s {
+ if ch <= ' ' {
+ continue // ignore leading whitespace
+ }
+ return '0' <= ch && ch <= '9' || ch == '.' || ch == '-' || ch == '+'
+ }
+ return false
+}