Commit 92e8e1e0 authored by Kirill Smelkov's avatar Kirill Smelkov

.

parent 789c2941
...@@ -31,6 +31,7 @@ import ( ...@@ -31,6 +31,7 @@ import (
"go/ast" "go/ast"
"go/parser" "go/parser"
"go/token" "go/token"
"go/types"
"log" "log"
"os" "os"
"sort" "sort"
...@@ -41,34 +42,53 @@ import ( ...@@ -41,34 +42,53 @@ import (
) )
// traceEvent represents 1 trace:event definition // traceEvent represents 1 trace:event definition
// 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) ? //Pkg loader.PackageInfo // XXX or loader.PackageInfo.Pkg (*types.Package) ?
//Pos token.Position //Pos token.Position
//Text string //Text string
//Name string //Name string
//Argv string //Argv string
*ast.FuncDecl *ast.FuncDecl
} }
// TypedArgv returns argument list with types // TypedArgv returns argument list with types
func (te *traceEvent) TypedArgv() string { func (te *traceEvent) TypedArgv() string {
//format.Node(&buf, fset, te.FuncDecl.Params) //format.Node(&buf, fset, te.FuncDecl.Type.Params)
argv := []string{}
for _, field := range te.FuncDecl.Params.List { for _, field := range te.FuncDecl.Type.Params.List {
namev := []string{} namev := []string{}
for _, name := range field.Names { for _, name := range field.Names {
namev = append(namev, name) 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 // Argv returns comma-separated argument-list
func (te *traceEvent) Argv() string { func (te *traceEvent) Argv() string {
argv := []string{} argv := []string{}
for _, field := range te.FuncDecl.Params.List { for _, field := range te.FuncDecl.Type.Params.List {
for _, name := range field.Names { for _, name := range field.Names {
argv = append(argv, name) argv = append(argv, name.Name)
} }
} }
...@@ -77,39 +97,43 @@ func (te *traceEvent) Argv() string { ...@@ -77,39 +97,43 @@ func (te *traceEvent) Argv() string {
// byEventName provides []traceEvent ordering by event name // byEventName provides []traceEvent ordering by event name
type byEventName []*traceEvent type byEventName []*traceEvent
//func (v byEventName) Less(i, j int) bool { return v[i].Text < v[j].Text }
func (v byEventName) Less(i, j int) bool { return v[i].Name.Name < v[j].Name.Name } func (v byEventName) Less(i, j int) bool { return v[i].Name.Name < v[j].Name.Name }
func (v byEventName) Swap(i, j int) { v[i], v[j] = v[j], v[i] } func (v byEventName) Swap(i, j int) { v[i], v[j] = v[j], v[i] }
func (v byEventName) Len() int { return len(v) } func (v byEventName) Len() int { return len(v) }
// traceEventCode is code template for one trace event // traceEventCode is code template generated for one trace event
const traceEventCode = ` const traceEventCode = `
// traceevent: {{.Name}}({{.Type.Params}}) XXX or better raw .Text (e.g. comments) // traceevent: {{.Name}}({{.TypedArgv}}) XXX better raw .Text (e.g. comments)
{{/* probe type for this trace event */}}
type _t_{{.Name}} struct { type _t_{{.Name}} struct {
tracing.Probe tracing.Probe
probefunc func{{.Type.Params}} probefunc func({{.TypedArgv}})
} }
{{/* list of probes attached (nil if nothing) */}}
var _{{.Name}} *_t_{{.Name}} var _{{.Name}} *_t_{{.Name}}
{{/* after https://github.com/golang/go/issues/19348 is done this separate {{/* 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 * checking function will be inlined and tracepoint won't cost a function
* call when it is disabled */}} * call when it is disabled */}}
func {{.Name}}{{.Type.Params}} { func {{.Name}}({{.TypedArgv}}) {
if _{{.Name}} != nil { if _{{.Name}} != nil {
_{{.Name}}_run({{.Type.Params}}) // XXX argv without types here _{{.Name}}_run({{.Argv}})
} }
} }
{{/* function to notify attached probes */}}
func _{{.Name}}{{.Argv}}_run({{.Argv}}) { func _{{.Name}}{{.Argv}}_run({{.Argv}}) {
for p := _{{.Name}}; p != nil; p = (*_t_{{.Name}})(unsafe.Pointer(p.Next())) { for p := _{{.Name}}; p != nil; p = (*_t_{{.Name}})(unsafe.Pointer(p.Next())) {
p.probefunc({{.Type.Params}}) // XXX argv without types here p.probefunc({{.Argv}})
} }
} }
// XXX ... is only types from argv {{/* function to attach a probe to tracepoint */}}
func {{.Name}}_Attach(pg *tracing.ProbeGroup, probe func({{.Type.Params}})) *tracing.Probe { func {{.Name}}_Attach(pg *tracing.ProbeGroup, probe func({{.TypedArgv}})) *tracing.Probe {
p := _t_{{.Name}}{probefunc: probe} p := _t_{{.Name}}{probefunc: probe}
tracing.AttachProbe(pg, (**tracing.Probe)(unsafe.Pointer(&_{{.Name}}), &p.Probe) tracing.AttachProbe(pg, (**tracing.Probe)(unsafe.Pointer(&_{{.Name}}), &p.Probe)
return &p.Probe return &p.Probe
...@@ -118,14 +142,14 @@ func {{.Name}}_Attach(pg *tracing.ProbeGroup, probe func({{.Type.Params}})) *tra ...@@ -118,14 +142,14 @@ func {{.Name}}_Attach(pg *tracing.ProbeGroup, probe func({{.Type.Params}})) *tra
var traceEventCodeTmpl = template.Must(template.New("traceevent").Parse(traceEventCode)) var traceEventCodeTmpl = template.Must(template.New("traceevent").Parse(traceEventCode))
// parseTraceEvent parses trace event definition into XXX // parseTraceEvent parses trace event definition into traceEvent
// text is text argument after "//trace:event " // text is text argument after "//trace:event "
func parseTraceEvent(text string) (*traceEvent, error) { func parseTraceEvent(text string) (*traceEvent, error) {
if !strings.HasPrefix(text, "trace") { if !strings.HasPrefix(text, "trace") {
return nil, fmt.Errorf("trace event must start with \"trace\"") // XXXpos return nil, fmt.Errorf("trace event must start with \"trace\"") // XXX pos
} }
// trace trace event definition as func declaration // trace event definition as func declaration
text = "package xxx\nfunc " + text // XXX text = "package xxx\nfunc " + text // XXX
fset := token.NewFileSet() // XXX fset := token.NewFileSet() // XXX
filename := "tracefunc.go" // XXX filename := "tracefunc.go" // XXX
...@@ -142,6 +166,7 @@ func parseTraceEvent(text string) (*traceEvent, error) { ...@@ -142,6 +166,7 @@ func parseTraceEvent(text string) (*traceEvent, error) {
if !ok { if !ok {
return nil, fmt.Errorf("trace event must be func-like, not %v", f.Decls[0]) return nil, fmt.Errorf("trace event must be func-like, not %v", f.Decls[0])
} }
// XXX ok to allow methods (declf.Recv != nil) ?
if declf.Type.Results != nil { if declf.Type.Results != nil {
return nil, fmt.Errorf("trace event must not return results") return nil, fmt.Errorf("trace event must not return results")
} }
...@@ -169,13 +194,13 @@ func tracegen(pkgpath string) error { ...@@ -169,13 +194,13 @@ func tracegen(pkgpath string) error {
pkg := lprog.InitialPackages()[0] pkg := lprog.InitialPackages()[0]
//fmt.Println(pkg) //fmt.Println(pkg)
eventv := []*traceEvent{} // events this package defines eventv := []*traceEvent{} // events this package defines
importv := map[/*pkgpath*/string][]traceEvent{} // events this package imports importv := map[/*pkgpath*/string][]traceEvent{} // events this package imports
// go through files of the package and process //trace: directives // go through files of the package and process //trace: directives
for _, file := range pkg.Files { // ast.File for _, file := range pkg.Files { // ast.File
for _, commgroup := range file.Comments { // ast.CommentGroup for _, commgroup := range file.Comments { // ast.CommentGroup
for _, comment := range commgroup.List {// ast.Comment for _, comment := range commgroup.List { // ast.Comment
pos := lprog.Fset.Position(comment.Slash) pos := lprog.Fset.Position(comment.Slash)
//fmt.Printf("%v %q\n", pos, comment.Text) //fmt.Printf("%v %q\n", pos, comment.Text)
......
...@@ -15,8 +15,7 @@ ...@@ -15,8 +15,7 @@
// //
// See COPYING file for full licensing terms. // See COPYING file for full licensing terms.
// Package tracing provides runtime support for Go tracing facilities // Package tracing provides runtime and usage support for Go tracing facilities
// XXX ^^^ += "and usage" ?
// TODO describe how to define tracepoints // TODO describe how to define tracepoints
// TODO doc: // TODO doc:
// - tracepoints // - tracepoints
......
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