Permalink
Please sign in to comment.
Showing
with
169 additions
and 0 deletions.
| @@ -0,0 +1,169 @@ | ||
| +--[[ | ||
| +Copyright (C) 2013-2014 Draios inc. | ||
| +Copyright (C) 2015 Brendan Gregg. | ||
| + | ||
| +This program is free software: you can redistribute it and/or modify | ||
| +it under the terms of the GNU General Public License version 2 as | ||
| +published by the Free Software Foundation. | ||
| + | ||
| + | ||
| +This program is distributed in the hope that it will be useful, | ||
| +but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| +GNU General Public License for more details. | ||
| + | ||
| +You should have received a copy of the GNU General Public License | ||
| +along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| +--]] | ||
| + | ||
| +-- Chisel description | ||
| +description = "This visualizes the subsecond offset time of system call execution. This allows repetitive patterns to be identified, which are lost when averaging at a one second granularity. The Y axis (vertical) shows the passage of time. The X axis (horizontal) shows the passage of time within whole or fractions of a second. By default, the X axis range is 1000 milliseconds; this can be specified as an argument (try 100). Each bucket of the heat map, or spectrogram, is shown as a colored rectangle. The color shows how many syscalls fell into that time and subsecond offset range. It can be black (no calls), green (tens of calls/s), yellow (hundreds of calls/s) or red (Thousands of calls/s). Use this chisel in conjunction with filters to visualize latencies for certain processes, types of I/O activity, file systems, etc." | ||
| +short_description = "Visualize subsecond offset execution time." | ||
| +category = "CPU Usage" | ||
| + | ||
| +-- Chisel argument list | ||
| +args = { | ||
| + { | ||
| + name = "refresh_time", | ||
| + description = "chart refresh time in milliseconds", | ||
| + argtype = "int", | ||
| + optional = true | ||
| + }, | ||
| +} | ||
| + | ||
| +require "common" | ||
| +terminal = require "ansiterminal" | ||
| +terminal.enable_color(true) | ||
| + | ||
| +refresh_time = 1000 * 1000 * 1000 | ||
| +refresh_per_sec = 1 * 1000 * 1000 * 1000 / refresh_time | ||
| +max_label_len = 0 | ||
| +frequencies = {} | ||
| +colpalette = {22, 28, 64, 34, 2, 76, 46, 118, 154, 191, 227, 226, 11, 220, 209, 208, 202, 197, 9, 1} | ||
| + | ||
| +function on_set_arg(name, val) | ||
| + if name == "refresh_time" then | ||
| + refresh_time = parse_numeric_input(val, name) * 1 * 1000 * 1000 | ||
| + refresh_per_sec = 1 * 1000 * 1000 * 1000 / refresh_time | ||
| + return true | ||
| + end | ||
| + | ||
| + return false | ||
| +end | ||
| + | ||
| +function on_init() | ||
| + is_tty = sysdig.is_tty() | ||
| + | ||
| + if not is_tty then | ||
| + print("This chisel only works on ANSI terminals. Aborting.") | ||
| + return false | ||
| + end | ||
| + | ||
| + tinfo = sysdig.get_terminal_info() | ||
| + w = tinfo.width | ||
| + h = tinfo.height | ||
| + max_label_len = string.len("|" .. (0.9 * refresh_time / 10000000) .. "ms") | ||
| + | ||
| + -- trace syscall entry | ||
| + chisel.set_filter("evt.dir=>") | ||
| + | ||
| + rawtime = chisel.request_field("evt.rawtime") | ||
| + | ||
| + terminal.hidecursor() | ||
| + | ||
| + print("Tracing syscalls... red (hot) == high frequency <-> green == low frequency.\n") | ||
| + | ||
| + return true | ||
| +end | ||
| + | ||
| +function on_capture_start() | ||
| + chisel.set_interval_ns(refresh_time) | ||
| + return true | ||
| +end | ||
| + | ||
| +function on_event() | ||
| + local subsec = evt.field(rawtime) | ||
| + | ||
| + -- subsec is normalized to terminal column location | ||
| + subsec = math.floor((((subsec * 1000 / refresh_time) % 1000) / 1000) * w) | ||
| + | ||
| + if frequencies[subsec] == nil then | ||
| + frequencies[subsec] = 1 | ||
| + else | ||
| + frequencies[subsec] = frequencies[subsec] + 1 | ||
| + end | ||
| + | ||
| + return true | ||
| +end | ||
| + | ||
| +function mkcol(n) | ||
| + local col = math.floor(math.log10(n * refresh_per_sec + 1) / math.log10(1.6)) | ||
| + | ||
| + if col < 1 then | ||
| + col = 1 | ||
| + end | ||
| + | ||
| + if col > #colpalette then | ||
| + col = #colpalette | ||
| + end | ||
| + | ||
| + return colpalette[col] | ||
| +end | ||
| + | ||
| +function on_interval(ts_s, ts_ns, delta) | ||
| + terminal.moveup(1) | ||
| + | ||
| + for x = 1, w do | ||
| + local fr = frequencies[x] | ||
| + | ||
| + if fr == nil or fr == 0 then | ||
| + terminal.setbgcol(0) | ||
| + else | ||
| + terminal.setbgcol(mkcol(fr)) | ||
| + end | ||
| + | ||
| + io.write(" ") | ||
| + end | ||
| + | ||
| + io.write(terminal.reset .. "\n") | ||
| + | ||
| + local x = 0 | ||
| + while true do | ||
| + if x >= w then | ||
| + break | ||
| + end | ||
| + | ||
| + local curtime = math.floor(x * 10 / w) | ||
| + local prevtime = math.floor((x - 1) * 10 / w) | ||
| + | ||
| + if curtime ~= prevtime then | ||
| + if (x <= w - max_label_len) then | ||
| + local tstr = "|" .. (math.floor(10 * x / w) * refresh_time / 10000000) .. "ms" | ||
| + io.write(tstr) | ||
| + x = x + string.len(tstr) | ||
| + else | ||
| + io.write(" ") | ||
| + x = x + 1 | ||
| + end | ||
| + else | ||
| + io.write(" ") | ||
| + x = x + 1 | ||
| + end | ||
| + end | ||
| + | ||
| + io.write("\n") | ||
| + | ||
| + frequencies = {} | ||
| + | ||
| + return true | ||
| +end | ||
| + | ||
| +function on_capture_end(ts_s, ts_ns, delta) | ||
| + if is_tty then | ||
| + print(terminal.reset) | ||
| + terminal.showcursor() | ||
| + end | ||
| + | ||
| + return true | ||
| +end | ||
| + |
0 comments on commit
2f21604