linux-mm.kvack.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/2] Fixes for compaction_test
@ 2024-05-15  9:36 Dev Jain
  2024-05-15  9:36 ` [PATCH 1/2] selftests/mm: compaction_test: Fix incorrect write of zero to nr_hugepages Dev Jain
  2024-05-15  9:36 ` [PATCH 2/2] selftests/mm: compaction_test: Fix trivial test success and reduce probability of OOM-killer invocation Dev Jain
  0 siblings, 2 replies; 7+ messages in thread
From: Dev Jain @ 2024-05-15  9:36 UTC (permalink / raw)
  To: akpm, shuah
  Cc: linux-mm, linux-kselftest, linux-kernel, Anshuman.Khandual,
	sjayaram, Dev Jain

The compaction_test memory selftest introduces fragmentation in memory
and then tries to allocate as many hugepages as possible. This series
addresses some problems.

First off, correctly set the number of hugepages to zero before trying
to set a large number of them.

Now, consider a situation in which, at the start of the test, a non-zero
number of hugepages have been already set (while running the entire
selftests/mm suite, or manually by the admin). The test operates on 80%
of memory to avoid OOM-killer invocation, and because some memory is
already blocked by hugepages, it would increase the chance of OOM-killing.
Also, since mem_free used in check_compaction() is the value before we
set nr_hugepages to zero, the chance that the compaction_index will
be small is very high if the preset nr_hugepages was high, leading to a
bogus test success.

This series applies on top of the stable 6.9 kernel.
 
Dev Jain (2):
  selftests/mm: compaction_test: Fix incorrect write of zero to
    nr_hugepages
  selftests/mm: compaction_test: Fix trivial test success and reduce
    probability of OOM-killer invocation

 tools/testing/selftests/mm/compaction_test.c | 70 ++++++++++++++------
 1 file changed, 50 insertions(+), 20 deletions(-)

-- 
2.30.2



^ permalink raw reply	[flat|nested] 7+ messages in thread

* [PATCH 1/2] selftests/mm: compaction_test: Fix incorrect write of zero to nr_hugepages
  2024-05-15  9:36 [PATCH 0/2] Fixes for compaction_test Dev Jain
@ 2024-05-15  9:36 ` Dev Jain
  2024-05-20  0:00   ` Andrew Morton
  2024-05-15  9:36 ` [PATCH 2/2] selftests/mm: compaction_test: Fix trivial test success and reduce probability of OOM-killer invocation Dev Jain
  1 sibling, 1 reply; 7+ messages in thread
From: Dev Jain @ 2024-05-15  9:36 UTC (permalink / raw)
  To: akpm, shuah
  Cc: linux-mm, linux-kselftest, linux-kernel, Anshuman.Khandual,
	sjayaram, Dev Jain, stable

nr_hugepages is not set to zero because the file offset has not been reset
after read(). Fix that using lseek().

Fixes: bd67d5c15cc1 ("Test compaction of mlocked memory")
Cc: stable@vger.kernel.org 
Signed-off-by: Dev Jain <dev.jain@arm.com>
---
Merge dependency: https://lore.kernel.org/all/20240513082842.4117782-1-dev.jain@arm.com/
Andrew, does it sound reasonable to have the fixes tag in the above
patch too, along with this series?

 tools/testing/selftests/mm/compaction_test.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/tools/testing/selftests/mm/compaction_test.c b/tools/testing/selftests/mm/compaction_test.c
index 533999b6c284..c5be395f8363 100644
--- a/tools/testing/selftests/mm/compaction_test.c
+++ b/tools/testing/selftests/mm/compaction_test.c
@@ -107,6 +107,8 @@ int check_compaction(unsigned long mem_free, unsigned int hugepage_size)
 		goto close_fd;
 	}
 
+	lseek(fd, 0, SEEK_SET);
+
 	/* Start with the initial condition of 0 huge pages*/
 	if (write(fd, "0", sizeof(char)) != sizeof(char)) {
 		ksft_print_msg("Failed to write 0 to /proc/sys/vm/nr_hugepages: %s\n",
-- 
2.30.2



^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH 2/2] selftests/mm: compaction_test: Fix trivial test success and reduce probability of OOM-killer invocation
  2024-05-15  9:36 [PATCH 0/2] Fixes for compaction_test Dev Jain
  2024-05-15  9:36 ` [PATCH 1/2] selftests/mm: compaction_test: Fix incorrect write of zero to nr_hugepages Dev Jain
