@phenixrts/aerospike
Version:
Aerospike Client Library
328 lines (281 loc) • 7.5 kB
JavaScript
// *****************************************************************************
// Copyright 2013-2019 Aerospike, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License")
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// *****************************************************************************
var Table = require('cli-table')
const OPERATION_STATUS = 0
const OPERATION_TIME_DIFF = 1
// histograms
// 1. For status code of each operation.
// 2. Latency histogram.
var hist = {}
var timeHist = {
'<= 1': 0,
'> 1': 0,
'> 2': 0,
'> 4': 0,
'> 8': 0,
'> 16': 0,
'> 32': 0
}
var trans = { total: { count: 0, min_tps: Infinity, max_tps: 0 } }
var startTime
var totalDuration
const TABLE_CHARS = {
top: '',
'top-mid': '',
'top-left': '',
'top-right': '',
bottom: '',
'bottom-mid': '',
'bottom-left': '',
'bottom-right': '',
left: '',
'left-mid': '',
mid: '',
'mid-mid': '',
right: '',
'right-mid': '',
middle: ''
}
const TABLE_STYLE = {
'padding-left': 4,
'padding-right': 0,
head: ['blue'],
border: ['grey'],
compact: true
}
function sum (l, r) {
return l + r
}
function duration (time) {
return (time[0] * 1000) + (time[1] / 1000000)
}
function parseTimeToSecs (time) {
if (time !== undefined) {
var timeMatch = time.toString().match(/(\d+)([smh])?/)
if (timeMatch !== null) {
if (timeMatch[2] !== null) {
time = parseInt(timeMatch[1], 10)
var timeUnit = timeMatch[2]
switch (timeUnit) {
case 'm':
time = time * 60
break
case 'h':
time = time * 60 * 60
break
}
}
}
}
return time
}
function timeHistogram (operations) {
operations
.map(op => {
const elapsed = op[OPERATION_TIME_DIFF]
return Math.floor(duration(elapsed))
})
.forEach(d => {
if (d > 32) {
timeHist['> 32']++
} else if (d > 16) {
timeHist['> 16']++
} else if (d > 8) {
timeHist['> 8']++
} else if (d > 4) {
timeHist['> 4']++
} else if (d > 2) {
timeHist['> 2']++
} else if (d > 1) {
timeHist['> 1']++
} else {
timeHist['<= 1']++
}
})
}
function numberFormat (v, precision) {
return v.toFixed(precision || 0).toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',')
}
function timeUnits (v) {
var u = v === 1 ? 'second' : 'seconds'
if (Math.abs(v) >= 60) {
v = v / 60
u = v === 1 ? 'minute' : 'minutes'
}
if (Math.abs(v) >= 60) {
v = v / 60
u = v === 1 ? 'hour' : 'hours'
}
return numberFormat(v, 2) + ' ' + u
}
function calculateTPS (transactions) {
const seconds = totalDuration / 1000
for (const key in transactions) {
const stat = transactions[key]
stat.tps = stat.count / seconds
}
}
function statusHistogram (operations) {
operations.map(function (op) {
return op[OPERATION_STATUS]
}).forEach(function (status) {
hist[status] = (hist[status] || 0) + 1
})
}
function printTable (table, print, prefix) {
table.toString().split('\n').forEach(function (l) {
if (l.length > 0) {
print((prefix || '') + l)
}
})
}
function printEnvTable (print, prefix) {
var envTable = new Table({
chars: TABLE_CHARS,
style: TABLE_STYLE
})
envTable.push({ 'Node.js Version': process.versions.node })
envTable.push({ UV_THREADPOOL_SIZE: process.env.UV_THREADPOOL_SIZE || '-' })
printTable(envTable, print, prefix)
}
function printConfigTable (config, print, prefix) {
var configTable = new Table({
chars: TABLE_CHARS,
style: TABLE_STYLE
})
configTable.push({ operations: config.operations })
configTable.push({ iterations: config.iterations === undefined ? 'undefined' : config.iterations })
configTable.push({ processes: config.processes })
configTable.push({ promises: !!config.promises })
configTable.push({ time: config.time === undefined ? 'undefined' : timeUnits(config.time) })
printTable(configTable, print, prefix)
}
function printTransactions (transactions, print, prefix) {
var thead = []
thead.push('')
for (var t in transactions) {
thead.push(t)
}
var table = new Table({
head: thead,
chars: TABLE_CHARS,
style: TABLE_STYLE
})
const columns = Object.keys(transactions).map(key => transactions[key])
const totals = columns.map(col => numberFormat(col.count, 0))
table.push({ Total: totals })
const avgTps = columns.map(col => numberFormat(col.tps, 0))
table.push({ TPS: avgTps })
const minTps = columns.map(col => numberFormat(col.min_tps, 0))
table.push({ 'Min TPS': minTps })
const maxTps = columns.map(col => numberFormat(col.max_tps, 0))
table.push({ 'Max TPS': maxTps })
printTable(table, print, prefix)
}
function printHistogram (histogram, print, prefix) {
var total = Object.keys(histogram).map(function (k) {
return histogram[k]
}).reduce(sum)
var thead = []
var tbody = []
for (var k in histogram) {
thead.push(k)
tbody.push(numberFormat(histogram[k] / total * 100, 1) + '%')
}
var table = new Table({
head: thead,
chars: TABLE_CHARS,
style: TABLE_STYLE
})
table.push(tbody)
printTable(table, print, prefix)
}
function start () {
startTime = process.hrtime()
}
function stop () {
const elapsed = process.hrtime(startTime)
totalDuration = duration(elapsed)
}
function iteration (operations) {
statusHistogram(operations)
timeHistogram(operations)
}
function aggregateIntervalStats (statName, tx) {
var stats = trans[statName] = trans[statName] || { count: 0, max_tps: 0, min_tps: Infinity }
stats.count += tx
if (tx > stats.max_tps) stats.max_tps = tx
if (tx < stats.min_tps) stats.min_tps = tx
}
function interval (intervalStats) {
var totalTX = 0
for (var stat in intervalStats) {
var tx = intervalStats[stat][0]
totalTX += tx
aggregateIntervalStats(stat, tx)
}
aggregateIntervalStats('total', totalTX)
}
function reportFinal (argv, print) {
calculateTPS(trans)
if (!argv.json) {
print()
print('SUMMARY')
print()
print(' Environment')
printEnvTable(print)
print()
print(' Configuration')
printConfigTable(argv, print)
print()
print(' Transactions')
printTransactions(trans, print)
print()
print(' Durations')
printHistogram(timeHist, print)
print()
print(' Status Codes')
printHistogram(hist, print)
print()
} else {
var output = {
env: {
nodejs: process.versions.node,
UV_THREADPOOL_SIZE: process.env.UV_THREADPOOL_SIZE || null
},
configuration: {
operations: argv.operations,
iterations: argv.iterations,
processes: argv.processes
},
duration: totalDuration,
transactions: trans,
durations: timeHist,
status_codes: hist
}
console.log('%j', output)
}
return 0
}
module.exports = {
start,
stop,
iteration,
interval,
printHistogram,
reportFinal,
parseTimeToSecs
}