Merge various information into systemstat (#2764)

* Merge various information to systemstat
pull/2770/head
Hzj_jie 7 years ago committed by Frans de Jonge
parent 108ed374b3
commit 999898fa69

@ -35,7 +35,8 @@ Source: <a href="http://snippets.luacode.org/snippets/String_splitting_130">http
----@string str string to split
----@param pattern the pattern to split against
----@bool capture
function util.gsplit(str, pattern, capture)
----@bool capture_empty_entity
function util.gsplit(str, pattern, capture, capture_empty_entity)
pattern = pattern and tostring(pattern) or '%s+'
if (''):find(pattern) then
error('pattern matches empty string!', 2)
@ -45,7 +46,7 @@ function util.gsplit(str, pattern, capture)
repeat
local first, last = str:find(pattern, index)
if first and last then
if index < first then
if index < first or (index == first and capture_empty_entity) then
coroutine.yield(str:sub(index, first - 1))
end
if capture then
@ -372,4 +373,18 @@ function util.fixUtf8(str, replacement)
return str
end
--- Splits input string with the splitter into a table. This function ignores the last empty entity.
--
--- @string str the string to be split
--- @string splitter
--- @bool capture_empty_entity
--- @treturn an array-like table
function util.splitToArray(str, splitter, capture_empty_entity)
local result = {}
for word in util.gsplit(str, splitter, false, capture_empty_entity) do
table.insert(result, word)
end
return result
end
return util

@ -1,56 +0,0 @@
local Device = require("device")
local filter
-- TODO(Hzj_jie): Find the right filter for PocketBook
if Device:isKobo() or Device:isPocketBook() then
filter = "mmcblk"
elseif Device:isKindle() then
filter = "' /mnt/us$'"
elseif Device:isSDL() then
filter = "/dev/sd"
else
return { disabled = true, }
end
local InfoMessage = require("ui/widget/infomessage")
local UIManager = require("ui/uimanager")
local WidgetContainer = require("ui/widget/container/widgetcontainer")
local _ = require("gettext")
local StorageStat = WidgetContainer:new{
name = "storagestat",
menuItem = {
text = _("Storage statistics"),
callback = function()
local std_out = io.popen(
"df -h | sed -r 's/ +/ /g' | grep " .. filter ..
" | cut -d ' ' -f 2,3,4,5,6 | " ..
"awk '{print $5\": \\n Available: \" $3\"/\" $1 \"\\n Used: \" $4}'"
)
local msg
if std_out then
msg = std_out:read("*all")
std_out:close()
end
if msg == nil or msg == "" then
msg = _("Failed to retrieve storage information.")
end
UIManager:show(InfoMessage:new{
text = msg,
})
end
}
}
function StorageStat:init()
self.ui.menu:registerToMainMenu(self)
end
function StorageStat:addToMainMenu(menu_items)
menu_items.storage_stat = self.menuItem
end
return StorageStat

@ -1,6 +1,8 @@
local Device = require("device")
local KeyValuePage = require("ui/widget/keyvaluepage")
local UIManager = require("ui/uimanager")
local WidgetContainer = require("ui/widget/container/widgetcontainer")
local util = require("util")
local _ = require("gettext")
local SystemStat = {
@ -13,6 +15,197 @@ local SystemStat = {
discharge_count = 0,
}
function SystemStat:init()
if Device:isKobo() or Device:isPocketBook() then
self.storage_filter = "mmcblk"
elseif Device:isKindle() then
self.storage_filter = "' /mnt/us$'"
elseif Device:isSDL() then
self.storage_filter = "/dev/sd"
end
end
function SystemStat:put(p)
table.insert(self.kv_pairs, p)
end
function SystemStat:appendCounters()
self:put({_("KOReader Started at"), os.date("%c", self.start_sec)})
if self.suspend_sec then
self:put({_(" Last suspend time"), os.date("%c", self.suspend_sec)})
end
if self.resume_sec then
self:put({_(" Last resume time"), os.date("%c", self.resume_sec)})
end
self:put({_(" Up hours"),
string.format("%.2f", os.difftime(os.time(), self.start_sec) / 60 / 60)})
self:put({_("Counters"), ""})
self:put({_(" wake-ups"), self.wakeup_count})
self:put({_(" sleeps"), self.sleep_count})
self:put({_(" charge cycles"), self.charge_count})
self:put({_(" discharge cycles"), self.discharge_count})
end
local function systemInfo()
local result = {}
do
local stat = io.open("/proc/stat", "r")
if stat ~= nil then
for line in util.gsplit(stat:read("*all"), "\n", false) do
local t = util.splitToArray(line, " ")
if #t >= 5 and string.lower(t[1]) == "cpu" then
local n1, n2, n3, n4
n1 = tonumber(t[2])
n2 = tonumber(t[3])
n3 = tonumber(t[4])
n4 = tonumber(t[5])
if n1 ~= nil and n2 ~= nil and n3 ~= nil and n4 ~= nil then
result.cpu = {
user = n1,
nice = n2,
system = n3,
idle = n4,
total = n1 + n2 + n3 + n4
}
break
end
end
end
stat:close()
end
end
do
local meminfo = io.open("/proc/meminfo", "r")
if meminfo ~= nil then
result.memory = {}
for line in util.gsplit(meminfo:read("*all"), "\n", false) do
local t = util.splitToArray(line, " ")
if #t >= 2 then
if string.lower(t[1]) == "memtotal:" then
local n = tonumber(t[2])
if n ~= nil then
result.memory.total = n
end
elseif string.lower(t[1]) == "memfree:" then
local n = tonumber(t[2])
if n ~= nil then
result.memory.free = n
end
elseif string.lower(t[1]) == "memavailable:" then
local n = tonumber(t[2])
if n ~= nil then
result.memory.available = n
end
end
end
end
meminfo:close()
end
end
return result
end
function SystemStat:appendSystemInfo()
local stat = systemInfo()
if stat.cpu ~= nil then
self:put({_("System information"), ""})
self:put({_(" Total ticks (million)"),
string.format("%.2f", stat.cpu.total / 1000000)})
self:put({_(" Idle ticks (million)"),
string.format("%.2f", stat.cpu.idle / 1000000)})
self:put({_(" Processor usage %"),
string.format("%.2f", (1 - stat.cpu.idle / stat.cpu.total) * 100)})
end
if stat.memory ~= nil then
if stat.memory.total ~= nil then
self:put({_(" Total memory (MB)"),
string.format("%.2f", stat.memory.total / 1024)})
end
if stat.memory.free ~= nil then
self:put({_(" Free memory (MB)"),
string.format("%.2f", stat.memory.free / 1024)})
end
if stat.memory.available ~= nil then
self:put({_(" Available memory (MB)"),
string.format("%.2f", stat.memory.available / 1024)})
end
end
end
function SystemStat:appendProcessInfo()
local stat = io.open("/proc/self/stat", "r")
if stat == nil then return end
local t = util.splitToArray(stat:read("*all"), " ")
stat:close()
local n1, n2
if #t == 0 then return end
self:put({_("Process"), ""})
self:put({_(" ID"), t[1]})
if #t < 14 then return end
n1 = tonumber(t[14])
n2 = tonumber(t[15])
if n1 ~= nil then
if n2 ~= nil then
n1 = n1 + n2
end
local sys_stat = systemInfo()
if sys_stat.cpu ~= nil and sys_stat.cpu.total ~= nil then
self:put({_(" Processor usage %"),
string.format("%.2f", n1 / sys_stat.cpu.total * 100)})
else
self:put({_(" Processor usage ticks (million)"), n1 / 1000000})
end
end
if #t < 20 then return end
n1 = tonumber(t[20])
if n1 ~= nil then
self:put({_(" Threads"), tostring(n1)})
end
if #t < 23 then return end
n1 = tonumber(t[23])
if n1 ~= nil then
self:put({_(" Virtual memory (MB)"), string.format("%.2f", n1 / 1024 / 1024)})
end
if #t < 24 then return end
n1 = tonumber(t[24])
if n1 ~= nil then
self:put({_(" RAM usage (MB)"), string.format("%.2f", n1 / 256)})
end
end
function SystemStat:appendStorageInfo()
if self.storage_filter == nil then return end
local std_out = io.popen(
"df -h | sed -r 's/ +/ /g' | grep " .. self.storage_filter ..
" | sed 's/ /\\t/g' | cut -f 2,4,5,6"
)
if not std_out then return end
self:put({_("Storage information"), ""})
for line in util.gsplit(std_out:read("*all"), "\n", false) do
local t = util.splitToArray(line, "\t")
if #t ~= 4 then
self:put({_(" Unexpected"), line})
else
self:put({_(" Mount point"), t[4]})
self:put({_(" Available"), t[2]})
self:put({_(" Total"), t[1]})
self:put({_(" Used percentage"), t[3]})
end
end
std_out:close()
end
function SystemStat:onSuspend()
self.suspend_sec = os.time()
self.sleep_count = self.sleep_count + 1
@ -32,28 +225,19 @@ function SystemStat:onNotCharging()
end
function SystemStat:showStatistics()
local kv_pairs = {
{_("KOReader Started at"), os.date("%c", self.start_sec)},
{_("Up hours"), string.format("%.2f", os.difftime(os.time(), self.start_sec) / 60 / 60)},
{_("Number of wake-ups"), self.wakeup_count},
{_("Number of sleeps"), self.sleep_count},
{_("Number of charge cycles"), self.charge_count},
{_("Number of discharge cycles"), self.discharge_count},
}
if self.suspend_sec then
local kv_pairs_suspend = {_("Last suspend time"), os.date("%c", self.suspend_sec)}
table.insert(kv_pairs, kv_pairs_suspend)
end
if self.resume_sec then
local kv_pairs_resume = {_("Last resume time"), os.date("%c", self.resume_sec)}
table.insert(kv_pairs, kv_pairs_resume)
end
self.kv_pairs = {}
self:appendCounters()
self:appendProcessInfo()
self:appendStorageInfo()
self:appendSystemInfo()
UIManager:show(KeyValuePage:new{
title = _("System statistics"),
kv_pairs = kv_pairs,
kv_pairs = self.kv_pairs,
})
end
SystemStat:init()
local SystemStatWidget = WidgetContainer:new{
name = "systemstat",
}

@ -13,6 +13,7 @@ local Screen = require("device").screen
local Terminal = WidgetContainer:new{
name = "terminal",
dump_file = util.realpath(DataStorage:getDataDir()) .. "/terminal_output.txt",
command = "",
}
function Terminal:init()
@ -22,6 +23,7 @@ end
function Terminal:start()
self.input = InputDialog:new{
title = _("Enter a command and press \"Execute\""),
input = self.command,
text_height = Screen:getHeight() * 0.4,
input_type = "string",
buttons = {{{
@ -43,14 +45,14 @@ function Terminal:start()
end
function Terminal:execute()
local command = self.input:getInputText()
self.command = self.input:getInputText()
UIManager:show(InfoMessage:new{
text = _("Executing…"),
timeout = 0.1,
})
UIManager:forceRePaint()
local std_out = io.popen(command)
local entries = { command }
local std_out = io.popen(self.command)
local entries = { self.command }
if std_out then
while true do
local line = std_out:read()

@ -38,6 +38,22 @@ describe("util module", function()
assert.are_same(argv, {"./sdcv", "-nj", "words", "a lot", "more or less", "--data-dir=dict"})
end)
it("should split with splitter", function()
local words = {}
for word in util.gsplit("a-b-c-d", "-", false) do
table.insert(words, word)
end
assert.are_same(words, {"a", "b", "c", "d"})
end)
it("should also split with splitter", function()
local words = {}
for word in util.gsplit("a-b-c-d-", "-", false) do
table.insert(words, word)
end
assert.are_same(words, {"a", "b", "c", "d"})
end)
it("should split line into words", function()
local words = util.splitToWords("one two,three four . five")
assert.are_same(words, {
@ -251,4 +267,18 @@ describe("util module", function()
assert.is_equal(util.fixUtf8("glück schließen", "_"), "glück schließen")
end)
it("should split input to array", function()
assert.are_same(util.splitToArray("100\tabc\t\tdef\tghi200\t", "\t", true),
{"100", "abc", "", "def", "ghi200"})
end)
it("should also split input to array", function()
assert.are_same(util.splitToArray("abcabcabcabca", "a", true),
{"", "bc", "bc", "bc", "bc"})
end)
it("should split input to array without empty entities", function()
assert.are_same(util.splitToArray("100 abc def ghi200 ", " ", false),
{"100", "abc", "def", "ghi200"})
end)
end)

Loading…
Cancel
Save