in perftest/jscrund.js [392:846]
function main() {
var config_file_exists = false;
/* Default options: */
var options = {
'doClass' : 'A',
'adapter' : 'ndb',
'database': 'jscrund',
'modes': 'indy,each,bulk',
'tests': null,
'iterations': [4000],
'stats': false,
'spi': false,
'log': false,
'nRuns': 1,
'setProp' : {},
'delay_pre' : 0,
'delay_post' : 0,
'B_varchar_size' : 10,
'deployment' : 'test'
};
/* Options from config file */
try {
var config_file = require("./jscrund.config");
config_file_exists = true;
for(var i in config_file.options) {
if(config_file.options.hasOwnProperty(i)) {
options[i] = config_file.options[i];
}
}
}
catch(e) {
if (e.message.indexOf('Cannot find module') === -1) {
console.log(e);
console.log(e.name, 'reading jscrund.config:', e.message, '\nPlease correct this error and try again.\n');
process.exit(0);
}
}
/* Options from command line */
parse_command_line(options);
if (options.exit) {
usage();
process.exit(0);
}
/* Global udebug level; may have been set by options */
DEBUG = JSCRUND.udebug.is_debug();
DETAIL = JSCRUND.udebug.is_detail();
/* Create the string value for varchar tests */
if(options.B_varchar_size > 0) {
options.B_varchar_value = "";
for(var i = 0 ; i < options.B_varchar_size ; i++) {
options.B_varchar_value += String.fromCharCode(48 + (i % 64));
}
}
/* Fetch the backend implementation */
if(options.spi) {
JSCRUND.spiAdapter = require('./jscrund_dbspi');
JSCRUND.implementation = new JSCRUND.spiAdapter.implementation();
} else if(options.adapter == 'sql') {
JSCRUND.sqlAdapter = require('./jscrund_sql');
JSCRUND.implementation = new JSCRUND.sqlAdapter.implementation();
} else if(options.adapter == 'null') {
JSCRUND.nullAdapter = require('./jscrund_null');
JSCRUND.implementation = new JSCRUND.nullAdapter.implementation();
} else {
JSCRUND.implementation = new JSCRUND.mysqljs.implementation();
}
/* Get connection properties */
var properties;
if(typeof JSCRUND.implementation.getConnectionProperties === 'function') {
properties = JSCRUND.implementation.getConnectionProperties();
} else {
properties = new JSCRUND.mynode.ConnectionProperties(options.adapter, options.deployment);
}
/* Then mix in properties from the command line */
properties.database = options.database;
for(i in options.setProp) {
if(options.setProp.hasOwnProperty(i)) {
properties[i] = options.setProp[i];
}
}
/* Finally store the complete properties object in the options */
options.properties = properties;
/* Force GC is available if node is run with the --expose-gc option
*/
options.use_gc = ( typeof global.gc === 'function' );
var logFile = new ResultLog(options.log);
new JSCRUND.mynode.TableMapping("a").applyToClass(A);
new JSCRUND.mynode.TableMapping("b").applyToClass(B);
options.annotations = [ A, B ];
var generateAllParameters = function(numberOfParameters) {
var result = [];
for (var i = 0; i < numberOfParameters; ++i) {
result[i] = generateParameters(i);
}
return result;
};
var generateParameters = function(i) {
return {'key': generateKey(i), 'object': generateObject(i)};
};
var generateKey = function(i) {
return i;
};
var generateObject = function(i) {
var result;
if(options.doClass == "A") {
result = new A();
} else if(options.doClass == "B") {
result = new B();
} else {
assert(false);
}
result.init(i);
return result;
};
// mainTestLoop (-r 10)
// batchSizeLoop (-i 1,10,100)
// ModeLoop (--modes=indy,each)
// TestsLoop (--tests=persist,remove)
var runTests = function(options) {
var timer = new Timer();
var modeNames = options.modes.split('\,');
var modeNumber = 0;
var mode;
var modeName;
var testNames;
var testNumber = 0;
var operation;
var testName;
var key;
var object;
var numberOfBatchLoops = options.iterations.length;
var batchLoopNumber = 0;
var numberOfIterations;
var iteration;
var nRun = 0;
var nRuns = (options.nRuns < 0 ? Infinity : options.nRuns);
var nReport = 0;
var operationsDoneCallback;
var testsDoneCallback;
var resultStats = [];
var parameters;
/* Which tests to run */
if(options.tests) { // Explicit test names
testNames = options.tests.split('\,');
} else {
switch(options.doClass) {
case 'B':
testNames = [ 'persist', 'setVarchar', 'find', 'clearVarchar', 'remove' ];
break;
case 'A':
default:
testNames = [ 'persist', 'find', 'remove' ];
break;
};
}
/** Recursively call the operation numberOfIterations times in autocommit mode
* and then call the operationsDoneCallback
*/
var indyOperationsLoop = function(err) {
if(DETAIL) JSCRUND.udebug.log_detail('jscrund.indyOperationsLoop iteration:', iteration, 'err:', err);
// check result
if (err) {
appendError(err);
}
// call implementation operation
if (iteration < numberOfIterations) {
operation.apply(JSCRUND.implementation, [parameters[iteration], indyOperationsLoop]);
iteration++;
} else {
if(DETAIL) JSCRUND.udebug.log_detail('jscrund.indyOperationsLoop iteration:', iteration, 'complete.');
timer.stop();
resultStats.push({
name: testName + "," + modeName,
time: timer.interval
});
setImmediate(operationsDoneCallback);
}
};
/** Call indyOperationsLoop for all of the tests in testNames
*/
var indyTestsLoop = function() {
testName = testNames[testNumber];
operation = JSCRUND.implementation[testName];
operationsDoneCallback = indyTestsLoop;
if (testNumber < testNames.length) {
if(options.use_gc) global.gc(); // Full GC between tests
testNumber++;
if(DETAIL) JSCRUND.udebug.log_detail('jscrund.indyTestsLoop', testNumber, 'of', testNames.length, ':', testName);
iteration = 0;
timer.start(modeName, testName, numberOfIterations);
setImmediate(indyOperationsLoop, null);
} else {
// done with all indy tests
// stop timer and report
setImmediate(testsDoneCallback);
}
};
/** Finish the each operations loop after commit.
*/
var eachCommitDoneCallback = function(err) {
// check result
if (err) {
appendError(err);
}
timer.stop();
resultStats.push({
name: testName + "," + modeName,
time: timer.interval
});
setImmediate(operationsDoneCallback);
};
/** Call the operation numberOfIterations times within a transaction
* and then call the operationsDoneCallback
*/
var eachOperationsLoop = function(err) {
if(DETAIL) JSCRUND.udebug.log_detail('jscrund.eachOperationsLoop iteration:', iteration, 'err:', err);
// check result
if (err) {
appendError(err);
}
// call implementation operation
if (iteration < numberOfIterations) {
operation.apply(JSCRUND.implementation, [parameters[iteration], eachOperationsLoop]);
iteration++;
} else {
if(DETAIL) JSCRUND.udebug.log_detail('jscrund.eachOperationLoop iteration:', iteration, 'complete.');
JSCRUND.implementation.commit(eachCommitDoneCallback);
}
};
/** Call eachOperationsLoop for all of the tests in testNames
*/
var eachTestsLoop = function() {
testName = testNames[testNumber];
operation = JSCRUND.implementation[testName];
operationsDoneCallback = eachTestsLoop;
if (testNumber < testNames.length) {
if(options.use_gc) global.gc(); // Full GC between tests
testNumber++;
if(DETAIL) JSCRUND.udebug.log_detail('jscrund.eachTestsLoop', testNumber, 'of', testNames.length, ':', testName);
iteration = 0;
timer.start(modeName, testName, numberOfIterations);
JSCRUND.implementation.begin(function(err) {
setImmediate(eachOperationsLoop, null);
});
} else {
// done with all each tests
// stop timer and report
testsDoneCallback();
}
};
/** Check the results of a bulk execute.
*/
var bulkCheckBatchCallback = function(err) {
if(DETAIL) JSCRUND.udebug.log_detail('jscrund.bulkCheckBatchCallback', err);
// check result
if (err) {
appendError(err);
}
timer.stop();
resultStats.push({
name: testName + "," + modeName,
time: timer.interval
});
setImmediate(bulkTestsLoop);
};
/** Check the results of a bulk operation. It will be executed
* numberOfIterations times per test.
*/
var bulkCheckOperationCallback = function(err) {
if(DETAIL) JSCRUND.udebug.log_detail('jscrund.bulkCheckOperationCallback', err);
if (err) {
appendError(err);
}
};
/** Construct one batch and execute it for all of the tests in testNames
*/
var bulkTestsLoop = function() {
testName = testNames[testNumber];
operation = JSCRUND.implementation[testName];
operationsDoneCallback = bulkTestsLoop;
if (testNumber < testNames.length) {
if(options.use_gc) global.gc(); // Full GC between tests
testNumber++;
if(DETAIL) JSCRUND.udebug.log_detail('jscrund.bulkTestsLoop', testNumber, 'of', testNames.length, ':', testName);
timer.start(modeName, testName, numberOfIterations);
JSCRUND.implementation.createBatch(function(err) {
for (iteration = 0; iteration < numberOfIterations; ++iteration) {
operation.apply(JSCRUND.implementation, [parameters[iteration], bulkCheckOperationCallback]);
}
JSCRUND.implementation.executeBatch(bulkCheckBatchCallback);
});
} else {
// done with all bulk tests
testsDoneCallback();
}
};
/** Run all modes specified in --modes: default is indy, each, bulk.
*
*/
var modeLoop = function() {
modeName = modeNames[modeNumber];
mode = modes[modeNumber];
testNumber = 0;
if (modeNumber < modes.length) {
modeNumber++;
console.log('\njscrund.modeLoop ', modeName, "[ size",numberOfIterations,"]");
mode.apply(runTests);
} else {
if (JSCRUND.errors.length !== 0) {
console.log(JSCRUND.errors);
}
report();
batchSizeLoop();
}
};
function report() {
var opNames, opTimes, r, adapter;
adapter = options.adapter + (options.spi ? "(spi)" : "");
opNames = "rtime[ms]," + adapter + '\t';
opTimes = "" + numberOfIterations + '\t';
while (r = resultStats.shift()) {
opNames += r.name + '\t';
opTimes += r.time + '\t';
}
if(! nReport++) {
logFile.write(opNames + '\n');
}
logFile.write(opTimes + '\n');
}
/** Iterate over batch sizes
*/
function batchSizeLoop() {
if(batchLoopNumber < numberOfBatchLoops) {
numberOfIterations = options.iterations[batchLoopNumber];
batchLoopNumber++;
parameters = generateAllParameters(numberOfIterations);
modeNumber = 0;
setImmediate(modeLoop);
} else {
mainTestLoop();
}
}
/** Run test with all modes.
*/
var mainTestLoop = function() {
if (nRun++ >= nRuns) {
console.log('\ndone: ' + nRuns + ' runs.');
console.log("\nappending results to file: " + logFile.name);
logFile.close();
if (options.stats) {
JSCRUND.stats.peek();
}
JSCRUND.implementation.close(function(err) {
if(options.delay_post > 0) {
console.log("Delaying", options.delay_post, "seconds");
setTimeout(process.exit, 1000 * options.delay_post);
} else {
process.exit(err ? 1 : 0);
}
});
} else {
console.log('\nRun #' + nRun + ' of ' + nRuns);
batchLoopNumber = 0;
if(nRun === 2 && (options.delay_pre > 0)) {
console.log("Waiting", options.delay_pre, "seconds...");
setTimeout(batchSizeLoop, 1000 * options.delay_pre);
options.delay_pre = 0;
} else {
batchSizeLoop();
}
}
};
// runTests starts here
var modeTable = {
'indy': indyTestsLoop,
'each': eachTestsLoop,
'bulk': bulkTestsLoop
};
var modes = [];
for (var m = 0; m < modeNames.length; ++m) {
modes.push(modeTable[modeNames[m]]);
}
console.log('running tests with options:\n', options);
JSCRUND.implementation.initialize(options, function(err) {
// initialization complete
if (err) {
console.log('Error initializing JSCRUND.implementation:', err);
process.exit(1);
} else {
testsDoneCallback = modeLoop;
mainTestLoop();
}
});
};
// create database
JSCRUND.metadataManager = require("jones-ndb").getDBMetadataManager(properties);
JSCRUND.metadataManager.runSQL(path.join(__dirname, "./create.sql"), function(err) {
if (err) {
console.log('Error creating tables.', err);
process.exit(1);
}
// if database create successful, run tests
runTests(options);
});
}