Finding Slow Build Steps With Grunt
Recently I wanted to visualize my build steps with Grunt and be able to track how many tasks were executed and be able to plot them on a timeline to show where bottlenecks were.
This turned out to be surprisingly difficult so I thought it would be interesting to show how this was done.
Now you can easily include a sub-task into each individual grunt task in order to time it and plot but this is not sustainable. For large teams, large projects, this would require a ton of maintenance. The better alternative is to hook into Grunt’s lower level task object so you know something about every single task executed.
WTF is this?
If you examine the Grunt source code (and I encourage you do — the comments are hilarious) you’ll find two implementations of a Task class. The lowest level class that all tasks inherit from is found in grunt.util.task.Task.
From within this class you have everything you need to know when a class is created and executed.
So what I did was simply overwrite this in the snippet below and then proxy requests to the original. This proxy method stores a timestamp when invoked and then writes data to a file when the task is completed.
I decided just to write the following data for each task:
[start timestamp, stop timestamp, task name]
Why write to a file?
The project I was working on was using concurrent grunt tasks and thus I could not store this data in memory because for each concurrent grunt task a new child process is spawned that executes the grunt file (and whatever tasks associated with the call) so in-memory is only useful if you don’t use child processes for your builds. Files allow for atomic writes therefore multiple processes can write to it and tasks will be represented in the proper order.
Ok so now what?
Now with this data I’m able to visualize a Grunt files task tree in order to identify both complexity, potential issues, and most importantly bottlenecks. I put together a quick visualization below which showcases this.
I’m not planning on making this into a Grunt plugin or anything like this. You can do that if you want. There is already another plugin out there called time-grunt but it does not seem to work with grunt-exec tasks and that constitutes A LOT of build steps on projects I work on. My approach hooks into every single Grunt task and reports on that data.
Gist below — have fun.
Originally published at www.jason-palmer.com.