spica
Version:
Supervisor, Coroutine, Channel, select, AtomicPromise, Cancellation, Cache, List, Queue, Stack, and some utils.
245 lines (227 loc) • 7.64 kB
text/typescript
import { TLRU } from './tlru.clock';
import { LRU } from './lru';
import { xorshift } from './random';
import zipfian from 'zipfian-integer';
describe('Unit: lib/tlru.clock', () => {
describe('TLRU-Clock', () => {
it('basic', function () {
{
const cache = new TLRU<number, 1>(4, 1, 0, true);
for (const i of [0, 1, 2, 3, 4, 5, 6, 7]) {
cache.get(i) ?? cache.add(i, 1);
}
assert.deepStrictEqual(
[...cache].map(t => t[0]),
[7, 6, 5, 4]);
}
{
const cache = new TLRU<number, 1>(4, 1, 0, false);
for (const i of [0, 1, 2, 3, 4, 5, 6, 7]) {
cache.get(i) ?? cache.add(i, 1);
}
assert.deepStrictEqual(
[...cache].map(t => t[0]),
[7, 6, 5, 4]);
}
{
const cache = new TLRU<number, 1>(4, 1, 0, true);
for (const i of [0, 0, 1, 2, 3, 4, 5, 6, 7]) {
cache.get(i) ?? cache.add(i, 1);
}
assert.deepStrictEqual(
[...cache].map(t => t[0]),
[3, 2, 6, 7]);
}
{
const cache = new TLRU<number, 1>(4, 1, 0, false);
for (const i of [0, 0, 1, 2, 3, 4, 5, 6, 7]) {
cache.get(i) ?? cache.add(i, 1);
}
assert.deepStrictEqual(
[...cache].map(t => t[0]),
[3, 2, 6, 7]);
}
{
const cache = new TLRU<number, 1>(4, 1, 0, true);
for (const i of [0, 1, 2, 3, 3, 4, 5, 6, 7, 8]) {
cache.get(i) ?? cache.add(i, 1);
}
assert.deepStrictEqual(
[...cache].map(t => t[0]),
[7, 3, 6, 8]);
}
{
const cache = new TLRU<number, 1>(4, 1, 0, false);
for (const i of [0, 1, 2, 3, 3, 4, 5, 6, 7, 8]) {
cache.get(i) ?? cache.add(i, 1);
}
assert.deepStrictEqual(
[...cache].map(t => t[0]),
[7, 6, 5, 8]);
}
{
const cache = new TLRU<number, 1>(4, 1, 0, true);
for (const i of [0, 1, 2, 3, 4, 4, 5, 6, 7, 8]) {
cache.get(i) ?? cache.add(i, 1);
}
assert.deepStrictEqual(
[...cache].map(t => t[0]),
[8, 4, 7, 6]);
}
{
const cache = new TLRU<number, 1>(4, 1, 0, false);
for (const i of [0, 1, 2, 3, 4, 4, 5, 6, 7, 8]) {
cache.get(i) ?? cache.add(i, 1);
}
assert.deepStrictEqual(
[...cache].map(t => t[0]),
[8, 7, 6, 5]);
}
{
const cache = new TLRU<number, 1>(4, 1, 0, true);
for (const i of [0, 1, 2, 3, 4, 5, 6, 6, 7, 8, 9]) {
cache.get(i) ?? cache.add(i, 1);
}
assert.deepStrictEqual(
[...cache].map(t => t[0]),
[8, 6, 7, 9]);
}
{
const cache = new TLRU<number, 1>(4, 1, 0, false);
for (const i of [0, 1, 2, 3, 4, 5, 6, 6, 7, 8, 9]) {
cache.get(i) ?? cache.add(i, 1);
}
assert.deepStrictEqual(
[...cache].map(t => t[0]),
[8, 7, 5, 9]);
}
{
const cache = new TLRU<number, 1>(4, 1, 0, true);
for (const i of [0, 1, 2, 3, 4, 5, 6, 7, 7, 8, 9]) {
cache.get(i) ?? cache.add(i, 1);
}
assert.deepStrictEqual(
[...cache].map(t => t[0]),
[7, 6, 9, 8]);
}
{
const cache = new TLRU<number, 1>(4, 1, 0, false);
for (const i of [0, 1, 2, 3, 4, 5, 6, 7, 7, 8, 9]) {
cache.get(i) ?? cache.add(i, 1);
}
assert.deepStrictEqual(
[...cache].map(t => t[0]),
[7, 6, 9, 8]);
}
{
const cache = new TLRU<number, 1>(4, 100, 0, true);
for (const i of [0, 1, 2, 2, 3, 3, 4, 5, 6, 7, 8, 9]) {
cache.get(i) ?? cache.add(i, 1);
}
assert.deepStrictEqual(
[...cache].map(t => t[0]),
[7, 3, 9, 8]);
}
{
const cache = new TLRU<number, 1>(4, 100, 0, false);
for (const i of [0, 1, 2, 2, 3, 3, 4, 5, 6, 7, 8, 9]) {
cache.get(i) ?? cache.add(i, 1);
}
assert.deepStrictEqual(
[...cache].map(t => t[0]),
[7, 6, 9, 8]);
}
});
it('order', function () {
const capacity = 4;
const cache = new TLRU<number, 1>(capacity);
for (let i = 0; i < capacity; ++i) {
cache.add(~i, 1);
}
for (const i of [1, 2, 3, 3, 2, 4]) {
cache.get(i) ?? cache.add(i, 1);
}
assert.deepStrictEqual(
[...cache].map(t => t[0]),
[2, 3, 4, 1]);
});
for (let i = 0; i < 1000; ++i) it(`verify ${i}`, function () {
this.timeout(10 * 1e3);
const capacity = 4;
const cache = new TLRU<number, number>(capacity, i % 3, (i % 4 + 99) % 100, i % 2 === 0);
const trials = capacity * 1000;
const random = xorshift.random(i + 1);
for (let i = 0; i < trials; ++i) {
const key = random() * capacity * 2 | 0;
if (cache.has(key)) {
assert(cache.get(key) === ~key);
}
else {
cache.add(key, ~key);
}
}
assert(cache.length === capacity);
});
class Stats {
trc = 0;
lru = 0;
}
it('even 100', function () {
this.timeout(10 * 1e3);
const capacity = 100;
const trc = new TLRU<number, 1>(capacity);
const lru = new LRU<number, 1>(capacity);
const trials = capacity * 1000;
const random = xorshift.random(1);
const stats = new Stats();
for (let i = 0; i < trials; ++i) {
const key = random() * capacity * 10 | 0;
stats.trc += trc.get(key) ?? +trc.set(key, 1) & 0;
stats.lru += lru.get(key) ?? +lru.set(key, 1) & 0;
}
console.debug('TLRU-Clock even 100');
console.debug('LRU hits', stats.lru);
console.debug('TRC hits', stats.trc);
console.debug('TRC / LRU hit ratio', `${stats.trc / stats.lru * 100 | 0}%`);
assert(stats.trc / stats.lru * 100 >>> 0 === 99);
});
it('zipf 100', function () {
this.timeout(10 * 1e3);
const capacity = 100;
const trc = new TLRU<number, 1>(capacity);
const lru = new LRU<number, 1>(capacity);
const trials = capacity * 1000;
const random = zipfian(1, capacity * 1e3, 0.8, xorshift.random(1));
const stats = new Stats();
for (let i = 0; i < trials; ++i) {
const key = random();
stats.trc += trc.get(key) ?? +trc.set(key, 1) & 0;
stats.lru += lru.get(key) ?? +lru.set(key, 1) & 0;
}
console.debug('TLRU-Clock zipf 100');
console.debug('LRU hits', stats.lru);
console.debug('TRC hits', stats.trc);
console.debug('TRC / LRU hit ratio', `${stats.trc / stats.lru * 100 | 0}%`);
assert(stats.trc / stats.lru * 100 >>> 0 === 166);
});
it('zipf 1,000', function () {
this.timeout(60 * 1e3);
const capacity = 1000;
const trc = new TLRU<number, 1>(capacity);
const lru = new LRU<number, 1>(capacity);
const trials = capacity * 100;
const random = zipfian(1, capacity * 1e3, 0.8, xorshift.random(1));
const stats = new Stats();
for (let i = 0; i < trials; ++i) {
const key = random();
stats.trc += trc.get(key) ?? +trc.set(key, 1) & 0;
stats.lru += lru.get(key) ?? +lru.set(key, 1) & 0;
}
console.debug('TLRU-Clock zipf 1000');
console.debug('LRU hits', stats.lru);
console.debug('TRC hits', stats.trc);
console.debug('TRC / LRU hit ratio', `${stats.trc / stats.lru * 100 | 0}%`);
assert(stats.trc / stats.lru * 100 >>> 0 === 145);
});
});
});