Commit 29170dee authored by Kirill Smelkov's avatar Kirill Smelkov

X tracing: Polish

parent 4d0cd894
This diff is collapsed.
// Copyright (C) 2017 Nexedi SA and Contributors.
// Kirill Smelkov <kirr@nexedi.com>
//
// This program is free software: you can Use, Study, Modify and Redistribute
// it under the terms of the GNU General Public License version 3, or (at your
// option) any later version, as published by the Free Software Foundation.
//
// You can also Link and Combine this program with other software covered by
// the terms of any of the Free Software licenses or any of the Open Source
// Initiative approved licenses and Convey the resulting work. Corresponding
// source of such a combination shall include the source code for all other
// software used.
//
// This program is distributed WITHOUT ANY WARRANTY; without even the implied
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
//
// See COPYING file for full licensing terms.
// See https://www.nexedi.com/licensing for rationale and options.
package main package main
import ( import (
"bytes"
"fmt" "fmt"
"go/build" "go/build"
"io/ioutil" "io/ioutil"
...@@ -28,10 +48,11 @@ func xglob(t *testing.T, pattern string) []string { ...@@ -28,10 +48,11 @@ func xglob(t *testing.T, pattern string) []string {
type TreePrepareMode int type TreePrepareMode int
const ( const (
TreePrepareGolden TreePrepareMode = iota // prepare golden tree - how `gotrace gen` result should look like TreePrepareGolden TreePrepareMode = iota // prepare golden tree - how `gotrace gen` result should look like
TreePrepareWork // prepare work tree - inital state for `gotrace gen` to run TreePrepareWork // prepare work tree - inital state for `gotrace gen` to run
) )
// prepareTestTree copies files from src to dst recursively processing *.ok and *.rm depending on mode // prepareTestTree copies files from src to dst recursively processing *.ok and *.rm depending on mode.
//
// dst should not initially exist // dst should not initially exist
func prepareTestTree(src, dst string, mode TreePrepareMode) error { func prepareTestTree(src, dst string, mode TreePrepareMode) error {
err := os.MkdirAll(dst, 0777) err := os.MkdirAll(dst, 0777)
...@@ -113,12 +134,12 @@ func diffR(patha, pathb string) (diff string, err error) { ...@@ -113,12 +134,12 @@ func diffR(patha, pathb string) (diff string, err error) {
return string(out), err return string(out), err
} }
func TestGoTraceGen(t *testing.T) { func TestGoTrace(t *testing.T) {
tmp, err := ioutil.TempDir("", "t-gotrace") tmp, err := ioutil.TempDir("", "t-gotrace")
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
//defer os.RemoveAll(tmp) defer os.RemoveAll(tmp)
good := tmp + "/good" good := tmp + "/good"
work := tmp + "/work" work := tmp + "/work"
...@@ -128,19 +149,19 @@ func TestGoTraceGen(t *testing.T) { ...@@ -128,19 +149,19 @@ func TestGoTraceGen(t *testing.T) {
// test build context with GOPATH set to work tree // test build context with GOPATH set to work tree
var tBuildCtx = &build.Context{ var tBuildCtx = &build.Context{
GOARCH: "amd64", GOARCH: "amd64",
GOOS: "linux", GOOS: "linux",
GOROOT: runtime.GOROOT(), GOROOT: runtime.GOROOT(),
GOPATH: work, GOPATH: work,
CgoEnabled: true, CgoEnabled: true,
Compiler: runtime.Compiler, Compiler: runtime.Compiler,
} }
// XXX autodetect (go list ?) // XXX autodetect (go list ?)
testv := []string{"a/pkg1", "b/pkg2", "c/pkg3", "d/pkg4"} testv := []string{"a/pkg1", "b/pkg2", "c/pkg3", "d/pkg4"}
//testv := []string{"c/pkg3"}
for _, tpkg := range testv { for _, tpkg := range testv {
// verify `gotrace gen`
err = tracegen(tpkg, tBuildCtx, "" /* = local imorts disabled */) err = tracegen(tpkg, tBuildCtx, "" /* = local imorts disabled */)
if err != nil { if err != nil {
t.Errorf("%v: %v", tpkg, err) t.Errorf("%v: %v", tpkg, err)
...@@ -154,5 +175,22 @@ func TestGoTraceGen(t *testing.T) { ...@@ -154,5 +175,22 @@ func TestGoTraceGen(t *testing.T) {
if diff != "" { if diff != "" {
t.Errorf("%v: gold & work differ:\n%s", tpkg, diff) t.Errorf("%v: gold & work differ:\n%s", tpkg, diff)
} }
// verify `gotrace list`
var tlistBuf bytes.Buffer
err = tracelist(&tlistBuf, tpkg, tBuildCtx, "" /* = local imports disabled */)
if err != nil {
t.Fatalf("%v: %v", tpkg, err)
}
tlistOk, err := ioutil.ReadFile(work + "/src/" + tpkg + "/tracelist.txt")
if err != nil {
t.Fatalf("%v: %v", tpkg, err)
}
tlist := tlistBuf.Bytes()
if !bytes.Equal(tlist, tlistOk) {
t.Errorf("%v: tracelist differ:\nhave:\n%s\nwant:\n%s", tpkg, tlist, tlistOk)
}
} }
} }
a/pkg1:traceDoSomething
a/pkg1:traceNewT
a/pkg1:traceNewTPre
a/pkg1:traceURLParsed
...@@ -32,7 +32,7 @@ type Buffer struct { ...@@ -32,7 +32,7 @@ type Buffer struct {
} }
func (b *Buffer) emit(format string, argv ...interface{}) { func (b *Buffer) emit(format string, argv ...interface{}) {
fmt.Fprintf(b, format + "\n", argv...) fmt.Fprintf(b, format+"\n", argv...)
} }
......
...@@ -27,12 +27,15 @@ import "unsafe" ...@@ -27,12 +27,15 @@ import "unsafe"
// symbols are e.g. in go/src/runtime/race/race_linux_amd64.syso // symbols are e.g. in go/src/runtime/race/race_linux_amd64.syso
#cgo LDFLAGS: -Wl,--unresolved-symbols=ignore-in-object-files #cgo LDFLAGS: -Wl,--unresolved-symbols=ignore-in-object-files
// __tsan::ThreadIgnoreBegin(__tsan::ThreadState*, unsigned long)
// __tsan::ThreadIgnoreEnd(__tsan::ThreadState*, unsigned long)
extern void _ZN6__tsan17ThreadIgnoreBeginEPNS_11ThreadStateEm(void *, unsigned long); extern void _ZN6__tsan17ThreadIgnoreBeginEPNS_11ThreadStateEm(void *, unsigned long);
extern void _ZN6__tsan15ThreadIgnoreEndEPNS_11ThreadStateEm(void *, unsigned long); extern void _ZN6__tsan15ThreadIgnoreEndEPNS_11ThreadStateEm(void *, unsigned long);
*/ */
import "C" import "C"
// NOTE runtime.RaceDisable disables only "sync" part, not "read/write" // Ways to tell race-detector to ignore "read/write" events from current thread.
// NOTE runtime.RaceDisable disables only "sync" part, not "read/write".
func IgnoreBegin(racectx uintptr) { func IgnoreBegin(racectx uintptr) {
C._ZN6__tsan17ThreadIgnoreBeginEPNS_11ThreadStateEm(unsafe.Pointer(racectx), 0) C._ZN6__tsan17ThreadIgnoreBeginEPNS_11ThreadStateEm(unsafe.Pointer(racectx), 0)
......
...@@ -23,5 +23,5 @@ package race ...@@ -23,5 +23,5 @@ package race
// race ignore begin/end stubs // race ignore begin/end stubs
func IgnoreBegin(racectx uintptr) {} func IgnoreBegin(racectx uintptr) {}
func IgnoreEnd(racectx uintptr) {} func IgnoreEnd(racectx uintptr) {}
...@@ -10,7 +10,7 @@ govern= # e.g. 109 for go1.9 ...@@ -10,7 +10,7 @@ govern= # e.g. 109 for go1.9
# goset <goexec> - set <goexec> as current go # goset <goexec> - set <goexec> as current go
goset() { goset() {
goexec=$1 goexec=$1
# go1.1 go1.2 go1.3 go1.4 go1.5 go1.6 go1.7 go1.8 go1.9 go1.10 -> go1.10` # go1.1 go1.2 go1.3 go1.4 go1.5 go1.6 go1.7 go1.8 go1.9 go1.10 -> go1.10
gover=`$goexec list -f '{{ range context.ReleaseTags }} {{ .}}{{end}}' runtime |awk '{print $NF}'` gover=`$goexec list -f '{{ range context.ReleaseTags }} {{ .}}{{end}}' runtime |awk '{print $NF}'`
IFS=. read gomaj gomin < <(echo "$gover") IFS=. read gomaj gomin < <(echo "$gover")
govern=$((${gomaj#go} * 100 + $gomin)) govern=$((${gomaj#go} * 100 + $gomin))
......
...@@ -23,5 +23,5 @@ package xruntime ...@@ -23,5 +23,5 @@ package xruntime
// empty stubs for Race*() // empty stubs for Race*()
func RaceIgnoreBegin() {} func RaceIgnoreBegin() {}
func RaceIgnoreEnd() {} func RaceIgnoreEnd() {}
...@@ -18,12 +18,11 @@ ...@@ -18,12 +18,11 @@
// See https://www.nexedi.com/licensing for rationale and options. // See https://www.nexedi.com/licensing for rationale and options.
package xruntime package xruntime
// stop-the-world that should probably be in xruntime, but I'm (yet) hesitating // stop-the-world that should probably be in public xruntime, but I'm (yet)
// to expose the API to public. // hesitating to expose the API to public.
import _ "unsafe" import _ "unsafe"
//go:linkname runtime_stopTheWorld runtime.stopTheWorld //go:linkname runtime_stopTheWorld runtime.stopTheWorld
//go:linkname runtime_startTheWorld runtime.startTheWorld //go:linkname runtime_startTheWorld runtime.startTheWorld
...@@ -41,7 +40,7 @@ func StopTheWorld(reason string) { ...@@ -41,7 +40,7 @@ func StopTheWorld(reason string) {
runtime_stopTheWorld(reason) runtime_stopTheWorld(reason)
} }
// StartTheWorld restarts the world after it was stopped by StopTheWorld // StartTheWorld restarts the world after it was stopped by StopTheWorld.
func StartTheWorld() { func StartTheWorld() {
runtime_startTheWorld() runtime_startTheWorld()
} }
...@@ -21,5 +21,5 @@ package xruntime ...@@ -21,5 +21,5 @@ package xruntime
//go:generate ./g_typedef //go:generate ./g_typedef
// getg returns pointer to current goroutine descriptor // getg returns pointer to current goroutine descriptor.
func getg() *g func getg() *g
...@@ -106,9 +106,9 @@ To get better understanding of what happens when it is possible to record ...@@ -106,9 +106,9 @@ To get better understanding of what happens when it is possible to record
events into a stream and later either visualize or postprocess them. events into a stream and later either visualize or postprocess them.
This is similar to how Go execution tracer works: This is similar to how Go execution tracer works:
https://golang.org/s/go15trace https://golang.org/s/go15trace
https://golang.org/pkg/runtime/trace https://golang.org/pkg/runtime/trace
https://golang.org/cmd/trace https://golang.org/cmd/trace
though there it records only predefined set of events related to Go runtime. though there it records only predefined set of events related to Go runtime.
...@@ -146,7 +146,7 @@ a set of goroutines in tested code in question ...@@ -146,7 +146,7 @@ a set of goroutines in tested code in question
- produce events in correct order, and - produce events in correct order, and
- at every event associated internal state is correct. - at every event associated internal state is correct.
TODO example TODO example.
Cross package tracing Cross package tracing
...@@ -291,7 +291,7 @@ func AttachProbe(pg *ProbeGroup, listp **Probe, probe *Probe) { ...@@ -291,7 +291,7 @@ func AttachProbe(pg *ProbeGroup, listp **Probe, probe *Probe) {
// Detach detaches probe from a tracepoint. // Detach detaches probe from a tracepoint.
// //
// Must be called under Lock // Must be called under Lock.
func (p *Probe) Detach() { func (p *Probe) Detach() {
verifyLocked() verifyLocked()
...@@ -326,7 +326,7 @@ type ProbeGroup struct { ...@@ -326,7 +326,7 @@ type ProbeGroup struct {
// Add adds a probe to the group. // Add adds a probe to the group.
// //
// Must be called under Lock // Must be called under Lock.
func (pg *ProbeGroup) Add(p *Probe) { func (pg *ProbeGroup) Add(p *Probe) {
verifyLocked() verifyLocked()
pg.probev = append(pg.probev, p) pg.probev = append(pg.probev, p)
...@@ -334,7 +334,7 @@ func (pg *ProbeGroup) Add(p *Probe) { ...@@ -334,7 +334,7 @@ func (pg *ProbeGroup) Add(p *Probe) {
// Done detaches all probes registered to the group. // Done detaches all probes registered to the group.
// //
// Must be called under normal conditions, not under Lock // Must be called under normal conditions, not under Lock.
func (pg *ProbeGroup) Done() { func (pg *ProbeGroup) Done() {
verifyUnlocked() verifyUnlocked()
Lock() Lock()
......
...@@ -30,7 +30,7 @@ import ( ...@@ -30,7 +30,7 @@ import (
) )
func TestAttachDetach(t *testing.T) { func TestAttachDetach(t *testing.T) {
var traceX *Probe // list head of a tracing event var traceX *Probe // list head of a tracing event
// check that traceX probe list has such and such content and also that .prev // check that traceX probe list has such and such content and also that .prev
// pointers in all elements are right // pointers in all elements are right
...@@ -102,7 +102,7 @@ func TestAttachDetach(t *testing.T) { ...@@ -102,7 +102,7 @@ func TestAttachDetach(t *testing.T) {
// should be ok, but since race detector does not know we stopped the world it // should be ok, but since race detector does not know we stopped the world it
// could complain. // could complain.
func TestUseDetach(t *testing.T) { func TestUseDetach(t *testing.T) {
var traceX *Probe // list head of a tracing event var traceX *Probe // list head of a tracing event
// attach probe to traceX // attach probe to traceX
probe := Probe{} probe := Probe{}
...@@ -114,7 +114,7 @@ func TestUseDetach(t *testing.T) { ...@@ -114,7 +114,7 @@ func TestUseDetach(t *testing.T) {
go func() { go func() {
// delay a bit so that main goroutine first spins some time // delay a bit so that main goroutine first spins some time
// with non-empty probe list // with non-empty probe list
time.Sleep(1*time.Millisecond) time.Sleep(1 * time.Millisecond)
Lock() Lock()
probe.Detach() probe.Detach()
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment