Linux: Depend on liberation-fonts package for RPMs.
[chromium-blink-merge.git] / chrome / test / data / indexeddb / perf_test.js
blobbf0f6e853d45a774f583c02c9b72f2bb36995bbb
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 var overallTestStartTime = window.performance.now();
6 var kUseIndex = true;
7 var kDontUseIndex = false;
8 var kReadKeysOnly = true;
9 var kReadDataToo = false;
10 var kWriteToo = true;
11 var kDontWrite = false;
12 var kWriteSameStore = true;
13 var kWriteDifferentStore = false;
14 var kPlaceholderArg = false;
15 var kDontRead = false;
16 var kAlternateWithReads = true;
18 var tests = [
19 // Create a single small item in a single object store, then delete everything.
20 [testCreateAndDeleteDatabase, 1, 1, 1],
21 // Create many small items in a single object store, then delete everything.
22 [testCreateAndDeleteDatabase, 1000, 1, 1],
23 // Create a single small item in many object stores, then delete everything.
24 [testCreateAndDeleteDatabase, 1, 1000, 1],
25 // Create many large items in a single object store, then delete everything.
26 [testCreateAndDeleteDatabase, 1000, 1, 10000],
27 // Create a single small item in a single object store.
28 [testCreateKeysInStores, 1, 1, 1],
29 // Create many small items in a single object store.
30 [testCreateKeysInStores, 1000, 1, 1],
31 // Create a single small item in many object stores.
32 [testCreateKeysInStores, 1, 1000, 1],
33 // Create many large items in a single object store.
34 [testCreateKeysInStores, 1000, 1, 10000],
35 // Read one item per transaction.
36 [testRandomReadsAndWrites, 1000, 1, 0, 1000, kDontUseIndex],
37 // Read a few random items in each of many transactions.
38 [testRandomReadsAndWrites, 1000, 5, 0, 100, kDontUseIndex],
39 // Read many random items in each of a few transactions.
40 [testRandomReadsAndWrites, 1000, 500, 0, 5, kDontUseIndex],
41 // Read many random items in each of a few transactions, in a large store.
42 [testRandomReadsAndWrites, 10000, 500, 0, 5, kDontUseIndex],
43 // Read a few random items from an index, in each of many transactions.
44 [testRandomReadsAndWrites, 1000, 5, 0, 100, kUseIndex],
45 // Read many random items from an index, in each of a few transactions.
46 [testRandomReadsAndWrites, 1000, 500, 0, 5, kUseIndex],
47 // Read many random items from an index, in each of a few transactions, in a
48 // large store.
49 [testRandomReadsAndWrites, 10000, 500, 0, 5, kUseIndex],
50 // Read and write a few random items in each of many transactions.
51 [testRandomReadsAndWrites, 1000, 5, 5, 50, kDontUseIndex],
52 // Read and write a few random items, reading from an index, in each of many
53 // transactions.
54 [testRandomReadsAndWrites, 1000, 5, 5, 50, kUseIndex],
55 // Read a long, contiguous sequence of an object store via a cursor.
56 [testCursorReadsAndRandomWrites, kReadDataToo, kDontUseIndex, kDontWrite,
57 kPlaceholderArg],
58 // Read a sequence of an object store via a cursor, writing
59 // transformed values into another.
60 [testCursorReadsAndRandomWrites, kReadDataToo, kDontUseIndex, kWriteToo,
61 kWriteDifferentStore],
62 // Read a sequence of an object store via a cursor, writing
63 // transformed values into another.
64 [testCursorReadsAndRandomWrites, kReadDataToo, kDontUseIndex, kWriteToo,
65 kWriteSameStore],
66 // Read a sequence of an index into an object store via a cursor.
67 [testCursorReadsAndRandomWrites, kReadDataToo, kUseIndex, kDontWrite,
68 kPlaceholderArg],
69 // Read a sequence of an index into an object store via a key cursor.
70 [testCursorReadsAndRandomWrites, kReadKeysOnly, kUseIndex, kDontWrite,
71 kPlaceholderArg],
72 // Make a small bunch of batches of reads of the same keys from an object store.
73 [testReadCache, 10, kDontUseIndex],
74 // Make a bunch of batches of reads of the same keys from an index.
75 [testReadCache, 50, kUseIndex],
76 // Make a small bunch of batches of reads of the same keys from an object store.
77 [testReadCache, 10, kDontUseIndex],
78 // Make a bunch of batches of reads of the same keys from an index.
79 [testReadCache, 50, kUseIndex],
80 // Create and delete an index on a store that already contains data [produces
81 // a timing result for each of creation and deletion].
82 [testCreateAndDeleteIndex, 5000],
83 // Walk through multiple cursors into the same object store, round-robin, until
84 // you've reached the end of each of them.
85 [testWalkingMultipleCursors, 5],
86 // Walk through many cursors into the same object store, round-robin, until
87 // you've reached the end of each of them.
88 [testWalkingMultipleCursors, 50],
89 // Open an object store cursor, then continue(key) to the last value.
90 [testCursorSeeks, 2000, 10, 4, kDontUseIndex],
91 // Open an index key cursor, then continue(key) to the last value.
92 [testCursorSeeks, 2000, 10, 4, kUseIndex],
95 var currentTest = 0;
96 var done = false;
98 function test() {
99 runNextTest();
102 var testFilter;
104 function runNextTest() {
105 var filter = testFilter | window.location.hash.slice(1);
106 var test, f;
107 while (currentTest < tests.length) {
108 test = tests[currentTest];
109 f = test.shift();
110 if (!filter || f.name == filter)
111 break;
112 ++currentTest;
115 if (currentTest < tests.length) {
116 test.push(runNextTest);
117 f.apply(null, test);
118 ++currentTest;
119 } else {
120 onAllTestsComplete();
124 function onAllTestsComplete() {
125 var overallDuration = window.performance.now() - overallTestStartTime;
126 automation.addResult("OverallTestDuration", overallDuration);
127 automation.setDone();
128 done = true;
131 // This is the only test that includes database creation and deletion in its
132 // results; the others just test specific operations. To see only the
133 // creation/deletion without the specific operations used to build up the data
134 // in the object stores here, subtract off the results of
135 // testCreateKeysInStores.
136 function testCreateAndDeleteDatabase(
137 numKeys, numStores, payloadLength, onTestComplete) {
138 var testName = getDisplayName(arguments);
139 assert(numKeys >= 0);
140 assert(numStores >= 1);
141 var objectStoreNames = [];
142 for (var i=0; i < numStores; ++i) {
143 objectStoreNames.push("store " + i);
145 var value = stringOfLength(payloadLength);
146 function getValue() {
147 return value;
150 automation.setStatus("Creating database.");
151 var startTime = window.performance.now();
153 createDatabase(testName, objectStoreNames, onCreated, onError);
155 function onCreated(db) {
156 automation.setStatus("Constructing transaction.");
157 var transaction =
158 getTransaction(db, objectStoreNames, "readwrite",
159 function() { onValuesWritten(db); });
160 putLinearValues(transaction, objectStoreNames, numKeys, null, getValue);
163 function onValuesWritten(db) {
164 automation.setStatus("Deleting database.");
165 db.close();
166 deleteDatabase(testName, onDeleted);
169 function onDeleted() {
170 var duration = window.performance.now() - startTime;
171 automation.addResult(testName, duration);
172 automation.setStatus("Deleted database.");
173 onTestComplete();
177 function testCreateKeysInStores(
178 numKeys, numStores, payloadLength, onTestComplete) {
179 var testName = getDisplayName(arguments);
180 assert(numKeys >= 0);
181 assert(numStores >= 1);
182 var objectStoreNames = [];
183 for (var i=0; i < numStores; ++i) {
184 objectStoreNames.push("store " + i);
186 var value = stringOfLength(payloadLength);
187 function getValue() {
188 return value;
191 automation.setStatus("Creating database.");
192 createDatabase(testName, objectStoreNames, onCreated, onError);
194 function onCreated(db) {
195 automation.setStatus("Constructing transaction.");
196 var completionFunc =
197 getCompletionFunc(db, testName, window.performance.now(),
198 onTestComplete);
199 var transaction =
200 getTransaction(db, objectStoreNames, "readwrite", completionFunc);
201 putLinearValues(transaction, objectStoreNames, numKeys, null, getValue);
205 function testRandomReadsAndWrites(
206 numKeys, numReadsPerTransaction, numWritesPerTransaction, numTransactions,
207 useIndexForReads, onTestComplete) {
208 var indexName;
209 if (useIndexForReads)
210 indexName = "index";
211 var testName = getDisplayName(arguments);
212 var objectStoreNames = ["store"];
213 var getKey = getSimpleKey;
214 var getValue = useIndexForReads ? getIndexableValue : getSimpleValue;
216 automation.setStatus("Creating database.");
217 var options;
218 if (useIndexForReads) {
219 options = [{
220 indexName: indexName,
221 indexKeyPath: "id",
222 indexIsUnique: false,
223 indexIsMultiEntry: false,
226 createDatabase(testName, objectStoreNames, onCreated, onError, options);
228 function onCreated(db) {
229 automation.setStatus("Setting up test database.");
230 var transaction = getTransaction(db, objectStoreNames, "readwrite",
231 function() { onSetupComplete(db); });
232 putLinearValues(transaction, objectStoreNames, numKeys, null,
233 function() { return "test value"; });
236 function onSetupComplete(db) {
237 automation.setStatus("Setup complete.");
238 var completionFunc =
239 getCompletionFunc(db, testName, window.performance.now(),
240 onTestComplete);
241 var mode = "readonly";
242 if (numWritesPerTransaction)
243 mode = "readwrite";
244 runTransactionBatch(db, numTransactions, batchFunc, objectStoreNames, mode,
245 completionFunc);
248 function batchFunc(transaction) {
249 getRandomValues(transaction, objectStoreNames, numReadsPerTransaction,
250 numKeys, indexName, getKey);
251 putRandomValues(transaction, objectStoreNames, numWritesPerTransaction,
252 numKeys, getKey, getValue);
256 function testReadCache(numTransactions, useIndexForReads, onTestComplete) {
257 var numKeys = 10000;
258 var numReadsPerTransaction = 50;
259 var numTransactionsLeft = numTransactions;
260 var indexName;
261 if (useIndexForReads)
262 indexName = "index";
263 var testName = getDisplayName(arguments);
264 var objectStoreNames = ["store"];
265 var getKey = getSimpleKey;
266 var getValue = useIndexForReads ? getIndexableValue : getSimpleValue;
267 var keys = [];
269 for (var i=0; i < numReadsPerTransaction; ++i) {
270 keys.push(getKey(Math.floor(random() * numKeys)));
273 automation.setStatus("Creating database.");
274 var options;
275 if (useIndexForReads) {
276 options = [{
277 indexName: indexName,
278 indexKeyPath: "id",
279 indexIsUnique: false,
280 indexIsMultiEntry: false,
283 createDatabase(testName, objectStoreNames, onCreated, onError, options);
285 function onCreated(db) {
286 automation.setStatus("Setting up test database.");
287 var transaction = getTransaction(db, objectStoreNames, "readwrite",
288 function() { onSetupComplete(db); });
289 putLinearValues(transaction, objectStoreNames, numKeys, getKey,
290 getValue);
293 var completionFunc;
294 function onSetupComplete(db) {
295 automation.setStatus("Setup complete.");
296 completionFunc =
297 getCompletionFunc(db, testName, window.performance.now(),
298 onTestComplete);
299 runTransactionBatch(db, numTransactions, batchFunc, objectStoreNames,
300 "readonly", completionFunc);
303 function batchFunc(transaction) {
304 getSpecificValues(transaction, objectStoreNames, indexName, keys);
308 function testCreateAndDeleteIndex(numKeys, onTestComplete) {
309 var testName = getDisplayName(arguments);
310 var objectStoreNames = ["store"];
312 automation.setStatus("Creating database.");
313 createDatabase(testName, objectStoreNames, onCreated, onError);
315 var startTime;
316 function onCreated(db) {
317 automation.setStatus("Initializing data.");
318 var transaction = getTransaction(db, objectStoreNames, "readwrite",
319 function() { onPopulated(db); });
320 putLinearValues(transaction, objectStoreNames, numKeys, null, getValue);
323 function getValue(i) {
324 return { firstName: i + " first name", lastName: i + " last name" };
327 function onPopulated(db) {
328 db.close();
329 automation.setStatus("Building index.");
330 startTime = window.performance.now();
331 var f = function(objectStore) {
332 objectStore.createIndex("index", "firstName", {unique: true});
334 alterObjectStores(testName, objectStoreNames, f, onIndexCreated, onError);
337 var indexCreationCompleteTime;
338 function onIndexCreated(db) {
339 db.close();
340 indexCreationCompleteTime = window.performance.now();
341 automation.addResult("testCreateIndex",
342 indexCreationCompleteTime - startTime);
343 var f = function(objectStore) {
344 objectStore.deleteIndex("index");
346 automation.setStatus("Deleting index.");
347 alterObjectStores(testName, objectStoreNames, f, onIndexDeleted, onError);
350 function onIndexDeleted(db) {
351 var duration = window.performance.now() - indexCreationCompleteTime;
352 // Ignore the cleanup time for this test.
353 automation.addResult("testDeleteIndex", duration);
354 automation.setStatus("Deleting database.");
355 db.close();
356 deleteDatabase(testName, onDeleted);
359 function onDeleted() {
360 automation.setStatus("Deleted database.");
361 onTestComplete();
365 function testCursorReadsAndRandomWrites(
366 readKeysOnly, useIndexForReads, writeAlso, sameStoreForWrites,
367 onTestComplete) {
368 // There's no key cursor unless you're reading from an index.
369 assert(useIndexForReads || !readKeysOnly);
370 // If we're writing to another store, having an index would constrain our
371 // writes, as we create both object stores with the same configurations.
372 // We could do that if needed, but it's simpler not to.
373 assert(!useIndexForReads || !writeAlso);
374 var numKeys = 10000;
375 var numReadsPerTransaction = 1000;
376 var testName = getDisplayName(arguments);
377 var objectStoreNames = ["input store"];
378 var outputStoreName;
379 if (writeAlso) {
380 if (sameStoreForWrites) {
381 outputStoreName = objectStoreNames[0];
382 } else {
383 outputStoreName = "output store";
384 objectStoreNames.push(outputStoreName);
387 var getKeyForRead = getSimpleKey;
388 var indexName;
389 if (useIndexForReads) {
390 indexName = "index";
391 getKeyForRead = function(i) {
392 // This depends on the implementations of getValuesFromCursor and
393 // getObjectValue. We reverse the order of the iteration here so that
394 // setting up bounds from k to k+n with n>0 works. Without this reversal,
395 // the upper bound is below the lower bound.
396 return getBackwardIndexKey(numKeys - i);
400 automation.setStatus("Creating database.");
401 var options;
402 if (useIndexForReads) {
403 options = [{
404 indexName: indexName,
405 indexKeyPath: "lastName", // depends on getBackwardIndexKey()
406 indexIsUnique: true,
407 indexIsMultiEntry: false,
410 createDatabase(testName, objectStoreNames, onCreated, onError, options);
412 function onCreated(db) {
413 automation.setStatus("Setting up test database.");
414 var transaction = getTransaction(db, objectStoreNames, "readwrite",
415 function() { onSetupComplete(db); });
416 putLinearValues(transaction, objectStoreNames, numKeys, getSimpleKey,
417 getObjectValue);
419 function onSetupComplete(db) {
420 automation.setStatus("Setup complete.");
421 var completionFunc =
422 getCompletionFunc(db, testName, window.performance.now(),
423 onTestComplete);
424 var mode = "readonly";
425 if (writeAlso)
426 mode = "readwrite";
427 var transaction =
428 getTransaction(db, objectStoreNames, mode, completionFunc);
430 getValuesFromCursor(
431 transaction, objectStoreNames[0], numReadsPerTransaction, numKeys,
432 indexName, getKeyForRead, readKeysOnly, outputStoreName);
436 function testWalkingMultipleCursors(numCursors, onTestComplete) {
437 var numKeys = 1000;
438 var numHitsPerKey = 10;
439 var testName = getDisplayName(arguments);
440 var objectStoreNames = ["input store"];
441 var indexName = "index name";
442 var getKey = getSimpleKey;
443 var getValue = getIndexableValue;
445 automation.setStatus("Creating database.");
446 var options = [{
447 indexName: indexName,
448 indexKeyPath: "id",
449 indexIsUnique: false,
450 indexIsMultiEntry: false,
452 createDatabase(testName, objectStoreNames, onCreated, onError, options);
454 function onCreated(db) {
455 automation.setStatus("Setting up test database.");
456 var transaction = getTransaction(db, objectStoreNames, "readwrite",
457 function() { onSetupComplete(db); });
458 // This loop adds the same value numHitsPerKey times for each key.
459 for (var i = 0; i < numHitsPerKey; ++i) {
460 putLinearValues(transaction, objectStoreNames, numKeys, getKeyFunc(i),
461 getValue);
464 // While the value is the same each time through the putLinearValues loop, we
465 // want the key to keep increaasing for each copy.
466 function getKeyFunc(k) {
467 return function(i) {
468 return getKey(k * numKeys + i);
471 var completionFunc;
472 function onSetupComplete(db) {
473 automation.setStatus("Setup complete.");
474 completionFunc =
475 getCompletionFunc(db, testName, window.performance.now(),
476 onTestComplete);
477 var transaction =
478 getTransaction(db, objectStoreNames, "readonly", verifyComplete);
480 walkSeveralCursors(transaction, numKeys);
482 var responseCounts = [];
483 var cursorsRunning = numCursors;
484 function walkSeveralCursors(transaction, numKeys) {
485 var source = transaction.objectStore(objectStoreNames[0]).index(indexName);
486 var requests = [];
487 var continueCursorIndex = 0;
488 for (var i = 0; i < numCursors; ++i) {
489 var rand = Math.floor(random() * numKeys);
490 // Since we have numHitsPerKey copies of each value in the database,
491 // IDBKeyRange.only will return numHitsPerKey results, each referring to a
492 // different key with the matching value.
493 var request = source.openCursor(IDBKeyRange.only(getSimpleValue(rand)));
494 responseCounts.push(0);
495 request.onerror = onError;
496 request.onsuccess = function(event) {
497 assert(cursorsRunning);
498 var request = event.target;
499 if (!("requestIndex" in request)) {
500 assert(requests.length < numCursors);
501 request.requestIndex = requests.length;
502 requests.push(request);
504 var cursor = event.target.result;
505 if (cursor) {
506 assert(responseCounts[request.requestIndex] < numHitsPerKey);
507 ++responseCounts[request.requestIndex];
508 } else {
509 assert(responseCounts[request.requestIndex] == numHitsPerKey);
510 --cursorsRunning;
512 if (cursorsRunning) {
513 if (requests.length == numCursors) {
514 requests[continueCursorIndex++].result.continue();
515 continueCursorIndex %= numCursors;
521 function verifyComplete() {
522 assert(!cursorsRunning);
523 completionFunc();
527 function testCursorSeeks(
528 numKeys, numSeeksPerTransaction, numTransactions, useIndexForReads,
529 onTestComplete) {
530 var testName = getDisplayName(arguments);
531 var objectStoreNames = ["store"];
532 var getKey = useIndexForReads ? getForwardIndexKey : getSimpleKey;
533 var indexName;
534 if (useIndexForReads) {
535 indexName = "index";
538 automation.setStatus("Creating database.");
539 var options;
540 if (useIndexForReads) {
541 options = [{
542 indexName: indexName,
543 indexKeyPath: "firstName",
544 indexIsUnique: true,
545 indexIsMultiEntry: false,
548 createDatabase(testName, objectStoreNames, onCreated, onError, options);
550 function onCreated(db) {
551 automation.setStatus("Setting up test database.");
552 var transaction = getTransaction(db, objectStoreNames, "readwrite",
553 function() { onSetupComplete(db); });
554 putLinearValues(transaction, objectStoreNames, numKeys, getSimpleKey,
555 getObjectValue);
558 function onSetupComplete(db) {
559 automation.setStatus("Setup complete.");
560 var completionFunc =
561 getCompletionFunc(db, testName, window.performance.now(),
562 onTestComplete);
563 var mode = "readonly";
564 runTransactionBatch(db, numTransactions, batchFunc, objectStoreNames, mode,
565 completionFunc);
568 function batchFunc(transaction) {
569 for (var i in objectStoreNames) {
570 var source = transaction.objectStore(objectStoreNames[i]);
571 if (useIndexForReads)
572 source = source.index(indexName);
573 for (var j = 0; j < numSeeksPerTransaction; ++j) {
574 randomSeek(source);
579 function randomSeek(source) {
580 var request = useIndexForReads ? source.openKeyCursor()
581 : source.openCursor();
582 var first = true;
583 request.onerror = onError;
584 request.onsuccess = function() {
585 var cursor = request.result;
586 if (cursor && first) {
587 first = false;
588 cursor.continue(getKey(numKeys - 1));