Commit 8c5eab16 authored by Kirill Smelkov's avatar Kirill Smelkov

.

parent 5de3f3b9
......@@ -734,6 +734,9 @@ func (c *Conn) err(op string, e error) error {
// ---- exchange of messages ----
//trace:event traceConnRecv(c *Conn, msg Msg)
//trace:event traceConnSend(c *Conn, msg Msg) // XXX -> traceConnSendPre ?
// Recv receives message
// it receives packet and decodes message from it
func (c *Conn) Recv() (Msg, error) {
......
......@@ -24,15 +24,6 @@ import (
"lab.nexedi.com/kirr/neo/go/xcommon/tracing"
)
// XXX put under 'build +tracedef'
//trace:event
// func traceConnRecv(c *Conn, msg Msg)
// func traceConnSend(c *Conn, msg Msg) // XXX -> traceConnSendPre ?
// TODO autogenerate vvv from ^^^
// XXX after https://github.com/golang/go/issues/19348 won't cost a function
// call when tracepoint is disabled
......
......@@ -29,14 +29,77 @@ import (
"flag"
"fmt"
"go/parser"
"go/token"
"log"
"os"
"sort"
"strings"
"text/template"
"golang.org/x/tools/go/loader"
)
// traceEvent represents 1 trace:event definition
type traceEvent struct {
Pkg loader.PackageInfo // XXX or loader.PackageInfo.Pkg (*types.Package) ?
Pos token.Position
Text string
Name string
Argv string
}
// byEventName provides []traceEvent ordering by event name
type byEventName []traceEvent
func (v byEventName) Less(i, j int) bool { return v[i].Text < v[j].Text }
func (v byEventName) Swap(i, j int) { v[i], v[j] = v[j], v[i] }
func (v byEventName) Len() int { return len(v) }
// traceEventCode is code template for one trace event
const traceEventCode = `
// traceevent: {{.Text}} XXX .Text -> .Name.Signature
XXX .Signature -> .Argvdef
type _t_{{.Name}} struct {
tracing.Probe
probefunc func{{.Argv}}
}
var _{{.Name}} *_t_{{.Name}}
{{/* 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}}{{.Argv}} {
if _{{.Name}} != nil {
_{{.Name}}_run(...) // XXX argv without types here
}
}
func _{{.Name}}{{.Argv}}_run({{.Argv}}) {
for p := _{{.Name}}; p != nil; p = (*_t_{{.Name}})(unsafe.Pointer(p.Next())) {
p.probefunc(...) // XXX argv without types here
}
}
// XXX ... is only types from argv
func {{.Name}}_Attach(pg *tracing.ProbeGroup, probe func(...)) *tracing.Probe {
p := _t_{{.Name}}{probefunc: probe}
tracing.AttachProbe(pg, (**tracing.Probe)(unsafe.Pointer(&_{{.Name}}), &p.Probe)
return &p.Probe
}
`
var traceEventCodeTmpl = template.Must(template.New("traceevent").Parse(traceEventCode))
// tracegen generates code according to tracing directives in a package @ pkgpath
func tracegen(pkgpath string) error {
conf := loader.Config{ParserMode: parser.ParseComments}
// XXX typechecking is much slower than parsing + we don't need to
// load anything except the package in question
// TODO -> use just AST parsing for loading
conf := loader.Config{
ParserMode: parser.ParseComments,
TypeCheckFuncBodies: func(path string) bool { return false },
}
conf.Import(pkgpath)
// load package + all its imports
......@@ -45,15 +108,65 @@ func tracegen(pkgpath string) error {
log.Fatal(err)
}
pkg := lprog.InitialPackages()[0]
//fmt.Println(pkg)
eventv := []traceEvent{} // events this package defines
importv := map[/*pkgpath*/string][]traceEvent{} // events this package imports
// go through files of the package and process //trace: directives
for _, file := range lprog.Package(pkgpath).Files {
for _, commgroup := range file.Comments {
for _, comment := range commgroup.List {
fmt.Println(comment) // .Slash .Text
for _, file := range pkg.Files { // ast.File
for _, commgroup := range file.Comments { // ast.CommentGroup
for _, comment := range commgroup.List {// ast.Comment
pos := lprog.Fset.Position(comment.Slash)
//fmt.Printf("%v %q\n", pos, comment.Text)
// only directives starting from beginning of line
if pos.Column != 1 {
continue
}
if !strings.HasPrefix(comment.Text, "//trace:") {
continue
}
textv := strings.SplitN(comment.Text, " ", 2)
if len(textv) != 2 {
log.Fatalf("%v: invalid directive format")
}
directive, arg := textv[0], textv[1]
switch directive {
case "//trace:event":
if !strings.HasPrefix(arg, "trace") {
log.Fatalf("%v: trace event must start with \"trace\"", pos)
}
event := traceEvent{Pos: pos, Text: arg, Name: "name", Argv: "argv"} // XXX
eventv = append(eventv, event)
case "//trace:import":
panic("TODO")
// TODO arg is pkgpath - get trace events from tha
default:
log.Fatalf("%v: unknown tracing directive %q", pos, directive)
}
}
}
}
// generate code for trace:event definitions
sort.Sort(byEventName(eventv))
for _, event := range eventv {
err = traceEventCodeTmpl.Execute(os.Stdout, event)
if err != nil {
panic(err)
}
}
// generate code for trace:import imports
_ = importv
return nil // XXX
}
......
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