From patchwork Wed Jan 20 11:15:50 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kieran Bingham X-Patchwork-Id: 60032 Delivered-To: patch@linaro.org Received: by 10.112.130.2 with SMTP id oa2csp3109445lbb; Wed, 20 Jan 2016 03:17:03 -0800 (PST) X-Received: by 10.66.150.228 with SMTP id ul4mr51938553pab.15.1453288623462; Wed, 20 Jan 2016 03:17:03 -0800 (PST) Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id 62si54616464pfj.93.2016.01.20.03.17.03; Wed, 20 Jan 2016 03:17:03 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dkim=pass header.i=@linaro.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S935339AbcATLRB (ORCPT + 29 others); Wed, 20 Jan 2016 06:17:01 -0500 Received: from mail-wm0-f50.google.com ([74.125.82.50]:32967 "EHLO mail-wm0-f50.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S935298AbcATLQa (ORCPT ); Wed, 20 Jan 2016 06:16:30 -0500 Received: by mail-wm0-f50.google.com with SMTP id 123so128217609wmz.0 for ; Wed, 20 Jan 2016 03:16:29 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=EHZ9G2jw6FfzKy44RtXh0ViWDRp0vS60odOj8C2dv0c=; b=GtQadnmimeBM0kEgS9KOJ7ntmEuWWOV1xv4+j8jjJjDdbJMRLBVlCNVu+UzYZ6wzcN nZ4egXJSe2GWnQj68Ve/CYCbwo+ndA8mL6Z6SoVhQgJ0L1kv3HQtISMmbEuxCSESimJP VQXQPwc2cpCX+9q3ErXq5i/Sgbp9/XsGq7QuY= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=EHZ9G2jw6FfzKy44RtXh0ViWDRp0vS60odOj8C2dv0c=; b=THgHfsP0tqgCV44/SOwjjojLx95a9WWXgeGBIy3NK7z4CXx/G7O+/ktX1bVQFVHeoY FbVuuxI3giFDDsL7SCaCOLKk6djR4UVsXFzRPnDUmoVHINP8Z6RWduNLz6g0S4AOfCwO /DyJRQOAXsFfxKKdmP9LevrFfKUPWN/n9wYkk4MHdY9GheR4znJmAEBCjyUUqdkNrFTz 0w2kbj0vEcaomE6TiK93GcyE6ovP1Ixzl3/EJaVMsG/6TUAMQvHHH7HKKtMEuVYZjWfm ldAT3fJoaU7PyNp5WvsMTiwPFMVYm4Fuet1hqduE4AMv/0OeGK6/f/0s+EIWfmf+xc5R ODtw== X-Gm-Message-State: AG10YORP319CSLwDHQjO8QIcwsp61/SD/EnFVzd3hpOuMNnJKv5Zd3gLtpkRlituku1Tz6OY X-Received: by 10.28.214.76 with SMTP id n73mr3634296wmg.52.1453288588953; Wed, 20 Jan 2016 03:16:28 -0800 (PST) Received: from localhost.localdomain (cpc87017-aztw30-2-0-cust65.18-1.cable.virginm.net. [92.232.232.66]) by smtp.gmail.com with ESMTPSA id bg1sm28398065wjc.27.2016.01.20.03.16.28 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Wed, 20 Jan 2016 03:16:28 -0800 (PST) From: Kieran Bingham To: jan.kiszka@siemens.com Cc: Kieran Bingham , linux-kernel@vger.kernel.org, maxime.coquelin@st.com, peter.griffin@linaro.org, lee.jones@linaro.org Subject: [PATCH 5/5] scripts/gdb: Add meminfo command Date: Wed, 20 Jan 2016 11:15:50 +0000 Message-Id: <1453288550-4706-6-git-send-email-kieran.bingham@linaro.org> X-Mailer: git-send-email 2.5.0 In-Reply-To: <1453288550-4706-1-git-send-email-kieran.bingham@linaro.org> References: <1453288550-4706-1-git-send-email-kieran.bingham@linaro.org> Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org 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 --- 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. 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? 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! scripts/gdb/linux/constants.py.in | 22 +++++ scripts/gdb/linux/proc.py | 173 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 195 insertions(+) -- 2.5.0 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 +#include +#include + #include +#include #include +#include + /* 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() + 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()