Received: by 2002:a05:6358:9144:b0:117:f937:c515 with SMTP id r4csp191364rwr; Tue, 2 May 2023 18:40:29 -0700 (PDT) X-Google-Smtp-Source: ACHHUZ7bSypIR4kTRCYVCQVwHIlHKUXjXLRtgXHmArPX1mMk5RNHWx2cgKbccub2trkz1LMo9BJv X-Received: by 2002:a05:6a00:1a50:b0:634:7ba3:d140 with SMTP id h16-20020a056a001a5000b006347ba3d140mr26744189pfv.15.1683078028856; Tue, 02 May 2023 18:40:28 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1683078028; cv=none; d=google.com; s=arc-20160816; b=QwjAYlNqUD1zuCyW+lN5LBmIDIoNf2KMYS8yNEOYviAPRJOmYpMpbXf03MOB/KByAF IDya0u8q/mBXz61Pu+nOVR7XrfgBpooj74SSYB9N4QymDtNVGE9DIVB848bV+7IVzVzu NzaKn+eF2uAHXD0WYACs4DafW+cAWbIZ4B9B5EvnAjKSJAG3tENj3aCI/nZdaSi8rwat YwgRDxyFw+z01TXChVzcLZ5CsZ3DWt/MJYtTYl69KugbXKqfS4JugehTtWRbu1280pm5 otKSaVxtZeoFv8unaTFo/f73mE98lFlWXoopKWX8HGj1dL8ohFPZCKBt0UrHtn+DVhQ+ fmDA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from :dkim-signature; bh=smcp8zMjIvenU/5ttiTpkkwH8ja2gF/kjyxXZVmyP2o=; b=uOHp1W6egWYajmSBonnfs6uUm9bZiEnvspmtaGjsnodQebTllJUNl3zBXk+u/tcC3m IyTu+cAySYU1/BDh4KVp33EMlC1Z76v5+R2KWFwmo3QUWur7akVswfOSetwZPJtKaEXj YRKUtr7exGpcgaFQ0jwQ9sTWC+1SA1otDKkpI4zjI3r7y52Lt4ZCTXNUak6ru8qvTzKS K8NBv6tNUi8CJqPCnOoGzAvsF5yufzUP77V9r8Lz69HUe7UKbaufsWUxdF0qS/20U7Mr tF3Z7E51iadOjBL6wJ+xAX72il7RWiGBd3nwMLGbxMNkiIN/WXjjHmxO0lb64rp34r0v y9+Q== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@gmail.com header.s=20221208 header.b=OjfScoX4; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Return-Path: Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id y9-20020aa79ae9000000b0063d6362a486si29888402pfp.106.2023.05.02.18.39.51; Tue, 02 May 2023 18:40:28 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@gmail.com header.s=20221208 header.b=OjfScoX4; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229631AbjECBgX (ORCPT + 99 others); Tue, 2 May 2023 21:36:23 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:33842 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229458AbjECBgP (ORCPT ); Tue, 2 May 2023 21:36:15 -0400 Received: from mail-pg1-x52d.google.com (mail-pg1-x52d.google.com [IPv6:2607:f8b0:4864:20::52d]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 797FF273A; Tue, 2 May 2023 18:36:13 -0700 (PDT) Received: by mail-pg1-x52d.google.com with SMTP id 41be03b00d2f7-52c3ffc8d13so1709402a12.2; Tue, 02 May 2023 18:36:13 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20221208; t=1683077772; x=1685669772; 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=smcp8zMjIvenU/5ttiTpkkwH8ja2gF/kjyxXZVmyP2o=; b=OjfScoX4IsdshgVkTAAiqStkhaB2dp21ScM4MVEUB5zwEv4pSpSusB6ivbbOac6+Tr 5xbiwomvIJyRKtVNPKwkqT2ORZGpPdoitC0bxtNvglisHxHr1sWP1Y2aFQhF0bRxNEdi 9ud+8QrdtXdhYdqPlsZ52O3MDPe6lOFA34bgjgBlhb8/31xaNbOt8Km/w9QmmDi1Yk/D HZyMSkmx2y183cohr4Bc6Vs9wZyVbQHOlIghjn/bD/iL4XmtCb3BEpGaJs96QV98MAVC /CaJWbvbXETp6+5AAWXpXiz8yti04DeRzMAlvbCdPOuH+K6LYYEzvFBU+mL48cK81qlH ihsw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1683077772; x=1685669772; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=smcp8zMjIvenU/5ttiTpkkwH8ja2gF/kjyxXZVmyP2o=; b=i6mes8dl0whRCVtsjAHD2Y+LpIHeh6SUMXFJkla8SmOTJ6IJ6lMIrWKAOSpiy/5LIN vCxVIiey3bAP6mqOt2MBH2y2y9wmzKkkyMpB1trAKvm+MIS7Q/ieR7mgqP3HwC1ZGtuM 8GQhjFosC+CzsMcJvWZ+BBrod2hXFP/GxicOmCPi07j+t8CIVAwG96f6rUfwtem8MxwY qfJ++JX84jN+0+h4obSEznWrM8tBBY45bH66CrrurNV+ZbNwCS6axwqDl21cSZy8Ifse PT27xRK4QXoGeVOy1RBGMQCRZvLEp5ggY4IlmlytIsFEdsxFwyewrIM+N2ogvOKIHulC UISw== X-Gm-Message-State: AC+VfDzKPNaBlIiRRM9TXKHvpys8vNphDlaOqQTvsWSqj0GBNjR91b1M ZTifCu25P1QhdCwnTqJPD5HvbiIgNVk= X-Received: by 2002:a17:90a:9204:b0:247:90d8:41fd with SMTP id m4-20020a17090a920400b0024790d841fdmr21084489pjo.26.1683077772331; Tue, 02 May 2023 18:36:12 -0700 (PDT) Received: from localhost (fwdproxy-prn-013.fbsv.net. [2a03:2880:ff:d::face:b00c]) by smtp.gmail.com with ESMTPSA id o15-20020a17090ac08f00b0024b79a69361sm134622pjs.32.2023.05.02.18.36.11 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 02 May 2023 18:36:12 -0700 (PDT) From: Nhat Pham To: akpm@linux-foundation.org Cc: hannes@cmpxchg.org, linux-mm@kvack.org, linux-kernel@vger.kernel.org, bfoster@redhat.com, willy@infradead.org, linux-api@vger.kernel.org, kernel-team@meta.com Subject: [PATCH v13 3/3] selftests: Add selftests for cachestat Date: Tue, 2 May 2023 18:36:08 -0700 Message-Id: <20230503013608.2431726-4-nphamcs@gmail.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20230503013608.2431726-1-nphamcs@gmail.com> References: <20230503013608.2431726-1-nphamcs@gmail.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Spam-Status: No, score=-2.1 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,FREEMAIL_FROM, RCVD_IN_DNSWL_NONE,SPF_HELO_NONE,SPF_PASS,T_SCC_BODY_TEXT_LINE, URIBL_BLOCKED autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Test cachestat on a newly created file, /dev/ files, and /proc/ files. Also test on a shmem file (which can also be tested with huge pages since tmpfs supports huge pages). Signed-off-by: Nhat Pham --- MAINTAINERS | 7 + tools/testing/selftests/Makefile | 1 + tools/testing/selftests/cachestat/.gitignore | 2 + tools/testing/selftests/cachestat/Makefile | 8 + .../selftests/cachestat/test_cachestat.c | 258 ++++++++++++++++++ 5 files changed, 276 insertions(+) create mode 100644 tools/testing/selftests/cachestat/.gitignore create mode 100644 tools/testing/selftests/cachestat/Makefile create mode 100644 tools/testing/selftests/cachestat/test_cachestat.c diff --git a/MAINTAINERS b/MAINTAINERS index 32772c383ab7..a02946fdd680 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -4510,6 +4510,13 @@ S: Supported F: Documentation/filesystems/caching/cachefiles.rst F: fs/cachefiles/ +CACHESTAT: PAGE CACHE STATS FOR A FILE +M: Nhat Pham +M: Johannes Weiner +L: linux-mm@kvack.org +S: Maintained +F: tools/testing/selftests/cachestat/test_cachestat.c + CADENCE MIPI-CSI2 BRIDGES M: Maxime Ripard L: linux-media@vger.kernel.org diff --git a/tools/testing/selftests/Makefile b/tools/testing/selftests/Makefile index 97dcdaa656f6..5994e56e1214 100644 --- a/tools/testing/selftests/Makefile +++ b/tools/testing/selftests/Makefile @@ -4,6 +4,7 @@ TARGETS += amd-pstate TARGETS += arm64 TARGETS += bpf TARGETS += breakpoints +TARGETS += cachestat TARGETS += capabilities TARGETS += cgroup TARGETS += clone3 diff --git a/tools/testing/selftests/cachestat/.gitignore b/tools/testing/selftests/cachestat/.gitignore new file mode 100644 index 000000000000..d6c30b43a4bb --- /dev/null +++ b/tools/testing/selftests/cachestat/.gitignore @@ -0,0 +1,2 @@ +# SPDX-License-Identifier: GPL-2.0-only +test_cachestat diff --git a/tools/testing/selftests/cachestat/Makefile b/tools/testing/selftests/cachestat/Makefile new file mode 100644 index 000000000000..fca73aaa7d14 --- /dev/null +++ b/tools/testing/selftests/cachestat/Makefile @@ -0,0 +1,8 @@ +# SPDX-License-Identifier: GPL-2.0 +TEST_GEN_PROGS := test_cachestat + +CFLAGS += $(KHDR_INCLUDES) +CFLAGS += -Wall +CFLAGS += -lrt + +include ../lib.mk diff --git a/tools/testing/selftests/cachestat/test_cachestat.c b/tools/testing/selftests/cachestat/test_cachestat.c new file mode 100644 index 000000000000..c3823b809c25 --- /dev/null +++ b/tools/testing/selftests/cachestat/test_cachestat.c @@ -0,0 +1,258 @@ +// SPDX-License-Identifier: GPL-2.0 +#define _GNU_SOURCE + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../kselftest.h" + +static const char * const dev_files[] = { + "/dev/zero", "/dev/null", "/dev/urandom", + "/proc/version", "/proc" +}; +static const int cachestat_nr = 451; + +void print_cachestat(struct cachestat *cs) +{ + ksft_print_msg( + "Using cachestat: Cached: %lu, Dirty: %lu, Writeback: %lu, Evicted: %lu, Recently Evicted: %lu\n", + cs->nr_cache, cs->nr_dirty, cs->nr_writeback, + cs->nr_evicted, cs->nr_recently_evicted); +} + +bool write_exactly(int fd, size_t filesize) +{ + char data[filesize]; + bool ret = true; + int random_fd = open("/dev/urandom", O_RDONLY); + + if (random_fd < 0) { + ksft_print_msg("Unable to access urandom.\n"); + ret = false; + goto out; + } else { + int remained = filesize; + char *cursor = data; + + while (remained) { + ssize_t read_len = read(random_fd, cursor, remained); + + if (read_len <= 0) { + ksft_print_msg("Unable to read from urandom.\n"); + ret = false; + goto close_random_fd; + } + + remained -= read_len; + cursor += read_len; + } + + /* write random data to fd */ + remained = filesize; + cursor = data; + while (remained) { + ssize_t write_len = write(fd, cursor, remained); + + if (write_len <= 0) { + ksft_print_msg("Unable write random data to file.\n"); + ret = false; + goto close_random_fd; + } + + remained -= write_len; + cursor += write_len; + } + } + +close_random_fd: + close(random_fd); +out: + return ret; +} + +/* + * Open/create the file at filename, (optionally) write random data to it + * (exactly num_pages), then test the cachestat syscall on this file. + * + * If test_fsync == true, fsync the file, then check the number of dirty + * pages. + */ +bool test_cachestat(const char *filename, bool write_random, bool create, + bool test_fsync, unsigned long num_pages, int open_flags, + mode_t open_mode) +{ + size_t PS = sysconf(_SC_PAGESIZE); + int filesize = num_pages * PS; + bool ret = true; + long syscall_ret; + struct cachestat cs; + struct cachestat_range cs_range = { 0, filesize }; + + int fd = open(filename, open_flags, open_mode); + + if (fd == -1) { + ksft_print_msg("Unable to create/open file.\n"); + ret = false; + goto out; + } else { + ksft_print_msg("Create/open %s\n", filename); + } + + if (write_random) { + if (!write_exactly(fd, filesize)) { + ksft_print_msg("Unable to access urandom.\n"); + ret = false; + goto out1; + } + } + + syscall_ret = syscall(cachestat_nr, fd, &cs_range, &cs, 0); + + ksft_print_msg("Cachestat call returned %ld\n", syscall_ret); + + if (syscall_ret) { + ksft_print_msg("Cachestat returned non-zero.\n"); + ret = false; + goto out1; + + } else { + print_cachestat(&cs); + + if (write_random) { + if (cs.nr_cache + cs.nr_evicted != num_pages) { + ksft_print_msg( + "Total number of cached and evicted pages is off.\n"); + ret = false; + } + } + } + + if (test_fsync) { + if (fsync(fd)) { + ksft_print_msg("fsync fails.\n"); + ret = false; + } else { + syscall_ret = syscall(cachestat_nr, fd, &cs_range, &cs, 0); + + ksft_print_msg("Cachestat call (after fsync) returned %ld\n", + syscall_ret); + + if (!syscall_ret) { + print_cachestat(&cs); + + if (cs.nr_dirty) { + ret = false; + ksft_print_msg( + "Number of dirty should be zero after fsync.\n"); + } + } else { + ksft_print_msg("Cachestat (after fsync) returned non-zero.\n"); + ret = false; + goto out1; + } + } + } + +out1: + close(fd); + + if (create) + remove(filename); +out: + return ret; +} + +bool test_cachestat_shmem(void) +{ + size_t PS = sysconf(_SC_PAGESIZE); + size_t filesize = PS * 512 * 2; /* 2 2MB huge pages */ + int syscall_ret; + size_t compute_len = PS * 512; + struct cachestat_range cs_range = { PS, compute_len }; + char *filename = "tmpshmcstat"; + struct cachestat cs; + bool ret = true; + unsigned long num_pages = compute_len / PS; + int fd = shm_open(filename, O_CREAT | O_RDWR, 0600); + + if (fd < 0) { + ksft_print_msg("Unable to create shmem file.\n"); + ret = false; + goto out; + } + + if (ftruncate(fd, filesize)) { + ksft_print_msg("Unable to trucate shmem file.\n"); + ret = false; + goto close_fd; + } + + if (!write_exactly(fd, filesize)) { + ksft_print_msg("Unable to write to shmem file.\n"); + ret = false; + goto close_fd; + } + + syscall_ret = syscall(cachestat_nr, fd, &cs_range, &cs, 0); + + if (syscall_ret) { + ksft_print_msg("Cachestat returned non-zero.\n"); + ret = false; + goto close_fd; + } else { + print_cachestat(&cs); + if (cs.nr_cache + cs.nr_evicted != num_pages) { + ksft_print_msg( + "Total number of cached and evicted pages is off.\n"); + ret = false; + } + } + +close_fd: + shm_unlink(filename); +out: + return ret; +} + +int main(void) +{ + int ret = 0; + + for (int i = 0; i < 5; i++) { + const char *dev_filename = dev_files[i]; + + if (test_cachestat(dev_filename, false, false, false, + 4, O_RDONLY, 0400)) + ksft_test_result_pass("cachestat works with %s\n", dev_filename); + else { + ksft_test_result_fail("cachestat fails with %s\n", dev_filename); + ret = 1; + } + } + + if (test_cachestat("tmpfilecachestat", true, true, + true, 4, O_CREAT | O_RDWR, 0400 | 0600)) + ksft_test_result_pass("cachestat works with a normal file\n"); + else { + ksft_test_result_fail("cachestat fails with normal file\n"); + ret = 1; + } + + if (test_cachestat_shmem()) + ksft_test_result_pass("cachestat works with a shmem file\n"); + else { + ksft_test_result_fail("cachestat fails with a shmem file\n"); + ret = 1; + } + + return ret; +} -- 2.34.1