diff --git a/test/benchmark/binary_trees.dart b/test/benchmark/binary_trees.dart new file mode 100644 index 00000000..f14551d0 --- /dev/null +++ b/test/benchmark/binary_trees.dart @@ -0,0 +1,60 @@ +// Ported from the Wren version. + +class Tree { + var _item; + var _left; + var _right; + + Tree(item, depth) { + _item = item; + if (depth > 0) { + var item2 = item + item; + depth--; + _left = new Tree(item2 - 1, depth); + _right = new Tree(item2, depth); + } + } + + get check { + if (_left == null) { + return _item; + } + + return _item + _left.check - _right.check; + } +} + +main() { + var minDepth = 4; + var maxDepth = 12; + var stretchDepth = maxDepth + 1; + + Stopwatch watch = new Stopwatch(); + watch.start(); + + print("stretch tree of depth ${stretchDepth} check: " + "${new Tree(0, stretchDepth).check}"); + + var longLivedTree = new Tree(0, maxDepth); + + // iterations = 2 ** maxDepth + var iterations = 1; + for (var d = 0; d < maxDepth; d++) { + iterations = iterations * 2; + } + + var depth = minDepth; + while (depth < stretchDepth) { + var check = 0; + for (var i = 1; i <= iterations; i++) { + check += new Tree(i, depth).check + new Tree(-i, depth).check; + } + + print("${iterations * 2} trees of depth ${depth} check: ${check}"); + iterations ~/= 4; + depth += 2; + } + + print("long lived tree of depth ${maxDepth} check: ${longLivedTree.check}"); + print("elapsed: ${watch.elapsedMilliseconds / 1000}"); +} diff --git a/test/benchmark/delta_blue.dart b/test/benchmark/delta_blue.dart new file mode 100644 index 00000000..5043f7dd --- /dev/null +++ b/test/benchmark/delta_blue.dart @@ -0,0 +1,728 @@ +// Copyright 2011 Google Inc. All Rights Reserved. +// Copyright 1996 John Maloney and Mario Wolczko +// +// This file is part of GNU Smalltalk. +// +// GNU Smalltalk is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the Free +// Software Foundation; either version 2, or (at your option) any later version. +// +// GNU Smalltalk is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more +// details. +// +// You should have received a copy of the GNU General Public License along with +// GNU Smalltalk; see the file COPYING. If not, write to the Free Software +// Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +// Translated first from Smalltalk to JavaScript, and finally to +// Dart by Google 2008-2010. + +/** + * A Dart implementation of the DeltaBlue constraint-solving + * algorithm, as described in: + * + * "The DeltaBlue Algorithm: An Incremental Constraint Hierarchy Solver" + * Bjorn N. Freeman-Benson and John Maloney + * January 1990 Communications of the ACM, + * also available as University of Washington TR 89-08-06. + * + * Beware: this benchmark is written in a grotesque style where + * the constraint model is built by side-effects from constructors. + * I've kept it this way to avoid deviating too much from the original + * implementation. + */ + +var total = 0; + +//Greg: Not using the dart benchmark harness, so I can observe warm up behaviour. +main() { + int iterations = 40; + + Stopwatch watch = new Stopwatch(); + watch.start(); + + for (int i = 0; i < iterations; i++) { + chainTest(100); + projectionTest(100); + } + + print(total); + print("elapsed: ${watch.elapsedMilliseconds / 1000}"); +} + +/** + * Strengths are used to measure the relative importance of constraints. + * New strengths may be inserted in the strength hierarchy without + * disrupting current constraints. Strengths cannot be created outside + * this class, so == can be used for value comparison. + */ +class Strength { + + final int value; + final String name; + + const Strength(this.value, this.name); + + Strength nextWeaker() => + const [WEAKEST, WEAK_DEFAULT, NORMAL, STRONG_DEFAULT, + PREFERRED, STRONG_REFERRED][value]; + + static bool stronger(Strength s1, Strength s2) { + return s1.value < s2.value; + } + + static bool weaker(Strength s1, Strength s2) { + return s1.value > s2.value; + } + + static Strength weakest(Strength s1, Strength s2) { + return weaker(s1, s2) ? s1 : s2; + } + + static Strength strongest(Strength s1, Strength s2) { + return stronger(s1, s2) ? s1 : s2; + } +} + + +// Compile time computed constants. +const REQUIRED = const Strength(0, "required"); +const STRONG_REFERRED = const Strength(1, "strongPreferred"); +const PREFERRED = const Strength(2, "preferred"); +const STRONG_DEFAULT = const Strength(3, "strongDefault"); +const NORMAL = const Strength(4, "normal"); +const WEAK_DEFAULT = const Strength(5, "weakDefault"); +const WEAKEST = const Strength(6, "weakest"); + + +abstract class Constraint { + + final Strength strength; + + const Constraint(this.strength); + + bool isSatisfied(); + void markUnsatisfied(); + void addToGraph(); + void removeFromGraph(); + void chooseMethod(int mark); + void markInputs(int mark); + bool inputsKnown(int mark); + Variable output(); + void execute(); + void recalculate(); + + /// Activate this constraint and attempt to satisfy it. + void addConstraint() { + addToGraph(); + planner.incrementalAdd(this); + } + + /** + * Attempt to find a way to enforce this constraint. If successful, + * record the solution, perhaps modifying the current dataflow + * graph. Answer the constraint that this constraint overrides, if + * there is one, or nil, if there isn't. + * Assume: I am not already satisfied. + */ + Constraint satisfy(mark) { + chooseMethod(mark); + if (!isSatisfied()) { + if (strength == REQUIRED) { + print("Could not satisfy a required constraint!"); + } + return null; + } + markInputs(mark); + Variable out = output(); + Constraint overridden = out.determinedBy; + if (overridden != null) overridden.markUnsatisfied(); + out.determinedBy = this; + if (!planner.addPropagate(this, mark)) print("Cycle encountered"); + out.mark = mark; + return overridden; + } + + void destroyConstraint() { + if (isSatisfied()) planner.incrementalRemove(this); + removeFromGraph(); + } + + /** + * Normal constraints are not input constraints. An input constraint + * is one that depends on external state, such as the mouse, the + * keybord, a clock, or some arbitraty piece of imperative code. + */ + bool isInput() => false; +} + +/** + * Abstract superclass for constraints having a single possible output variable. + */ +abstract class UnaryConstraint extends Constraint { + + final Variable myOutput; + bool satisfied = false; + + UnaryConstraint(this.myOutput, Strength strength) : super(strength) { + addConstraint(); + } + + /// Adds this constraint to the constraint graph + void addToGraph() { + myOutput.addConstraint(this); + satisfied = false; + } + + /// Decides if this constraint can be satisfied and records that decision. + void chooseMethod(int mark) { + satisfied = (myOutput.mark != mark) + && Strength.stronger(strength, myOutput.walkStrength); + } + + /// Returns true if this constraint is satisfied in the current solution. + bool isSatisfied() => satisfied; + + void markInputs(int mark) { + // has no inputs. + } + + /// Returns the current output variable. + Variable output() => myOutput; + + /** + * Calculate the walkabout strength, the stay flag, and, if it is + * 'stay', the value for the current output of this constraint. Assume + * this constraint is satisfied. + */ + void recalculate() { + myOutput.walkStrength = strength; + myOutput.stay = !isInput(); + if (myOutput.stay) execute(); // Stay optimization. + } + + /// Records that this constraint is unsatisfied. + void markUnsatisfied() { + satisfied = false; + } + + bool inputsKnown(int mark) => true; + + void removeFromGraph() { + if (myOutput != null) myOutput.removeConstraint(this); + satisfied = false; + } +} + + +/** + * Variables that should, with some level of preference, stay the same. + * Planners may exploit the fact that instances, if satisfied, will not + * change their output during plan execution. This is called "stay + * optimization". + */ +class StayConstraint extends UnaryConstraint { + + StayConstraint(Variable v, Strength str) : super(v, str); + + void execute() { + // Stay constraints do nothing. + } +} + + +/** + * A unary input constraint used to mark a variable that the client + * wishes to change. + */ +class EditConstraint extends UnaryConstraint { + + EditConstraint(Variable v, Strength str) : super(v, str); + + /// Edits indicate that a variable is to be changed by imperative code. + bool isInput() => true; + + void execute() { + // Edit constraints do nothing. + } +} + + +// Directions. +const int NONE = 1; +const int FORWARD = 2; +const int BACKWARD = 0; + + +/** + * Abstract superclass for constraints having two possible output + * variables. + */ +abstract class BinaryConstraint extends Constraint { + + Variable v1; + Variable v2; + int direction = NONE; + + BinaryConstraint(this.v1, this.v2, Strength strength) : super(strength) { + addConstraint(); + } + + /** + * Decides if this constraint can be satisfied and which way it + * should flow based on the relative strength of the variables related, + * and record that decision. + */ + void chooseMethod(int mark) { + if (v1.mark == mark) { + direction = (v2.mark != mark && + Strength.stronger(strength, v2.walkStrength)) + ? FORWARD : NONE; + } + if (v2.mark == mark) { + direction = (v1.mark != mark && + Strength.stronger(strength, v1.walkStrength)) + ? BACKWARD : NONE; + } + if (Strength.weaker(v1.walkStrength, v2.walkStrength)) { + direction = Strength.stronger(strength, v1.walkStrength) + ? BACKWARD : NONE; + } else { + direction = Strength.stronger(strength, v2.walkStrength) + ? FORWARD : BACKWARD; + } + } + + /// Add this constraint to the constraint graph. + void addToGraph() { + v1.addConstraint(this); + v2.addConstraint(this); + direction = NONE; + } + + /// Answer true if this constraint is satisfied in the current solution. + bool isSatisfied() => direction != NONE; + + /// Mark the input variable with the given mark. + void markInputs(int mark) { + input().mark = mark; + } + + /// Returns the current input variable + Variable input() => direction == FORWARD ? v1 : v2; + + /// Returns the current output variable. + Variable output() => direction == FORWARD ? v2 : v1; + + /** + * Calculate the walkabout strength, the stay flag, and, if it is + * 'stay', the value for the current output of this + * constraint. Assume this constraint is satisfied. + */ + void recalculate() { + Variable ihn = input(), out = output(); + out.walkStrength = Strength.weakest(strength, ihn.walkStrength); + out.stay = ihn.stay; + if (out.stay) execute(); + } + + /// Record the fact that this constraint is unsatisfied. + void markUnsatisfied() { + direction = NONE; + } + + bool inputsKnown(int mark) { + Variable i = input(); + return i.mark == mark || i.stay || i.determinedBy == null; + } + + void removeFromGraph() { + if (v1 != null) v1.removeConstraint(this); + if (v2 != null) v2.removeConstraint(this); + direction = NONE; + } +} + + +/** + * Relates two variables by the linear scaling relationship: "v2 = + * (v1 * scale) + offset". Either v1 or v2 may be changed to maintain + * this relationship but the scale factor and offset are considered + * read-only. + */ + +class ScaleConstraint extends BinaryConstraint { + + final Variable scale; + final Variable offset; + + ScaleConstraint(Variable src, this.scale, this.offset, + Variable dest, Strength strength) + : super(src, dest, strength); + + /// Adds this constraint to the constraint graph. + void addToGraph() { + super.addToGraph(); + scale.addConstraint(this); + offset.addConstraint(this); + } + + void removeFromGraph() { + super.removeFromGraph(); + if (scale != null) scale.removeConstraint(this); + if (offset != null) offset.removeConstraint(this); + } + + void markInputs(int mark) { + super.markInputs(mark); + scale.mark = offset.mark = mark; + } + + /// Enforce this constraint. Assume that it is satisfied. + void execute() { + if (direction == FORWARD) { + v2.value = v1.value * scale.value + offset.value; + } else { + v1.value = (v2.value - offset.value) ~/ scale.value; + } + } + + /** + * Calculate the walkabout strength, the stay flag, and, if it is + * 'stay', the value for the current output of this constraint. Assume + * this constraint is satisfied. + */ + void recalculate() { + Variable ihn = input(), out = output(); + out.walkStrength = Strength.weakest(strength, ihn.walkStrength); + out.stay = ihn.stay && scale.stay && offset.stay; + if (out.stay) execute(); + } + +} + + +/** + * Constrains two variables to have the same value. + */ +class EqualityConstraint extends BinaryConstraint { + + EqualityConstraint(Variable v1, Variable v2, Strength strength) + : super(v1, v2, strength); + + /// Enforce this constraint. Assume that it is satisfied. + void execute() { + output().value = input().value; + } +} + + +/** + * A constrained variable. In addition to its value, it maintain the + * structure of the constraint graph, the current dataflow graph, and + * various parameters of interest to the DeltaBlue incremental + * constraint solver. + **/ +class Variable { + + List constraints = []; + Constraint determinedBy; + int mark = 0; + Strength walkStrength = WEAKEST; + bool stay = true; + int value; + final String name; + + Variable(this.name, this.value); + + /** + * Add the given constraint to the set of all constraints that refer + * this variable. + */ + void addConstraint(Constraint c) { + constraints.add(c); + } + + /// Removes all traces of c from this variable. + void removeConstraint(Constraint c) { + constraints = constraints.where((e) => c != e).toList(); + if (determinedBy == c) determinedBy = null; + } +} + + +class Planner { + + int currentMark = 0; + + /** + * Attempt to satisfy the given constraint and, if successful, + * incrementally update the dataflow graph. Details: If satifying + * the constraint is successful, it may override a weaker constraint + * on its output. The algorithm attempts to resatisfy that + * constraint using some other method. This process is repeated + * until either a) it reaches a variable that was not previously + * determined by any constraint or b) it reaches a constraint that + * is too weak to be satisfied using any of its methods. The + * variables of constraints that have been processed are marked with + * a unique mark value so that we know where we've been. This allows + * the algorithm to avoid getting into an infinite loop even if the + * constraint graph has an inadvertent cycle. + */ + void incrementalAdd(Constraint c) { + int mark = newMark(); + for(Constraint overridden = c.satisfy(mark); + overridden != null; + overridden = overridden.satisfy(mark)); + } + + /** + * Entry point for retracting a constraint. Remove the given + * constraint and incrementally update the dataflow graph. + * Details: Retracting the given constraint may allow some currently + * unsatisfiable downstream constraint to be satisfied. We therefore collect + * a list of unsatisfied downstream constraints and attempt to + * satisfy each one in turn. This list is traversed by constraint + * strength, strongest first, as a heuristic for avoiding + * unnecessarily adding and then overriding weak constraints. + * Assume: [c] is satisfied. + */ + void incrementalRemove(Constraint c) { + Variable out = c.output(); + c.markUnsatisfied(); + c.removeFromGraph(); + List unsatisfied = removePropagateFrom(out); + Strength strength = REQUIRED; + do { + for (int i = 0; i < unsatisfied.length; i++) { + Constraint u = unsatisfied[i]; + if (u.strength == strength) incrementalAdd(u); + } + strength = strength.nextWeaker(); + } while (strength != WEAKEST); + } + + /// Select a previously unused mark value. + int newMark() => ++currentMark; + + /** + * Extract a plan for resatisfaction starting from the given source + * constraints, usually a set of input constraints. This method + * assumes that stay optimization is desired; the plan will contain + * only constraints whose output variables are not stay. Constraints + * that do no computation, such as stay and edit constraints, are + * not included in the plan. + * Details: The outputs of a constraint are marked when it is added + * to the plan under construction. A constraint may be appended to + * the plan when all its input variables are known. A variable is + * known if either a) the variable is marked (indicating that has + * been computed by a constraint appearing earlier in the plan), b) + * the variable is 'stay' (i.e. it is a constant at plan execution + * time), or c) the variable is not determined by any + * constraint. The last provision is for past states of history + * variables, which are not stay but which are also not computed by + * any constraint. + * Assume: [sources] are all satisfied. + */ + Plan makePlan(List sources) { + int mark = newMark(); + Plan plan = new Plan(); + List todo = sources; + while (todo.length > 0) { + Constraint c = todo.removeLast(); + if (c.output().mark != mark && c.inputsKnown(mark)) { + plan.addConstraint(c); + c.output().mark = mark; + addConstraintsConsumingTo(c.output(), todo); + } + } + return plan; + } + + /** + * Extract a plan for resatisfying starting from the output of the + * given [constraints], usually a set of input constraints. + */ + Plan extractPlanFromConstraints(List constraints) { + List sources = []; + for (int i = 0; i < constraints.length; i++) { + Constraint c = constraints[i]; + // if not in plan already and eligible for inclusion. + if (c.isInput() && c.isSatisfied()) sources.add(c); + } + return makePlan(sources); + } + + /** + * Recompute the walkabout strengths and stay flags of all variables + * downstream of the given constraint and recompute the actual + * values of all variables whose stay flag is true. If a cycle is + * detected, remove the given constraint and answer + * false. Otherwise, answer true. + * Details: Cycles are detected when a marked variable is + * encountered downstream of the given constraint. The sender is + * assumed to have marked the inputs of the given constraint with + * the given mark. Thus, encountering a marked node downstream of + * the output constraint means that there is a path from the + * constraint's output to one of its inputs. + */ + bool addPropagate(Constraint c, int mark) { + List todo = [c]; + while (todo.length > 0) { + Constraint d = todo.removeLast(); + if (d.output().mark == mark) { + incrementalRemove(c); + return false; + } + d.recalculate(); + addConstraintsConsumingTo(d.output(), todo); + } + return true; + } + + /** + * Update the walkabout strengths and stay flags of all variables + * downstream of the given constraint. Answer a collection of + * unsatisfied constraints sorted in order of decreasing strength. + */ + List removePropagateFrom(Variable out) { + out.determinedBy = null; + out.walkStrength = WEAKEST; + out.stay = true; + List unsatisfied = []; + List todo = [out]; + while (todo.length > 0) { + Variable v = todo.removeLast(); + for (int i = 0; i < v.constraints.length; i++) { + Constraint c = v.constraints[i]; + if (!c.isSatisfied()) unsatisfied.add(c); + } + Constraint determining = v.determinedBy; + for (int i = 0; i < v.constraints.length; i++) { + Constraint next = v.constraints[i]; + if (next != determining && next.isSatisfied()) { + next.recalculate(); + todo.add(next.output()); + } + } + } + return unsatisfied; + } + + void addConstraintsConsumingTo(Variable v, List coll) { + Constraint determining = v.determinedBy; + for (int i = 0; i < v.constraints.length; i++) { + Constraint c = v.constraints[i]; + if (c != determining && c.isSatisfied()) coll.add(c); + } + } +} + + +/** + * A Plan is an ordered list of constraints to be executed in sequence + * to resatisfy all currently satisfiable constraints in the face of + * one or more changing inputs. + */ +class Plan { + List list = []; + + void addConstraint(Constraint c) { + list.add(c); + } + + int size() => list.length; + + void execute() { + for (int i = 0; i < list.length; i++) { + list[i].execute(); + } + } +} + + +/** + * This is the standard DeltaBlue benchmark. A long chain of equality + * constraints is constructed with a stay constraint on one end. An + * edit constraint is then added to the opposite end and the time is + * measured for adding and removing this constraint, and extracting + * and executing a constraint satisfaction plan. There are two cases. + * In case 1, the added constraint is stronger than the stay + * constraint and values must propagate down the entire length of the + * chain. In case 2, the added constraint is weaker than the stay + * constraint so it cannot be accomodated. The cost in this case is, + * of course, very low. Typical situations lie somewhere between these + * two extremes. + */ +void chainTest(int n) { + planner = new Planner(); + Variable prev = null, first = null, last = null; + // Build chain of n equality constraints. + for (int i = 0; i <= n; i++) { + Variable v = new Variable("v", 0); + if (prev != null) new EqualityConstraint(prev, v, REQUIRED); + if (i == 0) first = v; + if (i == n) last = v; + prev = v; + } + new StayConstraint(last, STRONG_DEFAULT); + EditConstraint edit = new EditConstraint(first, PREFERRED); + Plan plan = planner.extractPlanFromConstraints([edit]); + for (int i = 0; i < 100; i++) { + first.value = i; + plan.execute(); + total += last.value; + } +} + +/** + * This test constructs a two sets of variables related to each + * other by a simple linear transformation (scale and offset). The + * time is measured to change a variable on either side of the + * mapping and to change the scale and offset factors. + */ +void projectionTest(int n) { + planner = new Planner(); + Variable scale = new Variable("scale", 10); + Variable offset = new Variable("offset", 1000); + Variable src = null, dst = null; + + List dests = []; + for (int i = 0; i < n; i++) { + src = new Variable("src", i); + dst = new Variable("dst", i); + dests.add(dst); + new StayConstraint(src, NORMAL); + new ScaleConstraint(src, scale, offset, dst, REQUIRED); + } + change(src, 17); + total += dst.value; + if (dst.value != 1170) print("Projection 1 failed"); + change(dst, 1050); + total += src.value; + if (src.value != 5) print("Projection 2 failed"); + change(scale, 5); + for (int i = 0; i < n - 1; i++) { + total += dests[i].value; + if (dests[i].value != i * 5 + 1000) print("Projection 3 failed"); + } + change(offset, 2000); + for (int i = 0; i < n - 1; i++) { + total += dests[i].value; + if (dests[i].value != i * 5 + 2000) print("Projection 4 failed"); + } +} + +void change(Variable v, int newValue) { + EditConstraint edit = new EditConstraint(v, PREFERRED); + Plan plan = planner.extractPlanFromConstraints([edit]); + for (int i = 0; i < 10; i++) { + v.value = newValue; + plan.execute(); + } + edit.destroyConstraint(); +} + +Planner planner; diff --git a/test/benchmark/fib.dart b/test/benchmark/fib.dart new file mode 100644 index 00000000..f35d622d --- /dev/null +++ b/test/benchmark/fib.dart @@ -0,0 +1,13 @@ +fib(n) { + if (n < 2) return n; + return fib(n - 1) + fib(n - 2); +} + +main() { + Stopwatch watch = new Stopwatch(); + watch.start(); + for (var i = 0; i < 5; i++) { + print(fib(28)); + } + print("elapsed: ${watch.elapsedMilliseconds / 1000}"); +} diff --git a/test/benchmark/for.dart b/test/benchmark/for.dart new file mode 100644 index 00000000..7ea4023f --- /dev/null +++ b/test/benchmark/for.dart @@ -0,0 +1,13 @@ +main() { + var list = []; + + Stopwatch watch = new Stopwatch(); + watch.start(); + for (var i = 0; i < 1000000; i++) list.add(i); + + var sum = 0; + for (i in list) sum += i; + + print(sum); + print("elapsed: ${watch.elapsedMilliseconds / 1000}"); +} diff --git a/test/benchmark/map_numeric.dart.skip b/test/benchmark/map_numeric.dart.skip new file mode 100644 index 00000000..da1dfab0 --- /dev/null +++ b/test/benchmark/map_numeric.dart.skip @@ -0,0 +1,24 @@ +// Skipping this for now because it is >10x slower than the other languages (!) +// and makes the benchmark running annoyingly slow. +main() { + Stopwatch watch = new Stopwatch(); + watch.start(); + + var map = {}; + + for (var i = 1; i <= 1000000; i++) { + map[i] = i; + } + + var sum = 0; + for (var i = 1; i <= 1000000; i++) { + sum += map[i]; + } + print(sum); + + for (var i = 1; i <= 1000000; i++) { + map.remove(i); + } + + print("elapsed: ${watch.elapsedMilliseconds / 1000}"); +} diff --git a/test/benchmark/method_call.dart b/test/benchmark/method_call.dart new file mode 100644 index 00000000..540a8266 --- /dev/null +++ b/test/benchmark/method_call.dart @@ -0,0 +1,78 @@ +class Toggle { + var _state; + + Toggle(startState) { + _state = startState; + } + + get value => _state; + + activate() { + _state = !_state; + return this; + } +} + +class NthToggle extends Toggle { + var _count; + var _countMax; + + NthToggle(startState, maxCounter) + : super(startState) { + _countMax = maxCounter; + _count = 0; + } + + activate() { + _count = _count + 1; + if (_count >= _countMax) { + super.activate(); + _count = 0; + } + + return this; + } +} + +main() { + Stopwatch watch = new Stopwatch(); + watch.start(); + + var n = 100000; + var val = true; + var toggle = new Toggle(val); + + for (var i = 0; i < n; i++) { + val = toggle.activate().value; + val = toggle.activate().value; + val = toggle.activate().value; + val = toggle.activate().value; + val = toggle.activate().value; + val = toggle.activate().value; + val = toggle.activate().value; + val = toggle.activate().value; + val = toggle.activate().value; + val = toggle.activate().value; + } + + print(toggle.value); + + val = true; + var ntoggle = new NthToggle(val, 3); + + for (var i = 0; i < n; i++) { + val = ntoggle.activate().value; + val = ntoggle.activate().value; + val = ntoggle.activate().value; + val = ntoggle.activate().value; + val = ntoggle.activate().value; + val = ntoggle.activate().value; + val = ntoggle.activate().value; + val = ntoggle.activate().value; + val = ntoggle.activate().value; + val = ntoggle.activate().value; + } + + print(ntoggle.value); + print("elapsed: ${watch.elapsedMilliseconds / 1000}"); +} diff --git a/util/benchmark.py b/util/benchmark.py index 2c8ad693..9e165952 100755 --- a/util/benchmark.py +++ b/util/benchmark.py @@ -90,6 +90,7 @@ BENCHMARK("string_equals", r"""3000000""") LANGUAGES = [ ("wren", [os.path.join(WREN_BIN, 'wren')], ".wren"), + ("dart", ["fletch", "run"], ".dart"), ("lua", ["lua"], ".lua"), ("luajit (-joff)", ["luajit", "-joff"], ".lua"), ("python", ["python"], ".py"),