All of lore.kernel.org
 help / color / mirror / Atom feed
From: Kieran Bingham <kieran.bingham@linaro.org>
To: jan.kiszka@siemens.com, linux-kernel@vger.kernel.org
Cc: lee.jones@linaro.org, peter.griffin@linaro.org, maxime.coquelin@st.com
Subject: Re: [PATCH 8/8] scripts/gdb: Add meminfo command
Date: Wed, 24 Feb 2016 09:44:15 +0000	[thread overview]
Message-ID: <56CD7B6F.6030100@linaro.org> (raw)
In-Reply-To: <1456154652-29023-9-git-send-email-kieran.bingham@linaro.org>

I had missed some PEP8 line length warnings on this patch - I've now
fixed them up. And a spurious 'pass' statement appeared (highlighted
inline), which I've removed.
--
Kieran

On 22/02/16 15:24, 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>
> 
> ---
> 
> Changes from v1:
>  - Updated to use LX_ macros for constants
>  - Utilise the LX_CONFIG() options for conditional printing
>  - Fixed meminfo command on Jan's target .config
>  - Added missing segments to meminfo command (HUGEPAGE, QUICKLIST)
>  - Adjusted for new list_for_each_entry() function
>  - Fixed up for !CONFIG_SWAP and !CONFIG_MMU targets (Tested STM32)
> ---
>  scripts/gdb/linux/constants.py.in |  34 ++++++
>  scripts/gdb/linux/proc.py         | 219 ++++++++++++++++++++++++++++++++++++++
>  2 files changed, 253 insertions(+)
> 
> diff --git a/scripts/gdb/linux/constants.py.in b/scripts/gdb/linux/constants.py.in
> index 57213ad8cf75..66562a8242bd 100644
> --- a/scripts/gdb/linux/constants.py.in
> +++ b/scripts/gdb/linux/constants.py.in
> @@ -12,8 +12,16 @@
>   *
>   */
>  
> +#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/huge_mm.h>
> +#include <linux/vmalloc.h>
> +
>  
>  /* We need to stringify expanded macros so that they can be parsed */
>  
> @@ -51,3 +59,29 @@ LX_VALUE(MNT_NOATIME)
>  LX_VALUE(MNT_NODIRATIME)
>  LX_VALUE(MNT_RELATIME)
>  
> +/* asm/page.h */
> +LX_GDBPARSED(PAGE_SHIFT)
> +
> +/* asm/thread_info.h */
> +LX_GDBPARSED(THREAD_SIZE)
> +
> +/* linux/vmalloc.h */
> +LX_GDBPARSED(VMALLOC_TOTAL)
> +
> +/* linux/swap.h */
> +LX_GDBPARSED(MAX_SWAPFILES)
> +
> +
> +/* Kernel Configs */
> +LX_CONFIG(CONFIG_HIGHMEM)
> +LX_CONFIG(CONFIG_MEMORY_FAILURE)
> +LX_CONFIG(CONFIG_TRANSPARENT_HUGEPAGE)
> +LX_CONFIG(CONFIG_CMA)
> +LX_CONFIG(CONFIG_MMU)
> +LX_CONFIG(CONFIG_SWAP)
> +
> +#ifndef CONFIG_NR_QUICK
> +#define CONFIG_NR_QUICK 0
> +#endif
> +LX_VALUE(CONFIG_NR_QUICK)
> +LX_CONFIG(CONFIG_QUICKLIST)
> diff --git a/scripts/gdb/linux/proc.py b/scripts/gdb/linux/proc.py
> index 44804e10493e..95933f66ea3e 100644
> --- a/scripts/gdb/linux/proc.py
> +++ b/scripts/gdb/linux/proc.py
> @@ -204,3 +204,222 @@ values of that process namespace"""
>                          info_opts(MNT_INFO, m_flags)))
>  
>  LxMounts()
> +
> +
> +bdev_type = utils.CachedType("struct block_device")
> +bdev_ptr_type = bdev_type.get_type().pointer()
> +
> +
> +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.list_for_each_entry(bdevs_head, bdev_ptr_type, "bd_list"):
> +            try:
> +                pages += bdev['bd_inode']['i_mapping']['nrpages']
> +            except:
> +                # Any memory read failures are simply not counted
> +                pass
> +        return pages
> +
> +    def total_swapcache_pages(self):
> +        pages = 0
> +        if not constants.LX_CONFIG_SWAP:
> +            return 0
> +
> +        for i in range(0, int(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):
> +        total_swap_pages = 0
> +        overcommit = int(gdb.parse_and_eval("sysctl_overcommit_kbytes"))
> +        overcommit_ratio = int(gdb.parse_and_eval("sysctl_overcommit_ratio"))
> +
> +        if constants.LX_CONFIG_SWAP:
> +            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
> +
> +    def quicklist_total_size(self):
> +        count = 0
> +        quicklist = utils.gdb_eval_or_none("quicklist")
> +        if quicklist is None:
> +            return 0
> +
> +        for cpu in cpus.each_online_cpu():
> +            ql = cpus.per_cpu(quicklist, cpu)
> +            for q in range(0, constants.LX_CONFIG_NR_QUICK):
> +                # for (q = ql; q < ql + CONFIG_NR_QUICK; q++)
> +                # count += q->nr_pages
> +                count += ql[q]['nr_pages']
> +
> +        return count
> +
> +    # Main lx-meminfo command execution
> +    # See fs/proc/meminfo.c:meminfo_proc_show()
> +    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()
> +        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
> +
> +        kernelstack = int(self.gps("NR_KERNEL_STACK") *
> +                          constants.LX_THREAD_SIZE / 1024)
> +
> +        commitlimit = int(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"))
> +            )
> +        if constants.LX_CONFIG_HIGHMEM:
> +            totalhigh = int(gdb.parse_and_eval("totalhigh_pages"))
> +            freehigh = int(gdb.parse_and_eval("nr_free_highpages()"))
> +            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))
> +                )
> +        if not constants.LX_CONFIG_MMU:
> +            mmap_pages_allocated = gdb.parse_and_eval("mmap_pages_allocated.counter")
> +            gdb.write(
> +                "MmapCopy:       {:8d} kB\n".format(self.K(mmap_pages_allocated))
> +
> +                )

> +            pass

Hrm ... No idea where this 'pass' statement crept in ... It has been
dropped for the next patch version.

> +
> +        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 constants.LX_CONFIG_QUICKLIST:
> +            quicklist = self.quicklist_total_size()
> +            gdb.write(
> +               "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"))
> +            )
> +
> +        gdb.write(
> +            "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)
> +            )
> +
> +        # These are always zero now
> +        gdb.write(
> +            "VmallocUsed:    {:8d} kB\n".format(0) +
> +            "VmallocChunk:   {:8d} kB\n".format(0)
> +            )
> +
> +        if constants.LX_CONFIG_MEMORY_FAILURE:
> +            gdb.write(
> +                "HardwareCorrupted: {:8d} kB\n"
> +            )
> +        if constants.LX_CONFIG_TRANSPARENT_HUGEPAGE:
> +            huge = self.gps("NR_ANON_TRANSPARENT_HUGEPAGES")
> +            # HPAGE_PMD_NR can not be determined in constants.py
> +            gdb.write(
> +                "AnonHugePages:  {:8d} kB ( * HPAGE_PMD_NR )\n"
> +                .format(self.K(huge))
> +            )
> +        if constants.LX_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()
> 

  reply	other threads:[~2016-02-24  9:44 UTC|newest]

Thread overview: 12+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2016-02-22 15:24 [PATCHv2 0/8] gdb/scripts: Linux awareness debug commands Kieran Bingham
2016-02-22 15:24 ` [PATCH 1/8] scripts/gdb: Provide linux constants Kieran Bingham
2016-02-22 15:24 ` [PATCH 2/8] scripts/gdb: Provide a kernel list item generators Kieran Bingham
2016-02-22 15:24 ` [PATCH 3/8] scripts/gdb: Convert modules usage to lists functions Kieran Bingham
2016-02-22 15:24 ` [PATCH 4/8] scripts/gdb: Provide exception catching parser Kieran Bingham
2016-02-22 15:24 ` [PATCH 5/8] scripts/gdb: Support !CONFIG_MODULES gracefully Kieran Bingham
2016-02-22 15:24 ` [PATCH 6/8] scripts/gdb: Add io resource readers Kieran Bingham
2016-02-22 15:24 ` [PATCH 7/8] scripts/gdb: Add mount point list command Kieran Bingham
2016-02-22 15:24 ` [PATCH 8/8] scripts/gdb: Add meminfo command Kieran Bingham
2016-02-24  9:44   ` Kieran Bingham [this message]
2016-02-29 16:36 ` [PATCHv2 0/8] gdb/scripts: Linux awareness debug commands Jan Kiszka
2016-02-29 17:01   ` 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=56CD7B6F.6030100@linaro.org \
    --to=kieran.bingham@linaro.org \
    --cc=jan.kiszka@siemens.com \
    --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.