├── .gitignore ├── AUTHORS ├── LICENSE ├── README.md ├── c └── c_hook.c ├── collect-traces ├── correct-traces ├── lua │ ├── accumulate.lua.trace │ ├── coroutine-error.lua.trace │ ├── coroutine-one.lua.trace │ ├── coroutine-two.lua.trace │ ├── inner-function.lua.trace │ ├── one-line-horror-one.lua.trace │ ├── one-line-horror-three.lua.trace │ ├── one-line-horror-two.lua.trace │ ├── pcall-one.lua.trace │ ├── pcall-three.lua.trace │ ├── pcall-two.lua.trace │ ├── tailcall.lua.trace │ ├── tron.lua.trace │ └── wrap-error.lua.trace └── luajit │ ├── accumulate.lua.trace │ ├── coroutine-error.lua.trace │ ├── coroutine-one.lua.trace │ ├── coroutine-two.lua.trace │ ├── inner-function.lua.trace │ ├── one-line-horror-one.lua.trace │ ├── one-line-horror-three.lua.trace │ ├── one-line-horror-two.lua.trace │ ├── pcall-one.lua.trace │ ├── pcall-three.lua.trace │ ├── pcall-two.lua.trace │ ├── tailcall.lua.trace │ ├── tron.lua.trace │ └── wrap-error.lua.trace ├── lua ├── jit │ └── annotate.lua ├── luatrace.lua ├── luatrace │ ├── profile.lua │ └── trace_file.lua ├── test-annotate.lua ├── test │ ├── accumulate.lua │ ├── command-line.lua │ ├── coroutine-error.lua │ ├── coroutine-one.lua │ ├── coroutine-two.lua │ ├── inner-function.lua │ ├── one-line-horror-one.lua │ ├── one-line-horror-three.lua │ ├── one-line-horror-two.lua │ ├── pcall-one.lua │ ├── pcall-three.lua │ ├── pcall-two.lua │ ├── recursive.lua │ ├── tailcall.lua │ ├── trace_file-doc.lua │ ├── tron.lua │ └── wrap-error.lua ├── uatrace.lua └── uatrace │ └── profile.lua ├── makefile ├── rockspec ├── luatrace-scm-1.rockspec └── luatrace-scm-2.rockspec ├── run-tests └── sh └── luatrace.profile /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | Thumbs.db 3 | *.so 4 | *.dll 5 | 6 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | Leyland, Geoff (Incremental IP Ltd) -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2011 Incremental IP Limited 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | 21 | 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # luatrace - tracing, profiling and coverage for Lua 2 | 3 | ## 1. What? 4 | 5 | luatrace is a Lua module that collects information about what your code is doing 6 | and how long it takes, and can analyse that information to generate profile and 7 | coverage reports. 8 | 9 | luatrace adds a layer on top of Lua's debug hooks to make it easier to collect 10 | information for profiling and coverage analysis. 11 | luatrace traces of every line executed, not just calls. 12 | 13 | luatrace can trace through coroutine resumes and yields, and through xpcalls, 14 | pcalls and errors. 15 | On some platforms it uses high resolution timers to collect times of the order 16 | of nanoseconds. 17 | 18 | To use it, install luatrace with `sudo make install`, 19 | run your code with `lua -luatrace ` and then analyse it 20 | with `luatrace.profile`. The profiler will display a list of the top 20 functions 21 | by time, and write a copy of all the source traced annotated with times for each 22 | line. 23 | 24 | Alternatively, you can `local luatrace = require("luatrace")` and surround the code 25 | you wish to trace with `luatrace.tron()` and `luatrace.troff()`. 26 | 27 | If you wish to use the profiler directly rather than on a trace file you can use 28 | `lua -luatrace.profile ` or `local luatrace = require("luatrace.profile")`. 29 | 30 | You can pass settings to `luatrace.tron`. 31 | Probably the only interesting one is the name of the file to write the trace to, 32 | for example, you might have Lua code that calls `luatrace.tron{trace_file_name="mytrace.txt"}`. 33 | Later, you can run the profiler on this trace with the command-line 34 | `luatrace.profile mytrace.txt`. 35 | 36 | luatrace runs under "plain" Lua and LuaJIT with the -joff option (LuaJIT doesn't 37 | call hooks in compiled code, and luatrace loses track of where it's up to) 38 | 39 | luatrace is brought to you by [Incremental](http://www.incremental.co.nz/) () 40 | and is available under the [MIT Licence](http://www.opensource.org/licenses/mit-license.php). 41 | 42 | 43 | ## 2. How? 44 | 45 | luatrace is separated into two parts - the trace collector, and the backends that 46 | record and process the traces. 47 | 48 | The trace collector uses Lua's debug hooks and adds timing information and a 49 | little bit of processing to make the traces easier to use. 50 | 51 | Timing is provided in one of three ways: 52 | 53 | + Lua - with a debug hook calling `os.clock` 54 | + LuaJIT - with a debug hook calling `ffi.C.clock` - `os.clock` is not yet 55 | implemented as a fast function 56 | + Lua and LuaJIT - if the c_hook has been built then that's used instead of the 57 | Lua or LuaJIT hook. It's always better to use the C hook. 58 | 59 | By default the C hook uses the C library's `clock` and should call it closer to 60 | actual code execution, so the traces should be more accurate. 61 | On some plaforms the C hook uses a high-resolution timer: 62 | 63 | + On mach plaforms (ie OS X), the c_hook uses the `mach_absolute_time` 64 | + On Linux, it uses `clock_gettime` 65 | + On Windows, it uses `QueryPerformanceCounter` 66 | 67 | However, although the timing might be collected at nanosecond resolution, there 68 | are many reasons why profiles are not accurate to within a nanosecond! 69 | 70 | The collector outputs traces by calling a recorder's `record` function with a 71 | range of arguments: 72 | 73 | + `("S", , )` - the trace has started somewhere in a function defined on line 74 | + `(">", , )` - there's been a call to a function defined on line 75 | + `("T", , )` - there's been a tailcall to a function defined on line (LuaJIT only) 76 | + `("<")` - return from a function 77 | + `("R", )` - Resume the thread thread_id 78 | + `("Y")` - Yield 79 | + `("P")` - pcall - the current line is protected for the duration of the following call 80 | + `("E")` - Error - unwind the stack looking for a "P" 81 | + `(,