Tags:

As I mentioned in my earlier blog post, we are now working torward stabilizing the development version of PhantomJS. One thing I would like to elaborate here with respect to the features of this forthcoming PhantomJS 2 is its improved JavaScript support.

With the fresher WebKit (thanks to Qt 5.3’s QtWebKit module), PhantomJS 2 also benefits from a lot of JavaScript improvement in JavaScriptCore, the JavaScript engine of WebKit. This brings PhantomJS to the more-or-less expectation of features which are supposed to be supported by a modern web browser.

test262

In fact, if we run the official test suite for ECMA-262, the ECMAScript Language Specification version 5.1, at test262.ecmascript.org, then we will see that PhantomJS (just like Safari 7) only fails 2 tests. If you compare it with other browsers, Chrome 36 has 4 failures and Firefox 31 has 42 failing tests. In a way, we can say that (by leveraging JavaScriptCore), PhantomJS is pretty much as standard compliant as it could get.

failures

Among others, many will rejoice for the availability of Function.prototype.bind (bug 10522), something that is missing from the old QtWebKit in Qt 4.8. There were various attempts to solve this in the past, see my previous post to the mailing-list. However, as I wrote there, sometimes our collective effort was not enough to move the mountain.

Another related improvement is the handling of the special object arguments. Just like other modern browsers, now you can JSON.stringify this object (bug 11845), use in a for-in loop (bug 11558, bug 10315), and call Object.keys on it (bug 11746).

PhantomJS 2 will be released whenever it is ready (monitor the mailing-list if you want to get notified). Meanwhile, if you want to compile it yourself and play with this bleeding-edge version, follow the step-by-step instructions. If you are on Linux or OS X (like typical geeks these days), building it yourself should take just 30 minutes on a fairly decent machine.

Good things come to those who wait!

Tags:

cgdb

Mastering GNU Debugger (gdb) is an essential skill for many programmers these days. In many cases, debugging using gdb is carried out straight from your favorite editor or IDE. For a quick stand-alone debugging session, a nice alternative is to use a visual, terminal-based wrapper for GDB called cgdb.

The usage of cgdb is designed to appeal vim users. When you launch cgdb, it shows a split-screen arrangement. The bottom half is the usual gdb console while the top half shows the content of the file where the program currently stops. The size of the window can be easily adjusted, I often shrink the gdb console to a minimum since I like to see more file content.

Everytime gdb does the single-stepping or moving to the next source line, the corresponding line in the source view will be highlighted. It is even customizable, either with an arrow indicator on the gutter or by highlighting the entire line. The source view window is always synchronized, if gdb jumps to another file then you will immediately see the content of that file.

Opening another source is also easy, thanks to its vim-like incremental filename search. Once a particular file is open, setting a breakpoint on a certain line is as simple as specifying the line number in the gdb console.

There are many different things you can do with cgdb, refer to its documentation for the details. If you are stuck with plain vanilla gdb hitherto, I highly recommend using cgdb for fun and profit!

Tags:

raptorRecently, Google engineers landed a new optimizing JavaScript compiler for V8, codenamed TurboFan. As the name implies, this is supposed to further improve JavaScript execution speed, likely to be better than its predecessor, Crankshaft. While TurboFan is still in its early stage, that doesn’t mean we can’t take a look at it.

Playing with this TurboFan flavor of V8 is not difficult. First you need to build the bleeding-edge branch, where this 70,000-lines of code currently resides. After the new V8 shell is freshly baked, we can have some fun and inspecting TurboFan’s work.

I did not have the time to dig really deep yet, so for now we just take a peek at the initial stage of the new optimizing compiler’s pipeline.

Let’s have a simple test program:

function answer() {
  return 42;
}
print(answer());

If this is test.js, then we can play with TurboFan by running:

/path/to/v8/shell --always-opt \
  --trace-turbo \
  --turbo-types \
  --turbo-filter=answer \
  test.js

We use the --always-opt option so that the code is optimized immediately (otherwise, only e.g. hot loops will be optimized). In order to inspect TurboFan, --trace-turbo and --turbo-types options are necessary. Last but not least, we are only interested in our own function answer() to be examined, hence the use of --turbo-filter option. If we pass * instead, V8 will dump too much information, mostly on other internals slightly irrelevant for this discussion.

We can see that TurboFan is doing its magic by looking at the first few lines of the output:

---------------------------------------------------
Begin compiling method answer using Turbofan

For further investigation, it is better to redirect the output to a log file. The log file will contain the data for 4 different graphs: initial untyped graph, context specialized graph, lowered typed graph, and lowered generic graph. This is the result of the Turbofan compiling pipeline. Every graph is easy to visualize since it is printed in the de-facto dot format.

First, we need to separate each individual graph:

csplit -s -f graph log "/--/" {4}

Assuming GraphViz is installed, we can see the first graph, the initial untyped, by running:

tail -n +2 graph01 | dot -T png > untyped.png

which is shown in the following screenshot:

untyped

