From patchwork Mon Jan 6 11:21:03 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Hao Ge X-Patchwork-Id: 13927207 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from kanga.kvack.org (kanga.kvack.org [205.233.56.17]) by smtp.lore.kernel.org (Postfix) with ESMTP id 7AB28E77188 for ; Mon, 6 Jan 2025 11:22:12 +0000 (UTC) Received: by kanga.kvack.org (Postfix) id ED7616B0089; Mon, 6 Jan 2025 06:22:11 -0500 (EST) Received: by kanga.kvack.org (Postfix, from userid 40) id E85D46B0092; Mon, 6 Jan 2025 06:22:11 -0500 (EST) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id D74BE6B0093; Mon, 6 Jan 2025 06:22:11 -0500 (EST) X-Delivered-To: linux-mm@kvack.org Received: from relay.hostedemail.com (smtprelay0010.hostedemail.com [216.40.44.10]) by kanga.kvack.org (Postfix) with ESMTP id B7ACA6B0089 for ; Mon, 6 Jan 2025 06:22:11 -0500 (EST) Received: from smtpin12.hostedemail.com (a10.router.float.18 [10.200.18.1]) by unirelay06.hostedemail.com (Postfix) with ESMTP id 397A0B0D08 for ; Mon, 6 Jan 2025 11:22:11 +0000 (UTC) X-FDA: 82976788062.12.44206FF Received: from out-183.mta0.migadu.com (out-183.mta0.migadu.com [91.218.175.183]) by imf27.hostedemail.com (Postfix) with ESMTP id 744554000C for ; Mon, 6 Jan 2025 11:22:09 +0000 (UTC) Authentication-Results: imf27.hostedemail.com; dkim=pass header.d=linux.dev header.s=key1 header.b=qAG7W4jj; spf=pass (imf27.hostedemail.com: domain of hao.ge@linux.dev designates 91.218.175.183 as permitted sender) smtp.mailfrom=hao.ge@linux.dev; dmarc=pass (policy=none) header.from=linux.dev ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=hostedemail.com; s=arc-20220608; t=1736162529; h=from:from:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-transfer-encoding:content-transfer-encoding: in-reply-to:references:dkim-signature; bh=0Xw8ufFZe9gNpfTNOnMpE79QJyb64gfXitJNrGdbwSo=; b=EWrv+KhDM5nVqAJ0xUArV8Kt/InoHtT9kKErROw1smFOGS5aDVdIFAb9LzWfNWYFX8ldJj GxPobiRLOkjP1r64Rlyq8k0KNMZEeNbYu/kFIbUs0844lqj357nRKcNhZnZYedf9ikiB6V 2LDCSU2jgbHlNZv77/gHGeCfCdl+XEs= ARC-Seal: i=1; s=arc-20220608; d=hostedemail.com; t=1736162529; a=rsa-sha256; cv=none; b=5PUn+iI6wR++n1cAFfTOwcAE5OmeP7Q6Jjr+Q0l7DKlqR6FlJ38kRahqqdAGUFXtcV1cEb dskkbxE6N11Bdq0ovOjf7tdLqm4TpapIC6mNhkBxFBgb4ixmRmIvMNsp3/tb1Pkhwcugnq +G0U08tcHkIDMqB78ZLjHI5WX/8U7Rc= ARC-Authentication-Results: i=1; imf27.hostedemail.com; dkim=pass header.d=linux.dev header.s=key1 header.b=qAG7W4jj; spf=pass (imf27.hostedemail.com: domain of hao.ge@linux.dev designates 91.218.175.183 as permitted sender) smtp.mailfrom=hao.ge@linux.dev; dmarc=pass (policy=none) header.from=linux.dev X-Report-Abuse: Please report any abuse attempt to abuse@migadu.com and include these headers. DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.dev; s=key1; t=1736162522; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding; bh=0Xw8ufFZe9gNpfTNOnMpE79QJyb64gfXitJNrGdbwSo=; b=qAG7W4jjoLSbP56vUwZ3H6toPhiNgezZcIHFdixKOpNVLEVWTqrkdhghSR+DR+jOhjjKfq nfCqr+gfPJz6P2Vlf3pPTvU12NZBAPvBkMpShNNMBA234Lpk/+GRZAAPBV9KG64J7/c6Ic eK4Rc0wJomvdLKD0no7Qll72BvrXMgM= From: Hao Ge To: akpm@linux-foundation.org, surenb@google.com, kent.overstreet@linux.dev Cc: linux-kernel@vger.kernel.org, linux-mm@kvack.org, hao.ge@linux.dev, Hao Ge Subject: [PATCH] tools/mm: Introduce a tool to handle entries in allocinfo Date: Mon, 6 Jan 2025 19:21:03 +0800 Message-Id: <20250106112103.25401-1-hao.ge@linux.dev> MIME-Version: 1.0 X-Migadu-Flow: FLOW_OUT X-Rspamd-Server: rspam02 X-Rspamd-Queue-Id: 744554000C X-Stat-Signature: 151qm53qyw6iyhfejmqii6u78jcw4d7z X-Rspam-User: X-HE-Tag: 1736162529-700457 X-HE-Meta: U2FsdGVkX181p9mmFtJfeOFHOfYrbJGAKeJOdR8MXn8sZcpLDehaE+uyaLGq3US6NRRPJVgOJEEmSYKKHuJoMnTfy3vkmG2QLzxB1gwg3PiAejKdD11Ek6uaLOcdsLpCQJ6NZ/MkYzV5ifN7Ihg83xo8UOzld94m1GWou8bsextMcu3XxMuMCgdIGPbkJmHLhIp4Px39lMuvvu3c6RUrZ8IDkUkpBKjzAiDnU/MR+am7jhzLF66DEQ4Ld3bfdUUYufwAMZ66sivbNQrD8SNJBGecBEOx8gOZ6UjQigpSTR7WBcE+PgJH5szTWjC+VNaCcaygHknz55TY4zonYidT+obaKRNtmJhzKBmKkJFBHPsGrb5v4UmHdcrSdJ+8wUW/F2D9AZP/nsvavKdml+oSjwYNrbdUETIK4CjX2jBkn3pYygDpP47Us3JySKa+cxZSScUC+ClcdgwrlFfTir3jTdLHRDurWddU3DrkxhFl5oflnXFF7Z6qRdg3BqvNTQMcXzqg3ahFVubZE1It0kKvnHPmWuckhKDw8iHBHsj055s+pqmImdRyMdWtOU+2VlASqhTl5Hc7NFLl1VYYM4CLDHAc6uM2QA4JhT957lQyjZKnD+Eh+mfNZ5Tb3l3zFENRIRZFAHeaFkf5Rnsi2RjzIto+3gQ+HOCJmg2qKAKxLk07eFBL/cwvDg2inXomr4HZvWCKRXGRM9A/sIjFAUsJLB0N29m5fy+IAgt6729njx8qwtvP8wHwvouXHNqhhDvlsiIGd7/RQQo+a77bwVPT1pq/xiztCSQNPFtTU5Reudzs3rONVHMPu9NFvkUs+uFJV2obb81pptVardwU5grwJIgkHpMtf1WKVEsruGD4XUHZaSQIp0oT5SQMVRPGWArswuOwomrnqBXnPvat8+hooV92xXPg/y+kQ8kACdolTqnpxY9xrL1lGvRl7QOWaOUaqT0++WPUIbSC2lA7DYM yFxWcRP6 4km8+jY9OrH7ORXhWNSJoRHdTdTrzJTctZIZ6BDFlzGpnsqc6kIQn82RDlOQoISFZ0931q1vHsSQ28d9Orddev04/eH/C8S0G5T8rUvPeYTg31AVq8Kq2W6yUr1i51eghOcPMov78oljZprJcdqKgcvZDYJ85EzlR8tUb X-Bogosity: Ham, tests=bogofilter, spamicity=0.000000, version=1.2.4 Sender: owner-linux-mm@kvack.org Precedence: bulk X-Loop: owner-majordomo@kvack.org List-ID: List-Subscribe: List-Unsubscribe: From: Hao Ge Some users always say that the information provided by /proc/allocinfo is too extensive or bulky. However, from allocinfo's own perspective, it is not at fault as it needs to provide comprehensive information. Users can then select the information that is useful to them based on their own needs. For commonly used scenarios, we can develop a tool to facilitate users in filtering and utilizing relevant information from allocinfo. Currently, there is only one filtering feature available, which is to filter out entries where the 'bytes' field is 0 (since it is often used to understand the current memory allocation status, as previously mentioned by David Wang, who noticed that 2/3 of the lines have an accumulative counter of 0, indicating no memory activities,it will fill up the entire screen,by using the "-s" parameter, a lot of unnecessary information for this scenario can be filtered out.) In subsequent phases, we will continue to add more features to this tool, with the goal of making it convenient for most people to use the memory allocation profiling tool. Signed-off-by: Hao Ge --- MAINTAINERS | 1 + tools/mm/Makefile | 4 +- tools/mm/allocinfo_tool.c | 150 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 153 insertions(+), 2 deletions(-) create mode 100644 tools/mm/allocinfo_tool.c diff --git a/MAINTAINERS b/MAINTAINERS index 910305c11e8a..cfc3f9f0c046 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -15000,6 +15000,7 @@ F: Documentation/mm/allocation-profiling.rst F: include/linux/alloc_tag.h F: include/linux/pgalloc_tag.h F: lib/alloc_tag.c +F: tools/mm/allocinfo_tool.c MEMORY CONTROLLER DRIVERS M: Krzysztof Kozlowski diff --git a/tools/mm/Makefile b/tools/mm/Makefile index f5725b5c23aa..f669d534a82b 100644 --- a/tools/mm/Makefile +++ b/tools/mm/Makefile @@ -3,7 +3,7 @@ # include ../scripts/Makefile.include -BUILD_TARGETS=page-types slabinfo page_owner_sort thp_swap_allocator_test +BUILD_TARGETS=page-types slabinfo page_owner_sort thp_swap_allocator_test allocinfo_tool INSTALL_TARGETS = $(BUILD_TARGETS) thpmaps LIB_DIR = ../lib/api @@ -23,7 +23,7 @@ $(LIBS): $(CC) $(CFLAGS) -o $@ $< $(LDFLAGS) clean: - $(RM) page-types slabinfo page_owner_sort thp_swap_allocator_test + $(RM) page-types slabinfo page_owner_sort thp_swap_allocator_test allocinfo_tool make -C $(LIB_DIR) clean sbindir ?= /usr/sbin diff --git a/tools/mm/allocinfo_tool.c b/tools/mm/allocinfo_tool.c new file mode 100644 index 000000000000..817f46d07a50 --- /dev/null +++ b/tools/mm/allocinfo_tool.c @@ -0,0 +1,150 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * allocinfo_tool: Tool to parse allocinfo + * + * Authors: Hao Ge + * + * Compile with: + * gcc -o allocinfo_tool allocinfo_tool.c + */ + +#include +#include +#include +#include +#include + +#define ALLOCINFO_FILE "/proc/allocinfo" +#define BUF_SIZE 1024 +#define NAME_MAX_LENTH 64 + +struct alloc_tag_counters { + signed long long bytes; + unsigned long long calls; +}; + +struct codetag { + unsigned int lineno; + char modname[NAME_MAX_LENTH]; + char function[NAME_MAX_LENTH]; + char filename[NAME_MAX_LENTH]; +}; + +struct alloc_info { + struct alloc_tag_counters counters; + struct codetag tag; + int has_modname; +}; + +static int arg_opt; + +enum OPT_BIT { + SKIP_ZERO = 1 << 0, +}; + +void usage(void) +{ + printf("Usage: ./allocinfo_tool [OPTIONS]\n" + "-s\t\t\tskip bytes for 0 allocinfo entries\n" + ); +} + +int parse_alloc_info(char *line, struct alloc_info *info) +{ + if (sscanf(line, "%12lli %8llu %[^:]:%d [%[^]]] func:%s", + &info->counters.bytes, &info->counters.calls, + info->tag.filename, &info->tag.lineno, + info->tag.modname, info->tag.function) == 6){ + info->has_modname = 1; + return 1; + }; + + if (sscanf(line, "%12llu %8llu %[^:]:%u func:%s", + &info->counters.bytes, &info->counters.calls, + info->tag.filename, &info->tag.lineno, + info->tag.function) == 5){ + info->has_modname = 0; + return 1; + } + + return 0; +} + +int read_alloc_info(void) +{ + FILE *file = fopen(ALLOCINFO_FILE, "r"); + + if (!file) { + perror("Failed to open /proc/allocinfo"); + return EXIT_FAILURE; + } + + int line = 0, i = 0; + char *buffer = malloc(BUF_SIZE); + struct alloc_info *info; + + while (fgets(buffer, BUF_SIZE, file)) { + + /* + * allocinfo - version: 1.0 + * # + */ + if (line < 2) { + printf("%s", buffer); + line++; + continue; + } + + info = realloc(info, sizeof(struct alloc_info) * (i + 1)); + + if (parse_alloc_info(buffer, info + i) == 0) { + printf("Mismatch with the format of /proc/allocinfo"); + return 0; + } + + if ((arg_opt & SKIP_ZERO) && (info[i].counters.bytes == 0)) + continue; + + printf("%12lli %8llu ", info[i].counters.bytes, info[i].counters.calls); + + if (info[i].has_modname) + printf("%s:%u [%s] func:%s", + info[i].tag.filename, info[i].tag.lineno, + info[i].tag.modname, info[i].tag.function); + else + printf("%s:%u func:%s", + info[i].tag.filename, info[i].tag.lineno, + info[i].tag.function); + printf(" "); + printf("\n"); + i++; + } + + free(info); + free(buffer); + fclose(file); +} + +int main(int argc, char *argv[]) +{ + + int opt; + struct option longopts[] = { + { "s", 0, NULL, 1}, + { 0, 0, 0, 0}, + }; + + while ((opt = getopt_long(argc, argv, "s", longopts, NULL)) != -1) { + switch (opt) { + case 's': + arg_opt = arg_opt | SKIP_ZERO; + break; + default: + usage(); + exit(1); + } + } + + read_alloc_info(); + +}