From: Jan Kiszka <jan.kiszka@siemens.com>
To: Kieran Bingham <kieran.bingham@linaro.org>
Cc: linux-kernel@vger.kernel.org, maxime.coquelin@st.com,
peter.griffin@linaro.org, lee.jones@linaro.org
Subject: Re: [PATCH 5/5] scripts/gdb: Add meminfo command
Date: Sat, 23 Jan 2016 16:21:33 +0100 [thread overview]
Message-ID: <56A39A7D.1020907@siemens.com> (raw)
In-Reply-To: <1453288550-4706-6-git-send-email-kieran.bingham@linaro.org>
On 2016-01-20 12:15, Kieran Bingham wrote:
> Provide an equivalent of /proc/meminfo which should be available from
> core dumps, or crashed kernels. This should allow a debugger to identify
> if memory pressures were applicable in the instance of their issue
>
> Signed-off-by: Kieran Bingham <kieran.bingham@linaro.org>
> ---
>
> This command has proved to be much more difficult that I first thought it
> would be!
>
> It also poses a couple of interesting issues, which is why I submit this
> patch in a much more unfinished form.
Yeah, seems so - see below ;)
>
> The meminfo implementation at fs/proc/meminfo.c makes several function calls
> to collate information, which makes duplicating here more difficult.
>
> I suspect the best option here is to not present lines of which we can not
> obtain accurate data for, (much better than presenting inaccurate information)
>
> Would this go in agreement with you?
I didn't grab the use cases yet, so just a general suggestion: if the
inaccurate information may still have some value, you can mark it as
inaccurate and still print it.
>
> Finally, do you have any ideas on the best way to manage code which
> is #ifdef'd on kernel config options? (#ifdef CONFIG_HIGHMEM for example).
>
> In a similar vein to the constants.py, I considered that we could iterate all
> of the kernel configuration options and store them in a dictionary some how.
>
> That may be awkward, however, and I wondered what ideas anyone had!
Why not convert the (relevant) configs inside constants.py into a
python variable? CONFIG_IS_ENABLED should make this easy.
>
>
> scripts/gdb/linux/constants.py.in | 22 +++++
> scripts/gdb/linux/proc.py | 173 ++++++++++++++++++++++++++++++++++++++
> 2 files changed, 195 insertions(+)
>
> diff --git a/scripts/gdb/linux/constants.py.in b/scripts/gdb/linux/constants.py.in
> index 739a15d2e984..306bd601ae4e 100644
> --- a/scripts/gdb/linux/constants.py.in
> +++ b/scripts/gdb/linux/constants.py.in
> @@ -12,8 +12,15 @@
> *
> */
>
> +#include <asm/page.h>
> +#include <asm/pgtable.h>
> +#include <asm/thread_info.h>
> +
> #include <linux/fs.h>
> +#include <linux/swap.h>
> #include <linux/mount.h>
> +#include <linux/vmalloc.h>
> +
>
> /* We need to stringify expanded macros so that they can be parsed */
>
> @@ -41,3 +48,18 @@ LX_MNT_NOATIME = MNT_NOATIME
> LX_MNT_NODIRATIME = MNT_NODIRATIME
> LX_MNT_RELATIME = MNT_RELATIME
>
> +/* asm/page.h */
> +LX_PAGE_SHIFT = XSTRING(PAGE_SHIFT)
> +lx_page_shift = gdb.parse_and_eval(LX_PAGE_SHIFT)
> +
> +/* asm/thread_info.h */
> +LX_THREAD_SIZE = XSTRING(THREAD_SIZE)
> +lx_thread_size = gdb.parse_and_eval(LX_THREAD_SIZE)
> +
> +/* linux/vmalloc.h */
> +LX_VMALLOC_TOTAL = XSTRING(VMALLOC_TOTAL)
> +lx_vmalloc_total = gdb.parse_and_eval(LX_VMALLOC_TOTAL)
> +
> +/* linux/swap.h */
> +LX_MAX_SWAPFILES = XSTRING(MAX_SWAPFILES)
> +lx_max_swapfiles = gdb.parse_and_eval(LX_MAX_SWAPFILES)
> diff --git a/scripts/gdb/linux/proc.py b/scripts/gdb/linux/proc.py
> index b79ce2a33a3d..ac9e1aac2403 100644
> --- a/scripts/gdb/linux/proc.py
> +++ b/scripts/gdb/linux/proc.py
> @@ -206,3 +206,176 @@ values of that process namespace"""
> info_opts(MNT_INFO, m_flags)))
>
> LxMounts()
> +
> +
> +bdev_type = utils.CachedType("struct block_device")
> +
> +
> +class LxMeminfo(gdb.Command):
> + """ Identify the memory usage, statistics, and availability
> +
> +Equivalent to cat /proc/meminfo on a running target """
> +
> + def __init__(self):
> + super(LxMeminfo, self).__init__("lx-meminfo", gdb.COMMAND_DATA)
> +
> + def K(self, val):
> + # Convert from PAGES to KB
> + return int(val << (constants.lx_page_shift - 10))
> +
> + def page_K(self, remote_value):
> + # Obtain page value, and Convert from PAGES to KB
> + val = int(gdb.parse_and_eval(remote_value))
> + return self.K(val)
> +
> + def gps(self, enum_zone_stat_item):
> + # Access the Global Page State structure
> + # I would prefer to read this structure in one go and then index
> + # from the enum. But we can't determine the enum values with out
> + # a call to GDB anyway so we may as well take the easy route and
> + # get the value.
> + remote_value = "vm_stat[" + enum_zone_stat_item + "].counter"
> + return int(gdb.parse_and_eval(remote_value))
> +
> + def gps_K(self, enum_zone_stat_item):
> + return self.K(self.gps(enum_zone_stat_item))
> +
> + def nr_blockdev_pages(self):
> + bdevs_head = gdb.parse_and_eval("all_bdevs")
> + pages = 0
> + for bdev in lists.items(bdev_type, "bd_list", bdevs_head):
> + pages += bdev['bd_inode']['i_mapping']['nrpages']
> + return pages
> +
> + def total_swapcache_pages(self):
> + pages = 0
> + for i in range(0, constants.lx_max_swapfiles):
> + swap_space = "swapper_spaces[" + str(i) + "].nrpages"
> + pages += int(gdb.parse_and_eval(swap_space))
> + return pages
> +
> + def vm_commit_limit(self, totalram_pages):
> + overcommit = int(gdb.parse_and_eval("sysctl_overcommit_kbytes"))
> + overcommit_ratio = int(gdb.parse_and_eval("sysctl_overcommit_ratio"))
> + total_swap_pages = int(gdb.parse_and_eval("total_swap_pages"))
> + hugetlb_total_pages = 0 # hugetlb_total_pages()!!
> +
> + if overcommit:
> + allowed = overcommit >> (constants.lx_page_shift - 10)
> + else:
> + allowed = ((totalram_pages - hugetlb_total_pages *
> + overcommit_ratio / 100))
> +
> + allowed += total_swap_pages
> + return allowed
> +
> + # Main lx-meminfo command execution
> + def invoke(self, arg, from_tty):
> + totalram = int(gdb.parse_and_eval("totalram_pages"))
> + freeram = self.gps("NR_FREE_PAGES")
> + reclaimable = self.gps("NR_SLAB_RECLAIMABLE")
> + unreclaimable = self.gps("NR_SLAB_UNRECLAIMABLE")
> + slab = reclaimable + unreclaimable
> + # for_each_zone(zone)
> + # wmark_low += zone->watermark[WMARK_LOW];
> + wmark_low = 0 # Zone parsing is unimplemented
> +
> + available = freeram - wmark_low
> + available += reclaimable - min(reclaimable / 2, wmark_low)
> +
> + bufferram = self.nr_blockdev_pages()
Something goes wrong here:
(gdb) lx-meminfo
Traceback (most recent call last):
File "/data/linux/build-dbg/scripts/gdb/linux/proc.py", line 286, in invoke
bufferram = self.nr_blockdev_pages()
File "/data/linux/build-dbg/scripts/gdb/linux/proc.py", line 246, in nr_blockdev_pages
for bdev in lists.items(bdev_type, "bd_list", bdevs_head):
File "/data/linux/build-dbg/scripts/gdb/linux/lists.py", line 26, in items
yield utils.container_of(next_item, list_type, list_location)
File "/data/linux/build-dbg/scripts/gdb/linux/utils.py", line 52, in container_of
offset_of(typeobj, member)).cast(typeobj)
File "/data/linux/build-dbg/scripts/gdb/linux/utils.py", line 46, in offset_of
element = gdb.Value(0).cast(typeobj)
RuntimeError: Argument must be a type.
Error occurred in Python command: Argument must be a type.
If you need my kernel config to reproduce, just let me know.
> + total_swapcache_pages = self.total_swapcache_pages()
> +
> + file_pages = self.gps("NR_FILE_PAGES")
> + cached = file_pages - total_swapcache_pages - bufferram
> +
> + # LRU Pages
> + active_pages_anon = self.gps("NR_ACTIVE_ANON")
> + inactive_pages_anon = self.gps("NR_INACTIVE_ANON")
> + active_pages_file = self.gps("NR_ACTIVE_FILE")
> + inactive_pages_file = self.gps("NR_INACTIVE_FILE")
> + unevictable_pages = self.gps("NR_UNEVICTABLE")
> + active_pages = active_pages_anon + active_pages_file
> + inactive_pages = inactive_pages_anon + inactive_pages_file
> +
> + totalhigh = int(gdb.parse_and_eval("totalhigh_pages"))
> + # We can't run this on a core dump file ...
> + # if running target ()
> + freehigh = int(gdb.parse_and_eval("nr_free_highpages()"))
> + # else freehigh = 0
> +
> + kernelstack = int(self.gps("NR_KERNEL_STACK") *
> + constants.lx_thread_size / 1024)
> +
> + commitlimit = self.vm_commit_limit(totalram)
> + committed_as = int(gdb.parse_and_eval("vm_committed_as.count"))
> +
> + vmalloc_total = int(constants.lx_vmalloc_total >> 10)
> +
> + gdb.write(
> + "MemTotal: {:8d} kB\n".format(self.K(totalram)) +
> + "MemFree: {:8d} kB\n".format(self.K(freeram)) +
> + "MemAvailable: {:8d} kB\n".format(self.K(available)) +
> + "Buffers: {:8d} kB\n".format(self.K(bufferram)) +
> + "Cached: {:8d} kB\n".format(self.K(cached)) +
> + "SwapCached: {:8d} kB\n".format(self.K(total_swapcache_pages)) +
> + "Active: {:8d} kB\n".format(self.K(active_pages)) +
> + "Inactive: {:8d} kB\n".format(self.K(inactive_pages)) +
> + "Active(anon): {:8d} kB\n".format(self.K(active_pages_anon)) +
> + "Inactive(anon): {:8d} kB\n".format(self.K(inactive_pages_anon)) +
> + "Active(file): {:8d} kB\n".format(self.K(active_pages_file)) +
> + "Inactive(file): {:8d} kB\n".format(self.K(inactive_pages_file)) +
> + "Unevictable: {:8d} kB\n".format(self.K(unevictable_pages)) +
> + "Mlocked: {:8d} kB\n".format(self.gps_K("NR_MLOCK"))
> + )
> + # ifdef CONFIG_HIGHMEM || core dump?
> + gdb.write(
> + "HighTotal: {:8d} kB\n".format(self.K(totalhigh)) +
> + "HighFree: {:8d} kB\n".format(self.K(freehigh)) +
> + "LowTotal: {:8d} kB\n".format(self.K(totalram-totalhigh)) +
> + "LowFree: {:8d} kB\n".format(self.K(freeram-freehigh))
> + )
> + # endif
> + # ifndef CONFIG_MMU
> + # gdb.write(
> + # mmap_pages_allocated
> + # )
> + # endif
> + gdb.write(
> + "SwapTotal: {:8d} kB\n".format(self.K(0)) +
> + "SwapFree: {:8d} kB\n".format(self.K(0)) +
> + "Dirty: {:8d} kB\n".format(self.gps_K("NR_FILE_DIRTY")) +
> + "Writeback: {:8d} kB\n".format(self.gps_K("NR_WRITEBACK")) +
> + "AnonPages: {:8d} kB\n".format(self.gps_K("NR_ANON_PAGES")) +
> + "Mapped: {:8d} kB\n".format(self.gps_K("NR_FILE_MAPPED")) +
> + "Shmem: {:8d} kB\n".format(self.gps_K("NR_SHMEM")) +
> + "Slab: {:8d} kB\n".format(self.K(slab)) +
> + "SReclaimable: {:8d} kB\n".format(self.K(reclaimable)) +
> + "SUnreclaim: {:8d} kB\n".format(self.K(unreclaimable)) +
> + "KernelStack: {:8d} kB\n".format(kernelstack) +
> + "PageTables: {:8d} kB\n".format(self.gps_K("NR_PAGETABLE"))
> + )
> +
> + # if CONFIG_QUICKLIST
> + # "Quicklists: {:8d} kB\n".format(self.K(quicklist)))
> +
> + gdb.write(
> + "NFS_Unstable: {:8d} kB\n".format(self.gps_K("NR_UNSTABLE_NFS")) +
> + "Bounce: {:8d} kB\n".format(self.gps_K("NR_BOUNCE")) +
> + "WritebackTmp: {:8d} kB\n".format(self.gps_K("NR_WRITEBACK_TEMP")) +
> + "CommitLimit: {:8d} kB\n".format(self.K(commitlimit)) +
> + "Committed_AS: {:8d} kB\n".format(self.K(committed_as)) +
> + "VmallocTotal: {:8d} kB\n".format(vmalloc_total) +
> + "VmallocUsed: {:8d} kB\n".format(0) +
> + "VmallocChunk: {:8d} kB\n".format(0)
> + )
> + # if CONFIG_MEMORY_FAILURE
> + # "HardwareCorrupted: %5lu kB\n"
> + # ifdef CONFIG_CMA
> + totalcma_pages = int(gdb.parse_and_eval("totalcma_pages"))
> + gdb.write(
> + "CmaTotal: {:8d} kB\n".format(self.K(totalcma_pages)) +
> + "CmaFree: {:8d} kB\n".format(self.gps_K("NR_FREE_CMA_PAGES"))
> + )
> +
> +LxMeminfo()
>
Jan
--
Siemens AG, Corporate Technology, CT RDA ITP SES-DE
Corporate Competence Center Embedded Linux
next prev parent reply other threads:[~2016-01-23 15:22 UTC|newest]
Thread overview: 20+ messages / expand[flat|nested] mbox.gz Atom feed top
2016-01-20 11:15 [RFC PATCH 0/5] scripts/gdb: Linux awareness debug commands Kieran Bingham
2016-01-20 11:15 ` [PATCH 1/5] scripts/gdb: Provide linux constants Kieran Bingham
2016-01-23 15:05 ` Jan Kiszka
2016-01-24 0:11 ` Kieran Bingham
2016-01-20 11:15 ` [PATCH 2/5] scripts/gdb: Provide a kernel list item generator Kieran Bingham
2016-01-23 15:08 ` Jan Kiszka
2016-01-24 0:15 ` Kieran Bingham
2016-01-20 11:15 ` [PATCH 3/5] scripts/gdb: Add io resource readers Kieran Bingham
2016-01-23 15:12 ` Jan Kiszka
2016-01-24 0:17 ` Kieran Bingham
2016-01-20 11:15 ` [PATCH 4/5] scripts/gdb: Add mount point list command Kieran Bingham
2016-01-20 11:42 ` Jan Kiszka
2016-01-20 11:51 ` Kieran Bingham
2016-01-20 12:08 ` Jan Kiszka
2016-01-23 12:34 ` Jan Kiszka
2016-01-23 15:27 ` Jan Kiszka
2016-01-24 0:24 ` Kieran Bingham
2016-01-20 11:15 ` [PATCH 5/5] scripts/gdb: Add meminfo command Kieran Bingham
2016-01-23 15:21 ` Jan Kiszka [this message]
2016-01-24 0:30 ` Kieran Bingham
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=56A39A7D.1020907@siemens.com \
--to=jan.kiszka@siemens.com \
--cc=kieran.bingham@linaro.org \
--cc=lee.jones@linaro.org \
--cc=linux-kernel@vger.kernel.org \
--cc=maxime.coquelin@st.com \
--cc=peter.griffin@linaro.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.