On 30.08.2007 [13:06:51 +1000], David Gibson wrote:
> On Wed, Aug 29, 2007 at 04:20:10PM -0700, Nishanth Aravamudan wrote:
> > stack_grow_into_huge: fix-up testcase for 64-bit binaries
> >
> > Currently, we mmap in a huge page arbitrarily and then start growing the
> > stack down. For 64-bit binaries, though, the stack may be rather high up
> > in the address space, and there is no guarantee our huge page mapping is
> > anywhere near it. So, instead, try to mmap() in a hugepage very close to
> > the stack. If we fail, just keep moving down a hugepage at a time, until
> > we succeed. For x86/x86_64, this should happen relatively quickly. For
> > ppc64, this should put us in the segment just below the one containing
> > the stack.
> >
> > Then, in the child process, only grow the stack down to the point where
> > it is below the mmap() address. If we're still running at that point,
> > we've clearly not been signalled.
> >
> > Tested on x86_64, but wanted to get some review from others.
>
> Heh. I was thinking about doing something vaguely like this for
> ppc64, since the 64-bit version of the test takes so long to run.
>
> I think what you have is good - certainly makes the test more robust.
> However, it doesn't actually speed the test up all that much for
> ppc64. There, the hugepage has to go not in the previous segment from
> the stack but in the previous "address space slice" since we only keep
> track of which segments are hugepage and which aren't at 1TB
> granularity above the 4GB point. So the test still needs to grow the
> stack by a full 1TB to trigger the signal.
>
> In addition to what you have I think it would be an idea to increase
> the size of the alloca() chunk in do_child for 64-bit versions.
>
> Also one nit: is alloc(0) guaranteed to return an address on the
> stack? Since the result of alloca(0) should never be dereferenced
> anyway, one could imagine an implementation where it returned an
> arbitrary pointer, or NULL.
How does this look:
stack_grow_into_huge: fix-up testcase for 64-bit binaries
Currently, we mmap in a huge page arbitrarily and then start growing the
stack down. For 64-bit binaries, though, the stack may be rather high up
in the address space, and there is no guarantee our huge page mapping is
anywhere near it. So, instead, try to mmap() in a hugepage very close to
the stack (determined by a stack variable's address). If we fail, just
keep moving down a hugepage at a time, until we succeed. For x86/x86_64,
this should happen relatively quickly. For ppc64, this should put us in
the segment just below the one containing the stack.
Then, in the child process, only grow the stack down to the point where
it is below the mmap() address. If we're still running at that point,
we've clearly not been signalled.
Finally, vary how much we grow the stack by for 64-bit binaries.
This specifically should help on ppc64, where we will need to go a full
TB down the address space and thus only allocating 16M at a time makes
the benchmark take quite a while to run.
Tested on x86_64, but wanted to get some review from others.
Signed-off-by: Nishanth Aravamudan <nacc@...>
diff --git a/tests/stack_grow_into_huge.c b/tests/stack_grow_into_huge.c
index 8507df9..9a63d6b 100644
--- a/tests/stack_grow_into_huge.c
+++ b/tests/stack_grow_into_huge.c
@@ -48,13 +48,19 @@
* 0d59a01bc461bbab4017ff449b8401151ef44cf6.
*/
-void do_child()
+#ifdef __LP64__
+#define STACK_ALLOCATION_SIZE (256*1024*1024)
+#else
+#define STACK_ALLOCATION_SIZE (16*1024*1024)
+#endif
+
+void do_child(void *stop_address)
{
- while (1) {
- volatile int *x;
+ volatile int *x;
+ do {
x = alloca(16*1024*1024);
*x = 1;
- }
+ } while ((void *)x >= stop_address);
}
int main(int argc, char *argv[])
@@ -63,6 +69,8 @@ int main(int argc, char *argv[])
struct rlimit r;
char *b;
long hpage_size = gethugepagesize();
+ void *stack_address, *mmap_address, *heap_address;
+ unsigned long stack;
test_init(argc, argv);
@@ -77,17 +85,35 @@ int main(int argc, char *argv[])
if (fd < 0)
CONFIG("Couldn't get hugepage fd");
- b = mmap(0, hpage_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
- if (b != MAP_FAILED)
- munmap(b, hpage_size);
- else
+ stack_address = &stack;
+ heap_address = sbrk(0);
+
+ /*
+ * paranoia: start mapping two hugepages below the start of the stack,
+ * in case the alignment would cause us to map over something if we
+ * only used a gap of one hugepage.
+ */
+ mmap_address = PALIGN(stack_address - 2 * hpage_size, hpage_size);
+
+ do {
+ b = mmap(mmap_address, hpage_size, PROT_READ|PROT_WRITE,
+ MAP_FIXED|MAP_SHARED, fd, 0);
+ mmap_address -= hpage_size;
+ /*
+ * if we get all the way down to the heap, stop trying
+ */
+ if (mmap_address <= heap_address)
+ break;
+ } while (b == MAP_FAILED);
+
+ if (b == MAP_FAILED)
FAIL("mmap");
if ((pid = fork()) < 0)
FAIL("fork");
if (pid == 0) {
- do_child();
+ do_child(mmap_address);
exit(0);
}
--
Nishanth Aravamudan <nacc@...>
IBM Linux Technology Center
|