Received: by 2002:a05:6a10:206:0:0:0:0 with SMTP id 6csp1334860pxj; Sat, 12 Jun 2021 05:39:07 -0700 (PDT) X-Google-Smtp-Source: ABdhPJz5CF/0yjyJoC2VWSjH/eWKdDUKivzZkMXyPijZlbaRNh8lt3LY5zBWT4vL6i5uQ0o2QzwN X-Received: by 2002:a05:6402:885:: with SMTP id e5mr8605710edy.248.1623501547730; Sat, 12 Jun 2021 05:39:07 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1623501547; cv=none; d=google.com; s=arc-20160816; b=uFDQbgQBSvEkFbs5onen+s83BjOH8hbe5hPM+ME4hJTeXBfR8yE1JF/20r7QoUDLiI EP0t4sRwyTl/9/BoBW7FNBaSYGBNciLxIIoW5yB1eS6qRw8JqBth5XRG8Kc7Zf0ZtD0M wIv/t6Y3C+Ns10Hc8i6L4sMSR1PIpiHHoHcquatzlGjfk2UNgX+/SejdehFcfrT9gT7T 61Ryw3WN/egQ/dh3x/tNCKpb0pPNL4o9Chabd6OzSvPrymtf1gqzwUlv+yTBMygILTWx rYD0hrqTvekp5JloGgVhYlYwWz3/EI/q85dVvfrRgvPMGR+/AC2YDuY4XSFf/0mqMKrM G4Vw== 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=lTQKmMRat0zLLjLTg60IuFoUE4mlUd1rf/gNdQ4/W4A=; b=DPL8hRrB1s9Y35CWN5KOG9qyMcHj8eJhTrDC/nw2s5wj4qo9sHx3lMmgMPvZvwI6lm 6ulqvEOwDYdgu5gnCi59+ihh9yiFcBE8yGYc/wODoTgyxuwgMnExOZWkvI9ncMXwse9m RclY1MU0V5qJOAArMEP424vNKZKbK3bUcTaxC2uWfdQ9vpbPMLTqIMBUfwv8vMrjvH5i fqN0dSs7cjQMNm0FPgiOkH8kL4595C9akGwWa4XoLwT2if4Z/EB9MaCvDiUqdtuUn7iE M9Nu8vUNZc4lujOfEJqG5BguBLUOLpdr7xdHc3UmtljV/5N9BZLmmXISfOHKlqFCh7Ie reGg== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@gmail.com header.s=20161025 header.b=sud1x9t+; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 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 vger.kernel.org (vger.kernel.org. [23.128.96.18]) by mx.google.com with ESMTP id y13si6889812edo.465.2021.06.12.05.38.45; Sat, 12 Jun 2021 05:39:07 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) client-ip=23.128.96.18; Authentication-Results: mx.google.com; dkim=pass header.i=@gmail.com header.s=20161025 header.b=sud1x9t+; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 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 S231360AbhFLMjv (ORCPT + 99 others); Sat, 12 Jun 2021 08:39:51 -0400 Received: from mail-qt1-f173.google.com ([209.85.160.173]:40823 "EHLO mail-qt1-f173.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231336AbhFLMju (ORCPT ); Sat, 12 Jun 2021 08:39:50 -0400 Received: by mail-qt1-f173.google.com with SMTP id t9so4801746qtw.7; Sat, 12 Jun 2021 05:37:50 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=lTQKmMRat0zLLjLTg60IuFoUE4mlUd1rf/gNdQ4/W4A=; b=sud1x9t+JlGX6t3Z9dEy61OEyQ2SPI2v7pDnpNbqGtHdR1ln4fagnUl4r1TgyKbZI9 TDspQqb93S9sWLeRzWbRKpMkwGBd2vNVpFqY4K0t4xNnorqK3jca6nOzwPsxO1KOpu0a fCDUHrR2emLWld2MwmhAjHihRzk+qU/FGkgYeWq+c336ObNTcEtY+Yv4uz+gsLr1XcSI N8swN6ijbzakvpBRs3e6Xd9OnrBJiBxzgB1zb5W4VqdlY/7JTFJThlyLQP+nyYZkt/ht FCwwzujOyWfJcBaN05zEEFkKxH1EdAP5rPE91vDoY7bMBge3BrjDF0oflLQYdC99bZ7P f3NQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=lTQKmMRat0zLLjLTg60IuFoUE4mlUd1rf/gNdQ4/W4A=; b=G8lRgIx9hkwRx3FsZe2fyofjzwLHiPzus8uoCv+zAOglhXVR86hRUrpwEYG+QHHDXO 1YOSi+Ryf7d4DPY6M7eMjNUxYz7Vs/LHQCuUc6QslmBeIqhZyYZs5quw+cIxCUOrpsjn ZIeSjMF0G70dJG9ScKDFuGXqn+8+5gPSQgoURhyk16jMIgdEH+xfkCzfg1w98s99eBR1 L6aZbyT/0QnIBQdvbaMe8CWPx4I191wWnCKWM022I7UZ68d3BW7EeaCZ3CUs8IDsmP08 p7/FVjIphEUKtbuoCMDz0BDkYRe16IXmMm6EbK8N5U8h0SXgpmLXLScEA5WKJMW+RhTk i9BQ== X-Gm-Message-State: AOAM532sidxMU4C0t2j9eK+8teTxevEj1p8e+ygdBVvytA65omDJJzsM +o/4He4NlCCnYBcUZ7oQOoIhiw68z3XARw== X-Received: by 2002:a05:622a:1008:: with SMTP id d8mr6905020qte.257.1623501410183; Sat, 12 Jun 2021 05:36:50 -0700 (PDT) Received: from localhost ([70.127.84.75]) by smtp.gmail.com with ESMTPSA id p199sm6477550qka.128.2021.06.12.05.36.49 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sat, 12 Jun 2021 05:36:49 -0700 (PDT) From: Yury Norov To: linux-kernel@vger.kernel.org, linux-arch@vger.kernel.org, Benjamin Herrenschmidt , Catalin Marinas , Will Deacon , Yoshinori Sato , Brian Cain , Geert Uytterhoeven , Thomas Bogendoerfer , Jonas Bonn , Stefan Kristiansson , "James E.J. Bottomley" , Palmer Dabbelt , Heiko Carstens , Rich Felker , David Hildenbrand , Jaegeuk Kim , Arnd Bergmann , Andy Shevchenko , Rasmus Villemoes , Andrew Morton , Alexander Lobakin , Samuel Mendoza-Jonas , Jakub Kicinski , Daniel Bristot de Oliveira , Alexey Klimov , Ingo Molnar Cc: Yury Norov Subject: [PATCH 5/8] lib: add find_first_and_bit() Date: Sat, 12 Jun 2021 05:36:36 -0700 Message-Id: <20210612123639.329047-6-yury.norov@gmail.com> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20210612123639.329047-1-yury.norov@gmail.com> References: <20210612123639.329047-1-yury.norov@gmail.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Currently find_first_and_bit() is an alias to find_next_and_bit(). However, it is widely used in cpumask, so it worth to optimize it. This patch adds its own implementation for find_first_and_bit(). On x86_64 find_bit_benchmark says: Before (#define find_first_and_bit(...) find_next_and_bit(..., 0): Start testing find_bit() with random-filled bitmap [ 140.291468] find_first_and_bit: 46890919 ns, 32671 iterations Start testing find_bit() with sparse bitmap [ 140.295028] find_first_and_bit: 7103 ns, 1 iterations After: Start testing find_bit() with random-filled bitmap [ 162.574907] find_first_and_bit: 25045813 ns, 32846 iterations Start testing find_bit() with sparse bitmap [ 162.578458] find_first_and_bit: 4900 ns, 1 iterations (Thanks to Alexey Klimov for thorough testing.) Signed-off-by: Yury Norov --- include/linux/find.h | 27 +++++++++++++++++++++++++++ lib/find_bit.c | 21 +++++++++++++++++++++ lib/find_bit_benchmark.c | 21 +++++++++++++++++++++ 3 files changed, 69 insertions(+) diff --git a/include/linux/find.h b/include/linux/find.h index ea57f7f38c49..6048f8c97418 100644 --- a/include/linux/find.h +++ b/include/linux/find.h @@ -12,6 +12,8 @@ extern unsigned long _find_next_bit(const unsigned long *addr1, const unsigned long *addr2, unsigned long nbits, unsigned long start, unsigned long invert, unsigned long le); extern unsigned long _find_first_bit(const unsigned long *addr, unsigned long size); +extern unsigned long _find_first_and_bit(const unsigned long *addr1, + const unsigned long *addr2, unsigned long size); extern unsigned long _find_first_zero_bit(const unsigned long *addr, unsigned long size); extern unsigned long _find_last_bit(const unsigned long *addr, unsigned long size); @@ -123,6 +125,31 @@ unsigned long find_first_bit(const unsigned long *addr, unsigned long size) } #endif +#ifndef find_first_and_bit +/** + * find_first_and_bit - find the first set bit in both memory regions + * @addr1: The first address to base the search on + * @addr2: The second address to base the search on + * @size: The bitmap size in bits + * + * Returns the bit number for the next set bit + * If no bits are set, returns @size. + */ +static inline +unsigned long find_first_and_bit(const unsigned long *addr1, + const unsigned long *addr2, + unsigned long size) +{ + if (small_const_nbits(size)) { + unsigned long val = *addr1 & *addr2 & GENMASK(size - 1, 0); + + return val ? __ffs(val) : size; + } + + return _find_first_and_bit(addr1, addr2, size); +} +#endif + #ifndef find_first_zero_bit /** * find_first_zero_bit - find the first cleared bit in a memory region diff --git a/lib/find_bit.c b/lib/find_bit.c index 0f8e2e369b1d..1b8e4b2a9cba 100644 --- a/lib/find_bit.c +++ b/lib/find_bit.c @@ -89,6 +89,27 @@ unsigned long _find_first_bit(const unsigned long *addr, unsigned long size) EXPORT_SYMBOL(_find_first_bit); #endif +#ifndef find_first_and_bit +/* + * Find the first set bit in two memory regions. + */ +unsigned long _find_first_and_bit(const unsigned long *addr1, + const unsigned long *addr2, + unsigned long size) +{ + unsigned long idx, val; + + for (idx = 0; idx * BITS_PER_LONG < size; idx++) { + val = addr1[idx] & addr2[idx]; + if (val) + return min(idx * BITS_PER_LONG + __ffs(val), size); + } + + return size; +} +EXPORT_SYMBOL(_find_first_and_bit); +#endif + #ifndef find_first_zero_bit /* * Find the first cleared bit in a memory region. diff --git a/lib/find_bit_benchmark.c b/lib/find_bit_benchmark.c index 5637c5711db9..db904b57d4b8 100644 --- a/lib/find_bit_benchmark.c +++ b/lib/find_bit_benchmark.c @@ -49,6 +49,25 @@ static int __init test_find_first_bit(void *bitmap, unsigned long len) return 0; } +static int __init test_find_first_and_bit(void *bitmap, const void *bitmap2, unsigned long len) +{ + static DECLARE_BITMAP(cp, BITMAP_LEN) __initdata; + unsigned long i, cnt; + ktime_t time; + + bitmap_copy(cp, bitmap, BITMAP_LEN); + + time = ktime_get(); + for (cnt = i = 0; i < len; cnt++) { + i = find_first_and_bit(cp, bitmap2, len); + __clear_bit(i, cp); + } + time = ktime_get() - time; + pr_err("find_first_and_bit: %18llu ns, %6ld iterations\n", time, cnt); + + return 0; +} + static int __init test_find_next_bit(const void *bitmap, unsigned long len) { unsigned long i, cnt; @@ -129,6 +148,7 @@ static int __init find_bit_test(void) * traverse only part of bitmap to avoid soft lockup. */ test_find_first_bit(bitmap, BITMAP_LEN / 10); + test_find_first_and_bit(bitmap, bitmap2, BITMAP_LEN / 2); test_find_next_and_bit(bitmap, bitmap2, BITMAP_LEN); pr_err("\nStart testing find_bit() with sparse bitmap\n"); @@ -145,6 +165,7 @@ static int __init find_bit_test(void) test_find_next_zero_bit(bitmap, BITMAP_LEN); test_find_last_bit(bitmap, BITMAP_LEN); test_find_first_bit(bitmap, BITMAP_LEN); + test_find_first_and_bit(bitmap, bitmap2, BITMAP_LEN); test_find_next_and_bit(bitmap, bitmap2, BITMAP_LEN); /* -- 2.30.2