blob: aba3ed750828c24c527c1a14d9cdfe8acce4695d [file] [log] [blame]
// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
/// Benchmarks for the PathSet class.
library watcher.benchmark.path_set;
import 'dart:io';
import 'dart:math' as math;
import 'package:benchmark_harness/benchmark_harness.dart';
import 'package:path/path.dart' as p;
import 'package:watcher/src/path_set.dart';
final String root = Platform.isWindows ? r"C:\root" : "/root";
/// Base class for benchmarks on [PathSet].
abstract class PathSetBenchmark extends BenchmarkBase {
PathSetBenchmark(String method) : super("PathSet.$method");
final PathSet pathSet = new PathSet(root);
/// Use a fixed [Random] with a constant seed to ensure the tests are
/// deterministic.
final math.Random random = new math.Random(1234);
/// Walks over a virtual directory [depth] levels deep invoking [callback]
/// for each "file".
///
/// Each virtual directory contains ten entries: either subdirectories or
/// files.
void walkTree(int depth, callback(String path)) {
recurse(path, remainingDepth) {
for (var i = 0; i < 10; i++) {
var padded = i.toString().padLeft(2, '0');
if (remainingDepth == 0) {
callback(p.join(path, "file_$padded.txt"));
} else {
var subdir = p.join(path, "subdirectory_$padded");
recurse(subdir, remainingDepth - 1);
}
}
}
recurse(root, depth);
}
}
class AddBenchmark extends PathSetBenchmark {
AddBenchmark() : super("add()");
final List<String> paths = [];
void setup() {
// Make a bunch of paths in about the same order we expect to get them from
// Directory.list().
walkTree(3, paths.add);
}
void run() {
for (var path in paths) pathSet.add(path);
}
}
class ContainsBenchmark extends PathSetBenchmark {
ContainsBenchmark() : super("contains()");
final List<String> paths = [];
void setup() {
// Add a bunch of paths to the set.
walkTree(3, (path) {
pathSet.add(path);
paths.add(path);
});
// Add some non-existent paths to test the false case.
for (var i = 0; i < 100; i++) {
paths.addAll([
"/nope",
"/root/nope",
"/root/subdirectory_04/nope",
"/root/subdirectory_04/subdirectory_04/nope",
"/root/subdirectory_04/subdirectory_04/subdirectory_04/nope",
"/root/subdirectory_04/subdirectory_04/subdirectory_04/nope/file_04.txt",
]);
}
}
void run() {
var contained = 0;
for (var path in paths) {
if (pathSet.contains(path)) contained++;
}
if (contained != 10000) throw "Wrong result: $contained";
}
}
class PathsBenchmark extends PathSetBenchmark {
PathsBenchmark() : super("toSet()");
void setup() {
walkTree(3, pathSet.add);
}
void run() {
var count = 0;
for (var _ in pathSet.paths) {
count++;
}
if (count != 10000) throw "Wrong result: $count";
}
}
class RemoveBenchmark extends PathSetBenchmark {
RemoveBenchmark() : super("remove()");
final List<String> paths = [];
void setup() {
// Make a bunch of paths. Do this here so that we don't spend benchmarked
// time synthesizing paths.
walkTree(3, (path) {
pathSet.add(path);
paths.add(path);
});
// Shuffle the paths so that we delete them in a random order that
// hopefully mimics real-world file system usage. Do the shuffling here so
// that we don't spend benchmarked time shuffling.
paths.shuffle(random);
}
void run() {
for (var path in paths) pathSet.remove(path);
}
}
main() {
new AddBenchmark().report();
new ContainsBenchmark().report();
new PathsBenchmark().report();
new RemoveBenchmark().report();
}