From nobody Sat Feb 7 08:28:32 2026 Received: from mail-ot1-f52.google.com (mail-ot1-f52.google.com [209.85.210.52]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 42E081C84BB for ; Mon, 2 Feb 2026 00:55:36 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.210.52 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1769993739; cv=none; b=UrjgqF2qheOGzQIA1Kux/ZmuIcSLV7gecLgMJ4hCtxwh701y85kckFzJXOpdsTQ09ljLn3jjCq3zjw5MrLcfvzBgWBIV9eLT6ZxEnZkpwlGyhs0hoT+SmG4nG/33VOEa/64UBqRubtsFFDCij9yevANDmntj1S4hpnxIvnazTzw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1769993739; c=relaxed/simple; bh=NlKcc2bK7s93mx20kEsBBPa+qxif8S6miT5xOZ3eqA4=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=eEpE0Ou6lO8sHYPOh/6n2EIs0yy1cvc1/dE4EOCfxpWPT/7c2umZmpM2+qKveaNm7U815ceLhudFfTnzkyGmd9xlO6VxPumNV3vOUbQdoqA735SAI4d0YQ+R/SyFAoqfuMp42sKzpj+fAyddGoHwjUBfXxE2iE7fhUEK5BgXAR0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=Htv9LLOA; arc=none smtp.client-ip=209.85.210.52 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="Htv9LLOA" Received: by mail-ot1-f52.google.com with SMTP id 46e09a7af769-7d18d0e6d71so2399031a34.1 for ; Sun, 01 Feb 2026 16:55:36 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1769993735; x=1770598535; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=4Sqbiib7KB6vkBOddWWUPu9R4jigpGCUz2K/91JUCWs=; b=Htv9LLOA9e8gLHKTs/X/WAUlzz1u/H8w5ZnxUyqCIhhklKAnd4ci0MxH//u9jlFdZh oPvQ94NwitHnhKacRd/qRUEX1yzPFjlIIKgCZXGGxpxnD2c2CNgH0lq+BjQ/UtKkVt// esmxRAOCpQtPjT6lQPc3gMh36ad3hTNmPNG5HIYAFFb1YP8Rqq6W+/AqWQW/aN6WeViW EFco/jn78J+cFJxTm6hgHfef7tGOPp938saxA0qzz9ZGNHjYjr9eIUE6e37B0nVTiJv+ etjEotoOqwjKtDEU6UrJvOYnOhJo15iFPMp0GLteV7jv8+p1PYDYYfibrj9KE55OIEH+ KERA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1769993735; x=1770598535; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=4Sqbiib7KB6vkBOddWWUPu9R4jigpGCUz2K/91JUCWs=; b=VPbi28wN4xuRs0OKh9Nw+gR64Vpv3BUCGl5RytcUnp6c/MLj4US/4WWcpyUYNH51KU p85KTGYuXrfnZMDXmMa1jkpBZp90whjPiaKcri3Dc5y9xkLzcr2yRFPAGextHDQundFD u6pur3uzhNSSslZhndUUbqLUBnKShVdeF2AvalBhnkVS7gOtB5BWukCtHLL4f1msvaVp mhy/iKkB3cTuwBxjrhA7eWKRkixpjwebnvJvSR55wK6vObvMhAuEydyT79B4vlsxdZpR TLSHuMvpeK/ziKhpmoBQ+0T6d1Tx4zZ5zIZyHA58R8zk+b46jkOHpzRrN5JmKtYanVyt evMA== X-Forwarded-Encrypted: i=1; AJvYcCXXdvAKSedw6WBAQ6WbFzmIldQ/xR8VtN6i2iiurZoDybSe2H+H8h4EODhFcq5hC/YMqBsBw8LmfZEEgwU=@vger.kernel.org X-Gm-Message-State: AOJu0YwrQUZdgiT13cUX1Xk774cflCl0/N/z0HqHUQl1VsJNJJN7xHk7 Stj+fZ5kNYFJHaDeBz5nhghdANF/4y/yPvBmdRZWF2qFu0HYEA3hQX1K X-Gm-Gg: AZuq6aJCn0lac8KF2AvVorU5xF7KEMjM90G1NJ0uMRI0kKYSsGACQy6cSogABdR9eGd +4xkTionBpCop16Qjwucwl9WYQ/mt9gQDYhOSJSMqolzuiOMj4YYvR2ib5Q7yDtO1nnz9SIUfqb u51z7I9K2ky6VNk4584fTaTZhVmU7s8WQPrx7wxP/Ihq9y0OBVIPf8Kpp3Ijml0/wg6BHtT8EW5 SjFxic/rPXw9+DOsRxpjVQRAkpmBmuWjYLcv6z6yyVUhm4TTWwJbrmC4q1hePGbattqq1SyQSU6 u8cgWMWHFLJYTe23Oiz1lM74xrBtIjCgZpXp6VoyCodK4RUxVTia8Yn47/tcaAKpKi9C9hlaw+t qBrzJgU2BS2MuxTY70CIwndEx4u4F/7ESMPO+1vm6FUIBvda7IckB1gQMROzakrE6nkV3Mte4fa INFvMsp8w= X-Received: by 2002:a05:6820:2213:b0:661:167b:72db with SMTP id 006d021491bc7-6630f35f037mr4965770eaf.38.1769993735072; Sun, 01 Feb 2026 16:55:35 -0800 (PST) Received: from localhost ([2a03:2880:10ff:2::]) by smtp.gmail.com with ESMTPSA id 586e51a60fabf-4095753b347sm9566016fac.17.2026.02.01.16.55.33 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 01 Feb 2026 16:55:34 -0800 (PST) From: Usama Arif To: ziy@nvidia.com, Andrew Morton , David Hildenbrand , lorenzo.stoakes@oracle.com, linux-mm@kvack.org Cc: hannes@cmpxchg.org, riel@surriel.com, shakeel.butt@linux.dev, kas@kernel.org, baohua@kernel.org, dev.jain@arm.com, baolin.wang@linux.alibaba.com, npache@redhat.com, Liam.Howlett@oracle.com, ryan.roberts@arm.com, vbabka@suse.cz, lance.yang@linux.dev, linux-kernel@vger.kernel.org, kernel-team@meta.com, Usama Arif Subject: [RFC 06/12] selftests/mm: add PUD THP basic allocation test Date: Sun, 1 Feb 2026 16:50:23 -0800 Message-ID: <20260202005451.774496-7-usamaarif642@gmail.com> X-Mailer: git-send-email 2.47.3 In-Reply-To: <20260202005451.774496-1-usamaarif642@gmail.com> References: <20260202005451.774496-1-usamaarif642@gmail.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Add a selftest for PUD-level THPs (1GB THPs) with test infrastructure and a basic allocation test. The test uses the kselftest harness FIXTURE/TEST_F framework. A shared fixture allocates a 2GB anonymous mapping and computes a PUD-aligned address within it. Helper functions read THP counters from /proc/vmstat and mTHP statistics from sysfs. The basic allocation test verifies the fundamental PUD THP allocation path by touching a PUD-aligned region and checking that the mTHP anon_fault_alloc counter increments, confirming a 1GB folio was allocated. Signed-off-by: Usama Arif --- tools/testing/selftests/mm/Makefile | 1 + tools/testing/selftests/mm/pud_thp_test.c | 161 ++++++++++++++++++++++ 2 files changed, 162 insertions(+) create mode 100644 tools/testing/selftests/mm/pud_thp_test.c diff --git a/tools/testing/selftests/mm/Makefile b/tools/testing/selftests/= mm/Makefile index eaf9312097f7b..ab79f1693941a 100644 --- a/tools/testing/selftests/mm/Makefile +++ b/tools/testing/selftests/mm/Makefile @@ -88,6 +88,7 @@ TEST_GEN_FILES +=3D pagemap_ioctl TEST_GEN_FILES +=3D pfnmap TEST_GEN_FILES +=3D process_madv TEST_GEN_FILES +=3D prctl_thp_disable +TEST_GEN_FILES +=3D pud_thp_test TEST_GEN_FILES +=3D thuge-gen TEST_GEN_FILES +=3D transhuge-stress TEST_GEN_FILES +=3D uffd-stress diff --git a/tools/testing/selftests/mm/pud_thp_test.c b/tools/testing/self= tests/mm/pud_thp_test.c new file mode 100644 index 0000000000000..6f0c02c6afd3a --- /dev/null +++ b/tools/testing/selftests/mm/pud_thp_test.c @@ -0,0 +1,161 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Test program for PUD-level Transparent Huge Pages (1GB anonymous THP) + * + * Prerequisites: + * - Kernel with PUD THP support (CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE_PU= D) + * - THP enabled: echo always > /sys/kernel/mm/transparent_hugepage/enabled + * - PUD THP enabled: echo always > /sys/kernel/mm/transparent_hugepage/hu= gepages-1048576kB/enabled + */ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "kselftest_harness.h" + +#define PUD_SIZE (1UL << 30) /* 1GB */ +#define PMD_SIZE (1UL << 21) /* 2MB */ +#define PAGE_SIZE (1UL << 12) /* 4KB */ + +#define TEST_REGION_SIZE (2 * PUD_SIZE) /* 2GB to ensure PUD alignment */ + +/* Get PUD-aligned address within a region */ +static inline void *pud_align(void *addr) +{ + return (void *)(((unsigned long)addr + PUD_SIZE - 1) & ~(PUD_SIZE - 1)); +} + +/* Read vmstat counter */ +static unsigned long read_vmstat(const char *name) +{ + FILE *fp; + char line[256]; + unsigned long value =3D 0; + + fp =3D fopen("/proc/vmstat", "r"); + if (!fp) + return 0; + + while (fgets(line, sizeof(line), fp)) { + if (strncmp(line, name, strlen(name)) =3D=3D 0 && + line[strlen(name)] =3D=3D ' ') { + sscanf(line + strlen(name), " %lu", &value); + break; + } + } + fclose(fp); + return value; +} + +/* Read mTHP stats for PUD order (1GB =3D 1048576kB) */ +static unsigned long read_mthp_stat(const char *stat_name) +{ + char path[256]; + char buf[64]; + int fd; + ssize_t ret; + unsigned long value =3D 0; + + snprintf(path, sizeof(path), + "/sys/kernel/mm/transparent_hugepage/hugepages-1048576kB/stats/%s", + stat_name); + fd =3D open(path, O_RDONLY); + if (fd < 0) + return 0; + ret =3D read(fd, buf, sizeof(buf) - 1); + close(fd); + if (ret <=3D 0) + return 0; + buf[ret] =3D '\0'; + sscanf(buf, "%lu", &value); + return value; +} + +/* Check if PUD THP is enabled */ +static int pud_thp_enabled(void) +{ + char buf[64]; + int fd; + ssize_t ret; + + fd =3D open("/sys/kernel/mm/transparent_hugepage/hugepages-1048576kB/enab= led", O_RDONLY); + if (fd < 0) + return 0; + ret =3D read(fd, buf, sizeof(buf) - 1); + close(fd); + if (ret <=3D 0) + return 0; + buf[ret] =3D '\0'; + + /* Check if [always] or [madvise] is set */ + if (strstr(buf, "[always]") || strstr(buf, "[madvise]")) + return 1; + return 0; +} + +/* + * Main fixture for PUD THP tests + * Allocates a 2GB region and provides a PUD-aligned pointer within it + */ +FIXTURE(pud_thp) +{ + void *mem; /* Base mmap allocation */ + void *aligned; /* PUD-aligned pointer within mem */ + unsigned long mthp_alloc_before; + unsigned long split_before; +}; + +FIXTURE_SETUP(pud_thp) +{ + if (!pud_thp_enabled()) + SKIP(return, "PUD THP not enabled in sysfs"); + + self->mthp_alloc_before =3D read_mthp_stat("anon_fault_alloc"); + self->split_before =3D read_vmstat("thp_split_pud"); + + self->mem =3D mmap(NULL, TEST_REGION_SIZE, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + ASSERT_NE(self->mem, MAP_FAILED); + + self->aligned =3D pud_align(self->mem); +} + +FIXTURE_TEARDOWN(pud_thp) +{ + if (self->mem && self->mem !=3D MAP_FAILED) + munmap(self->mem, TEST_REGION_SIZE); +} + +/* + * Test: Basic PUD THP allocation + * Verifies that touching a PUD-aligned region allocates a PUD THP + */ +TEST_F(pud_thp, basic_allocation) +{ + unsigned long mthp_alloc_after; + + /* Touch memory to trigger page fault and PUD THP allocation */ + memset(self->aligned, 0xAB, PUD_SIZE); + + mthp_alloc_after =3D read_mthp_stat("anon_fault_alloc"); + + /* + * If mTHP allocation counter increased, a PUD THP was allocated. + */ + if (mthp_alloc_after <=3D self->mthp_alloc_before) + SKIP(return, "PUD THP not allocated"); + + TH_LOG("PUD THP allocated (anon_fault_alloc: %lu -> %lu)", + self->mthp_alloc_before, mthp_alloc_after); +} + +TEST_HARNESS_MAIN --=20 2.47.3