This is the intermediate representation (IR) directed graph. You may recognize some nodes in the graph resembling the original JavaScript code such as the NumberConstant[42] and Return nodes. Each node has an operator and its associated IR opcode. This is very similar to the Sea of Nodes IR approach from Cliff Click (see Combining analyses, combining optimizations and A Simple Graph-Based Intermediate Representation) used by Java HotSpot compiler.

The above graph is built as the first compiler pipeline stage by traversing the abstract syntax tree. There is hardly a surprise here. The edges Start (node #0) and End (node #10) are self explanatory. For every function, the information on its Parameter (node #4) is always mandatory. Checking the stack is an inherent part of V8 internals, hence the need for JSCallRuntime (node #5).

Inside the function body, every statement will be visited by the AST builder. In our example, there is only one, a return statement. For this, the builder also needs to visit the argument, which happens to be a numeric literal. The final outcome is a node which represents the opcode Return (node #7) which also refers to the constant (node #6).

The node in gray (Return, node #9) indicates that it is “dead”, i.e. unused. This is actually a special return statement (returning undefined) which plays a role only if the function does not have an explicit return. Since it is not the case here, the node is not being used or referred anywhere, hence its dead status.

After this initial graph is obtained, the next stage are context specialization, type analysis, and IR lowering. These three topics are outside the scope (pun intended) of what I want to cover right now so we will have to discuss them some other time. However, note that our test.js is very simple, there is no assignment or any complicated operations and hence the subsequent compiler stages do not enhance the IR graph in any meaningful way. In fact, If you plot graph02 (using the similar dot command as before), you will see that the resulting image is exactly the same as in the previous screenshot.

Ultimately, TurboFan needs to generate some machine code. Predictably, it has its own code generator (currently for x86 and ARM, both 32-bit and 64-bit), it does not reuse the existing Hydrogen and Lithium code generators from Crankshaft. The machine code is emitted from the instruction sequence. If you take a look at the log file, the relevant part of the sequence is:

      14: ArchRet v6(=rax)

If you find out what v6 is, it refers to the constant 42. On x86-64, this instruction thus can be turned into a MOVQ RAX, 0x2A00000000 followed by RET 8. Straightforward, isn’t it?

TurboFan is still very young and I’m sure there is still lots of room to grow. In most recent episode of JavaScript engine optimization, WebKit enjoys a speed boost thanks to the new FTL (fourth-tier JIT compiler based on LLVM) while Firefox continues to refine its whole-method JIT compiler IonMonkey. Will TurboFan become the V8’s answer to them?

Welcome to the world, TurboFan!

Tags:

phantomjs2It is been a while since PhantomJS received a facelift. This is about to change, the current master branch is now running the unstable version of PhantomJS 2. Among others, thing brings the fresher Qt 5.3 and its updated QtWebKit module.

Thanks to the hard work of many contributors, in particular @Vitallium and KDAB, PhantomJS 2 is getting close to its final stage. There are still many things to do, from fixing the failing unit tests to running a thorough integration test, but at least the current master branch can be built on Linux, OS X, and Windows already.

A typical user will want to wait until the final release to get the official binaries. However, those who are brave enough to experiment with this bleeding-edge version are welcome to build it from source.

We still do not know when it is going to be ready for the final release, stay tuned and monitor the mailing-list.

With this new major version, we also have an opportunity to review and improve the development workflow. Several topics are already being discussed (feel free to participate, your feedback will be appreciated): removing CoffeeScript support, revamping the test system, searching for a better issue tracker, building a continuous integration system, and last but not least, modularization approach for future distribution. These tasks are far from trivial, any kind of help is always welcomed.

A journey of a thousand miles begins with a single step. And expect more rolling updates in the next few weeks!

Tags:

TeamCity from JetBrains is an easy-to-use and powerful continuous integration system. It is a commercial product, but there is a special zero-cost license for small projects and FOSS applications. While installing TeamCity is relatively easy, its setup is further simplified via the use of Docker.

logo_teamcityLike many other state-of-art continuous integration systems, TeamCity adopts the concept of build server and build agent. The server is responsible for the adminstration and build configurations. The actual build itself (compilation, packaging, deployment, etc) is carried out by one or more build agents. With this approach, it is also easy to provision the agent automatically so that the entire setup requires very little manual tweaks.

TeamCity Server only requires Java. The installation is rather straightforward. With Docker, this is even easier. I have prepared a special container for this, ariya/centos6-teamcity-server. The base system for the container is ariya/centos6-oracle-jre7, a CentOS 6.5 system running the official Oracle Java 7 (to be more precise, JRE 1.7.0_65-b17 at the time of this writing).

Assuming you have a system (VPS such as Linode or DigitalOcean, Amazon EC2 instance, a virtual machine, a real box) that already has Docker installed, setting up a TeamCity Server is as easy as running the following commands. Note that if you are on OS X, use boot2docker if you just want to experiment with this setup (see my previous blog post Docker on OS X for more details).

docker run -dt -name teamcity_server -p 8111:8111 ariya/centos6-teamcity-server

Give it a few minutes or so, now open the box’s address at port 8111 to start the web configuration of TeamCity Server (read the official TeamCity documentation for more details), as shown in the following screenshot. If your host system is using iptables, make sure to accept connections on port 8111. Note that TeamCity data will be stored in the special location /data/teamcity. This is a standard Docker volume, it is useful to allow easy mounting, back-up, or future upgrade.

teamcity

Once the server is configured, it is time assign a build agent to this server (otherwise, nothing can be built). Again, we will spawn a build agent easily using Docker by running the container named ariya/centos6-teamcity-agent. For the agent to work, we need to specify the server. Here is how you would run it:

docker run -e TEAMCITY_SERVER=http://buildserver:8111 \
    -dt -p 9090:9090 ariya/centos6-teamcity-agent

If you run this in the same host which is running the server container, you need to link them together:

docker run -e TEAMCITY_SERVER=http://teamcity_server:8111 \
    --link teamcity_server:teamcity_server -dt ariya/centos6-teamcity-agent

The environment variable TEAMCITY_SERVER is mandatory, it needs to point to the location of the instance of TeamCity server you started in the previous step. Once you run the container, it will contact the specified server, download the agent ZIP file, and set it up. Wait a few minutes since the build agent usually updates itself after the first contact to the server. If everything works correctly, you should see a new agent appearing on the Agents tab on your TeamCity server web interface. Authorize the agent and now it should be ready to take any build job!

If there is a problem launching the agent (docker ps) does not show the container running, try to run it again but this time with the option -it (interactive terminal) instead of -dt. This will dump some additional debugging message which can be helpful to assist troubleshooting.

Note that this agent container is also based on CentOS 6 with Java 7. Usually this is not enough as you may need other dependencies (different SDKs, compilers, libraries, etc). Ideally those dependencies should be resolved automatically, either by basing the container on a different system or by setting up the right automatic provisiniong. Refer to my previous blog post Build Agent: Template vs Provisioning for a more detailed overview.

Still have an excuse not to do continuous integration? I don’t think so!

Tags:

For an automated build system, a typical configuration involves the separation between the build server and the build agents (some systems call it master-slave or coordinator-runner). Such a configuration allows any addition or removal of new build agents, perhaps to improve the build performance, without causing too much disruption. When it is time to spawn a new build agent, there are at least two possible techniques: recreate it from the template or provision it from scratch.

vmExcept for various corner cases, build agents nowadays often run in a virtualized environment. This makes it easy to install, upgrade, and manage the agent. An important benefit of having it virtualized is the ability to take the snapshot of the state of the build agent. When there is a problem, it is possible to revert it to the last good known snapshot. In addition, that snapshot could serve as the agent template. If there is a need to have more build agents, maybe because the build jobs are getting larger and larger, then a new agent can be created by cloning it from the template.

With today’s technologies, template-based build agent is not difficult to handle. Vagrant permits a simplified workflow for managing virtual machines with VirtualBox, VMware, etc. Continuous integration system like TeamCity and Bamboo has a built-in support for Amazon EC2, a new instance from a specified AMI can be started and stopped automatically. And of course, running a new Linux system in a container is a child’s play with Docker.

This template-based approach, while convenient, has a major drawback. If the software to be built has an updated set of dependencies (patched libraries, different compiler, new OS), then all the build agents become outdated. It is of course enough to create a fresh agent from scratch based on the new dependencies and spawning a bunch of new agents from this template. Yet, this process is often not automated and error-prone, an accident waiting to happen.

In the previous blog post A Maturity Model for Build Automation, I did already outline the loose mapping of capability maturity model to the state of common automated build system. With this, it is easy to see how we can level up the above template-based approach. Instead of relying on a predefined configuration, a build agent should be able to create a working environment for the build from a provisioning script. The litmus test is rather simple: given a fresh virtual machine, the build agent must figure out all the dependencies, find out what’s missing and solve it, and then be in a state where it is ready to take any build job.

Again, today’s technologies make such those provisioning actions as easy as 1-2-3. We already have all kinds of powerful configuration management tools (CFEngine, Chef, Puppet, Ansible, etc). In many cases, relying on the OS package managers (apt-get, rpm, yum, Chocolatey, etc) or even framework-specific packaging solution (pip, npm, gem, etc) is more than enough. There is hardly any excuse not to adopt this provisioning solution.

Last but not least, it’s possible to combine these two to form a hybrid, optimized approach. Given a plain vanilla machine, the provisioning script can always upgrade it to the intended state. That should also still hold even if the machine is already polluted with some old dependencies. This opens an opportunity for doing both. In the context of Docker, it means that the base image needs to be refreshed with all the dependencies, e.g. different compiler and system libraries. At this point, the existing agents can still continue to function, perhaps installing missing stuff as necessary. However, once the base image is fully upgraded, the agent container can be rebuilt and it will bypass any redundant installation.

Care to share which approach do you use/experience/prefer?