Adding mapbox-gl branch

This commit is contained in:
Andreas Hocevar
2015-03-16 18:50:27 +01:00
parent 7985f030fa
commit 57ee7f52fd
3109 changed files with 943365 additions and 0 deletions
@@ -0,0 +1,270 @@
// Copyright 2011 The Closure Library Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS-IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/**
* @fileoverview A basic statistics tracker.
*
*/
goog.provide('goog.stats.BasicStat');
goog.require('goog.asserts');
goog.require('goog.log');
goog.require('goog.string.format');
goog.require('goog.structs.CircularBuffer');
/**
* Tracks basic statistics over a specified time interval.
*
* Statistics are kept in a fixed number of slots, each representing
* an equal portion of the time interval.
*
* Most methods optionally allow passing in the current time, so that
* higher level stats can synchronize operations on multiple child
* objects. Under normal usage, the default of goog.now() should be
* sufficient.
*
* @param {number} interval The stat interval, in milliseconds.
* @constructor
* @final
*/
goog.stats.BasicStat = function(interval) {
goog.asserts.assert(interval > 50);
/**
* The time interval that this statistic aggregates over.
* @type {number}
* @private
*/
this.interval_ = interval;
/**
* The number of milliseconds in each slot.
* @type {number}
* @private
*/
this.slotInterval_ = Math.floor(interval / goog.stats.BasicStat.NUM_SLOTS_);
/**
* The array of slots.
* @type {goog.structs.CircularBuffer}
* @private
*/
this.slots_ =
new goog.structs.CircularBuffer(goog.stats.BasicStat.NUM_SLOTS_);
};
/**
* The number of slots. This value limits the accuracy of the get()
* method to (this.interval_ / NUM_SLOTS). A 1-minute statistic would
* be accurate to within 2 seconds.
* @type {number}
* @private
*/
goog.stats.BasicStat.NUM_SLOTS_ = 50;
/**
* @type {goog.log.Logger}
* @private
*/
goog.stats.BasicStat.prototype.logger_ =
goog.log.getLogger('goog.stats.BasicStat');
/**
* @return {number} The interval which over statistics are being
* accumulated, in milliseconds.
*/
goog.stats.BasicStat.prototype.getInterval = function() {
return this.interval_;
};
/**
* Increments the count of this statistic by the specified amount.
*
* @param {number} amt The amount to increase the count by.
* @param {number=} opt_now The time, in milliseconds, to be treated
* as the "current" time. The current time must always be greater
* than or equal to the last time recorded by this stat tracker.
*/
goog.stats.BasicStat.prototype.incBy = function(amt, opt_now) {
var now = opt_now ? opt_now : goog.now();
this.checkForTimeTravel_(now);
var slot = /** @type {goog.stats.BasicStat.Slot_} */ (this.slots_.getLast());
if (!slot || now >= slot.end) {
slot = new goog.stats.BasicStat.Slot_(this.getSlotBoundary_(now));
this.slots_.add(slot);
}
slot.count += amt;
slot.min = Math.min(amt, slot.min);
slot.max = Math.max(amt, slot.max);
};
/**
* Returns the count of the statistic over its configured time
* interval.
* @param {number=} opt_now The time, in milliseconds, to be treated
* as the "current" time. The current time must always be greater
* than or equal to the last time recorded by this stat tracker.
* @return {number} The total count over the tracked interval.
*/
goog.stats.BasicStat.prototype.get = function(opt_now) {
return this.reduceSlots_(opt_now,
function(sum, slot) { return sum + slot.count; },
0);
};
/**
* Returns the magnitute of the largest atomic increment that occurred
* during the watched time interval.
* @param {number=} opt_now The time, in milliseconds, to be treated
* as the "current" time. The current time must always be greater
* than or equal to the last time recorded by this stat tracker.
* @return {number} The maximum count of this statistic.
*/
goog.stats.BasicStat.prototype.getMax = function(opt_now) {
return this.reduceSlots_(opt_now,
function(max, slot) { return Math.max(max, slot.max); },
Number.MIN_VALUE);
};
/**
* Returns the magnitute of the smallest atomic increment that
* occurred during the watched time interval.
* @param {number=} opt_now The time, in milliseconds, to be treated
* as the "current" time. The current time must always be greater
* than or equal to the last time recorded by this stat tracker.
* @return {number} The minimum count of this statistic.
*/
goog.stats.BasicStat.prototype.getMin = function(opt_now) {
return this.reduceSlots_(opt_now,
function(min, slot) { return Math.min(min, slot.min); },
Number.MAX_VALUE);
};
/**
* Passes each active slot into a function and accumulates the result.
*
* @param {number|undefined} now The current time, in milliseconds.
* @param {function(number, goog.stats.BasicStat.Slot_): number} func
* The function to call for every active slot. This function
* takes two arguments: the previous result and the new slot to
* include in the reduction.
* @param {number} val The initial value for the reduction.
* @return {number} The result of the reduction.
* @private
*/
goog.stats.BasicStat.prototype.reduceSlots_ = function(now, func, val) {
now = now || goog.now();
this.checkForTimeTravel_(now);
var rval = val;
var start = this.getSlotBoundary_(now) - this.interval_;
for (var i = this.slots_.getCount() - 1; i >= 0; --i) {
var slot = /** @type {goog.stats.BasicStat.Slot_} */ (this.slots_.get(i));
if (slot.end <= start) {
break;
}
rval = func(rval, slot);
}
return rval;
};
/**
* Computes the end time for the slot that should contain the count
* around the given time. This method ensures that every bucket is
* aligned on a "this.slotInterval_" millisecond boundary.
* @param {number} time The time to compute a boundary for.
* @return {number} The computed boundary.
* @private
*/
goog.stats.BasicStat.prototype.getSlotBoundary_ = function(time) {
return this.slotInterval_ * (Math.floor(time / this.slotInterval_) + 1);
};
/**
* Checks that time never goes backwards. If it does (for example,
* the user changes their system clock), the object state is cleared.
* @param {number} now The current time, in milliseconds.
* @private
*/
goog.stats.BasicStat.prototype.checkForTimeTravel_ = function(now) {
var slot = /** @type {goog.stats.BasicStat.Slot_} */ (this.slots_.getLast());
if (slot) {
var slotStart = slot.end - this.slotInterval_;
if (now < slotStart) {
goog.log.warning(this.logger_, goog.string.format(
'Went backwards in time: now=%d, slotStart=%d. Resetting state.',
now, slotStart));
this.reset_();
}
}
};
/**
* Clears any statistics tracked by this object, as though it were
* freshly created.
* @private
*/
goog.stats.BasicStat.prototype.reset_ = function() {
this.slots_.clear();
};
/**
* A struct containing information for each sub-interval.
* @param {number} end The end time for this slot, in milliseconds.
* @constructor
* @private
*/
goog.stats.BasicStat.Slot_ = function(end) {
/**
* End time of this slot, exclusive.
* @type {number}
*/
this.end = end;
};
/**
* Aggregated count within this slot.
* @type {number}
*/
goog.stats.BasicStat.Slot_.prototype.count = 0;
/**
* The smallest atomic increment of the count within this slot.
* @type {number}
*/
goog.stats.BasicStat.Slot_.prototype.min = Number.MAX_VALUE;
/**
* The largest atomic increment of the count within this slot.
* @type {number}
*/
goog.stats.BasicStat.Slot_.prototype.max = Number.MIN_VALUE;
@@ -0,0 +1,22 @@
<!DOCTYPE html>
<html>
<!--
Copyright 2011 The Closure Library Authors. All Rights Reserved.
Use of this source code is governed by the Apache License, Version 2.0.
See the COPYING file for details.
-->
<head>
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<title>
Closure Unit Tests - goog.stats.BasicStat
</title>
<script src="../base.js" type="text/javascript">
</script>
<script type="text/javascript">
goog.require('goog.stats.BasicStatTest');
</script>
</head>
<body>
</body>
</html>
@@ -0,0 +1,165 @@
// Copyright 2011 The Closure Library Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS-IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
goog.provide('goog.stats.BasicStatTest');
goog.setTestOnly('goog.stats.BasicStatTest');
goog.require('goog.array');
goog.require('goog.stats.BasicStat');
goog.require('goog.string.format');
goog.require('goog.testing.PseudoRandom');
goog.require('goog.testing.jsunit');
goog.require('goog.userAgent');
function testGetSlotBoundary() {
var stat = new goog.stats.BasicStat(1654);
assertEquals('Checking interval', 33, stat.slotInterval_);
assertEquals(132, stat.getSlotBoundary_(125));
assertEquals(165, stat.getSlotBoundary_(132));
assertEquals(132, stat.getSlotBoundary_(99));
assertEquals(99, stat.getSlotBoundary_(98));
}
function testCheckForTimeTravel() {
var stat = new goog.stats.BasicStat(1000);
// no slots yet, should always be OK
stat.checkForTimeTravel_(100);
stat.checkForTimeTravel_(-1);
stat.incBy(1, 125); // creates a first bucket, ending at t=140
// Even though these go backwards in time, our basic fuzzy check passes
// because we just check that the time is within the latest interval bucket.
stat.checkForTimeTravel_(141);
stat.checkForTimeTravel_(140);
stat.checkForTimeTravel_(139);
stat.checkForTimeTravel_(125);
stat.checkForTimeTravel_(124);
stat.checkForTimeTravel_(120);
// State should still be the same, all of the above times are valid.
assertEquals('State unchanged when called with good times', 1, stat.get(125));
stat.checkForTimeTravel_(119);
assertEquals('Reset after called with a bad time', 0, stat.get(125));
}
function testConstantIncrementPerSlot() {
var stat = new goog.stats.BasicStat(1000);
var now = 1000;
for (var i = 0; i < 50; ++i) {
var newMax = 1000 + i;
var newMin = 1000 - i;
stat.incBy(newMin, now);
stat.incBy(newMax, now);
var msg = goog.string.format(
'now=%d i=%d newMin=%d newMax=%d', now, i, newMin, newMax);
assertEquals(msg, 2000 * (i + 1), stat.get(now));
assertEquals(msg, newMax, stat.getMax(now));
assertEquals(msg, newMin, stat.getMin(now));
now += 20; // push into the next slots
}
// The next increment should cause old data to fall off.
stat.incBy(1, now);
assertEquals(2000 * 49 + 1, stat.get(now));
assertEquals(1, stat.getMin(now));
assertEquals(1049, stat.getMax(now));
now += 20; // drop off another bucket
stat.incBy(1, now);
assertEquals(2000 * 48 + 2, stat.get(now));
assertEquals(1, stat.getMin(now));
assertEquals(1049, stat.getMax(now));
}
function testSparseBuckets() {
var stat = new goog.stats.BasicStat(1000);
var now = 1000;
stat.incBy(10, now);
assertEquals(10, stat.get(now));
now += 5000; // the old slot is now still in memory, but should be ignored
stat.incBy(1, now);
assertEquals(1, stat.get(now));
}
function testFuzzy() {
var stat = new goog.stats.BasicStat(1000);
var test = new PerfectlySlowStat(1000);
var rand = new goog.testing.PseudoRandom(58849020);
var eventCount = 0;
// test over 5 simulated seconds (2 for IE, due to timeouts)
var simulationDuration = goog.userAgent.IE ? 2000 : 5000;
for (var now = 1000; now < simulationDuration; ) {
var count = Math.floor(rand.random() * 2147483648);
var delay = Math.floor(rand.random() * 25);
for (var i = 0; i <= delay; ++i) {
var time = now + i;
var msg = goog.string.format('now=%d eventCount=%d', time, eventCount);
var expected = test.getStats(now + i);
assertEquals(expected.count, stat.get(time));
assertEquals(expected.min, stat.getMin(time));
assertEquals(expected.max, stat.getMax(time));
}
now += delay;
stat.incBy(count, now);
test.incBy(count, now);
eventCount++;
}
}
/**
* A horribly inefficient implementation of BasicStat that stores
* every event in an array and dynamically filters to perform
* aggregations.
* @constructor
*/
var PerfectlySlowStat = function(interval) {
this.interval_ = interval;
this.slotSize_ = Math.floor(interval / goog.stats.BasicStat.NUM_SLOTS_);
this.events_ = [];
};
PerfectlySlowStat.prototype.incBy = function(amt, now) {
this.events_.push({'time': now, 'count': amt});
};
PerfectlySlowStat.prototype.getStats = function(now) {
var end = Math.floor(now / this.slotSize_) * this.slotSize_ + this.slotSize_;
var start = end - this.interval_;
var events = goog.array.filter(this.events_,
function(e) { return e.time >= start });
return {
'count': goog.array.reduce(events,
function(sum, e) { return sum + e.count },
0),
'min': goog.array.reduce(events,
function(min, e) { return Math.min(min, e.count); },
Number.MAX_VALUE),
'max': goog.array.reduce(events,
function(max, e) { return Math.max(max, e.count); },
Number.MIN_VALUE)
};
};