Skip to content

Commit

Permalink
Fix display bug for InitPlan nodes
Browse files Browse the repository at this point in the history
  • Loading branch information
Marcus Gartner committed Oct 23, 2019
1 parent ac59a96 commit de2cedf
Show file tree
Hide file tree
Showing 5 changed files with 106 additions and 29 deletions.
39 changes: 32 additions & 7 deletions pkg/flame/flame.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,41 +10,65 @@ import (
type Flame struct {
Name string `json:"name"`
Value float64 `json:"value"`
Time float64 `json:"time"`
Detail string `json:"detail"`
Color string `json:"color"`
InitPlan bool
Children []Flame `json:"children"`
}

const PLAN_COLOR = "#00C05A"
const INIT_COLOR = "#C0C0C0"

func New(p plan.Plan) Flame {
// TODO handle CTE InitPlan
planningFlame := Flame{
Name: "Query Planning",
Value: p.PlanningTime,
Time: p.PlanningTime,
Detail: "Time to generate the query plan",
Color: "#00C05A",
Color: PLAN_COLOR,
}

executionFlame := convert(p.ExecutionTree)
executionFlame := convert(p.ExecutionTree, "")

return Flame{
Name: "Total",
Value: planningFlame.Value + executionFlame.Value,
Time: planningFlame.Time + executionFlame.Time,
Detail: "This node includes planning and execution time",
Children: []Flame{planningFlame, executionFlame},
}
}

func convert(n plan.Node) Flame {
var subFlames []Flame
func convert(n plan.Node, color string) Flame {
initPlan := n.ParentRelationship == "InitPlan"
value := n.TotalTime

if initPlan {
color = INIT_COLOR
}

var subFlames []Flame
for _, subOp := range n.Children {
subFlames = append(subFlames, convert(subOp))

// Pass the color forward for grey InitPlan trees
f := convert(subOp, color)

// Add to the total value if the child is an InitPlan node
if f.InitPlan {
value += f.Value
}

subFlames = append(subFlames, f)
}

return Flame{
Name: name(n),
Value: n.TotalTime,
Value: value,
Time: n.TotalTime,
Detail: detail(n),
Color: color,
InitPlan: initPlan,
Children: subFlames,
}
}
Expand All @@ -67,6 +91,7 @@ func detail(n plan.Node) string {

rowTemplate := "<tr><th>%s</th><td>%v</td></tr>"

fmt.Fprintf(&b, rowTemplate, "Parent Relationship", n.ParentRelationship)
fmt.Fprintf(&b, rowTemplate, "Filter", n.Filter)
fmt.Fprintf(&b, rowTemplate, "Join Filter", n.JoinFilter)
fmt.Fprintf(&b, rowTemplate, "Hash Cond", n.HashCond)
Expand Down
62 changes: 56 additions & 6 deletions pkg/flame/flame_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,15 +30,63 @@ func TestNew(t *testing.T) {

assert.Equal(t, "Total", f.Name)
assert.Equal(t, 0.133, f.Value)
assert.Equal(t, 0.133, f.Time)

assert.Equal(t, "Query Planning", f.Children[0].Name)
assert.Equal(t, PLAN_COLOR, f.Children[0].Color)
assert.Equal(t, 0.01, f.Children[0].Value)
assert.Equal(t, 0.01, f.Children[0].Time)

assert.Equal(t, "Limit", f.Children[1].Name)
assert.Equal(t, 0.123, f.Children[1].Value)
assert.Equal(t, 0.123, f.Children[1].Time)

assert.Equal(t, "Seq Scan on bears", f.Children[1].Children[0].Name)
assert.Equal(t, 0.022, f.Children[1].Children[0].Value)
assert.Equal(t, 0.022, f.Children[1].Children[0].Time)
})

t.Run("handles InitPlan nodes", func(t *testing.T) {
p := plan.Plan{
ExecutionTree: plan.Node{
Method: "Seq Scan",
TotalTime: 0.12,
Children: []plan.Node{
{
Method: "Seq Scan",
Table: "bears",
ParentRelationship: "InitPlan",
TotalTime: 0.2,
Children: []plan.Node{
{
Method: "Seq Scan",
TotalTime: 0.12,
},
},
},
},
},
}

f := New(p)

assert.Equal(t, "Total", f.Name)
assert.Equal(t, 0.32, f.Value)
assert.Equal(t, 0.12, f.Time)

assert.Equal(t, "Seq Scan", f.Children[1].Name)
assert.Equal(t, 0.32, f.Children[1].Value)
assert.Equal(t, 0.12, f.Children[1].Time)
assert.Equal(t, "", f.Children[1].Color)
assert.False(t, f.Children[1].InitPlan)

assert.Equal(t, "Seq Scan on bears", f.Children[1].Children[0].Name)
assert.Equal(t, 0.2, f.Children[1].Children[0].Value)
assert.Equal(t, 0.2, f.Children[1].Children[0].Time)
assert.Equal(t, INIT_COLOR, f.Children[1].Children[0].Color)
assert.True(t, f.Children[1].Children[0].InitPlan)

assert.Equal(t, INIT_COLOR, f.Children[1].Children[0].Children[0].Color)
})

}
Expand Down Expand Up @@ -76,16 +124,18 @@ func Test_detail(t *testing.T) {

t.Run("returns a table of details", func(t *testing.T) {
n := plan.Node{
Filter: "(id = 123)",
BuffersHit: 8,
BuffersRead: 5,
MemoryUsage: 12,
HashBuckets: 1024,
HashBatches: 1,
ParentRelationship: "InitPlan",
Filter: "(id = 123)",
BuffersHit: 8,
BuffersRead: 5,
MemoryUsage: 12,
HashBuckets: 1024,
HashBatches: 1,
}

expected := strings.Join([]string{
"<table class=\"table table-striped table-bordered\"><tbody>",
"<tr><th>Parent Relationship</th><td>InitPlan</td></tr>",
"<tr><th>Filter</th><td>(id = 123)</td></tr>",
"<tr><th>Join Filter</th><td></td></tr>",
"<tr><th>Hash Cond</th><td></td></tr>",
Expand Down
2 changes: 1 addition & 1 deletion pkg/html/html.go
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ const flameTemplate = `
.offset([8, 0])
.attr('class', 'd3-flame-graph-tip')
.html(function(d) {
return d.data.name + " | " + d.data.value + "ms";
return d.data.name + " | " + d.data.time + "ms";
});
flameGraph.tooltip(tip);
Expand Down
31 changes: 16 additions & 15 deletions pkg/plan/plan.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,21 +12,22 @@ type Plan struct {
}

type Node struct {
Method string `json:"Node Type"`
Table string `json:"Relation Name"`
Index string `json:"Index Name"`
Filter string `json:"Filter"`
JoinFilter string `json:"Join Filter"`
HashCond string `json:"Hash Cond"`
IndexCond string `json:"Index Cond"`
RecheckCond string `json:"Recheck Cond"`
BuffersHit int `json:"Shared Hit Blocks"`
BuffersRead int `json:"Shared Read Blocks"`
MemoryUsage int `json:"Peak Memory Usage"`
HashBuckets int `json:"Hash Buckets"`
HashBatches int `json:"Hash Batches"`
TotalTime float64 `json:"Actual Total Time"`
Children []Node `json:"Plans"`
Method string `json:"Node Type"`
Table string `json:"Relation Name"`
Index string `json:"Index Name"`
ParentRelationship string `json:"Parent Relationship"`
Filter string `json:"Filter"`
JoinFilter string `json:"Join Filter"`
HashCond string `json:"Hash Cond"`
IndexCond string `json:"Index Cond"`
RecheckCond string `json:"Recheck Cond"`
BuffersHit int `json:"Shared Hit Blocks"`
BuffersRead int `json:"Shared Read Blocks"`
MemoryUsage int `json:"Peak Memory Usage"`
HashBuckets int `json:"Hash Buckets"`
HashBatches int `json:"Hash Batches"`
TotalTime float64 `json:"Actual Total Time"`
Children []Node `json:"Plans"`
}

var ErrEmptyPlanJSON = errors.New("empty plan JSON")
Expand Down
1 change: 1 addition & 0 deletions pkg/plan/plan_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ func TestNew(t *testing.T) {
assert.Equal(t, "Hash Join", child.Method)
assert.Equal(t, "users", child.Table)
assert.Equal(t, "users_pkey", child.Index)
assert.Equal(t, "Outer", child.ParentRelationship)
assert.Equal(t, "((title)::text ~ '.*sql.*'::text)", child.Filter)
assert.Equal(t, "(id = 123)", child.JoinFilter)
assert.Equal(t, "((p.user_id = c.user_id) AND (p.id = c.post_id))", child.HashCond)
Expand Down

0 comments on commit de2cedf

Please sign in to comment.