From c2f7fbcf2358cf83b103954ec0dc579aea39e3cb Mon Sep 17 00:00:00 2001 From: "Adrian C. (anrxc)" Date: Tue, 29 Mar 2011 02:21:53 +0200 Subject: [PATCH] dio: provide stats for all devices, rewritten by Joerg Old dio.lua was moved to contrib. New one is used like CPU widget is, request the device or parition in the format argument, {sda read_mb} as an example. New widget doesn't provide scheduler information, but I don't know anyone who used that. If you think this is wrong let me know. --- README | 10 +++---- TODO | 2 -- contrib/README | 8 ++++++ contrib/dio.lua | 72 ++++++++++++++++++++++++++++++++++++++++++++++ contrib/init.lua | 1 + widgets/dio.lua | 75 ++++++++++++++++++++++++------------------------ 6 files changed, 122 insertions(+), 46 deletions(-) create mode 100644 contrib/dio.lua diff --git a/README b/README index ef7d666..8f3b877 100644 --- a/README +++ b/README @@ -166,12 +166,10 @@ vicious.widgets.fs {/ avail_mb}, {/ avail_gb}, {/ avail_p}, {/home size_mb} etc. vicious.widgets.dio - - provides I/O statistics for requested storage devices - - takes the disk as an argument, i.e. "sda" (or a specific - partition, i.e. "sda/sda2") - - returns a table with string keys: {total_s}, {total_kb}, {total_mb}, - {read_s}, {read_kb}, {read_mb}, {write_s}, {write_kb}, {write_mb} - and {sched} + - provides I/O statistics for all available storage devices + - returns a table with string keys: {sda total_s}, {sda total_kb}, + {sda total_mb}, {sda read_s}, {sda read_kb}, {sda read_mb}, + {sda write_s}, {sda write_kb}, {sda write_mb}, {sdb1 total_s} etc. vicious.widgets.raid - provides state information for a requested RAID array diff --git a/TODO b/TODO index 5c125f0..5572be5 100644 --- a/TODO +++ b/TODO @@ -6,8 +6,6 @@ * Vicious ** TODO Consider commiting power drain support to bat.lua -** TODO Try replacing dio.lua with io.lua -*** TODO First io.lua should grab data for all devices ** TODO Document contrib widgets in contrib/README ** TODO Consider multigraph, graph stacking, support ** TODO Complete the hddtemp fix diff --git a/contrib/README b/contrib/README index 20b000e..16716ac 100644 --- a/contrib/README +++ b/contrib/README @@ -27,6 +27,14 @@ vicious.contrib.batpmu vicious.contrib.batproc - +vicious.contrib.dio + - provides I/O statistics for requested storage devices + - takes the disk as an argument, i.e. "sda" (or a specific + partition, i.e. "sda/sda2") + - returns a table with string keys: {total_s}, {total_kb}, {total_mb}, + {read_s}, {read_kb}, {read_mb}, {write_s}, {write_kb}, {write_mb} + and {sched} + vicious.contrib.mpc - diff --git a/contrib/dio.lua b/contrib/dio.lua new file mode 100644 index 0000000..40c4cad --- /dev/null +++ b/contrib/dio.lua @@ -0,0 +1,72 @@ +--------------------------------------------------- +-- Licensed under the GNU General Public License v2 +-- * (c) 2010, Adrian C. +--------------------------------------------------- + +-- {{{ Grab environment +local ipairs = ipairs +local setmetatable = setmetatable +local table = { insert = table.insert } +local string = { gmatch = string.gmatch } +local helpers = require("vicious.helpers") +-- }}} + + +-- Disk I/O: provides I/O statistics for requested storage devices +module("vicious.contrib.dio") + + +-- Initialize function tables +local disk_usage = {} +local disk_total = {} +-- Variable definitions +local unit = { ["s"] = 1, ["kb"] = 2, ["mb"] = 2048 } + +-- {{{ Disk I/O widget type +local function worker(format, disk) + if not disk then return end + + local disk_lines = { [disk] = {} } + local disk_stats = helpers.pathtotable("/sys/block/" .. disk) + + if disk_stats.stat then + local match = string.gmatch(disk_stats.stat, "[%s]+([%d]+)") + for i = 1, 11 do -- Store disk stats + table.insert(disk_lines[disk], match()) + end + end + + -- Ensure tables are initialized correctly + local diff_total = { [disk] = {} } + if not disk_total[disk] then + disk_usage[disk] = {} + disk_total[disk] = {} + + while #disk_total[disk] < #disk_lines[disk] do + table.insert(disk_total[disk], 0) + end + end + + for i, v in ipairs(disk_lines[disk]) do + -- Diskstats are absolute, substract our last reading + diff_total[disk][i] = v - disk_total[disk][i] + + -- Store totals + disk_total[disk][i] = v + end + + -- Calculate and store I/O + helpers.uformat(disk_usage[disk], "read", diff_total[disk][3], unit) + helpers.uformat(disk_usage[disk], "write", diff_total[disk][7], unit) + helpers.uformat(disk_usage[disk], "total", diff_total[disk][7] + diff_total[disk][3], unit) + + -- Store I/O scheduler + if disk_stats.queue and disk_stats.queue.scheduler then + disk_usage[disk]["{sched}"] = string.gmatch(disk_stats.queue.scheduler, "%[([%a]+)%]") + end + + return disk_usage[disk] +end +-- }}} + +setmetatable(_M, { __call = function(_, ...) return worker(...) end }) diff --git a/contrib/init.lua b/contrib/init.lua index e0f681a..a8c5ee6 100644 --- a/contrib/init.lua +++ b/contrib/init.lua @@ -9,6 +9,7 @@ require("vicious.contrib.batacpi") require("vicious.contrib.batpmu") require("vicious.contrib.batproc") +require("vicious.contrib.dio") require("vicious.contrib.mpc") require("vicious.contrib.netcfg") require("vicious.contrib.net") diff --git a/widgets/dio.lua b/widgets/dio.lua index edf4638..db6ba39 100644 --- a/widgets/dio.lua +++ b/widgets/dio.lua @@ -1,14 +1,17 @@ --------------------------------------------------- -- Licensed under the GNU General Public License v2 --- * (c) 2010, Adrian C. +-- * (c) 2011, Jörg T. --------------------------------------------------- -- {{{ Grab environment -local ipairs = ipairs +local pairs = pairs +local io = { lines = io.lines } local setmetatable = setmetatable -local table = { insert = table.insert } -local string = { gmatch = string.gmatch } local helpers = require("vicious.helpers") +local os = { + time = os.time, + difftime = os.difftime +} -- }}} @@ -18,54 +21,50 @@ module("vicious.widgets.dio") -- Initialize function tables local disk_usage = {} -local disk_total = {} --- Variable definitions +local disk_stats = {} +local disk_time = 0 +-- Constant definitions local unit = { ["s"] = 1, ["kb"] = 2, ["mb"] = 2048 } -- {{{ Disk I/O widget type -local function worker(format, disk) - if not disk then return end +local function worker(format) + local disk_lines = {} - local disk_lines = { [disk] = {} } - local disk_stats = helpers.pathtotable("/sys/block/" .. disk) - - if disk_stats.stat then - local match = string.gmatch(disk_stats.stat, "[%s]+([%d]+)") - for i = 1, 11 do -- Store disk stats - table.insert(disk_lines[disk], match()) - end + for line in io.lines("/proc/diskstats") do + local device, read, write = + -- Linux kernel docs: Documentation/iostats.txt + line:match("([^%s]+) %d+ %d+ (%d+) %d+ %d+ %d+ (%d+)") + disk_lines[device] = { read, write } end - -- Ensure tables are initialized correctly - local diff_total = { [disk] = {} } - if not disk_total[disk] then - disk_usage[disk] = {} - disk_total[disk] = {} + local time = os.time() + local interval = os.difftime(time, disk_time) + if interval == 0 then interval = 1 end - while #disk_total[disk] < #disk_lines[disk] do - table.insert(disk_total[disk], 0) + for device, stats in pairs(disk_lines) do + -- Avoid insane values on startup + local last_stats = disk_stats[device] or stats + + -- Check for overflows and counter resets (> 2^32) + if stats[1] < last_stats[1] or stats[2] < last_stats[2] then + last_stats[1], last_stats[2] = stats[1], stats[2] end - end - for i, v in ipairs(disk_lines[disk]) do -- Diskstats are absolute, substract our last reading - diff_total[disk][i] = v - disk_total[disk][i] + -- * divide by timediff because we don't know the timer value + local read = (stats[1] - last_stats[1]) / interval + local write = (stats[2] - last_stats[2]) / interval - -- Store totals - disk_total[disk][i] = v + -- Calculate and store I/O + helpers.uformat(disk_usage, device.." read", read, unit) + helpers.uformat(disk_usage, device.." write", write, unit) + helpers.uformat(disk_usage, device.." total", read + write, unit) end - -- Calculate and store I/O - helpers.uformat(disk_usage[disk], "read", diff_total[disk][3], unit) - helpers.uformat(disk_usage[disk], "write", diff_total[disk][7], unit) - helpers.uformat(disk_usage[disk], "total", diff_total[disk][7] + diff_total[disk][3], unit) + disk_time = time + disk_stats = disk_lines - -- Store I/O scheduler - if disk_stats.queue and disk_stats.queue.scheduler then - disk_usage[disk]["{sched}"] = string.gmatch(disk_stats.queue.scheduler, "%[([%a]+)%]") - end - - return disk_usage[disk] + return disk_usage end -- }}}