Verified Commit 5b237d1e authored by Aral Balkan's avatar Aral Balkan
Browse files

Initial add

parents
node_modules
# Automerge: simple profiling spikes
## N push() operations
__File:__ index.js
Pushes incremental numbers to an array in a document via the `change()` method.
Timings (on my MacBook) ranged from 6ms for 1 push to 43.75 seconds for 10,000. 100 pushes took 175ms and 1,000 took 1.345 seconds.
The storage requirements (tested very roughly using `util.inspect` to flatten the object, including all hidden fields) also seem to follow a similar curve. A single insert took up 3,557 bytes (size of original object: 18 bytes), 10: ~17KB, 100: ~160KB, 1,000: ~1.6MB, and the array with 10,000 numbers took up ~ 16MB (size of original object: ~80 bytes). My testing methodology doesn’t necessarily reflect the actual amount of space these objects would take up either in memory or on the file system. (See alt tests, below.)
It does look like the system would result in a sluggish interface on operations on an array with ~100 items or so.
## Push array with N items in a single operation
__File:__ index2.js
This time, instead of testing, say, 10,000 pushes to an array, I wanted to test a single change to the object where an array with 10,000 items is added.
The results I got mirror those of the first scenario.
The timings seem to follow a similar curve at first but the results I got for the array with 10,000 items was ~3x slower at ~115 seconds vs ~43 seconds using the first technique.
## Set N keys
__File:__ index3.js
When I posted my initial results from the tests above [on the Automerge issue tracker](https://github.com/automerge/automerge/issues/89), [@pvh](https://github.com/pvh) suggested that I also try setting object keys.
The timing results are generally about the same as with the push() example.
However, there is a ~2x improvement over storage requirements.
## Alternative means to calculating storage requirements
__Files:__ index1-alt.js, index2-alt.js, index3-alt.js
On the issue trackers, [@j-f1](https://github.com/j-f1) recommended that I try `Automerge.save(doc).length` instead of `util.inspect(doc, {showHidden: true, maxArrayLength: null}).length` to calculate the approximate memory/storage requirements. The former returns a lossless string serialisation of the Automerge document in a more concise format than the latter.
The former method returns results that are 3-5x smaller than the latter method.
The “truth” probably lies somewhere in the middle and closer to one or the other depending on whether we are looking at storage (which will match the former over the wire) or memory use (which will be closer to the latter). None of this takes into account any compression that may be applied at the storage/memory level.
The next step is to profile these in the browser so we can see actual memory usage.
\ No newline at end of file
// Profile: N push() operations
//
// Alt: Uses string returned from Automerge.save(doc) to measure size of the doc
// instead of util.inspect (as recommended by @j-f1).
// https://github.com/automerge/automerge/issues/89#issuecomment-387894287
const util = require('util')
const Automerge = require('automerge')
function profileNumInserts(numInserts)
{
let start, duration
let doc = Automerge.init()
doc = Automerge.change(doc, '', doc => {
doc.x = []
})
console.log(`Profiling ${numInserts} Inserts.`)
start = new Date()
for (let i = 0; i < numInserts; i++) {
doc = Automerge.change(doc, '', doc => {
doc.x.push(i)
})
}
duration = (new Date()) - start
console.log(`Took: ${duration}ms.`)
console.log(`Profiling ${numInserts} with regular array.push().`)
let x = []
start = new Date()
for (let i = 0; i < numInserts; i++) {
x.push(i)
}
duration = (new Date()) - start
console.log(`Took: ${duration}ms.`)
const docStr = Automerge.save(doc)
const xInspection = util.inspect(x, {showHidden: true, maxArrayLength: null})
console.log(`Size of doc: ${docStr.length} bytes.`)
console.log(`Size of regular array: ${xInspection.length} bytes.`)
console.log('\n---\n')
}
profileNumInserts(1)
profileNumInserts(10)
profileNumInserts(100)
profileNumInserts(1000)
profileNumInserts(10000)
// Profile: N push() operations
const util = require('util')
const Automerge = require('automerge')
function profileNumInserts(numInserts)
{
let start, duration
let doc = Automerge.init()
doc = Automerge.change(doc, '', doc => {
doc.x = []
})
console.log(`Profiling ${numInserts} Inserts.`)
start = new Date()
for (let i = 0; i < numInserts; i++) {
doc = Automerge.change(doc, '', doc => {
doc.x.push(i)
})
}
duration = (new Date()) - start
console.log(`Took: ${duration}ms.`)
console.log(`Profiling ${numInserts} with regular array.push().`)
let x = []
start = new Date()
for (let i = 0; i < numInserts; i++) {
x.push(i)
}
duration = (new Date()) - start
console.log(`Took: ${duration}ms.`)
const docinspection = util.inspect(doc, {showHidden: true, maxArrayLength: null})
const xInspection = util.inspect(x, {showHidden: true, maxArrayLength: null})
console.log(`Size of doc: ${docinspection.length} bytes.`)
console.log(`Size of regular array: ${xInspection.length} bytes.`)
console.log('\n---\n')
}
profileNumInserts(1)
profileNumInserts(10)
profileNumInserts(100)
profileNumInserts(1000)
profileNumInserts(10000)
// Profile: Push array with N items in a single operation.
// Uses string returned from Automerge.save(doc) to measure size of the doc
// instead of util.inspect as recommended by @j-f1
// https://github.com/automerge/automerge/issues/89#issuecomment-387894287
const util = require('util')
const Automerge = require('automerge')
function profileNumInserts2(numInserts)
{
let start, duration
let doc = Automerge.init()
let x = []
start = new Date()
for (let i = 0; i < numInserts; i++) {
x.push(i)
}
doc = Automerge.change(doc, '', doc => {
doc.x = []
})
console.log(`Profiling ${numInserts} Inserts as single object.`)
start = new Date()
doc = Automerge.change(doc, '', doc => {
doc.x = x
})
duration = (new Date()) - start
console.log(`Took: ${duration}ms.`)
const docStr = Automerge.save(doc)
console.log(`Size of doc: ${docStr.length} bytes.`)
console.log('\n---\n')
}
profileNumInserts2(1)
profileNumInserts2(10)
profileNumInserts2(100)
profileNumInserts2(1000)
profileNumInserts2(10000)
// Profile: Push array with N items in a single operation.
const util = require('util')
const Automerge = require('automerge')
function profileNumInserts2(numInserts)
{
let start, duration
let doc = Automerge.init()
let x = []
start = new Date()
for (let i = 0; i < numInserts; i++) {
x.push(i)
}
doc = Automerge.change(doc, '', doc => {
doc.x = []
})
console.log(`Profiling ${numInserts} Inserts as single object.`)
start = new Date()
doc = Automerge.change(doc, '', doc => {
doc.x = x
})
duration = (new Date()) - start
console.log(`Took: ${duration}ms.`)
const docinspection = util.inspect(doc, {showHidden: true, maxArrayLength: null})
console.log(`Size of doc: ${docinspection.length} bytes.`)
console.log('\n---\n')
}
profileNumInserts2(1)
profileNumInserts2(10)
profileNumInserts2(100)
profileNumInserts2(1000)
profileNumInserts2(10000)
// Profile: set N keys
// As suggested by @pvh
// https://github.com/automerge/automerge/issues/89#issuecomment-387883317
// Uses string returned from Automerge.save(doc) to measure size of the doc
// instead of util.inspect as recommended by @j-f1
// https://github.com/automerge/automerge/issues/89#issuecomment-387894287
const util = require('util')
const Automerge = require('automerge')
function profileNumInserts(numInserts)
{
let start, duration
let doc = Automerge.init()
doc = Automerge.change(doc, '', doc => {
doc.x = []
})
console.log(`Profiling ${numInserts} key sets.`)
start = new Date()
for (let i = 0; i < numInserts; i++) {
doc = Automerge.change(doc, '', doc => {
doc[`key${i}`] = true
})
}
duration = (new Date()) - start
console.log(`Took: ${duration}ms.`)
console.log(`Profiling ${numInserts} key sets on regular object`)
let x = {}
start = new Date()
for (let i = 0; i < numInserts; i++) {
x[`key${i}`] = true
}
duration = (new Date()) - start
console.log(`Took: ${duration}ms.`)
const docStr = Automerge.save(doc)
const xInspection = util.inspect(x, {showHidden: true, maxArrayLength: null})
console.log(`Size of doc: ${docStr.length} bytes.`)
console.log(`Size of regular object: ${xInspection.length} bytes.`)
console.log('\n---\n')
}
profileNumInserts(1)
profileNumInserts(10)
profileNumInserts(100)
profileNumInserts(1000)
profileNumInserts(10000)
// Profile: set N keys
// As suggested by @pvh
// https://github.com/automerge/automerge/issues/89#issuecomment-387883317
const util = require('util')
const Automerge = require('automerge')
function profileNumInserts(numInserts)
{
let start, duration
let doc = Automerge.init()
doc = Automerge.change(doc, '', doc => {
doc.x = []
})
console.log(`Profiling ${numInserts} key sets.`)
start = new Date()
for (let i = 0; i < numInserts; i++) {
doc = Automerge.change(doc, '', doc => {
doc[`key${i}`] = true
})
}
duration = (new Date()) - start
console.log(`Took: ${duration}ms.`)
console.log(`Profiling ${numInserts} key sets on regular object`)
let x = {}
start = new Date()
for (let i = 0; i < numInserts; i++) {
x[`key${i}`] = true
}
duration = (new Date()) - start
console.log(`Took: ${duration}ms.`)
const docinspection = util.inspect(doc, {showHidden: true, maxArrayLength: null})
const xInspection = util.inspect(x, {showHidden: true, maxArrayLength: null})
console.log(`Size of doc: ${docinspection.length} bytes.`)
console.log(`Size of regular object: ${xInspection.length} bytes.`)
console.log('\n---\n')
}
profileNumInserts(1)
profileNumInserts(10)
profileNumInserts(100)
profileNumInserts(1000)
profileNumInserts(10000)
{
"name": "automerge-play",
"version": "1.0.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
"automerge": {
"version": "0.7.7",
"resolved": "https://registry.npmjs.org/automerge/-/automerge-0.7.7.tgz",
"integrity": "sha512-FCuthCq4vwte5DH2704Be2uBjIrmk7GiB8FtoGtV9vw7RkRPo0yhrMp2tU+/Hs2qkmxNLdF5Fy4mFlMYTs+r4Q==",
"requires": {
"immutable": "^3.8.2",
"transit-immutable-js": "^0.7.0",
"transit-js": "^0.8.861",
"uuid": "^3.2.1"
}
},
"base64-js": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.0.tgz",
"integrity": "sha512-ccav/yGvoa80BQDljCxsmmQ3Xvx60/UpBIij5QN21W3wBi/hhIC9OoO+KLpu9IJTS9j4DRVJ3aDDF9cMSoa2lw=="
},
"buffer": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/buffer/-/buffer-5.1.0.tgz",
"integrity": "sha512-YkIRgwsZwJWTnyQrsBTWefizHh+8GYj3kbL1BTiAQ/9pwpino0G7B2gp5tx/FUBqUlvtxV85KNR3mwfAtv15Yw==",
"requires": {
"base64-js": "^1.0.2",
"ieee754": "^1.1.4"
}
},
"ieee754": {
"version": "1.1.11",
"resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.11.tgz",
"integrity": "sha512-VhDzCKN7K8ufStx/CLj5/PDTMgph+qwN5Pkd5i0sGnVwk56zJ0lkT8Qzi1xqWLS0Wp29DgDtNeS7v8/wMoZeHg=="
},
"immutable": {
"version": "3.8.2",
"resolved": "https://registry.npmjs.org/immutable/-/immutable-3.8.2.tgz",
"integrity": "sha1-wkOZUUVbs5kT2vKBN28VMOEErfM="
},
"object-sizeof": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/object-sizeof/-/object-sizeof-1.2.0.tgz",
"integrity": "sha1-Zjl8kjdok50vxtKjkwqYHhx/pos=",
"requires": {
"buffer": "^5.0.6"
}
},
"transit-immutable-js": {
"version": "0.7.0",
"resolved": "https://registry.npmjs.org/transit-immutable-js/-/transit-immutable-js-0.7.0.tgz",
"integrity": "sha1-mT4lCJtjEf9AIUD1VidtbSUwBdk="
},
"transit-js": {
"version": "0.8.861",
"resolved": "https://registry.npmjs.org/transit-js/-/transit-js-0.8.861.tgz",
"integrity": "sha512-4O9OrYPZw6C0M5gMTvaeOp+xYz6EF79JsyxIvqXHlt+pisSrioJWFOE80N8aCPoJLcNaXF442RZrVtdmd4wkDQ=="
},
"uuid": {
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.2.1.tgz",
"integrity": "sha512-jZnMwlb9Iku/O3smGWvZhauCf6cvvpKi4BKRiliS3cxnI+Gz9j5MEpTz2UFuXiKPJocb7gnsLHwiS05ige5BEA=="
}
}
}
{
"name": "automerge-simple-profiling-spikes",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "Aral Balkan",
"license": "MIT",
"dependencies": {
"automerge": "^0.7.7"
}
}
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