Use concrete value for quad.Quad

Comparison of -short benchmarks in cayley.

$ benchcmp pointer.bench concrete.bench
benchmark                                   old ns/op     new ns/op	delta
BenchmarkNamePredicate                      1673276       1655093	-1.09%
BenchmarkLargeSetsNoIntersection            318985907     261499984	-18.02%
BenchmarkNetAndSpeed                        104403743     41516981	-60.23%
BenchmarkKeanuAndNet                        17309258      16857513	-2.61%
BenchmarkKeanuAndSpeed                      20159161      19282833	-4.35%

Comparison of pathological cases are not so happy.

benchmark                                   old ns/op       new ns/op		delta
BenchmarkVeryLargeSetsSmallIntersection     55269775527     246084606672	+345.24%
BenchmarkHelplessContainsChecker            23436501319     24308906949		+3.72%

Profiling the worst case:

Pointer:
Total: 6121 samples
    1973  32.2%  32.2%     1973  32.2% runtime.findfunc
     773  12.6%  44.9%      773  12.6% readvarint
     510   8.3%  53.2%      511   8.3% step
     409   6.7%  59.9%      410   6.7% runtime.gentraceback
     390   6.4%  66.2%      391   6.4% pcvalue
     215   3.5%  69.8%      215   3.5% runtime.funcdata
     181   3.0%  72.7%      181   3.0% checkframecopy
     118   1.9%  74.6%      119   1.9% runtime.funcspdelta
      96   1.6%  76.2%       96   1.6% runtime.topofstack
      76   1.2%  77.5%       76   1.2% scanblock

Concrete:
Total: 25027 samples
    9437  37.7%  37.7%     9437  37.7% runtime.findfunc
    3853  15.4%  53.1%     3853  15.4% readvarint
    2366   9.5%  62.6%     2366   9.5% step
    2186   8.7%  71.3%     2186   8.7% runtime.gentraceback
    1816   7.3%  78.5%     1816   7.3% pcvalue
    1016   4.1%  82.6%     1016   4.1% runtime.funcdata
     859   3.4%  86.0%      859   3.4% checkframecopy
     506   2.0%  88.1%      506   2.0% runtime.funcspdelta
     410   1.6%  89.7%      410   1.6% runtime.topofstack
     303   1.2%  90.9%      303   1.2% runtime.newstack
This commit is contained in:
kortschak 2014-08-05 22:41:25 +09:30
parent 1ae81e6d00
commit 6acfdcc5d6
19 changed files with 183 additions and 183 deletions

View file

