-
-
Notifications
You must be signed in to change notification settings - Fork 95
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
11 changed files
with
493 additions
and
7 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
var randomString = require('pandemonium/random-string'); | ||
var random = require('pandemonium/random'); | ||
var typed = require('../../utils/typed-arrays.js'); | ||
var {snipToLast} = require('../../utils/snip.js'); | ||
|
||
module.exports.random = random; | ||
module.exports.randomString = randomString; | ||
|
||
function randArr(size, range, rng) { | ||
var ValArrayFactory = typed.getPointerArray(range); | ||
var arr = new ValArrayFactory(size) | ||
for (var ii = 0; ii < size; ii++) { | ||
arr[ii] = rng(ii); | ||
} | ||
return arr | ||
} | ||
module.exports.randArr = randArr; | ||
|
||
function longTailArr(size, range, power) { | ||
var intgen = longTailIntGen(range, power) | ||
return randArr(size, range, intgen); | ||
} | ||
module.exports.longTailArr = longTailArr; | ||
|
||
function flatDistArr(size, range) { | ||
var intgen = () => random(0, range - 1); | ||
return randArr(size, range, intgen); | ||
} | ||
module.exports.flatDistArr = flatDistArr; | ||
|
||
function ascendingArr(size, range) { | ||
var intgen = (ii) => (ii); | ||
return randArr(size, range, intgen); | ||
} | ||
module.exports.ascendingArr = ascendingArr; | ||
|
||
function longTailIntGen(range, power = -0.8) { | ||
return function intgen() { | ||
var rand = Math.random() | ||
var yy = (1 - rand)**(power) - 1 | ||
var result = Math.floor(0.25 * range * yy) | ||
if (result < range) { return result } | ||
return intgen() | ||
} | ||
} | ||
module.exports.longTailIntGen = longTailIntGen; | ||
|
||
function longTailStrGen(range, power = -0.8) { | ||
var intgen = longTailIntGen(range, power); | ||
return function strgen() { | ||
return String(intgen()) | ||
} | ||
} | ||
module.exports.longTailStrGen = longTailStrGen; | ||
|
||
function stringifyArr(arr) { | ||
var stringArr = []; | ||
for (var ii = 0; ii < arr.length; ii++) { | ||
stringArr.push(arr[ii]); | ||
} | ||
return stringArr; | ||
} | ||
module.exports.stringifyArr = stringifyArr; | ||
|
||
function comparePairTails([kk1, vv1], [kk2, vv2]) { | ||
if (vv2 > vv1) { return 1 } | ||
if (vv2 < vv1) { return -1 } | ||
if (kk2 > kk1) { return -1 } | ||
if (kk2 < kk1) { return 1 } | ||
return 1 | ||
} | ||
|
||
function showDistribution(arr, chunk = 1) { | ||
var counts = new Map(); | ||
for (var item of arr) { | ||
bin = chunk * Math.floor(item / chunk) | ||
if (! counts.has(bin)) { counts.set(bin, 0); } | ||
counts.set(bin, 1 + counts.get(bin)); | ||
} | ||
var entries = [...counts].sort(comparePairTails) | ||
var histo = new Map(entries) | ||
histo.last = entries[entries.length - 1] | ||
return histo | ||
} | ||
|
||
function examineDist(keys) { | ||
var histA = showDistribution(keys, 1) | ||
var histB = showDistribution(keys, 10000) | ||
console.log( | ||
oops, | ||
keys.length, | ||
histA.size, | ||
snipToLast(histA.entries(), new Map(), {maxToDump: 25, last: histA.last, size: histA.size}), | ||
histB, | ||
) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,145 @@ | ||
var random = require('pandemonium/random'); | ||
var Benchmark = require('benchmark') | ||
var Keymaster = require('./key-distributions.js'); | ||
var LRUCache = require('../../lru-cache.js'), | ||
LRUMap = require('../../lru-map.js'), | ||
LRUCacheWithDelete = require('../../lru-cache-with-delete.js'), | ||
LRUMapWithDelete = require('../../lru-map-with-delete.js'); | ||
|
||
var TEST_CAP = 30000 | ||
|
||
// 400k entries with approx 42k distinct values btwn 0 and 60k, distributed 300k/65k/23k/10k/5k/3k (~97% in the top 30k) | ||
var NumKeys97 = Keymaster.longTailArr(400000, 60000, -0.4); | ||
var StrKeys97 = Keymaster.stringifyArr(NumKeys97); | ||
var intgen97 = Keymaster.longTailIntGen(60000, -0.4); | ||
var strgen97 = Keymaster.longTailStrGen(60000, -0.4); | ||
NumKeys97.note = 'Long-tail pool of 42,000 distinct values, 97% in the top 30k, 75% in the top 10k'; StrKeys97.note = NumKeys97.note; | ||
// 400k entries with approx 50k distinct values btwn 0 and 60k, distributed 230k/80k/40k/22k/15k/10k (~88% in the top 30k) | ||
var NumKeys88 = Keymaster.longTailArr(400000, 60000, -0.7) | ||
// 400k entries with approx 60k distinct values btwn 0 and 60k, distributed 135k/85k/61k/48k/39k/33k (~70% in the top 30k) | ||
var NumKeys70 = Keymaster.longTailArr(400000, 60000, -10); | ||
var StrKeys70 = Keymaster.stringifyArr(NumKeys70); | ||
NumKeys70.note = 'Long-tail pool of ~60,000 distinct values, 70% in the top 30k, 33% in the top 10k'; StrKeys70.note = NumKeys70.note; | ||
// 120k entries with approx 52k distinct values btwn 0 and 60k, distributed evenly | ||
var NumKeysFlat = Keymaster.flatDistArr(120000, 60000); | ||
var StrKeysFlat = Keymaster.stringifyArr(NumKeysFlat); | ||
// 31k entries running 0-31k in order | ||
var NumKeysOrdered = Keymaster.ascendingArr(31000, 31000); | ||
var StrKeysOrdered = Keymaster.stringifyArr(NumKeysOrdered); | ||
|
||
const CACHES = [LRUCache, LRUCacheWithDelete, LRUMap, LRUMapWithDelete, LRUCache]; | ||
|
||
// var emptyCaches = makeCaches(); | ||
// scenario(emptyCaches, (cache) => (function() { readAll(cache, StrKeys97); })); | ||
|
||
var fullCaches = makeLoadedCaches(StrKeysOrdered); | ||
fullCaches.note = 'Pre-loaded 30k capacity caches'; | ||
|
||
// console.log(`Pre-loaded 30k capacity caches, 400k reps of | ||
// one write from equally-occurring pool of 60k distinct keys, then | ||
// one read from a long-tail pool of 60k distinct keys (70% in 30k, 33% in 10k)`); | ||
scenario('1x flat writes, 1x gentle spread read', fullCaches, (cache) => (function() { | ||
write1Read1(cache, [StrKeysFlat, StrKeys70], StrKeys70.length); | ||
})); | ||
|
||
console.log(`Pre-loaded 30k capacity caches, 400k reps of | ||
one write from equally-occurring pool of 60k distinct keys, | ||
then four reads from a long-tail pool of 60k distinct keys (70% in 30k, 33% in 10k)`); | ||
scenario('1x flat writes, 4x gentle spread read', fullCaches, (cache) => (function() { | ||
write1Read4(cache, [StrKeysFlat, StrKeys70], StrKeys70.length); | ||
})); | ||
|
||
console.log(`${fullCaches.note}\nRead one value then write one value from the same sharp (97/70) distribution`); | ||
scenario('individual get then set, sharp spread', fullCaches, (cache) => (function() { | ||
cache.get(strgen97()); | ||
cache.set(strgen97(), 'hi'); | ||
})); | ||
|
||
console.log(`${fullCaches.note}\nRead one value then write one value from a flat distribution 33% larger than the cache`); | ||
scenario('individual get then set, flat spread', fullCaches, (cache) => (function() { | ||
cache.get(String(random(0, 40000))); | ||
cache.set(String(random(0, 40000)), 'hi'); | ||
})); | ||
|
||
console.log(`Pre-loaded 30k capacity caches, random-order reads (no writes) of 42,000 distinct values. | ||
The top 30k of values occur ~97% of the time and the top 10k values 75% of the time.`); | ||
// | ||
scenario('read-only sharp spread', fullCaches, (cache) => (function() { readAll(cache, StrKeys97); })); | ||
|
||
console.log(`Pre-loaded 30k capacity caches, random-order reads (no writes) of 60,000 distinct values. | ||
The top 30k of values occur ~70% of the time and the top 10k values 33% of the time.`); | ||
// | ||
scenario('read-only gentle spread', fullCaches, (cache) => (function() { readAll(cache, StrKeys70); })); | ||
|
||
function readAll(cache, arrA, count) { | ||
if (! count) { count = arrA.length; } | ||
for (var ii = 0; ii < count; ii++) { | ||
cache.get(arrA[ii % arrA.length]) | ||
} | ||
} | ||
|
||
function writeAll(cache, arrA, count) { | ||
if (! count) { count = arrA.length; } | ||
for (var ii = 0; ii < count; ii++) { | ||
var storeme = arrA[ii % arrA.length] | ||
cache.set(storeme, storeme) | ||
} | ||
} | ||
|
||
function write1Read1(cache, [arrA, arrB], count) { | ||
var blen = arrB.length; | ||
if (! count) { count = arrA.length; } | ||
for (var ii = 0; ii < count; ii++) { | ||
var storeme = arrA[ii % arrA.length] | ||
cache.set(storeme, storeme) | ||
cache.get(arrB[ii % blen]) | ||
} | ||
} | ||
|
||
function write1Read4(cache, [arrA, arrB], count) { | ||
var blen = arrB.length; | ||
var boff0 = 0, boff1 = blen * 0.25, boff2 = blen * 0.50, boff1 = blen * 0.75; | ||
if (! count) { count = arrA.length; } | ||
for (var ii = 0; ii < count; ii++) { | ||
var storeme = arrA[ii % arrA.length] | ||
cache.set(storeme, storeme) | ||
cache.get(arrB[(ii + boff0) % blen]) | ||
cache.get(arrB[(ii + boff1) % blen]) | ||
cache.get(arrB[(ii + boff2) % blen]) | ||
cache.get(arrB[(ii + boff3) % blen]) | ||
} | ||
} | ||
|
||
function decoratedSuite(name) { | ||
return new Benchmark.Suite('Testing caches') | ||
.on('cycle', event => { | ||
const benchmark = event.target; | ||
console.log(benchmark.toString()); | ||
}) // .on('complete', function() { console.log('Fastest is ' + this.filter('fastest').map('name')); }); | ||
} | ||
|
||
function makeCaches(factories = CACHES) { | ||
return factories.map((CacheFactory) => { | ||
var cache = new CacheFactory(TEST_CAP); | ||
cache.name = CacheFactory.name; | ||
return cache; | ||
}) | ||
} | ||
|
||
function makeLoadedCaches(arrA, count) { | ||
if (! count) { count = arrA.length; } | ||
var caches = makeCaches() | ||
caches.forEach((cache) => { | ||
writeAll(cache, arrA, count); | ||
}) | ||
return caches; | ||
} | ||
|
||
function scenario(act, caches, actionsFactory, info) { | ||
var suite = decoratedSuite(act); | ||
caches.forEach((cache) => { | ||
var actions = actionsFactory(cache, info); | ||
suite.add(`${act} ${cache.name}`, actions); | ||
}) | ||
suite.run(); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.