| "use strict"; |
| |
| /* |
| * Copyright (C) 2018 Apple Inc. All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * 1. Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * 2. Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in the |
| * documentation and/or other materials provided with the distribution. |
| * |
| * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' |
| * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, |
| * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
| * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS |
| * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
| * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
| * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
| * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
| * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
| * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF |
| * THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| let seed; |
| function resetSeed() { |
| seed = 49734321; |
| } |
| resetSeed(); |
| |
| Math.random = (function() { |
| return function() { |
| // Robert Jenkins' 32 bit integer hash function. |
| seed = ((seed + 0x7ed55d16) + (seed << 12)) & 0xffffffff; |
| seed = ((seed ^ 0xc761c23c) ^ (seed >>> 19)) & 0xffffffff; |
| seed = ((seed + 0x165667b1) + (seed << 5)) & 0xffffffff; |
| seed = ((seed + 0xd3a2646c) ^ (seed << 9)) & 0xffffffff; |
| seed = ((seed + 0xfd7046c5) + (seed << 3)) & 0xffffffff; |
| seed = ((seed ^ 0xb55a4f09) ^ (seed >>> 16)) & 0xffffffff; |
| return (seed & 0xfffffff) / 0x10000000; |
| }; |
| })(); |
| |
| function computeIsLittleEndian() { |
| let buf = new ArrayBuffer(4); |
| let dv = new DataView(buf); |
| dv.setUint32(0, 0x11223344, true); |
| let view = new Uint8Array(buf); |
| return view[0] === 0x44; |
| } |
| |
| const isLittleEndian = computeIsLittleEndian(); |
| |
| function randomFileContents(bytes = ((Math.random() * 128) >>> 0) + 2056) { |
| let result = new ArrayBuffer(bytes); |
| let view = new Uint8Array(result); |
| for (let i = 0; i < bytes; ++i) |
| view[i] = (Math.random() * 255) >>> 0; |
| return new DataView(result); |
| } |
| |
| class File { |
| constructor(dataView, permissions) { |
| this._data = dataView; |
| } |
| |
| get data() { return this._data; } |
| |
| set data(dataView) { this._data = dataView; } |
| |
| swapByteOrder() { |
| for (let i = 0; i < Math.floor(this.data.byteLength / 8) * 8; i += 8) { |
| this.data.setFloat64(i, this.data.getFloat64(i, isLittleEndian), !isLittleEndian); |
| } |
| } |
| } |
| |
| class Directory { |
| constructor() { |
| this.structure = new Map; |
| } |
| |
| async addFile(name, file) { |
| let entry = this.structure.get(name); |
| if (entry !== undefined) { |
| if (entry instanceof File) |
| throw new Error("Can't replace file with file."); |
| if (entry instanceof Directory) |
| throw new Error("Can't replace a file with a new directory."); |
| throw new Error("Should not reach this code"); |
| } |
| |
| this.structure.set(name, file); |
| return file; |
| } |
| |
| async addDirectory(name, directory = new Directory) { |
| let entry = this.structure.get(name); |
| if (entry !== undefined) { |
| if (entry instanceof File) |
| throw new Error("Can't replace file with directory."); |
| if (entry instanceof Directory) |
| throw new Error("Can't replace directory with new directory."); |
| throw new Error("Should not reach this code"); |
| } |
| |
| this.structure.set(name, directory); |
| return directory; |
| } |
| |
| async* ls() { |
| for (let [name, entry] of this.structure) |
| yield { name, entry, isDirectory: entry instanceof Directory }; |
| } |
| |
| async* forEachFile() { |
| for await (let item of this.ls()) { |
| if (!item.isDirectory) |
| yield item; |
| } |
| } |
| |
| async* forEachFileRecursively() { |
| for await (let item of this.ls()) { |
| if (item.isDirectory) { |
| for await (let file of item.entry.forEachFileRecursively()) |
| yield file; |
| } else { |
| yield item; |
| } |
| } |
| } |
| |
| async* forEachDirectoryRecursively() { |
| for await (let item of this.ls()) { |
| if (!item.isDirectory) |
| continue; |
| |
| for await (let dirItem of item.entry.forEachDirectoryRecursively()) |
| yield dirItem; |
| |
| yield item; |
| } |
| } |
| |
| async fileCount() { |
| let count = 0; |
| for await (let item of this.ls()) { |
| if (!item.isDirectory) |
| ++count; |
| } |
| |
| return count; |
| } |
| |
| async rm(name) { |
| return this.structure.delete(name); |
| } |
| } |
| |
| async function setupDirectory() { |
| const fs = new Directory; |
| let dirs = [fs]; |
| for (let dir of dirs) { |
| for (let i = 0; i < 8; ++i) { |
| if (dirs.length < 250 && Math.random() >= 0.3) { |
| dirs.push(await dir.addDirectory(`dir-${i}`)); |
| } |
| } |
| } |
| |
| for (let dir of dirs) { |
| for (let i = 0; i < 5; ++i) { |
| if (Math.random() >= 0.6) { |
| await dir.addFile(`file-${i}`, new File(randomFileContents())); |
| } |
| } |
| } |
| |
| return fs; |
| } |
| |
| class Benchmark { |
| async runIteration() { |
| resetSeed(); |
| |
| try { |
| const fs = await setupDirectory(); |
| |
| for await (let { entry: file } of fs.forEachFileRecursively()) { |
| file.swapByteOrder(); |
| } |
| |
| for await (let { name, entry: dir } of fs.forEachDirectoryRecursively()) { |
| if ((await dir.fileCount()) > 3) { |
| for await (let { name } of dir.forEachFile()) { |
| let result = await dir.rm(name); |
| if (!result) |
| throw new Error("rm should have returned true"); |
| |
| } |
| } |
| } |
| } catch(e) { |
| console.log("Error running benchmark: ", e, e.line); |
| } |
| } |
| } |