@ -36,11 +36,11 @@ func (qs *store) ValueOf(s string) graph.Value {
return nil
}
func (qs *store) AddTriple(*quad.Quad) {}
func (qs *store) AddTriple(quad.Quad) {}
func (qs *store) AddTripleSet([]*quad.Quad) {}
func (qs *store) AddTripleSet([]quad.Quad) {}
func (qs *store) Quad(graph.Value) *quad.Quad { return &quad.Quad{} }
func (qs *store) Quad(graph.Value) quad.Quad { return quad.Quad{} }
func (qs *store) TripleIterator(d quad.Direction, i graph.Value) graph.Iterator {
return qs.iter
@ -74,4 +74,4 @@ func (qs *store) Close() {}
func (qs *store) TripleDirection(graph.Value, quad.Direction) graph.Value { return 0 }
func (qs *store) RemoveTriple(t *quad.Quad) {}
func (qs *store) RemoveTriple(t quad.Quad) {}

View file

@ -26,8 +26,8 @@ import (
"github.com/google/cayley/quad"
)
func makeTripleSet() []*quad.Quad {
tripleSet := []*quad.Quad{
func makeTripleSet() []quad.Quad {
tripleSet := []quad.Quad{
{"A", "follows", "B", ""},
{"C", "follows", "B", ""},
{"C", "follows", "D", ""},
@ -43,7 +43,7 @@ func makeTripleSet() []*quad.Quad {
return tripleSet
}
func iteratedTriples(qs graph.TripleStore, it graph.Iterator) []*quad.Quad {
func iteratedTriples(qs graph.TripleStore, it graph.Iterator) []quad.Quad {
var res ordered
for {
val, ok := graph.Next(it)
@ -56,7 +56,7 @@ func iteratedTriples(qs graph.TripleStore, it graph.Iterator) []*quad.Quad {
return res
}
type ordered []*quad.Quad
type ordered []quad.Quad
func (o ordered) Len() int { return len(o) }
func (o ordered) Less(i, j int) bool {
@ -143,7 +143,7 @@ func TestLoadDatabase(t *testing.T) {
t.Error("Failed to create leveldb TripleStore.")
}
qs.AddTriple(&quad.Quad{"Something", "points_to", "Something Else", "context"})
qs.AddTriple(quad.Quad{"Something", "points_to", "Something Else", "context"})
for _, pq := range []string{"Something", "points_to", "Something Else", "context"} {
if got := qs.NameOf(qs.ValueOf(pq)); got != pq {
t.Errorf("Failed to roundtrip %q, got:%q expect:%q", pq, got, pq)
@ -176,7 +176,7 @@ func TestLoadDatabase(t *testing.T) {
t.Errorf("Unexpected triplestore size, got:%d expect:5", s)
}
qs.RemoveTriple(&quad.Quad{"A", "follows", "B", ""})
qs.RemoveTriple(quad.Quad{"A", "follows", "B", ""})
if s := qs.Size(); s != 10 {
t.Errorf("Unexpected triplestore size after RemoveTriple, got:%d expect:10", s)
}
@ -301,7 +301,7 @@ func TestSetIterator(t *testing.T) {
qs.AddTripleSet(makeTripleSet())
expect := []*quad.Quad{
expect := []quad.Quad{
{"C", "follows", "B", ""},
{"C", "follows", "D", ""},
}
@ -326,7 +326,7 @@ func TestSetIterator(t *testing.T) {
// Object iterator.
it = qs.TripleIterator(quad.Object, qs.ValueOf("F"))
expect = []*quad.Quad{
expect = []quad.Quad{
{"B", "follows", "F", ""},
{"E", "follows", "F", ""},
}
@ -339,7 +339,7 @@ func TestSetIterator(t *testing.T) {
and.AddSubIterator(qs.TripleIterator(quad.Subject, qs.ValueOf("B")))
and.AddSubIterator(it)
expect = []*quad.Quad{
expect = []quad.Quad{
{"B", "follows", "F", ""},
}
if got := iteratedTriples(qs, and); !reflect.DeepEqual(got, expect) {
@ -349,7 +349,7 @@ func TestSetIterator(t *testing.T) {
// Predicate iterator.
it = qs.TripleIterator(quad.Predicate, qs.ValueOf("status"))
expect = []*quad.Quad{
expect = []quad.Quad{
{"B", "status", "cool", "status_graph"},
{"D", "status", "cool", "status_graph"},
{"G", "status", "cool", "status_graph"},
@ -362,7 +362,7 @@ func TestSetIterator(t *testing.T) {
// Label iterator.
it = qs.TripleIterator(quad.Label, qs.ValueOf("status_graph"))
expect = []*quad.Quad{
expect = []quad.Quad{
{"B", "status", "cool", "status_graph"},
{"D", "status", "cool", "status_graph"},
{"G", "status", "cool", "status_graph"},
@ -378,7 +378,7 @@ func TestSetIterator(t *testing.T) {
and.AddSubIterator(qs.TripleIterator(quad.Subject, qs.ValueOf("B")))
and.AddSubIterator(it)
expect = []*quad.Quad{
expect = []quad.Quad{
{"B", "status", "cool", "status_graph"},
}
if got := iteratedTriples(qs, and); !reflect.DeepEqual(got, expect) {
@ -391,7 +391,7 @@ func TestSetIterator(t *testing.T) {
and.AddSubIterator(it)
and.AddSubIterator(qs.TripleIterator(quad.Subject, qs.ValueOf("B")))
expect = []*quad.Quad{
expect = []quad.Quad{
{"B", "status", "cool", "status_graph"},
}
if got := iteratedTriples(qs, and); !reflect.DeepEqual(got, expect) {

View file

@ -116,7 +116,7 @@ func (qs *TripleStore) Size() int64 {
return qs.size
}
func (qs *TripleStore) createKeyFor(d [3]quad.Direction, triple *quad.Quad) []byte {
func (qs *TripleStore) createKeyFor(d [3]quad.Direction, triple quad.Quad) []byte {
key := make([]byte, 0, 2+(qs.hasher.Size()*3))
// TODO(kortschak) Remove dependence on String() method.
key = append(key, []byte{d[0].Prefix(), d[1].Prefix()}...)
@ -126,7 +126,7 @@ func (qs *TripleStore) createKeyFor(d [3]quad.Direction, triple *quad.Quad) []by
return key
}
func (qs *TripleStore) createProvKeyFor(d [3]quad.Direction, triple *quad.Quad) []byte {
func (qs *TripleStore) createProvKeyFor(d [3]quad.Direction, triple quad.Quad) []byte {
key := make([]byte, 0, 2+(qs.hasher.Size()*4))
// TODO(kortschak) Remove dependence on String() method.
key = append(key, []byte{quad.Label.Prefix(), d[0].Prefix()}...)
@ -144,7 +144,7 @@ func (qs *TripleStore) createValueKeyFor(s string) []byte {
return key
}
func (qs *TripleStore) AddTriple(t *quad.Quad) {
func (qs *TripleStore) AddTriple(t quad.Quad) {
batch := &leveldb.Batch{}
qs.buildWrite(batch, t)
err := qs.db.Write(batch, qs.writeopts)
@ -163,7 +163,7 @@ var (
pso = [3]quad.Direction{quad.Predicate, quad.Subject, quad.Object}
)
func (qs *TripleStore) RemoveTriple(t *quad.Quad) {
func (qs *TripleStore) RemoveTriple(t quad.Quad) {
_, err := qs.db.Get(qs.createKeyFor(spo, t), qs.readopts)
if err != nil && err != leveldb.ErrNotFound {
glog.Error("Couldn't access DB to confirm deletion")
@ -192,8 +192,8 @@ func (qs *TripleStore) RemoveTriple(t *quad.Quad) {
qs.size--
}
func (qs *TripleStore) buildTripleWrite(batch *leveldb.Batch, t *quad.Quad) {
bytes, err := json.Marshal(*t)
func (qs *TripleStore) buildTripleWrite(batch *leveldb.Batch, t quad.Quad) {
bytes, err := json.Marshal(t)
if err != nil {
glog.Errorf("Couldn't write to buffer for triple %s: %s", t, err)
return
@ -206,7 +206,7 @@ func (qs *TripleStore) buildTripleWrite(batch *leveldb.Batch, t *quad.Quad) {
}
}
func (qs *TripleStore) buildWrite(batch *leveldb.Batch, t *quad.Quad) {
func (qs *TripleStore) buildWrite(batch *leveldb.Batch, t quad.Quad) {
qs.buildTripleWrite(batch, t)
qs.UpdateValueKeyBy(t.Get(quad.Subject), 1, nil)
qs.UpdateValueKeyBy(t.Get(quad.Predicate), 1, nil)
@ -267,7 +267,7 @@ func (qs *TripleStore) UpdateValueKeyBy(name string, amount int, batch *leveldb.
}
}
func (qs *TripleStore) AddTripleSet(t_s []*quad.Quad) {
func (qs *TripleStore) AddTripleSet(t_s []quad.Quad) {
batch := &leveldb.Batch{}
newTs := len(t_s)
resizeMap := make(map[string]int)
@ -306,23 +306,23 @@ func (qs *TripleStore) Close() {
qs.open = false
}
func (qs *TripleStore) Quad(k graph.Value) *quad.Quad {
func (qs *TripleStore) Quad(k graph.Value) quad.Quad {
var triple quad.Quad
b, err := qs.db.Get(k.([]byte), qs.readopts)
if err != nil && err != leveldb.ErrNotFound {
glog.Error("Error: couldn't get triple from DB.")
return &quad.Quad{}
return quad.Quad{}
}
if err == leveldb.ErrNotFound {
// No harm, no foul.
return &quad.Quad{}
return quad.Quad{}
}
err = json.Unmarshal(b, &triple)
if err != nil {
glog.Error("Error: couldn't reconstruct triple.")
return &quad.Quad{}
return quad.Quad{}
}
return &triple
return triple
}
func (qs *TripleStore) convertStringToByteHash(s string) []byte {

View file

@ -101,13 +101,13 @@ func newTripleStore() *TripleStore {
return &ts
}
func (ts *TripleStore) AddTripleSet(triples []*quad.Quad) {
func (ts *TripleStore) AddTripleSet(triples []quad.Quad) {
for _, t := range triples {
ts.AddTriple(t)
}
}
func (ts *TripleStore) tripleExists(t *quad.Quad) (bool, int64) {
func (ts *TripleStore) tripleExists(t quad.Quad) (bool, int64) {
smallest := -1
var smallest_tree *llrb.LLRB
for d := quad.Subject; d <= quad.Label; d++ {
@ -137,19 +137,19 @@ func (ts *TripleStore) tripleExists(t *quad.Quad) (bool, int64) {
if !ok {
break
}
if t.Equals(&ts.triples[val.(int64)]) {
if t.Equals(ts.triples[val.(int64)]) {
return true, val.(int64)
}
}
return false, 0
}
func (ts *TripleStore) AddTriple(t *quad.Quad) {
func (ts *TripleStore) AddTriple(t quad.Quad) {
if exists, _ := ts.tripleExists(t); exists {
return
}
var tripleID int64
ts.triples = append(ts.triples, *t)
ts.triples = append(ts.triples, t)
tripleID = ts.tripleIdCounter
ts.size++
ts.tripleIdCounter++
@ -178,7 +178,7 @@ func (ts *TripleStore) AddTriple(t *quad.Quad) {
// TODO(barakmich): Add VIP indexing
}
func (ts *TripleStore) RemoveTriple(t *quad.Quad) {
func (ts *TripleStore) RemoveTriple(t quad.Quad) {
var tripleID int64
var exists bool
tripleID = 0
@ -224,8 +224,8 @@ func (ts *TripleStore) RemoveTriple(t *quad.Quad) {
}
}
func (ts *TripleStore) Quad(index graph.Value) *quad.Quad {
return &ts.triples[index.(int64)]
func (ts *TripleStore) Quad(index graph.Value) quad.Quad {
return ts.triples[index.(int64)]
}
func (ts *TripleStore) TripleIterator(d quad.Direction, value graph.Value) graph.Iterator {

View file

@ -37,7 +37,7 @@ import (
// \-->|#D#|------------->+---+
// +---+
//
var simpleGraph = []*quad.Quad{
var simpleGraph = []quad.Quad{
{"A", "follows", "B", ""},
{"C", "follows", "B", ""},
{"C", "follows", "D", ""},
@ -51,7 +51,7 @@ var simpleGraph = []*quad.Quad{
{"G", "status", "cool", "status_graph"},
}
func makeTestStore(data []*quad.Quad) (*TripleStore, []pair) {
func makeTestStore(data []quad.Quad) (*TripleStore, []pair) {
seen := make(map[string]struct{})
ts := newTripleStore()
var (
@ -175,7 +175,7 @@ func TestLinksToOptimization(t *testing.T) {
func TestRemoveTriple(t *testing.T) {
ts, _ := makeTestStore(simpleGraph)
ts.RemoveTriple(&quad.Quad{"E", "follows", "F", ""})
ts.RemoveTriple(quad.Quad{"E", "follows", "F", ""})
fixed := ts.FixedIterator()
fixed.Add(ts.ValueOf("E"))

View file

@ -91,7 +91,7 @@ func newTripleStore(addr string, options graph.Options) (graph.TripleStore, erro
return &qs, nil
}
func (qs *TripleStore) getIdForTriple(t *quad.Quad) string {
func (qs *TripleStore) getIdForTriple(t quad.Quad) string {
id := qs.ConvertStringToByteHash(t.Subject)
id += qs.ConvertStringToByteHash(t.Predicate)
id += qs.ConvertStringToByteHash(t.Object)
@ -150,7 +150,7 @@ func (qs *TripleStore) updateNodeBy(node_name string, inc int) {
}
}
func (qs *TripleStore) writeTriple(t *quad.Quad) bool {
func (qs *TripleStore) writeTriple(t quad.Quad) bool {
tripledoc := bson.M{
"_id": qs.getIdForTriple(t),
"Subject": t.Subject,
@ -170,7 +170,7 @@ func (qs *TripleStore) writeTriple(t *quad.Quad) bool {
return true
}
func (qs *TripleStore) AddTriple(t *quad.Quad) {
func (qs *TripleStore) AddTriple(t quad.Quad) {
_ = qs.writeTriple(t)
qs.updateNodeBy(t.Subject, 1)
qs.updateNodeBy(t.Predicate, 1)
@ -180,7 +180,7 @@ func (qs *TripleStore) AddTriple(t *quad.Quad) {
}
}
func (qs *TripleStore) AddTripleSet(in []*quad.Quad) {
func (qs *TripleStore) AddTripleSet(in []quad.Quad) {
qs.session.SetSafe(nil)
ids := make(map[string]int)
for _, t := range in {
@ -200,7 +200,7 @@ func (qs *TripleStore) AddTripleSet(in []*quad.Quad) {
qs.session.SetSafe(&mgo.Safe{})
}
func (qs *TripleStore) RemoveTriple(t *quad.Quad) {
func (qs *TripleStore) RemoveTriple(t quad.Quad) {
err := qs.db.C("triples").RemoveId(qs.getIdForTriple(t))
if err == mgo.ErrNotFound {
return
@ -216,13 +216,13 @@ func (qs *TripleStore) RemoveTriple(t *quad.Quad) {
}
}
func (qs *TripleStore) Quad(val graph.Value) *quad.Quad {
func (qs *TripleStore) Quad(val graph.Value) quad.Quad {
var bsonDoc bson.M
err := qs.db.C("triples").FindId(val.(string)).One(&bsonDoc)
if err != nil {
glog.Errorf("Error: Couldn't retrieve triple %s %v", val, err)
}
return &quad.Quad{
return quad.Quad{
bsonDoc["Subject"].(string),
bsonDoc["Predicate"].(string),
bsonDoc["Object"].(string),

View file

@ -40,17 +40,17 @@ type Value interface{}
type TripleStore interface {
// Add a triple to the store.
AddTriple(*quad.Quad)
AddTriple(quad.Quad)
// Add a set of triples to the store, atomically if possible.
AddTripleSet([]*quad.Quad)
AddTripleSet([]quad.Quad)
// Removes a triple matching the given one from the database,
// if it exists. Does nothing otherwise.
RemoveTriple(*quad.Quad)
RemoveTriple(quad.Quad)
// Given an opaque token, returns the triple for that token from the store.
Quad(Value) *quad.Quad
Quad(Value) quad.Quad
// Given a direction and a token, creates an iterator of links which have
// that node token in that directional field.