August 7th, 2014
commit 9d3c5b19a088f6e33888c215f44ab59da4ece302 Author: Nick Fitzgerald <firstname.lastname@example.org> Date: Fri May 21 22:56:49 2010 -0700 First commit
Four years later, the feature-complete, partially-implemented, and soon-to-be-finalized ECMAScript 6 supports lazy streams in the form of generators and its iterator protocol. Unfortunately, ES6 iterators are missing the higher order functions you expect: map, filter, reduce, etc.
Today, I'm happy to announce the release of
wu.js version 2.0, which has been
completely rewritten for ES6.
wu.js aims to provide higher order functions for ES6 iterables. Some of them
you already know (
reduce) and some of them might be new to
wu.js works with all ES6 iterables,
Sets, and generators you write yourself. You don't
have to wait for ES6 to be fully implemented by every JS engine,
wu.js can be
compiled to ES5 with the Tracuer compiler.
Here's a couple small examples:
const factorials = wu.count(1).reductions((last, n) => last * n); // (1, 2, 6, 24, ...) const isEven = x => x % 2 === 0; const evens = wu.filter(isEven); evens(wu.count()); // (0, 2, 4, 6, ...)
July 8th, 2014
We have members of the devtools team in our San Francisco, London, Vancouver, Paris, Toronto, and Portland offices, but many also work remotely.
Some of the things we're working on:
A performance tool that incorporates a sampling CPU-profiler, platform events tracing, and information from SpiderMonkey's Just-In-Time compiler
An allocations and heap usage profiler (this is what I'm working on, and I wrote about it here)
A WebGL shader live-editor, and a canvas debugger to step through individual draw calls
One of the most important things for me is that every line of code we write at Mozilla is Free and Open Source from day one, and we're dedicated to keeping the web open.
June 26th, 2014
On Tuesday, June 3rd, 2014, I gave a presentation on debugging web performance with Firefox DevTools to the Velocity Conf 2014, Santa Clara. I'm not sure how useful the slides are without me talking, but here they are:
March 12th, 2014
Before diving in, it makes sense to tell you where I am coming from. I
implemented the mozilla/source-map library and the source map support in
the Firefox Developer Tools' debugger. I'm a coauthor of the
document specifying source maps; although the actual design of the
format was done by John Lenz. I mostly documented and polished the parts
that weren't about the format itself: like how to find a script's source map. On
top of that, I've debugged scripts with source maps compiled from browserify,
r.js AMD module optimizer, CoffeeScript, ClojureScript, Emscripten,
UglifyJS, Closure Compiler, and more.
Source maps work pretty well for:
CSS preprocessors and transpilers. From what I can tell, this is the most prevalent use of source maps, and what they've ended up being best at!
types. For example ClojureScript's
Object nor a
Map, and a C++
String. The result
is that the debugger user is inspecting the compiler's implementation of the
data type rather than the source language data type.
A stepping debugger isn't useful without the ability to inspect bindings and values in the environment, and the above issues create humungous hurdles for doing that!
An ideal SourceMap.next format should support the existing use of source maps:
It should support debugging dynamically compiled sources which don't live at a remote URL, like those created in the "Try CoffeeScript" online editor.
The format should be compact and space-saving so that the network isn't a bottleneck when debugging remote targets.
It should optionally provide an
eval capability, for use from a REPL,
watch expression, or conditional breakpoint.
The format should be future-extensible. That is, when SourceMap.next v2 rolls out, any SourceMap.next v1 consumer should still be able to parse and use instances of SourceMap.next v2 (although without the new features, of course). DWARF did a great job solving this problem with its Debugging Information Entries.
The ideas I present here aren't fully baked yet, but I have confidence in the approach.
Annotating the AST enables us to take advantage of the hierarchy present in the tree. If you are searching for a specific annotation and the current AST node does not have it, recurse on the node's parent. This makes it easy to provide very detailed information or a less fine-grained summary. For example, in the following AST, rather than requiring source location annotations for each AssignmentExpression, Identifier, BinaryExpression, and Literal AST nodes, one could simply add the annotation to the AssignmentExpression node. Then, any queries for source location information on any of the other nodes would bubble up to the AssignmentExpression and yield its annotated source location information.
AssignmentExpression operator: "=" left: Identifier name: "answer" right: BinaryExpression operator: "*" left: Literal value: 6 right: literal value: 7
Here are a few debugging annotations that should cover the requirements listed above:
sourceList: An array of sources that were compiled to create this
node. A source would be either a URL pointing to a source file, or the
inlined source text, display name, and content type.
source: The source (as an index into the
sourceList) from which this AST
node was compiled.
line: The line number in the source file that corresponds to this AST
column: The column number in the source file that corresponds to this
all local variables introduced by this AST node. You can walk up the tree to
the root to create the lexical environment chain.
display and inspection in the debugger. For example, a ClojureScript
already know how to provide a reasonable view of
Objects that would work
fine for a ClojureScript
Map even though it wouldn't be the best way to
implement a ClojureScript
arbitrary snippets of the source language. Would accept an optional
parameter that dictated which frame the debugger is paused in, if any.
March 4th, 2014
A big push for the Firefox Developer Tools team this year is performance tools. Jim Blandy and I are collaborating on the memory half of performance tooling. What follows is a broad overview of our plans.
ubi::Node: An abstract base class that provides a generic
world, but also XPCOM and the DOM!
Category: A key/value pair with which we can tag an individual
ubi::Node. Some categories are simple booleans, such as whether a DOM node
is orphaned from its document. Others may have a value, for example an object
may be categorized by its prototype and constructor.
ubi::Nodes can have to
Census: A semi-lightweight traversal of the heap that provides accurate category counts without saving the full heap state. It gives us totals, but not the specifics of individuals.
Snapshot: A heavyweight traversal of the heap. It saves the full heap state for later inspection by creating a core dump.
Core dump: A binary blob containing the full serialized heap state at a past instant in time.
As we build the infrastructure and lay the foundation for the memory panel, we
will expose utility and testing functions developers can use now. Generally, the
console object will expose these functions.
The benefit of this approach is two-fold. First, it enables developers to cash in on our work quickly. Second, it gives us a larger testing population; helping us catch and fix bugs as soon as possible.
y, then any path from the global window to
must pass through
x. We can use this information in two practical ways:
If you nullify all references to
y such that
will also become unreachable and will eventually be garbage collected.
We can calculate the retained size of
x. That is, the amount of memory
that will be reclaimed if
x (and therefore also every
y such that
y) were to be garbage collected.
We can expose this information to developers with
By doing a BFS in the heap graph from the global window to an object, we find
the shortest retaining path for that object. We can use this path to construct
a developer-friendly label for that object. Often the label we provide will be a
"window.MyApp.WidgetView.element". Other times, we will be forced to display
labels that cannot be evaluated in the console:
"window.[[requestAnimationFrame renderLoop]].[[ closure environment ]].player.sprite".
This can be exposed to developers as a useful little pair of methods on
console. If you expect an object to be reclaimed by GC, you will be able to
tag it with
console.expectGarbageCollected(obj). Next, you would perform
whatever actions are supposed to trigger the clean up of that object. Finally,
you could call
console.logRetained() to log the retaining path of any objects
that you tagged via
console.expectGarbageCollected that have not been garbage
collected. I realize these aren't the greatest method names;
please tweet me your suggestions!
We will track the allocation site of every object in the heap. Allocation sites come into play in a few ways.
First, if you interact with one component of your app, and notice that an unrelated component is allocating or retaining objects, you most likely have an opportunity to reduce memory consumption. Perhaps that unrelated component can lazily delay any allocations it needs, thereby lowering your app's memory usage when that component isn't active.
Second, once developers know which objects are using their precious memory, the next info they need is where the objects were allocated. That leads to why they were allocated, and finally how to reduce those allocations. We can hack this workflow and group objects by allocation site then sort them for developers to effectively make the first step (which objects) redundant.
I'm not sure what the best way to expose this information to developers before
the complete memory panel is ready. Tracking allocations isn't lightweight; we
can't do it all the time, you have to turn the mode on. We could expose
console.stopTrackingAllocationSites(), and then allow calls to
obj was allocated while we were tracking
allocation sites. Or, we could expose
console.stopLoggingAllocationSites(), which could just dump every
allocation site to the console as it occurs. Tweet at me if you have
an opinion about the best API from which to expose this data.
The memory panel will feature a live-updating graph. To construct this graph we will frequently poll the recent categorized allocations, and the total, non-granular heap size. This gives us a fuzzy, slightly inaccurate picture of the heap over time, but it should be efficient enough for us to do at a high frequency. At a less frequent interval, we will take a census. This will be a reality check of sorts that gives us precise numbers for each category of objects in the heap.
You will be able to click on the graph to get a shallow view into the heap at that past moment in time. Alternatively, you will be able to select a region of the graph to view the difference in memory consumption between the start and end points of your selection.
If you need to deep dive into the full heap state, you'll be able to take snapshots, which are too heavy for us to automatically collect on an interval. These can be compared with other snapshots down to each individual object, so you will be able to see exactly what has been allocated and reclaimed in the time between when each snapshot was taken. They will also be exportable and importable as core dumps, so you could attach them to bug tickets, send to other developers, etc.
Darrin Henein has created a beautiful mockup of the memory panel. Caveat: despite said beauty, the mockup is still very much a work in progress, it is far from complete, and what we ship might look very different!
You can follow along with our work by watching the bugs in this bugzilla dependency graph.
2014 will be an exciting year for memory tooling in Firefox Developer Tools!
Newer Entries »
Source Maps are an Insufficient Debugging Format for the Web on June 19th, 2015
A Compact Representation of Captured Stack Frames for SpiderMonkey on April 10th, 2015
Memory Management in Oxischeme on February 22nd, 2015
Naming `eval` Scripts with the `//# sourceURL` Directive on December 5th, 2014
wu.js 2.0 on August 7th, 2014
Come work with me on Firefox Developer Tools on July 8th, 2014
Debugging Web Performance with Firefox DevTools - Velocity 2014 on June 26th, 2014
Beyond Source Maps on March 12th, 2014
Memory Tooling in Firefox Developer Tools in 2014 on March 4th, 2014