From 1b6bb03e88dddae4b5e1a4fae3544c4b70329210 Mon Sep 17 00:00:00 2001 From: Damien SAILLARD Date: Fri, 18 Apr 2014 17:54:01 +0200 Subject: [PATCH 1/4] prepare perf tests --- makefile | 7 ++++ package.json | 4 +-- test/perf/index.coffee | 73 +++++++++++++++++++++++++++++++++++++ test/unit/index.coffee | 81 +++++++++++++++++++++--------------------- 4 files changed, 122 insertions(+), 43 deletions(-) create mode 100644 test/perf/index.coffee diff --git a/makefile b/makefile index 175e0dc..7430b61 100644 --- a/makefile +++ b/makefile @@ -16,4 +16,11 @@ test-report: --reporter markdown \ test/unit > ./test-unit.md +test-perf: + @NODE_ENV=test ./node_modules/.bin/mocha $(T) \ + --compilers coffee:coffee-script \ + --recursive \ + --reporter $(REPORTER) \ + test/perf + .PHONY: test test-report diff --git a/package.json b/package.json index 0ed5b93..223a9f7 100644 --- a/package.json +++ b/package.json @@ -8,11 +8,11 @@ , "moment": "2.1.0" }, "devDependencies": { - "should": "1.2.2" - , "sinon": "v1.7.3" + "sinon": "v1.7.3" , "mocha": "1.12.1" , "async": "0.2.5" , "coffee-script": "1.5.0" + , "memwatch": "v0.2.2" }, "keywords": [ "nodeJs" diff --git a/test/perf/index.coffee b/test/perf/index.coffee new file mode 100644 index 0000000..853b4bf --- /dev/null +++ b/test/perf/index.coffee @@ -0,0 +1,73 @@ +require '../bootstrap' + +async = require 'async' +assert = require 'assert' +moment = require 'moment' +mongoose = require 'mongoose' + +Thingy = require '../models/thingy' +User = require '../models/user' + +ObjectId = mongoose.Types.ObjectId; + +describe "MongooseRattlePlugin", -> + thingy = {} + userId = new ObjectId() + + before (done) -> + async.waterfall [ + removeThingy = (next) -> + Thingy.remove next + createThingy = (numAffected, next) -> + new Thingy( + creator: userId + ).save next + addComments = (createdThingy, numAffected, next) -> + createdThingy.comments.push [ + message: 'dummy message' + creator: userId + ] + createdThingy.save next + ], (err) -> + Thingy.find (err, createdThingy) -> + thingy = createdThingy + done() + + describe "Plugin methods", -> + describe "document.getComment(commentId)", -> + it "not exceeding XKo node memory usage for the query with a document having 20 000 comments" + + describe "document.addComment(userId, message, callback)", -> + it "not exceeding XKo node memory usage for the query with a document having 20 000 comments" + + describe "document.editComment(userId, commentId, message, callback)", -> + it "not exceeding XKo node memory usage for the query with a document having 20 000 comments" + + describe "document.removeComment(userId, commentId, callback)", -> + it "not exceeding XKo node memory usage for the query with a document having 20 000 comments" + + describe "document.addLike(userId, callback)", -> + it "not exceeding XKo node memory usage for the query with a document having 20 000 comments" + + describe "document.removeLike(userId, callback)", -> + it "not exceeding XKo node memory usage for the query with a document having 20 000 comments" + + describe "document.addLikeToComment(userId, commentId, callback)", -> + it "not exceeding XKo node memory usage for the query with a document having 20 000 comments" + + describe "document.removeLikeFromComment(userId, commentId, callback)", -> + it "not exceeding XKo node memory usage for the query with a document having 20 000 comments" + + describe "Plugin statics", -> + + describe "document.getList", -> + describe "(num, maxNumLastPostComments, callback)", -> + it "not exceeding XKo node memory usage for the query with a document having 20 000 comments" + describe "(num, maxNumLastPostComments, options, callback)", -> + describe "from a creation date", -> + it "not exceeding XKo node memory usage for the query with a document having 20 000 comments" + describe "populating", -> + it "not exceeding XKo node memory usage for the query with a document having 20 000 comments" + + describe "document.getListOfCommentsById(rattleId, num, offsetFromEnd, callback)", -> + it "not exceeding XKo node memory usage for the query with a document having 20 000 comments" diff --git a/test/unit/index.coffee b/test/unit/index.coffee index b96060f..ad17cf4 100644 --- a/test/unit/index.coffee +++ b/test/unit/index.coffee @@ -4,7 +4,6 @@ async = require 'async' sinon = require 'sinon' assert = require 'assert' moment = require 'moment' -should = require 'should' mongoose = require 'mongoose' Thingy = require '../models/thingy' @@ -23,14 +22,14 @@ describe "MongooseRattlePlugin", -> describe "document.save(callback)", -> it "update dateCreation and dateUpdate when inserting", (done) -> clock = sinon.useFakeTimers() - new Thingy(creator: objectCreatorUserId, owner: objectCreatorUserId).save (err, thingySaved) -> + new Thingy(creator: objectCreatorUserId).save (err, thingySaved) -> assert.deepEqual(new Date(), thingySaved.dateCreation) assert.deepEqual(new Date(), thingySaved.dateUpdate) clock.restore() done() it "only update dateUpdate when updating", (done) -> clock = sinon.useFakeTimers(new Date(2011, 0, 1, 1, 1, 36).getTime()) - new Thingy(creator: objectCreatorUserId, owner: objectCreatorUserId).save (err, thingySaved) -> + new Thingy(creator: objectCreatorUserId).save (err, thingySaved) -> clock.restore() clock = sinon.useFakeTimers(new Date(2012, 0, 1, 1, 1, 36).getTime()) thingySaved.save (err, thingySaved) -> @@ -41,7 +40,7 @@ describe "MongooseRattlePlugin", -> describe "Plugin methods", -> beforeEach (done) -> - new Thingy(creator: objectCreatorUserId, owner: objectCreatorUserId).save (err, thingySaved) -> + new Thingy(creator: objectCreatorUserId).save (err, thingySaved) -> thingy = thingySaved done() @@ -75,10 +74,10 @@ describe "MongooseRattlePlugin", -> describe "document.addComment(userId, message, callback)", -> it "append a new comment and return comment id", (done) -> commentId = thingy.addComment commentorUserId, 'dummy message', (err) -> - should.not.exists(err) - should.exists(commentId) + assert !err + assert commentId Thingy.findById thingy._id, (err, updatedThingy) -> - should.exists(updatedThingy) + assert updatedThingy assert.equal(1, updatedThingy.comments.length) done() it "update dateCreation and dateUpdated", (done) -> @@ -90,7 +89,7 @@ describe "MongooseRattlePlugin", -> done() it "fails if message length is out of min and max", (done) -> thingy.addComment commentorUserId, '', (err) -> - should.exists(err) + assert err done() describe "document.editComment(userId, commentId, message, callback)", -> @@ -104,20 +103,20 @@ describe "MongooseRattlePlugin", -> it "fails if message length is out of min and max", (done) -> thingy.editComment commentorUserId, commentId, '', (err) -> - should.exists(err) + assert err done() describe 'when user is not the creator', -> it "always fails", (done) -> thingy.editComment 'n0t3x1t1n9', commentId, updatedMessage, (err) -> - should.exists(err) + assert err done() describe 'when user is the creator', -> checkEditCommentWhenOwner = (commentorUserId, commentId, updatedMessage, done) -> thingy.editComment commentorUserId, commentId, updatedMessage, (err) -> - should.not.exists(err) - should.exists(commentId) + assert !err + assert commentId Thingy.findById thingy._id, (err, updatedThingy) -> - should.exists(updatedThingy) + assert updatedThingy assert.equal(1, updatedThingy.comments.length) assert.equal(updatedMessage, updatedThingy.comments[0].message) done() @@ -150,29 +149,29 @@ describe "MongooseRattlePlugin", -> it "fails if comment doesn't exist", (done) -> thingy.removeComment commentorUserId, 'n0t3x1t1n9', (err, updatedThingy) -> - should.exists(err) + assert err done() describe 'when user is not the creator', -> it "it's not removing the comment", (done) -> thingy.removeComment 'n0t3x1t1n9', commentIds['level 1'], (err, updatedThingy) -> - should.exists(updatedThingy) - should.exists(updatedThingy.getComment(commentIds['level 1'])) + assert updatedThingy + assert updatedThingy.getComment(commentIds['level 1']) done() describe 'when user is the creator', -> it "can remove comment", (done) -> thingy.removeComment commentorUserId, commentIds['level 1'], (err, updatedThingy) -> - should.exists(updatedThingy) - should.not.exists(updatedThingy.getComment(commentIds['level 1'])) + assert updatedThingy + assert !updatedThingy.getComment(commentIds['level 1']) done() it "remove comment when userId param is a string", (done) -> thingy.removeComment String(commentorUserId), commentIds['level 1'], (err, updatedThingy) -> - should.exists(updatedThingy) - should.not.exists(updatedThingy.getComment(commentIds['level 1'])) + assert updatedThingy + assert !updatedThingy.getComment(commentIds['level 1']) done() it "remove comment when commentId is a string", (done) -> thingy.removeComment commentorUserId, String(commentIds['level 1']), (err, updatedThingy) -> - should.exists(updatedThingy) - should.not.exists(updatedThingy.getComment(commentIds['level 1'])) + assert updatedThingy + assert !updatedThingy.getComment(commentIds['level 1']) done() describe "document.addLike(userId, callback)", -> @@ -253,7 +252,7 @@ describe "MongooseRattlePlugin", -> it "fails if comment doesn't exist", (done) -> thingy.addLikeToComment commentorUserId, 'n0t3x1t1n9', (err, updatedThingy) -> - should.exists(err) + assert err done() it "add one user like if user doesn't already liked and comment exists", (done) -> thingy.addLikeToComment commentorUserId, commentId, (err, updatedThingy) -> @@ -285,7 +284,7 @@ describe "MongooseRattlePlugin", -> it "fails if comment doesn't exist", (done) -> thingy.removeLikeFromComment commentorUserId, 'n0t3x1t1n9', (err, updatedThingy) -> - should.exists(err) + assert err done() it "not affect current likes list if user didn'nt already liked", (done) -> thingy.removeLikeFromComment new ObjectId(), commentId, (err, updatedThingy) -> @@ -335,7 +334,7 @@ describe "MongooseRattlePlugin", -> it "get list of the number of 'num' last rattles and return likesCount instead of likes array", (done) -> Thingy.find {}, (err, rattles) -> Thingy.getList 1, 0, (err, rattles) -> - should.not.exists(err) + assert !err assert.equal rattles.length, 1 assert.deepEqual rattles[0].creator, creator2Id assert !rattles[0].likes @@ -343,23 +342,23 @@ describe "MongooseRattlePlugin", -> done() it "get all rattles if 'num' is greater than the number of rattles", (done) -> Thingy.getList 3, 0, (err, rattles) -> - should.not.exists(err) + assert !err assert.equal rattles.length, 2 done() it "each rattle get the maximum of 'maxLastComments' last comments", (done) -> Thingy.getList 1, 1, (err, rattles) -> - should.not.exists(err) + assert !err assert.equal rattles.length, 1 assert.deepEqual rattles[0].creator, creator2Id - should.exists(rattles[0].comments) + assert rattles[0].comments assert.equal rattles[0].comments.length, 1 assert.equal rattles[0].comments[0].message, '22' done() it "each all comments when 'maxLastComments' is greater than number of comments", (done) -> Thingy.getList 1, 3, (err, rattles) -> - should.not.exists(err) + assert !err assert.equal rattles.length, 1 - should.exists(rattles[0].comments) + assert rattles[0].comments assert.equal rattles[0].comments.length, 2 done() describe "(num, maxNumLastPostComments, options, callback)", -> @@ -368,7 +367,7 @@ describe "MongooseRattlePlugin", -> # retrieve last rattle Thingy.getList 1, 0, (err, rattles) -> Thingy.getList 1, 0, fromCreationDate: rattles[0].dateCreation, (err, rattles) -> - should.not.exists(err) + assert !err assert.equal rattles.length, 1 assert.deepEqual rattles[0].creator, creator1Id done() @@ -376,17 +375,17 @@ describe "MongooseRattlePlugin", -> # retrieve last rattle Thingy.getList 1, 0, (err, rattles) -> Thingy.getList 2, 0, fromCreationDate: rattles[0].dateCreation, (err, rattles) -> - should.not.exists(err) + assert !err assert.equal rattles.length, 1 done() it "each rattle get the maximum of 'maxLastComments' last comments", (done) -> # retrieve last rattle Thingy.getList 1, 0, (err, rattles) -> Thingy.getList 1, 1, fromCreationDate: rattles[0].dateCreation, (err, rattles) -> - should.not.exists(err) + assert !err assert.equal rattles.length, 1 assert.deepEqual rattles[0].creator, creator1Id - should.exists(rattles[0].comments) + assert rattles[0].comments assert.equal rattles[0].comments.length, 1 assert.equal rattles[0].comments[0].message, '12' done() @@ -395,9 +394,9 @@ describe "MongooseRattlePlugin", -> new User({_id: creator2Id, name: 'Dummy Name'}).save (err) -> # retrieve last rattle Thingy.getList 1, 0, {populate: 'creator'}, (err, rattles) -> - should.not.exists(err) + assert !err assert.equal rattles.length, 1 - should.exists(rattles[0].creator.name) + assert rattles[0].creator.name assert.equal rattles[0].creator.name, 'Dummy Name' done() @@ -431,31 +430,31 @@ describe "MongooseRattlePlugin", -> it "get last 'num' of comments for 'rattleId' when offsetFromEnd is 0", (done) -> Thingy.getListOfCommentsById rattleId, 1, 0, (err, comments) -> - should.not.exists(err) + assert !err assert.equal comments.length, 1 assert.equal comments[0].message, '13' done() it "get last num of comments from the offsetFromEnd", (done) -> Thingy.getListOfCommentsById rattleId, 1, 1, (err, comments) -> - should.not.exists(err) + assert !err assert.equal comments.length, 1 assert.equal comments[0].message, '12' done() it "get no comments when offsetFromEnd is equal to the number of comments", (done) -> Thingy.getListOfCommentsById rattleId, 1, 3, (err, comments) -> - should.not.exists(err) + assert !err assert.equal comments.length, 0 done() it "limit comments when offsetFromEnd + num is greater that the number of comments", (done) -> Thingy.getListOfCommentsById rattleId, 3, 1, (err, comments) -> - should.not.exists(err) + assert !err assert.equal comments[0].message, '11' assert.equal comments[1].message, '12' assert.equal comments.length, 2 done() it "keep comments order", (done) -> Thingy.getListOfCommentsById rattleId, 3, 0, (err, comments) -> - should.not.exists(err) + assert !err assert.equal comments[0].message, '11' assert.equal comments[1].message, '12' assert.equal comments[2].message, '13' From c980d87791ff43e4f1ab69ac6024dfdd5201dffe Mon Sep 17 00:00:00 2001 From: Damien SAILLARD Date: Tue, 22 Apr 2014 18:18:35 +0200 Subject: [PATCH 2/4] add script to generate big media --- makefile | 1 + test/perf/data.coffee | 71 ++++++++++++++++++++++++++++++++++++++++++ test/perf/index.coffee | 35 ++++++++++++++++----- 3 files changed, 100 insertions(+), 7 deletions(-) create mode 100644 test/perf/data.coffee diff --git a/makefile b/makefile index 7430b61..0c357ba 100644 --- a/makefile +++ b/makefile @@ -21,6 +21,7 @@ test-perf: --compilers coffee:coffee-script \ --recursive \ --reporter $(REPORTER) \ + --timeout 5000 \ test/perf .PHONY: test test-report diff --git a/test/perf/data.coffee b/test/perf/data.coffee new file mode 100644 index 0000000..08b9987 --- /dev/null +++ b/test/perf/data.coffee @@ -0,0 +1,71 @@ +mongoose = require 'mongoose' +async = require 'async' + +mongoose.connect "mongodb://127.0.0.1:27017/mongoose-rattle-test-perf", {}, (err) -> + throw err if err + +Thingy = require '../models/thingy' + +ObjectId = mongoose.Types.ObjectId; + +numLikes = 20000 +numCommentLikes = 20 +blockNumComments = 5000 +numBlocks = 4 + +thingy = {} +userId = new ObjectId() + +i = 0 +likes = [] +while i < numCommentLikes + likes.push new ObjectId() + i++ + +dummyComment = + message: 'duuuuuuuuuuuummmmmmmmmmmmmmmmyyyyyyyyyyyyy meeeeeeeeeeeeessssssssssssaaaaaaaaaaaaaageeeeee' + creator: new ObjectId() + likes: likes + likesCount: type: Number, default: 0 + dateCreation: type: Date + dateUpdate: type: Date + +i = 0 +comments = [] +while i < blockNumComments + comments.push dummyComment + i++ + +async.waterfall [ + removeThingy = (next) -> + console.log('Clear thingy collection'); + Thingy.remove next + createThingy = (numAffected, next) -> + console.log('Create a new thingy'); + new Thingy( + creator: userId + ).save next + addComments = (createdThingy, numAffected, next) -> + console.log('Add comments with likes'); + + i = 0 + async.whilst (-> + i < numBlocks + ), ((callback) -> + console.log('Add block ' + (i + 1) + ' of ' + blockNumComments + ' comments'); + Thingy.update { _id: createdThingy._id }, { $pushAll: { comments: comments } }, (err) -> + i++ + callback() + ), (err) -> + console.log('Add likes'); + i = 0 + likes = [] + while i < numLikes + likes.push new ObjectId() + i++ + createdThingy.likes = likes + createdThingy.save next + +], (err) -> + console.log('Thingy saved'); + process.exit(1); diff --git a/test/perf/index.coffee b/test/perf/index.coffee index 853b4bf..a516ac2 100644 --- a/test/perf/index.coffee +++ b/test/perf/index.coffee @@ -1,15 +1,19 @@ -require '../bootstrap' +mongoose = require 'mongoose' + +mongoose.connect "mongodb://127.0.0.1:27017/mongoose-rattle-test-perf", {}, (err) -> + throw err if err async = require 'async' assert = require 'assert' -moment = require 'moment' -mongoose = require 'mongoose' Thingy = require '../models/thingy' User = require '../models/user' ObjectId = mongoose.Types.ObjectId; +numLikes = 100 +numComments = 1000 + describe "MongooseRattlePlugin", -> thingy = {} userId = new ObjectId() @@ -23,10 +27,27 @@ describe "MongooseRattlePlugin", -> creator: userId ).save next addComments = (createdThingy, numAffected, next) -> - createdThingy.comments.push [ - message: 'dummy message' - creator: userId - ] + i = 0 + likes = [] + while i < numLikes + likes.push new ObjectId() + i++ + + dummyComment = + message: 'duuuuuuuuuuuummmmmmmmmmmmmmmmyyyyyyyyyyyyy meeeeeeeeeeeeessssssssssssaaaaaaaaaaaaaageeeeee' + creator: new ObjectId() + likes: likes + likesCount: type: Number, default: 0 + dateCreation: type: Date + dateUpdate: type: Date + + comments = [] + i = 0 + while i < numComments + comments.push dummyComment + i++ + + createdThingy.comments = comments createdThingy.save next ], (err) -> Thingy.find (err, createdThingy) -> From 624497bc27e4e36a895857ae602fc47ad32f242d Mon Sep 17 00:00:00 2001 From: Damien SAILLARD Date: Fri, 25 Apr 2014 18:06:18 +0200 Subject: [PATCH 3/4] try benchmark --- package.json | 2 + test/bootstrap-perf.coffee | 4 ++ test/perf-data.coffee | 86 ++++++++++++++++++++++++++++++++++++++ test/perf-stats.coffee | 47 +++++++++++++++++++++ test/perf/data.coffee | 71 ------------------------------- test/perf/index.coffee | 71 ++++++++++--------------------- 6 files changed, 162 insertions(+), 119 deletions(-) create mode 100644 test/bootstrap-perf.coffee create mode 100644 test/perf-data.coffee create mode 100644 test/perf-stats.coffee delete mode 100644 test/perf/data.coffee diff --git a/package.json b/package.json index 223a9f7..dc75409 100644 --- a/package.json +++ b/package.json @@ -13,6 +13,8 @@ , "async": "0.2.5" , "coffee-script": "1.5.0" , "memwatch": "v0.2.2" + , "winston": "v0.7.3" + , "chalk": "v0.4.0" }, "keywords": [ "nodeJs" diff --git a/test/bootstrap-perf.coffee b/test/bootstrap-perf.coffee new file mode 100644 index 0000000..f52e420 --- /dev/null +++ b/test/bootstrap-perf.coffee @@ -0,0 +1,4 @@ +mongoose = require 'mongoose' + +mongoose.connect "mongodb://127.0.0.1:27017/mongoose-rattle-test-perf", {}, (err) -> + throw err if err diff --git a/test/perf-data.coffee b/test/perf-data.coffee new file mode 100644 index 0000000..14bc944 --- /dev/null +++ b/test/perf-data.coffee @@ -0,0 +1,86 @@ +require './bootstrap-perf' + +mongoose = require 'mongoose' +async = require 'async' +winston = require 'winston' + +winston.remove winston.transports.Console +winston.add winston.transports.Console, colorize: true + +Thingy = require './models/thingy' + +ObjectId = mongoose.Types.ObjectId; + +numThingies = 5 +numLikes = 20000 +numCommentLikes = 20 +blockNumComments = 5000 +numBlocks = 4 + +i = 0 +likes = [] +while i < numCommentLikes + likes.push new ObjectId() + i++ + +dummyComment = + message: 'duuuuuuuuuuuummmmmmmmmmmmmmmmyyyyyyyyyyyyy meeeeeeeeeeeeessssssssssssaaaaaaaaaaaaaageeeeee' + creator: new ObjectId() + likes: likes + likesCount: type: Number, default: 0 + dateCreation: type: Date + dateUpdate: type: Date + +i = 0 +comments = [] +while i < blockNumComments + comments.push dummyComment + i++ + +createNewThingy = (callback) -> + async.waterfall [ + createThingy = (next) -> + winston.info('Create a new thingy'); + new Thingy( + creator: new ObjectId() + ).save next + addComments = (createdThingy, numAffected, next) -> + winston.info('Add comments with likes'); + + i = 0 + async.whilst (-> + i < numBlocks + ), ((callback) -> + winston.info('Add block ' + (i + 1) + ' of ' + blockNumComments + ' comments'); + Thingy.update { _id: createdThingy._id }, { $pushAll: { comments: comments } }, (err) -> + i++ + callback() + ), (err) -> + winston.info('Add likes'); + i = 0 + likes = [] + while i < numLikes + likes.push new ObjectId() + i++ + createdThingy.likes = likes + createdThingy.save next + + ], (err) -> + return callback(err) if err + winston.info('Thingy saved'); + callback() + + +winston.info('Clear thingy collection'); +Thingy.remove (err) -> + count = 0 + async.whilst (-> + count < numThingies + ), ((next) -> + createNewThingy (err) -> + return next(err) if err + count++ + next() + ), (err) -> + winston.error err if err + process.exit(1); \ No newline at end of file diff --git a/test/perf-stats.coffee b/test/perf-stats.coffee new file mode 100644 index 0000000..85dc08f --- /dev/null +++ b/test/perf-stats.coffee @@ -0,0 +1,47 @@ +require './bootstrap-perf' + +mongoose = require 'mongoose' +async = require 'async' +memwatch = require 'memwatch' +chalk = require 'chalk' + +log = (level, msg) -> + console.log(Array(level).join(' ') + msg) +title = (msg) -> + log(1, chalk.bold.magenta.underline(msg)) +description = (msg) -> + log(1, chalk.bold.italic(msg)) +target = (msg) -> + log(2, chalk.green(msg)) +task = (msg) -> + log(3, chalk.yellow(msg)) +info = (msg) -> + log(4, chalk.blue(msg)) + +Thingy = require './models/thingy' + +title('Benchmarking rattle plugin') +description('In collections: 2 documents with 20000 likes, 20000 comments with 20 likes each') + +async.series [ + getList = (done) -> + target('#getList') + task('retrieve two document with the last two comments') + count = 1 + async.whilst (-> + count <= 5 + ), ((next) -> + task('try ' + count) + # hd = new memwatch.HeapDiff() + start = Date.now() + Thingy.getList 2, 0, (err, thingies) -> + # diff = hd.end() + end = Date.now() + count++ + # log.info('memory diff after the operation (in bytes): ' + diff.change.size_bytes) + info('time for the operation (in ms): ' + (end - start)) + next() + return + ), done +], (err) -> + process.exit(1); diff --git a/test/perf/data.coffee b/test/perf/data.coffee deleted file mode 100644 index 08b9987..0000000 --- a/test/perf/data.coffee +++ /dev/null @@ -1,71 +0,0 @@ -mongoose = require 'mongoose' -async = require 'async' - -mongoose.connect "mongodb://127.0.0.1:27017/mongoose-rattle-test-perf", {}, (err) -> - throw err if err - -Thingy = require '../models/thingy' - -ObjectId = mongoose.Types.ObjectId; - -numLikes = 20000 -numCommentLikes = 20 -blockNumComments = 5000 -numBlocks = 4 - -thingy = {} -userId = new ObjectId() - -i = 0 -likes = [] -while i < numCommentLikes - likes.push new ObjectId() - i++ - -dummyComment = - message: 'duuuuuuuuuuuummmmmmmmmmmmmmmmyyyyyyyyyyyyy meeeeeeeeeeeeessssssssssssaaaaaaaaaaaaaageeeeee' - creator: new ObjectId() - likes: likes - likesCount: type: Number, default: 0 - dateCreation: type: Date - dateUpdate: type: Date - -i = 0 -comments = [] -while i < blockNumComments - comments.push dummyComment - i++ - -async.waterfall [ - removeThingy = (next) -> - console.log('Clear thingy collection'); - Thingy.remove next - createThingy = (numAffected, next) -> - console.log('Create a new thingy'); - new Thingy( - creator: userId - ).save next - addComments = (createdThingy, numAffected, next) -> - console.log('Add comments with likes'); - - i = 0 - async.whilst (-> - i < numBlocks - ), ((callback) -> - console.log('Add block ' + (i + 1) + ' of ' + blockNumComments + ' comments'); - Thingy.update { _id: createdThingy._id }, { $pushAll: { comments: comments } }, (err) -> - i++ - callback() - ), (err) -> - console.log('Add likes'); - i = 0 - likes = [] - while i < numLikes - likes.push new ObjectId() - i++ - createdThingy.likes = likes - createdThingy.save next - -], (err) -> - console.log('Thingy saved'); - process.exit(1); diff --git a/test/perf/index.coffee b/test/perf/index.coffee index a516ac2..dadd10b 100644 --- a/test/perf/index.coffee +++ b/test/perf/index.coffee @@ -1,58 +1,17 @@ -mongoose = require 'mongoose' - -mongoose.connect "mongodb://127.0.0.1:27017/mongoose-rattle-test-perf", {}, (err) -> - throw err if err +require '../bootstrap-perf' +mongoose = require 'mongoose' async = require 'async' assert = require 'assert' +memwatch = require 'memwatch' Thingy = require '../models/thingy' -User = require '../models/user' - -ObjectId = mongoose.Types.ObjectId; - -numLikes = 100 -numComments = 1000 describe "MongooseRattlePlugin", -> - thingy = {} - userId = new ObjectId() - before (done) -> - async.waterfall [ - removeThingy = (next) -> - Thingy.remove next - createThingy = (numAffected, next) -> - new Thingy( - creator: userId - ).save next - addComments = (createdThingy, numAffected, next) -> - i = 0 - likes = [] - while i < numLikes - likes.push new ObjectId() - i++ - - dummyComment = - message: 'duuuuuuuuuuuummmmmmmmmmmmmmmmyyyyyyyyyyyyy meeeeeeeeeeeeessssssssssssaaaaaaaaaaaaaageeeeee' - creator: new ObjectId() - likes: likes - likesCount: type: Number, default: 0 - dateCreation: type: Date - dateUpdate: type: Date - - comments = [] - i = 0 - while i < numComments - comments.push dummyComment - i++ - - createdThingy.comments = comments - createdThingy.save next - ], (err) -> - Thingy.find (err, createdThingy) -> - thingy = createdThingy - done() + Thingy.count (err, count) -> + throw new Error('You should populate with command "coffee test/perf-data"') if count is 0 + done() describe "Plugin methods", -> describe "document.getComment(commentId)", -> @@ -83,7 +42,23 @@ describe "MongooseRattlePlugin", -> describe "document.getList", -> describe "(num, maxNumLastPostComments, callback)", -> - it "not exceeding XKo node memory usage for the query with a document having 20 000 comments" + it "not exceeding 800Ko node memory usage for the operation", (done) -> + count = 0 + async.whilst (-> + count < 3 + ), ((next) -> + hd = new memwatch.HeapDiff() + start = Date.now() + Thingy.getList 1, 1, (err, thingies) -> + diff = hd.end() + end = Date.now() + count++ + assert.equal thingies.length, 1 + assert parseFloat(diff.change.size_bytes) < 100000 + console.log(end - start); + next() + return + ), done describe "(num, maxNumLastPostComments, options, callback)", -> describe "from a creation date", -> it "not exceeding XKo node memory usage for the query with a document having 20 000 comments" From f6974aa3a1d8b5ef8a02c8ffd513c000a3c62580 Mon Sep 17 00:00:00 2001 From: Damien SAILLARD Date: Tue, 16 Sep 2014 15:00:33 +0200 Subject: [PATCH 4/4] idea --- test/perf-stats.coffee | 71 ++++++++++++++++++++++++++++++------------ test/perf/index.coffee | 69 ---------------------------------------- 2 files changed, 51 insertions(+), 89 deletions(-) delete mode 100644 test/perf/index.coffee diff --git a/test/perf-stats.coffee b/test/perf-stats.coffee index 85dc08f..8f38e9d 100644 --- a/test/perf-stats.coffee +++ b/test/perf-stats.coffee @@ -13,35 +13,66 @@ description = (msg) -> log(1, chalk.bold.italic(msg)) target = (msg) -> log(2, chalk.green(msg)) -task = (msg) -> - log(3, chalk.yellow(msg)) info = (msg) -> log(4, chalk.blue(msg)) Thingy = require './models/thingy' -title('Benchmarking rattle plugin') +numOccurence = 3 + +# hd = new memwatch.HeapDiff() +# diff = hd.end() +# log.info('memory diff after the operation (in bytes): ' + diff.change.size_bytes) + +task = () -> + msg = arguments[0] + obj = arguments[1] + fctName = arguments[2] + args = Array::slice.call(arguments, 3, arguments.length - 1) + callback = arguments[arguments.length - 1] + + log(3, chalk.yellow(msg)) + count = 1 + totalTime = 0 + async.whilst (-> + count <= numOccurence + ), ((next) -> + start = Date.now() + + cb = (err) -> + return next(err) if err + end = Date.now() + time = end - start + totalTime += time + info("[iteration #{count}] time for the operation (in ms): #{time}") + count++ + next() + + fctArgs = args.slice(0) + fctArgs.push(cb) + obj[fctName].apply obj, fctArgs + return + ), (err) -> + return callback(err) if err + avg = Math.ceil(totalTime / numOccurence) + info("=> average time: #{avg}") + callback() + +title("Benchmarking rattle plugin (number of occurence: #{numOccurence})") description('In collections: 2 documents with 20000 likes, 20000 comments with 20 likes each') +# describe 'Thingy', -> +# describe 'getList', -> +# analyse('retrieve 2 documents with no comments', Thingy, 'getList', 2, 0, next) +# analyse('retrieve 3 documents with the last 5 comments', Thingy, 'getList', 3, 5, next) + async.series [ getList = (done) -> target('#getList') - task('retrieve two document with the last two comments') - count = 1 - async.whilst (-> - count <= 5 - ), ((next) -> - task('try ' + count) - # hd = new memwatch.HeapDiff() - start = Date.now() - Thingy.getList 2, 0, (err, thingies) -> - # diff = hd.end() - end = Date.now() - count++ - # log.info('memory diff after the operation (in bytes): ' + diff.change.size_bytes) - info('time for the operation (in ms): ' + (end - start)) - next() - return - ), done + async.series [ + (next) -> + task('retrieve two documents with no comments', Thingy, 'getList', 2, 0, next) + ], done + ], (err) -> process.exit(1); diff --git a/test/perf/index.coffee b/test/perf/index.coffee deleted file mode 100644 index dadd10b..0000000 --- a/test/perf/index.coffee +++ /dev/null @@ -1,69 +0,0 @@ -require '../bootstrap-perf' - -mongoose = require 'mongoose' -async = require 'async' -assert = require 'assert' -memwatch = require 'memwatch' - -Thingy = require '../models/thingy' - -describe "MongooseRattlePlugin", -> - before (done) -> - Thingy.count (err, count) -> - throw new Error('You should populate with command "coffee test/perf-data"') if count is 0 - done() - - describe "Plugin methods", -> - describe "document.getComment(commentId)", -> - it "not exceeding XKo node memory usage for the query with a document having 20 000 comments" - - describe "document.addComment(userId, message, callback)", -> - it "not exceeding XKo node memory usage for the query with a document having 20 000 comments" - - describe "document.editComment(userId, commentId, message, callback)", -> - it "not exceeding XKo node memory usage for the query with a document having 20 000 comments" - - describe "document.removeComment(userId, commentId, callback)", -> - it "not exceeding XKo node memory usage for the query with a document having 20 000 comments" - - describe "document.addLike(userId, callback)", -> - it "not exceeding XKo node memory usage for the query with a document having 20 000 comments" - - describe "document.removeLike(userId, callback)", -> - it "not exceeding XKo node memory usage for the query with a document having 20 000 comments" - - describe "document.addLikeToComment(userId, commentId, callback)", -> - it "not exceeding XKo node memory usage for the query with a document having 20 000 comments" - - describe "document.removeLikeFromComment(userId, commentId, callback)", -> - it "not exceeding XKo node memory usage for the query with a document having 20 000 comments" - - describe "Plugin statics", -> - - describe "document.getList", -> - describe "(num, maxNumLastPostComments, callback)", -> - it "not exceeding 800Ko node memory usage for the operation", (done) -> - count = 0 - async.whilst (-> - count < 3 - ), ((next) -> - hd = new memwatch.HeapDiff() - start = Date.now() - Thingy.getList 1, 1, (err, thingies) -> - diff = hd.end() - end = Date.now() - count++ - assert.equal thingies.length, 1 - assert parseFloat(diff.change.size_bytes) < 100000 - console.log(end - start); - next() - return - ), done - describe "(num, maxNumLastPostComments, options, callback)", -> - describe "from a creation date", -> - it "not exceeding XKo node memory usage for the query with a document having 20 000 comments" - describe "populating", -> - it "not exceeding XKo node memory usage for the query with a document having 20 000 comments" - - describe "document.getListOfCommentsById(rattleId, num, offsetFromEnd, callback)", -> - it "not exceeding XKo node memory usage for the query with a document having 20 000 comments"