@ 2024-05-15  9:36 ` Dev Jain
  2024-05-20  0:03   ` Andrew Morton
  1 sibling, 1 reply; 7+ messages in thread
From: Dev Jain @ 2024-05-15  9:36 UTC (permalink / raw)
  To: akpm, shuah
  Cc: linux-mm, linux-kselftest, linux-kernel, Anshuman.Khandual,
	sjayaram, Dev Jain, stable

Reset nr_hugepages to zero before the start of the test.

If a non-zero number of hugepages is already set before the start of the
test, the following problems arise:

 - The probability of the test getting OOM-killed increases.
Proof: The test wants to run on 80% of available memory to prevent
OOM-killing (see original code comments). Let the value of mem_free at the
start of the test, when nr_hugepages = 0, be x. In the other case, when
nr_hugepages > 0, let the memory consumed by hugepages be y. In the former
case, the test operates on 0.8 * x of memory. In the latter, the test
operates on 0.8 * (x - y) of memory, with y already filled, hence, memory
consumed is y + 0.8 * (x - y) = 0.8 * x + 0.2 * y > 0.8 * x. Q.E.D

 - The probability of a bogus test success increases.
Proof: Let the memory consumed by hugepages be greater than 25% of x,
with x and y defined as above. The definition of compaction_index is
c_index = (x - y)/z where z is the memory consumed by hugepages after
trying to increase them again. In check_compaction(), we set the number
of hugepages to zero, and then increase them back; the probability that
they will be set back to consume at least y amount of memory again is
very high (since there is not much delay between the two attempts of
changing nr_hugepages). Hence, z >= y > (x/4) (by the 25% assumption).
Therefore,
c_index = (x - y)/z <= (x - y)/y = x/y - 1 < 4 - 1 = 3
hence, c_index can always be forced to be less than 3, thereby the test
succeeding always. Q.E.D

NOTE: This patch depends on the previous one.

Fixes: bd67d5c15cc1 ("Test compaction of mlocked memory")
Cc: stable@vger.kernel.org
Signed-off-by: Dev Jain <dev.jain@arm.com>
---
 tools/testing/selftests/mm/compaction_test.c | 72 ++++++++++++++------
 1 file changed, 50 insertions(+), 22 deletions(-)

diff --git a/tools/testing/selftests/mm/compaction_test.c b/tools/testing/selftests/mm/compaction_test.c
index c5be395f8363..2ae059989771 100644
--- a/tools/testing/selftests/mm/compaction_test.c
+++ b/tools/testing/selftests/mm/compaction_test.c
@@ -82,12 +82,15 @@ int prereq(void)
 	return -1;
 }
 
-int check_compaction(unsigned long mem_free, unsigned int hugepage_size)
+int check_compaction(unsigned long mem_free, unsigned int hugepage_size,
+		     int initial_nr_hugepages)
 {
 	int fd, ret = -1;
 	int compaction_index = 0;
-	char initial_nr_hugepages[10] = {0};
 	char nr_hugepages[10] = {0};
+	char init_nr_hugepages[10] = {0};
+
+	sprintf(init_nr_hugepages, "%d", initial_nr_hugepages);
 
 	/* We want to test with 80% of available memory. Else, OOM killer comes
 	   in to play */
@@ -101,23 +104,6 @@ int check_compaction(unsigned long mem_free, unsigned int hugepage_size)
 		goto out;
 	}
 
