Commit 32038ac4 authored by Kirill Smelkov's avatar Kirill Smelkov

.

parent f3e8a1fd
...@@ -41,26 +41,22 @@ import ( ...@@ -41,26 +41,22 @@ import (
"golang.org/x/tools/go/loader" "golang.org/x/tools/go/loader"
) )
// traceEvent represents 1 trace:event definition // traceEvent represents 1 trace:event directive
// the definition is constructed on the fly via converting e.g.
//
// //trace:event traceConnRecv(c *Conn, msg Msg)
//
// into
//
// func traceConnRecv(c *Conn, msg Msg)
//
// the func declaration is not added anywhere in the sources - just its AST is
// constructed. XXX + types
type traceEvent struct { type traceEvent struct {
//Pkg loader.PackageInfo // XXX or loader.PackageInfo.Pkg (*types.Package) ? // TODO += Pos token.Position
//Pos token.Position
//Text string
//Name string
//Argv string
// TODO += Pos
Pkgi *loader.PackageInfo Pkgi *loader.PackageInfo
// declaration of function to signal the event
// the declaration is constructed on the fly via converting e.g.
//
// //trace:event traceConnRecv(c *Conn, msg Msg)
//
// into
//
// func traceConnRecv(c *Conn, msg Msg)
//
// the func declaration is not added anywhere in the sources - just its AST is
// constructed. XXX + types
*ast.FuncDecl *ast.FuncDecl
} }
...@@ -70,38 +66,13 @@ type traceImport struct { ...@@ -70,38 +66,13 @@ type traceImport struct {
PkgPath string PkgPath string
} }
// TypedArgv returns argument list with types // Package represents tracing-related information about a package
func (te *traceEvent) TypedArgv() string { type Package struct {
//format.Node(&buf, fset, te.FuncDecl.Type.Params) PkgPath string
argv := []string{} Eventv []*traceEvent // trace events this package defines
Importv []*traceImport // packages this package trace imports
for _, field := range te.FuncDecl.Type.Params.List {
namev := []string{}
for _, name := range field.Names {
namev = append(namev, name.Name)
}
arg := strings.Join(namev, ", ")
arg += " " + types.ExprString(field.Type)
argv = append(argv, arg)
}
return strings.Join(argv, ", ")
} }
// Argv returns comma-separated argument-list
func (te *traceEvent) Argv() string {
argv := []string{}
for _, field := range te.FuncDecl.Type.Params.List {
for _, name := range field.Names {
argv = append(argv, name.Name)
}
}
return strings.Join(argv, ", ")
}
// byEventName provides []*traceEvent ordering by event name // byEventName provides []*traceEvent ordering by event name
type byEventName []*traceEvent type byEventName []*traceEvent
...@@ -115,52 +86,6 @@ func (v byPkgPath) Less(i, j int) bool { return v[i].PkgPath < v[j].PkgPath } ...@@ -115,52 +86,6 @@ func (v byPkgPath) Less(i, j int) bool { return v[i].PkgPath < v[j].PkgPath }
func (v byPkgPath) Swap(i, j int) { v[i], v[j] = v[j], v[i] } func (v byPkgPath) Swap(i, j int) { v[i], v[j] = v[j], v[i] }
func (v byPkgPath) Len() int { return len(v) } func (v byPkgPath) Len() int { return len(v) }
// traceEventCodeTmpl is code template generated for one trace event
var traceEventCodeTmpl = template.Must(template.New("traceevent").Parse(`
// traceevent: {{.Name}}({{.TypedArgv}}) XXX better raw .Text (e.g. comments)
{{/* probe type for this trace event */ -}}
type _t_{{.Name}} struct {
tracing.Probe
probefunc func({{.TypedArgv}})
}
{{/* list of probes attached (nil if nothing) */ -}}
var _{{.Name}} *_t_{{.Name}}
{{/* function which event producer calls to notify about the event
*
* after https://github.com/golang/go/issues/19348 is done this separate
* checking function will be inlined and tracepoint won't cost a function
* call when it is disabled */ -}}
func {{.Name}}({{.TypedArgv}}) {
if _{{.Name}} != nil {
_{{.Name}}_run({{.Argv}})
}
}
{{/* function to notify attached probes */ -}}
func _{{.Name}}_run({{.Argv}}) {
for p := _{{.Name}}; p != nil; p = (*_t_{{.Name}})(unsafe.Pointer(p.Next())) {
p.probefunc({{.Argv}})
}
}
{{/* function to attach a probe to tracepoint */ -}}
func {{.Name}}_Attach(pg *tracing.ProbeGroup, probe func({{.TypedArgv}})) *tracing.Probe {
p := _t_{{.Name}}{probefunc: probe}
tracing.AttachProbe(pg, (**tracing.Probe)(unsafe.Pointer(&_{{.Name}}), &p.Probe)
return &p.Probe
}
`))
// traceEventImportTmpl is code template generated for importing one trace event
// FIXME func args typs must be qualified
var traceEventImportTmpl = template.Must(template.New("traceimport").Parse(`
//go:linkname {{.Pkgi.Pkg.Name}}_{{.Name}}_Attach {{.Pkgi.Pkg.Path}}.{{.Name}}_Attach
func {{.Pkgi.Pkg.Name}}_{{.Name}}_Attach(*tracing.ProbeGroup, func({{.TypedArgv}})) *tracing.Probe
`))
// parseTraceEvent parses trace event definition into traceEvent // parseTraceEvent parses trace event definition into traceEvent
// text is text argument after "//trace:event " // text is text argument after "//trace:event "
func parseTraceEvent(pkgi *loader.PackageInfo, text string) (*traceEvent, error) { func parseTraceEvent(pkgi *loader.PackageInfo, text string) (*traceEvent, error) {
...@@ -193,13 +118,6 @@ func parseTraceEvent(pkgi *loader.PackageInfo, text string) (*traceEvent, error) ...@@ -193,13 +118,6 @@ func parseTraceEvent(pkgi *loader.PackageInfo, text string) (*traceEvent, error)
return &traceEvent{pkgi, declf}, nil return &traceEvent{pkgi, declf}, nil
} }
// Package represents tracing-related information about a package
type Package struct {
PkgPath string
Eventv []*traceEvent // trace events this package defines
Importv []*traceImport // packages (pkgpath) this package trace imports
}
// packageTrace returns tracing information about a package // packageTrace returns tracing information about a package
func packageTrace(lprog *loader.Program, pkgi *loader.PackageInfo) *Package { func packageTrace(lprog *loader.Program, pkgi *loader.PackageInfo) *Package {
eventv := []*traceEvent{} eventv := []*traceEvent{}
...@@ -258,11 +176,103 @@ func packageTrace(lprog *loader.Program, pkgi *loader.PackageInfo) *Package { ...@@ -258,11 +176,103 @@ func packageTrace(lprog *loader.Program, pkgi *loader.PackageInfo) *Package {
return &Package{PkgPath: pkgi.Pkg.Path(), Eventv: eventv, Importv: importv} return &Package{PkgPath: pkgi.Pkg.Path(), Eventv: eventv, Importv: importv}
} }
// ----------------------------------------
// TypedArgv returns argument list with types
func (te *traceEvent) TypedArgv() string {
//format.Node(&buf, fset, te.FuncDecl.Type.Params)
argv := []string{}
for _, field := range te.FuncDecl.Type.Params.List {
namev := []string{}
for _, name := range field.Names {
namev = append(namev, name.Name)
}
arg := strings.Join(namev, ", ")
arg += " " + types.ExprString(field.Type)
argv = append(argv, arg)
}
return strings.Join(argv, ", ")
}
// Argv returns comma-separated argument-list
func (te *traceEvent) Argv() string {
argv := []string{}
for _, field := range te.FuncDecl.Type.Params.List {
for _, name := range field.Names {
argv = append(argv, name.Name)
}
}
return strings.Join(argv, ", ")
}
// traceEventCodeTmpl is code template generated for one trace event
var traceEventCodeTmpl = template.Must(template.New("traceevent").Parse(`
// traceevent: {{.Name}}({{.TypedArgv}}) XXX better raw .Text (e.g. comments)
{{/* probe type for this trace event */ -}}
type _t_{{.Name}} struct {
tracing.Probe
probefunc func({{.TypedArgv}})
}
{{/* list of probes attached (nil if nothing) */ -}}
var _{{.Name}} *_t_{{.Name}}
{{/* function which event producer calls to notify about the event
*
* after https://github.com/golang/go/issues/19348 is done this separate
* checking function will be inlined and tracepoint won't cost a function
* call when it is disabled */ -}}
func {{.Name}}({{.TypedArgv}}) {
if _{{.Name}} != nil {
_{{.Name}}_run({{.Argv}})
}
}
{{/* function to notify attached probes */ -}}
func _{{.Name}}_run({{.Argv}}) {
for p := _{{.Name}}; p != nil; p = (*_t_{{.Name}})(unsafe.Pointer(p.Next())) {
p.probefunc({{.Argv}})
}
}
{{/* function to attach a probe to tracepoint */ -}}
func {{.Name}}_Attach(pg *tracing.ProbeGroup, probe func({{.TypedArgv}})) *tracing.Probe {
p := _t_{{.Name}}{probefunc: probe}
tracing.AttachProbe(pg, (**tracing.Probe)(unsafe.Pointer(&_{{.Name}}), &p.Probe)
return &p.Probe
}
`))
// traceEventImportTmpl is code template generated for importing one trace event
// FIXME func args types must be qualified
var traceEventImportTmpl = template.Must(template.New("traceimport").Parse(`
//go:linkname {{.Pkgi.Pkg.Name}}_{{.Name}}_Attach {{.Pkgi.Pkg.Path}}.{{.Name}}_Attach
func {{.Pkgi.Pkg.Name}}_{{.Name}}_Attach(*tracing.ProbeGroup, func({{.TypedArgv}})) *tracing.Probe
`))
// XXX go123 in magic
const magic = "// Code generated by lab.nexedi.com/kirr/go123/tracing/cmd/gotrace; DO NOT EDIT.\n"
struct Buffer {
bytes.Buffer
}
func (b *Buffer) emit(format string, argv ...interface{}) {
fmt.Fprintf(b, format + "\n", ...argv)
}
// tracegen generates code according to tracing directives in a package @ pkgpath // tracegen generates code according to tracing directives in a package @ pkgpath
func tracegen(pkgpath string) error { func tracegen(pkgpath string) error {
// XXX typechecking is much slower than parsing + we don't need to // XXX typechecking is much slower than parsing + we don't need to
// load anything except the package in question // load anything except the package in question
// TODO -> use just AST parsing for loading // TODO -> use just AST parsing for loading?
conf := loader.Config{ conf := loader.Config{
ParserMode: parser.ParseComments, ParserMode: parser.ParseComments,
TypeCheckFuncBodies: func(path string) bool { return false }, TypeCheckFuncBodies: func(path string) bool { return false },
...@@ -275,11 +285,19 @@ func tracegen(pkgpath string) error { ...@@ -275,11 +285,19 @@ func tracegen(pkgpath string) error {
log.Fatal(err) log.Fatal(err)
} }
// tracing info for this specified package
pkgi := lprog.InitialPackages()[0] pkgi := lprog.InitialPackages()[0]
//fmt.Println(pkgi)
pkg := packageTrace(lprog, pkgi) pkg := packageTrace(lprog, pkgi)
buf := &bytes.Buffer{}
// prologue
buf.Write(magic)
buf.emit("\npackage %v", pkg.Pkg.Name)
buf.emit("\nimport (")
buf.emit("\t\tlab.nexedi.com/kirr/neo/go/xcommon/tracing")
// generate code for trace:event definitions // generate code for trace:event definitions
for _, event := range pkg.Eventv { for _, event := range pkg.Eventv {
err = traceEventCodeTmpl.Execute(os.Stdout, event) err = traceEventCodeTmpl.Execute(os.Stdout, event)
......
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