Skip to content

Commit

Permalink
Removed threads and added object pools in bbTree. 5% gain
Browse files Browse the repository at this point in the history
  • Loading branch information
josephg committed Jan 27, 2013
1 parent fe01221 commit 9eb49d3
Show file tree
Hide file tree
Showing 4 changed files with 177 additions and 181 deletions.
2 changes: 2 additions & 0 deletions benchmark/bench.js
Expand Up @@ -513,6 +513,7 @@ print('contacts: ' + numContacts);
print('node: ' + numNodes);
print('leaf: ' + numLeaves);
print('bb: ' + numBB);
print('pairs: ' + numPairs);
print('applyImpulse: ' + numApplyImpulse);
print('applyContact: ' + numApplyContact);

Expand All @@ -521,6 +522,7 @@ print(numContacts);
print(numNodes);
print(numLeaves);
print(numBB);
print(numPairs);
print(numApplyImpulse);
print(numApplyContact);

Expand Down
175 changes: 86 additions & 89 deletions cp.js
Expand Up @@ -1789,9 +1789,9 @@ var BBTree = cp.BBTree = function(staticIndex)

this.root = null;

// An object pool of tree nodes and pairs.
//this.pooledNodes = [];
//this.pooledPairs = [];
// A linked list containing an object pool of tree nodes and pairs.
this.pooledNodes = null;
this.pooledPairs = null;

this.stamp = 0;
};
Expand All @@ -1802,9 +1802,7 @@ var numNodes = 0;

var Node = function(tree, a, b)
{
//Node *node = NodeFromPool(tree);
this.obj = null;
//this.bb = bbMerge(a.bb, b.bb);
this.bb_l = min(a.bb_l, b.bb_l);
this.bb_b = min(a.bb_b, b.bb_b);
this.bb_r = max(a.bb_r, b.bb_r);
Expand All @@ -1813,16 +1811,25 @@ var Node = function(tree, a, b)

this.setA(a);
this.setB(b);
numNodes++;
};

BBTree.prototype.makeNode = function(a, b)
{
var node = this.pooledNodes;
if(node){
this.pooledNodes = node.parent;
node.constructor(this, a, b);
return node;
} else {
numNodes++;
return new Node(this, a, b);
}
};

var numLeaves = 0;
var Leaf = function(tree, obj)
{
//Node *node = NodeFromPool(tree);

this.obj = obj;
//this.bb = tree.getBB(obj);
tree.getBB(obj, this);

this.parent = null;
Expand Down Expand Up @@ -1873,45 +1880,59 @@ BBTree.prototype.incrementStamp = function()

// **** Pair/Thread Functions

var numPairs = 0;
// Objects created with constructors are faster than object literals. :(
var Pair = function(a, b)
var Pair = function(leafA, nextA, leafB, nextB)
{
this.a = a; this.b = b;
};
this.prevA = null;
this.leafA = leafA;
this.nextA = nextA;

var Thread = function(leaf, next)
{
this.prev = null;
this.next = next;
this.leaf = leaf;
this.prevB = null;
this.leafB = leafB;
this.nextB = nextB;
};

// Benchmark this code with object pools on & off.
/*
BBTree.prototype.pairRecycle = function(pair)
BBTree.prototype.makePair = function(leafA, nextA, leafB, nextB)
{
this.pooledPairs.push(pair);
//return new Pair(leafA, nextA, leafB, nextB);
var pair = this.pooledPairs;
if (pair)
{
this.pooledPairs = pair.prevA;

pair.prevA = null;
pair.leafA = leafA;
pair.nextA = nextA;

pair.prevB = null;
pair.leafB = leafB;
pair.nextB = nextB;

//pair.constructor(leafA, nextA, leafB, nextB);
return pair;
} else {
numPairs++;
return new Pair(leafA, nextA, leafB, nextB);
}
};

BBTree.prototype.pairFromPool = function()
Pair.prototype.recycle = function(tree)
{
return this.pooledPairs.pop() || new Pair(null, null);
this.prevA = tree.pooledPairs;
tree.pooledPairs = this;
};
*/

Thread.prototype.unlink = function()
var unlinkThread = function(prev, leaf, next)
{
var next = this.next;
var prev = this.prev;

if(next){
if(next.a.leaf == this.leaf) next.a.prev = prev; else next.b.prev = prev;
if(next.leafA === leaf) next.prevA = prev; else next.prevB = prev;
}

if(prev){
if(prev.a.leaf == this.leaf) prev.a.next = next; else prev.b.next = next;
if(prev.leafA === leaf) prev.nextA = next; else prev.nextB = next;
} else {
this.leaf.pairs = next;
leaf.pairs = next;
}
};

Expand All @@ -1923,61 +1944,45 @@ Leaf.prototype.clearPairs = function(tree)
this.pairs = null;

while(pair){
if(pair.a.leaf == this){
next = pair.a.next;
pair.b.unlink();
//tree.pairRecycle(pair);
pair = next;
if(pair.leafA === this){
next = pair.nextA;
unlinkThread(pair.prevB, pair.leafB, pair.nextB);
} else {
next = pair.b.next;
pair.a.unlink();
//tree.pairRecycle(pair);
pair = next;
next = pair.nextB;
unlinkThread(pair.prevA, pair.leafA, pair.nextA);
}
pair.recycle(tree);
pair = next;
}
}

var pairInsert = function(a, b, tree)
{
var nextA = a.pairs, nextB = b.pairs;
var pair = new Pair(new Thread(a, nextA), new Thread(b, nextB));
var pair = tree.makePair(a, nextA, b, nextB);
a.pairs = b.pairs = pair;

//var pair = tree.pairFromPool();
//Pair temp = {{null, a, nextA},{null, b, nextB}};
//*pair = temp;

if(nextA){
if(nextA.a.leaf == a) nextA.a.prev = pair; else nextA.b.prev = pair;
if(nextA.leafA === a) nextA.prevA = pair; else nextA.prevB = pair;
}

if(nextB){
if(nextB.a.leaf == b) nextB.a.prev = pair; else nextB.b.prev = pair;
if(nextB.leafA === b) nextB.prevA = pair; else nextB.prevB = pair;
}
};

// **** Node Functions

/*
static void
NodeRecycle(bbTree *tree, Node *node)
Node.prototype.recycle = function(tree)
{
node.parent = tree.pooledNodes;
tree.pooledNodes = node;
}
this.parent = tree.pooledNodes;
tree.pooledNodes = this;
};

static Node *
NodeFromPool(bbTree *tree)
Leaf.prototype.recycle = function(tree)
{
Node *node = tree.pooledNodes;
if(node){
tree.pooledNodes = node.parent;
return node;
} else {
// Pool is exhausted, make more
}
}*/
// Its not worth the overhead to recycle leaves.
};