-	if (read(fd, initial_nr_hugepages, sizeof(initial_nr_hugepages)) <= 0) {
-		ksft_print_msg("Failed to read from /proc/sys/vm/nr_hugepages: %s\n",
-			       strerror(errno));
-		goto close_fd;
-	}
-
-	lseek(fd, 0, SEEK_SET);
-
-	/* Start with the initial condition of 0 huge pages*/
-	if (write(fd, "0", sizeof(char)) != sizeof(char)) {
-		ksft_print_msg("Failed to write 0 to /proc/sys/vm/nr_hugepages: %s\n",
-			       strerror(errno));
-		goto close_fd;
-	}
-
-	lseek(fd, 0, SEEK_SET);
-
 	/* Request a large number of huge pages. The Kernel will allocate
 	   as much as it can */
 	if (write(fd, "100000", (6*sizeof(char))) != (6*sizeof(char))) {
@@ -140,8 +126,8 @@ int check_compaction(unsigned long mem_free, unsigned int hugepage_size)
 
 	lseek(fd, 0, SEEK_SET);
 
-	if (write(fd, initial_nr_hugepages, strlen(initial_nr_hugepages))
-	    != strlen(initial_nr_hugepages)) {
+	if (write(fd, init_nr_hugepages, strlen(init_nr_hugepages))
+	    != strlen(init_nr_hugepages)) {
 		ksft_print_msg("Failed to write value to /proc/sys/vm/nr_hugepages: %s\n",
 			       strerror(errno));
 		goto close_fd;
@@ -165,6 +151,42 @@ int check_compaction(unsigned long mem_free, unsigned int hugepage_size)
 	return ret;
 }
 
+int set_zero_hugepages(int *initial_nr_hugepages)
+{
+	int fd, ret = -1;
+	char nr_hugepages[10] = {0};
+
+	fd = open("/proc/sys/vm/nr_hugepages", O_RDWR | O_NONBLOCK);
+	if (fd < 0) {
+		ksft_print_msg("Failed to open /proc/sys/vm/nr_hugepages: %s\n",
+			       strerror(errno));
+		goto out;
+	}
+
+	if (read(fd, nr_hugepages, sizeof(nr_hugepages)) <= 0) {
+		ksft_print_msg("Failed to read from /proc/sys/vm/nr_hugepages: %s\n",
+			       strerror(errno));
+		goto close_fd;
+	}
+
+	lseek(fd, 0, SEEK_SET);
+
+	/* Start with the initial condition of 0 huge pages */
+	if (write(fd, "0", sizeof(char)) != sizeof(char)) {
+		ksft_print_msg("Failed to write 0 to /proc/sys/vm/nr_hugepages: %s\n",
+			       strerror(errno));
+		goto close_fd;
+	}
+
+	*initial_nr_hugepages = atoi(nr_hugepages);
+	ret = 0;
+
+ close_fd:
+	close(fd);
+
+ out:
+	return ret;
+}
 
 int main(int argc, char **argv)
 {
@@ -175,6 +197,7 @@ int main(int argc, char **argv)
 	unsigned long mem_free = 0;
 	unsigned long hugepage_size = 0;
 	long mem_fragmentable_MB = 0;
+	int initial_nr_hugepages;
 
 	ksft_print_header();
 
@@ -183,6 +206,10 @@ int main(int argc, char **argv)
 
 	ksft_set_plan(1);
 
+	/* start the test without hugepages reducing mem_free */
+	if (set_zero_hugepages(&initial_nr_hugepages))
+		return ksft_exit_fail();
+
 	lim.rlim_cur = RLIM_INFINITY;
 	lim.rlim_max = RLIM_INFINITY;
 	if (setrlimit(RLIMIT_MEMLOCK, &lim))
@@ -226,7 +253,8 @@ int main(int argc, char **argv)
 		entry = entry->next;
 	}
 
-	if (check_compaction(mem_free, hugepage_size) == 0)
+	if (check_compaction(mem_free, hugepage_size,
+			     initial_nr_hugepages) == 0)
 		return ksft_exit_pass();
 
 	return ksft_exit_fail();
-- 
2.30.2



^ permalink raw reply related	[flat|nested] 7+ messages in thread

* Re: [PATCH 1/2] selftests/mm: compaction_test: Fix incorrect write of zero to nr_hugepages
  2024-05-15  9:36 ` [PATCH 1/2] selftests/mm: compaction_test: Fix incorrect write of zero to nr_hugepages Dev Jain
@ 2024-05-20  0:00   ` Andrew Morton
  2024-05-20  5:28     ` Dev Jain
  0 siblings, 1 reply; 7+ messages in thread
From: Andrew Morton @ 2024-05-20  0:00 UTC (permalink / raw)
  To: Dev Jain
  Cc: shuah, linux-mm, linux-kselftest, linux-kernel, Anshuman.Khandual,
	sjayaram, stable

On Wed, 15 May 2024 15:06:32 +0530 Dev Jain <dev.jain@arm.com> wrote:

> nr_hugepages is not set to zero because the file offset has not been reset
> after read(). Fix that using lseek().
> 

Please fully describe the runtime effects of this bug.


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH 2/2] selftests/mm: compaction_test: Fix trivial test success and reduce probability of OOM-killer invocation
  2024-05-15  9:36 ` [PATCH 2/2] selftests/mm: compaction_test: Fix trivial test success and reduce probability of OOM-killer invocation Dev Jain
@ 2024-05-20  0:03   ` Andrew Morton
  2024-05-20  5:33     ` Dev Jain
  0 siblings, 1 reply; 7+ messages in thread
From: Andrew Morton @ 2024-05-20  0:03 UTC (permalink / raw)
  To: Dev Jain
  Cc: shuah, linux-mm, linux-kselftest, linux-kernel, Anshuman.Khandual,
	sjayaram, stable

On Wed, 15 May 2024 15:06:33 +0530 Dev Jain <dev.jain@arm.com> wrote:

> Reset nr_hugepages to zero before the start of the test.
> 
> If a non-zero number of hugepages is already set before the start of the
> test, the following problems arise:
> 
>  - The probability of the test getting OOM-killed increases.
> Proof: The test wants to run on 80% of available memory to prevent
> OOM-killing (see original code comments). Let the value of mem_free at the
> start of the test, when nr_hugepages = 0, be x. In the other case, when
> nr_hugepages > 0, let the memory consumed by hugepages be y. In the former
> case, the test operates on 0.8 * x of memory. In the latter, the test
> operates on 0.8 * (x - y) of memory, with y already filled, hence, memory
> consumed is y + 0.8 * (x - y) = 0.8 * x + 0.2 * y > 0.8 * x. Q.E.D
> 
>  - The probability of a bogus test success increases.
> Proof: Let the memory consumed by hugepages be greater than 25% of x,
> with x and y defined as above. The definition of compaction_index is
> c_index = (x - y)/z where z is the memory consumed by hugepages after
> trying to increase them again. In check_compaction(), we set the number
> of hugepages to zero, and then increase them back; the probability that
> they will be set back to consume at least y amount of memory again is
> very high (since there is not much delay between the two attempts of
> changing nr_hugepages). Hence, z >= y > (x/4) (by the 25% assumption).
> Therefore,
> c_index = (x - y)/z <= (x - y)/y = x/y - 1 < 4 - 1 = 3
> hence, c_index can always be forced to be less than 3, thereby the test
> succeeding always. Q.E.D
> 
> NOTE: This patch depends on the previous one.
> 
> -int check_compaction(unsigned long mem_free, unsigned int hugepage_size)
> +int check_compaction(unsigned long mem_free, unsigned int hugepage_size,
> +		     int initial_nr_hugepages)
>  {
>  	int fd, ret = -1;
>  	int compaction_index = 0;
> -	char initial_nr_hugepages[10] = {0};
>  	char nr_hugepages[10] = {0};
> +	char init_nr_hugepages[10] = {0};
> +
> +	sprintf(init_nr_hugepages, "%d", initial_nr_hugepages);

Well, [10] isn't really large enough.  "-1111111111" requires 12 chars,
with the trailing \0.  And I'd suggest an unsigned type and a %u -
negative initial_nr_hugepages doesn't make a lot of sense.

>  
> +int set_zero_hugepages(int *initial_nr_hugepages)
> +{
> +	int fd, ret = -1;
> +	char nr_hugepages[10] = {0};

Ditto?

> +	fd = open("/proc/sys/vm/nr_hugepages", O_RDWR | O_NONBLOCK);
> +	if (fd < 0) {
> +		ksft_print_msg("Failed to open /proc/sys/vm/nr_hugepages: %s\n",
> +			       strerror(errno));
> +		goto out;
> +	}
> +
> +	if (read(fd, nr_hugepages, sizeof(nr_hugepages)) <= 0) {
> +		ksft_print_msg("Failed to read from /proc/sys/vm/nr_hugepages: %s\n",
> +			       strerror(errno));
> +		goto close_fd;
> +	}
> +
> +	lseek(fd, 0, SEEK_SET);
> +
> +	/* Start with the initial condition of 0 huge pages */
> +	if (write(fd, "0", sizeof(char)) != sizeof(char)) {
> +		ksft_print_msg("Failed to write 0 to /proc/sys/vm/nr_hugepages: %s\n",
> +			       strerror(errno));
> +		goto close_fd;
> +	}
> +
> +	*initial_nr_hugepages = atoi(nr_hugepages);
> +	ret = 0;
> +
> + close_fd:
> +	close(fd);
> +
> + out:
> +	return ret;
> +}



^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH 1/2] selftests/mm: compaction_test: Fix incorrect write of zero to nr_hugepages
  2024-05-20  0:00   ` Andrew Morton
@ 2024-05-20  5:28     ` Dev Jain
  0 siblings, 0 replies; 7+ messages in thread
From: Dev Jain @ 2024-05-20  5:28 UTC (permalink / raw)
  To: Andrew Morton
  Cc: shuah, linux-mm, linux-kselftest, linux-kernel, Anshuman.Khandual,
	sjayaram, stable


On 5/20/24 05:30, Andrew Morton wrote:
> On Wed, 15 May 2024 15:06:32 +0530 Dev Jain <dev.jain@arm.com> wrote:
>
>> nr_hugepages is not set to zero because the file offset has not been reset
>> after read(). Fix that using lseek().
>>
> Please fully describe the runtime effects of this bug.


This is not a "bug", but a discrepancy; the following comment

by the author says "Start with the initial condition of 0 huge

pages", I am just ensuring that that is actually done. Although,

I am not sure about the utility of doing this in the first place,

since we are anyways trying to increase hugepages after that.

In the second patch, I have moved away this entire logic of

setting nr_hugepages to zero, to the place before we start

filling up memory; if you feel that this patch is unnecessary,

we may squash it.



^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH 2/2] selftests/mm: compaction_test: Fix trivial test success and reduce probability of OOM-killer invocation
  2024-05-20  0:03   ` Andrew Morton
@ 2024-05-20  5:33     ` Dev Jain
  0 siblings, 0 replies; 7+ messages in thread
From: Dev Jain @ 2024-05-20  5:33 UTC (permalink / raw)
  To: Andrew Morton
  Cc: shuah, linux-mm, linux-kselftest, linux-kernel, Anshuman.Khandual,
	sjayaram, stable


On 5/20/24 05:33, Andrew Morton wrote:
> On Wed, 15 May 2024 15:06:33 +0530 Dev Jain <dev.jain@arm.com> wrote:
>
>> Reset nr_hugepages to zero before the start of the test.
>>
>> If a non-zero number of hugepages is already set before the start of the
>> test, the following problems arise:
>>
>>   - The probability of the test getting OOM-killed increases.
>> Proof: The test wants to run on 80% of available memory to prevent
>> OOM-killing (see original code comments). Let the value of mem_free at the
>> start of the test, when nr_hugepages = 0, be x. In the other case, when
>> nr_hugepages > 0, let the memory consumed by hugepages be y. In the former
>> case, the test operates on 0.8 * x of memory. In the latter, the test
>> operates on 0.8 * (x - y) of memory, with y already filled, hence, memory
>> consumed is y + 0.8 * (x - y) = 0.8 * x + 0.2 * y > 0.8 * x. Q.E.D
>>
>>   - The probability of a bogus test success increases.
>> Proof: Let the memory consumed by hugepages be greater than 25% of x,
>> with x and y defined as above. The definition of compaction_index is
>> c_index = (x - y)/z where z is the memory consumed by hugepages after
>> trying to increase them again. In check_compaction(), we set the number
>> of hugepages to zero, and then increase them back; the probability that
>> they will be set back to consume at least y amount of memory again is
>> very high (since there is not much delay between the two attempts of
>> changing nr_hugepages). Hence, z >= y > (x/4) (by the 25% assumption).
>> Therefore,
>> c_index = (x - y)/z <= (x - y)/y = x/y - 1 < 4 - 1 = 3
>> hence, c_index can always be forced to be less than 3, thereby the test
>> succeeding always. Q.E.D
>>
>> NOTE: This patch depends on the previous one.
>>
>> -int check_compaction(unsigned long mem_free, unsigned int hugepage_size)
>> +int check_compaction(unsigned long mem_free, unsigned int hugepage_size,
>> +		     int initial_nr_hugepages)
>>   {
>>   	int fd, ret = -1;
>>   	int compaction_index = 0;
>> -	char initial_nr_hugepages[10] = {0};
>>   	char nr_hugepages[10] = {0};
>> +	char init_nr_hugepages[10] = {0};
>> +
>> +	sprintf(init_nr_hugepages, "%d", initial_nr_hugepages);
> Well, [10] isn't really large enough.  "-1111111111" requires 12 chars,
> with the trailing \0.  And I'd suggest an unsigned type and a %u -
> negative initial_nr_hugepages doesn't make a lot of sense.
>
>>   
>> +int set_zero_hugepages(int *initial_nr_hugepages)
>> +{
>> +	int fd, ret = -1;
>> +	char nr_hugepages[10] = {0};
> Ditto?


Sure, makes sense. I'll just change that to 20 and make it unsigned.

>
>> +	fd = open("/proc/sys/vm/nr_hugepages", O_RDWR | O_NONBLOCK);
>> +	if (fd < 0) {
>> +		ksft_print_msg("Failed to open /proc/sys/vm/nr_hugepages: %s\n",
>> +			       strerror(errno));
>> +		goto out;
>> +	}
>> +
>> +	if (read(fd, nr_hugepages, sizeof(nr_hugepages)) <= 0) {
>> +		ksft_print_msg("Failed to read from /proc/sys/vm/nr_hugepages: %s\n",
>> +			       strerror(errno));
>> +		goto close_fd;
>> +	}
>> +
>> +	lseek(fd, 0, SEEK_SET);
>> +
>> +	/* Start with the initial condition of 0 huge pages */
>> +	if (write(fd, "0", sizeof(char)) != sizeof(char)) {
>> +		ksft_print_msg("Failed to write 0 to /proc/sys/vm/nr_hugepages: %s\n",
>> +			       strerror(errno));
>> +		goto close_fd;
>> +	}
>> +
>> +	*initial_nr_hugepages = atoi(nr_hugepages);
>> +	ret = 0;
>> +
>> + close_fd:
>> +	close(fd);
>> +
>> + out:
>> +	return ret;
>> +}


^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2024-05-20  5:33 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-05-15  9:36 [PATCH 0/2] Fixes for compaction_test Dev Jain
2024-05-15  9:36 ` [PATCH 1/2] selftests/mm: compaction_test: Fix incorrect write of zero to nr_hugepages Dev Jain
2024-05-20  0:00   ` Andrew Morton
2024-05-20  5:28     ` Dev Jain
2024-05-15  9:36 ` [PATCH 2/2] selftests/mm: compaction_test: Fix trivial test success and reduce probability of OOM-killer invocation Dev Jain
2024-05-20  0:03   ` Andrew Morton
2024-05-20  5:33     ` Dev Jain

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).