From patchwork Thu Feb 8 15:53:28 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Steven Rostedt X-Patchwork-Id: 198453 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a05:7300:50ea:b0:106:860b:bbdd with SMTP id r10csp262325dyd; Thu, 8 Feb 2024 07:53:50 -0800 (PST) X-Forwarded-Encrypted: i=3; AJvYcCV3Zw3eVadr+f++X4dh7zSPlMe6m4HCpy3rzkwx7dynkOB9LeQw+4B2Dadw/koDe6ehIkd3/GWroPLOhfUEBUe8FkB1Uw== X-Google-Smtp-Source: AGHT+IE1Uy1a4j4fnd71yQALs+5KdxHhuBQtfEuCHqO1hB0cgtQs0Nw6WkndnglTOVg9eiRAs0AW X-Received: by 2002:a05:6808:14c2:b0:3bf:3856:2ca9 with SMTP id f2-20020a05680814c200b003bf38562ca9mr11355208oiw.1.1707407630628; Thu, 08 Feb 2024 07:53:50 -0800 (PST) ARC-Seal: i=2; a=rsa-sha256; t=1707407630; cv=pass; d=google.com; s=arc-20160816; b=jS9V943WE1BLxuD/s0AFB5bqkeHunSKDwLehbz4ZXUUjXxatw5oZMQ5wmDxNmI4SsW YVVeUFbo10h17rcEunj8ScuLpq0b6MwPKGtp2bkEGKBKkN0en2/+Q3N1OXCuwWVGDyuB swvoRXF/rhXB/XlT/gcgCIm5751SXWd9UEPcE8gD2I11PyEryCKEjjGVikIrN1lPqBsW 2QKEfLzOF8jz6uTuJjvfwSo3Sp77/sOTbNl/HZl8tqfSADVuXwUuRtYz0iX0NCBCkOal nvLYpau6mY66dzVynrvX5+K7DCwRnTXPy141/7HG6p5S9UN/lNRe+mEjrmtO8xyLUpBs +1NQ== ARC-Message-Signature: i=2; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=content-transfer-encoding:mime-version:list-unsubscribe :list-subscribe:list-id:precedence:message-id:subject:cc:to:from :date; bh=uYF31wg0/I5hMTC2Yns8u+S6ZFM74DPvZYc8Ka7geTE=; fh=iQGvIEnaSH0Eq80Er0N5tYzAJUrGN5Wr8gOiBta2zl8=; b=P7vIAGTy2CN6/4Z32zJS86L2Gi8fFYaeCPIdJxDfT9JxNChR2s76v0cTBZ8WeFEqva rJAv1JzyaYsLBLgxumfkOUtD4z2UiK7b6d2ULzHfpyqT97J5scKlGdoNSBfDyhoETp3J 935ZBmpoQpGjhBR+sF3XpR22Y6UkpCpCnhjPvAjHEAir/p44gM+oiW0ZxdBHXuTDFkix GyxC4+85Jfpg6P2RaiptoXXbSD60OJRDSMMrND61lZ8XoVZg087gMRhLRfOp14WUQmZk sEjru7v+6Z3tuTQtta4kTSvtuj425x0fYBxyPIa6gXx9XBHFLSrBeodJxro8r9Tpwicj Vdhw==; dara=google.com ARC-Authentication-Results: i=2; mx.google.com; arc=pass (i=1); spf=pass (google.com: domain of linux-kernel+bounces-58311-ouuuleilei=gmail.com@vger.kernel.org designates 147.75.199.223 as permitted sender) smtp.mailfrom="linux-kernel+bounces-58311-ouuuleilei=gmail.com@vger.kernel.org" X-Forwarded-Encrypted: i=2; AJvYcCVOugYL8H+5QDQa3XmgEUBX+0OPk6Gzd5emaczssomzQpYQvsQ//0di6IwlaSlxavfccooXPWrSVZMsaLQxhgaIwVOj3Q== Received: from ny.mirrors.kernel.org (ny.mirrors.kernel.org. [147.75.199.223]) by mx.google.com with ESMTPS id u21-20020a05622a011500b0042bf2cb2cffsi249605qtw.468.2024.02.08.07.53.50 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 08 Feb 2024 07:53:50 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel+bounces-58311-ouuuleilei=gmail.com@vger.kernel.org designates 147.75.199.223 as permitted sender) client-ip=147.75.199.223; Authentication-Results: mx.google.com; arc=pass (i=1); spf=pass (google.com: domain of linux-kernel+bounces-58311-ouuuleilei=gmail.com@vger.kernel.org designates 147.75.199.223 as permitted sender) smtp.mailfrom="linux-kernel+bounces-58311-ouuuleilei=gmail.com@vger.kernel.org" Received: from smtp.subspace.kernel.org (wormhole.subspace.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ny.mirrors.kernel.org (Postfix) with ESMTPS id 5FA201C21395 for ; Thu, 8 Feb 2024 15:53:50 +0000 (UTC) Received: from localhost.localdomain (localhost.localdomain [127.0.0.1]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 618CD7D3F9; Thu, 8 Feb 2024 15:53:37 +0000 (UTC) Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id A2D0F7B3FF; Thu, 8 Feb 2024 15:53:35 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1707407615; cv=none; b=moCGLEsh45TwQBk6rHvC+PfmIXqAHUss0U0sK+A5IpR8ms8Wn/xiX9vQEeXJd9YM/6e0mOBav63Cbf4sVVC9etazvL9UnrH8GNisrCwzpYsHiluCMz2zBqfzTXWYaWa3bVVPKdZx9Ce9Nwcpuial7oPPjiV8WOnlTHBURjISiV4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1707407615; c=relaxed/simple; bh=riINGfnd79EnQpYg7CsqL7ovhf6cZK3lm1VIv8aEOk4=; h=Date:From:To:Cc:Subject:Message-ID:MIME-Version:Content-Type; b=fd5ncBapaIt/snW3YlN4837xim0L9AG/36UVprbkRXz4ZBUw2JR9+n3jZQvhVb5Io3gKighIKejLb8wqhhWO5G2EWWJlQUurw/S5M5P5Gq5GHMtkpBazr9OEGNbDttBV/Kk5Ldkwl85ZeiyzLxQsjLebZ6XAiMwYTRrf6SPCLYg= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 Received: by smtp.kernel.org (Postfix) with ESMTPSA id 95C57C433F1; Thu, 8 Feb 2024 15:53:32 +0000 (UTC) Date: Thu, 8 Feb 2024 10:53:28 -0500 From: Steven Rostedt To: LKML , Linux trace kernel Cc: Masami Hiramatsu , Mathieu Desnoyers , Vincent Donnefort , Sven Schnelle , Mete Durlu , stable Subject: [PATCH] tracing: Fix wasted memory in saved_cmdlines logic Message-ID: <20240208105328.7e73f71d@rorschach.local.home> X-Mailer: Claws Mail 3.17.8 (GTK+ 2.24.33; x86_64-pc-linux-gnu) Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-getmail-retrieved-from-mailbox: INBOX X-GMAIL-THRID: 1790346663638149920 X-GMAIL-MSGID: 1790346663638149920 From: "Steven Rostedt (Google)" While looking at improving the saved_cmdlines cache I found a huge amount of wasted memory that should be used for the cmdlines. The tracing data saves pids during the trace. At sched switch, if a trace occurred, it will save the comm of the task that did the trace. This is saved in a "cache" that maps pids to comms and exposed to user space via the /sys/kernel/tracing/saved_cmdlines file. Currently it only caches by default 128 comms. The structure that uses this creates an array to store the pids using PID_MAX_DEFAULT (which is usually set to 32768). This causes the structure to be of the size of 131104 bytes on 64 bit machines. In hex: 131104 = 0x20020, and since the kernel allocates generic memory in powers of two, the kernel would allocate 0x40000 or 262144 bytes to store this structure. That leaves 131040 bytes of wasted space. Worse, the structure points to an allocated array to store the comm names, which is 16 bytes times the amount of names to save (currently 128), which is 2048 bytes. Instead of allocating a separate array, make the structure end with a variable length string and use the extra space for that. This is similar to a recommendation that Linus had made about eventfs_inode names: https://lore.kernel.org/all/20240130190355.11486-5-torvalds@linux-foundation.org/ Instead of allocating a separate string array to hold the saved comms, have the structure end with: char saved_cmdlines[]; and round up to the next power of two over sizeof(struct saved_cmdline_buffers) + num_cmdlines * TASK_COMM_LEN It will use this extra space for the saved_cmdline portion. Now, instead of saving only 128 comms by default, by using this wasted space at the end of the structure it can save over 8000 comms and even saves space by removing the need for allocating the other array. Cc: stable@vger.kernel.org Fixes: 939c7a4f04fcd ("tracing: Introduce saved_cmdlines_size file") Signed-off-by: Steven Rostedt (Google) Reviewed-by: Tim Chen --- kernel/trace/trace.c | 73 +++++++++++++++++++++----------------------- 1 file changed, 34 insertions(+), 39 deletions(-) diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index 2a7c6fd934e9..0b3e60b827f7 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c @@ -2320,7 +2320,7 @@ struct saved_cmdlines_buffer { unsigned *map_cmdline_to_pid; unsigned cmdline_num; int cmdline_idx; - char *saved_cmdlines; + char saved_cmdlines[]; }; static struct saved_cmdlines_buffer *savedcmd; @@ -2334,47 +2334,54 @@ static inline void set_cmdline(int idx, const char *cmdline) strncpy(get_saved_cmdlines(idx), cmdline, TASK_COMM_LEN); } -static int allocate_cmdlines_buffer(unsigned int val, - struct saved_cmdlines_buffer *s) +static void free_saved_cmdlines_buffer(struct saved_cmdlines_buffer *s) +{ + int order = get_order(sizeof(*s) + s->cmdline_num * TASK_COMM_LEN); + + kfree(s->map_cmdline_to_pid); + free_pages((unsigned long)s, order); +} + +static struct saved_cmdlines_buffer *allocate_cmdlines_buffer(unsigned int val) { + struct saved_cmdlines_buffer *s; + struct page *page; + int orig_size, size; + int order; + + /* Figure out how much is needed to hold the given number of cmdlines */ + orig_size = sizeof(*s) + val * TASK_COMM_LEN; + order = get_order(orig_size); + size = 1 << (order + PAGE_SHIFT); + page = alloc_pages(GFP_KERNEL, order); + if (!page) + return NULL; + + s = page_address(page); + memset(s, 0, sizeof(*s)); + + /* Round up to actual allocation */ + val = (size - sizeof(*s)) / TASK_COMM_LEN; + s->cmdline_num = val; + s->map_cmdline_to_pid = kmalloc_array(val, sizeof(*s->map_cmdline_to_pid), GFP_KERNEL); - if (!s->map_cmdline_to_pid) - return -ENOMEM; - - s->saved_cmdlines = kmalloc_array(TASK_COMM_LEN, val, GFP_KERNEL); - if (!s->saved_cmdlines) { - kfree(s->map_cmdline_to_pid); - return -ENOMEM; - } s->cmdline_idx = 0; - s->cmdline_num = val; memset(&s->map_pid_to_cmdline, NO_CMDLINE_MAP, sizeof(s->map_pid_to_cmdline)); memset(s->map_cmdline_to_pid, NO_CMDLINE_MAP, val * sizeof(*s->map_cmdline_to_pid)); - return 0; + return s; } static int trace_create_savedcmd(void) { - int ret; - - savedcmd = kmalloc(sizeof(*savedcmd), GFP_KERNEL); - if (!savedcmd) - return -ENOMEM; - - ret = allocate_cmdlines_buffer(SAVED_CMDLINES_DEFAULT, savedcmd); - if (ret < 0) { - kfree(savedcmd); - savedcmd = NULL; - return -ENOMEM; - } + savedcmd = allocate_cmdlines_buffer(SAVED_CMDLINES_DEFAULT); - return 0; + return savedcmd ? 0 : -ENOMEM; } int is_tracing_stopped(void) @@ -6056,26 +6063,14 @@ tracing_saved_cmdlines_size_read(struct file *filp, char __user *ubuf, return simple_read_from_buffer(ubuf, cnt, ppos, buf, r); } -static void free_saved_cmdlines_buffer(struct saved_cmdlines_buffer *s) -{ - kfree(s->saved_cmdlines); - kfree(s->map_cmdline_to_pid); - kfree(s); -} - static int tracing_resize_saved_cmdlines(unsigned int val) { struct saved_cmdlines_buffer *s, *savedcmd_temp; - s = kmalloc(sizeof(*s), GFP_KERNEL); + s = allocate_cmdlines_buffer(val); if (!s) return -ENOMEM; - if (allocate_cmdlines_buffer(val, s) < 0) { - kfree(s); - return -ENOMEM; - } - preempt_disable(); arch_spin_lock(&trace_cmdline_lock); savedcmd_temp = savedcmd;