forked from rsms/js-lru
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathbenchmark.js
155 lines (131 loc) · 4.52 KB
/
benchmark.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
// This is a benchmark suite which will run with nodejs.
// $ node --expose-gc benchmark.js
var assert = require('assert'),
util = require('util'),
LRUMap = require('./lru').LRUMap;
// Create a cache with N entries
var N = 10000;
// Run each measurement Iterations times
var Iterations = 1000;
var has_gc_access = typeof gc === 'function';
var gc_collect = has_gc_access ? gc : function(){};
Number.prototype.toHuman = function(divisor) {
var N = Math.round(divisor ? this/divisor : this);
var n = N.toString().split('.');
n[0] = n[0].replace(/(\d)(?=(\d\d\d)+(?!\d))/g, '$1,');
return n.join('.');
}
Number.prototype.toSignedHuman = function(divisor) {
var n = this.toHuman(divisor);
if (this > -1) n = '+'+n;
return n;
}
function measure(block) {
gc_collect();
var elapsed = 0, start, usec, n;
var sm = process.memoryUsage();
if (Iterations && Iterations > 0) {
start = new Date();
for (n = 0; n < Iterations; n++) {
block();
}
usec = ((new Date() - start) / Iterations) * 1000;
} else {
start = new Date();
block();
usec = (new Date() - start) * 1000;
}
var msg = '\n----------\n ' + block.toString().replace(/\n/g, "\n ") + '\n';
if (has_gc_access) {
gc_collect();
var em = process.memoryUsage();
var mrssd = em.rss - sm.rss;
var mhtotd = em.heapTotal - sm.heapTotal;
var mhusedd = em.heapUsed - sm.heapUsed;
msg += ' rss: ' + mrssd.toSignedHuman(1024) + ' kB -- (' +
sm.rss.toHuman(1024) + ' kB -> ' + em.rss.toHuman(1024) + ' kB)\n';
if (typeof sm.vsize === 'number') {
var mvsized = em.vsize - sm.vsize;
msg +=
' vsize: ' + mvsized.toSignedHuman(1024) + ' kB -- (' +
sm.vsize.toHuman(1024) + ' kB -> ' + em.vsize.toHuman(1024) + ' kB)\n';
}
msg += ' heap total: ' + mhtotd.toSignedHuman(1024) + ' kB -- (' +
sm.heapTotal.toHuman(1024) + ' kB -> ' + em.heapTotal.toHuman(1024) + ' kB)\n' +
' heap used: ' + mhusedd.toSignedHuman(1024) + ' kB -- (' +
sm.heapUsed.toHuman(1024) + ' kB -> ' + em.heapUsed.toHuman(1024) + ' kB)\n\n';
}
var call_avg = usec;
msg += ' -- ' + (call_avg / 1000) + ' ms avg per iteration --\n';
process.stdout.write(msg);
}
var c = new LRUMap(N);
console.log('N = ' + N + ', Iterations = ' + Iterations);
// We should probably spin up the system in some way, or repeat the benchmarks a
// few times, since initial heap resizing takes considerable time.
measure(function(){
// 1. put
// Simply append a new entry.
// There will be no reordering since we simply append to the tail.
for (var i=N; --i;)
c.set('key'+i, i);
});
measure(function(){
// 2. get recent -> old
// Get entries starting with newest, effectively reversing the list.
//
// a. For each get, a find is first executed implemented as a native object with
// keys mapping to entries, so this should be reasonably fast as most native
// objects are implemented as hash maps.
//
// b. For each get, the aquired item will be moved to tail which includes a
// maximum of 7 assignment operations (minimum 3).
for (var i=1,L=N+1; i<L; ++i)
c.get('key'+i, i);
});
measure(function(){
// 3. get old -> recent
// Get entries starting with oldest, effectively reversing the list.
//
// - Same conditions apply as for test 2.
for (var i=1,L=N+1; i<L; ++i)
c.get('key'+i);
});
measure(function(){
// 4. get missing
// Get try to get entries not in the cache.
// - Same conditions apply as for test 2, section a.
for (var i=1,L=N+1; i<L; ++i)
c.get('xkey'+i);
});
measure(function(){
// 5. put overflow
// Overflow the cache with N more items than it can hold.
// a. The complexity of put in this case should be:
// ( <get whith enough space> + <shift> )
for (var i=N; --i;)
c.set('key2_'+i, i);
});
measure(function(){
// 6. shift head -> tail
// Remove all entries going from head to tail
for (var i=1,L=N+1; i<L; ++i)
c.shift();
});
measure(function(){
// 7. put
// Simply put N new items into an empty cache with exactly N space.
for (var i=N; --i;)
c.set('key'+i, i);
});
// pre-build random key array
var shuffledKeys = Array.from(c.keys());
shuffledKeys.sort(function (){return Math.random()-0.5; });
measure(function(){
// 8. delete random
// a. Most operations (which are not entries at head or tail) will cause closes
// siblings to be relinked.
for (var i=shuffledKeys.length, key; key = shuffledKeys[--i]; ) {
c.delete('key'+i, i);
}
});