Node.prototype.setA = function(value)
{
Expand All @@ -1991,12 +1996,6 @@ Node.prototype.setB = function(value)
value.parent = this;
};

/*
static inline cpBool
NodeIsLeaf(Node *node)
{
return (node.obj != null);
}*/
Leaf.prototype.isLeaf = true;
Node.prototype.isLeaf = false;

Expand All @@ -2010,10 +2009,10 @@ Node.prototype.replaceChild = function(child, value, tree)
assertSoft(child == this.A || child == this.B, "Node is not a child of parent.");

if(this.A == child){
//NodeRecycle(tree, parent.A);
this.A.recycle(tree);
this.setA(value);
} else {
//NodeRecycle(tree, parent.B);
this.B.recycle(tree);
this.setB(value);
}

Expand Down Expand Up @@ -2055,7 +2054,7 @@ var subtreeInsert = function(subtree, leaf, tree)
if(subtree == null){
return leaf;
} else if(subtree.isLeaf){
return new Node(tree, leaf, subtree);
return tree.makeNode(leaf, subtree);
} else {
var cost_a = subtree.B.bbArea() + bbTreeMergedArea(subtree.A, leaf);
var cost_b = subtree.A.bbArea() + bbTreeMergedArea(subtree.B, leaf);
Expand Down Expand Up @@ -2144,16 +2143,14 @@ var subtreeSegmentQuery = function(subtree, a, b, t_exit, func)
}
};

/*
static void
SubtreeRecycle(bbTree *tree, Node *node)
BBTree.prototype.subtreeRecycle = function(node)
{
if(!NodeIsLeaf(node)){
SubtreeRecycle(tree, node.A);
SubtreeRecycle(tree, node.B);
NodeRecycle(tree, node);
if(node.isLeaf){
this.subtreeRecycle(node.A);
this.subtreeRecycle(node.B);
node.recycle(this);
}
}*/
};

var subtreeRemove = function(subtree, leaf, tree)
{
Expand All @@ -2164,7 +2161,7 @@ var subtreeRemove = function(subtree, leaf, tree)
if(parent == subtree){
var other = subtree.otherChild(leaf);
other.parent = subtree.parent;
//NodeRecycle(tree, subtree);
subtree.recycle(tree);
return other;
} else {
parent.parent.replaceChild(parent, parent.otherChild(leaf), tree);
Expand Down Expand Up @@ -2220,11 +2217,11 @@ var markLeaf = function(leaf, tree, staticRoot, func)
} else {
var pair = leaf.pairs;
while(pair){
if(leaf == pair.b.leaf){
if(func) func(pair.a.leaf.obj, leaf.obj);
pair = pair.b.next;
if(leaf === pair.leafB){
if(func) func(pair.leafA.obj, leaf.obj);
pair = pair.nextB;
} else {
pair = pair.a.next;
pair = pair.nextA;
}
}
}
Expand Down Expand Up @@ -2306,7 +2303,7 @@ BBTree.prototype.remove = function(obj, hashid)
this.count--;

leaf.clearPairs(this);
//NodeRecycle(tree, leaf);
leaf.recycle(this);
};

BBTree.prototype.contains = function(obj, hashid)
Expand Down Expand Up @@ -2398,7 +2395,7 @@ var partitionNodes = function(tree, nodes, offset, count)
if(count == 1){
return nodes[offset];
} else if(count == 2) {
return new Node(tree, nodes[offset], nodes[offset + 1]);
return tree.makeNode(nodes[offset], nodes[offset + 1]);
}

// Find the AABB for these nodes
Expand Down Expand Up @@ -2505,7 +2502,7 @@ BBTree.prototype.optimize = function()
nodes[i++] = this.nodes[hashid];
}

//SubtreeRecycle(tree, root);
tree.subtreeRecycle(root);
this.root = partitionNodes(tree, nodes, nodes.length);
};

Expand Down
6 changes: 3 additions & 3 deletions cp.min.js

Large diffs are not rendered by default.

0 comments on commit 9eb49d3

Please sign in to comment.