Bug #71355 [Com]: Fail to use huge page on power8 because of wrong page size

From: Date: Tue, 22 Mar 2016 11:56:56 +0000
Subject: Bug #71355 [Com]: Fail to use huge page on power8 because of wrong page size
References: 1  Groups: php.bugs 
Request: Send a blank email to php-bugs+get-200030@lists.php.net to get a copy of this message
Edit report at https://bugs.php.net/bug.php?id=71355&edit=1

 ID:                 71355
 Comment by:         jpauli@php.net
 Reported by:        jocelyn dot fournier at softizy dot com
 Summary:            Fail to use huge page on power8 because of wrong
                     page size
 Status:             Open
 Type:               Bug
 Package:            opcache
 Operating System:   Linux on Power
 PHP Version:        7.0.2
 Block user comment: N
 Private report:     N

 New Comment:

I wasn't aware of such a define.

We could use it if we can detect it at compile time, yes.
Could you try on your system if that gives good results ?


Previous Comments:
------------------------------------------------------------------------
[2016-03-21 19:47:09] jocelyn dot fournier at softizy dot com

/proc/meminfo should give you the Hugepagesize info.
What about using HPAGE_SIZE ?

------------------------------------------------------------------------
[2016-03-21 17:47:34] jpauli@php.net

The problem is that there is no way do dynamically discover the huge page size, knowing that some
systems have different sizes, and may map different memory arear using different page size. There is
nothing comparable to _SC_PAGESIZE or getpagesize(), which are part of POSIX.

One could parse /proc/mounts to find hugetlbfs entries.
Or we could rely on the excellent libhugetlbfs, but what if the system doesn't support it ?

https://github.com/libhugetlbfs/libhugetlbfs

Huge page mapping is really hard to manage in a crossplatform way, way more than classical memory
mappings where we have libc's malloc() on top of the Kernel calls, and where (nearly) every
system agreed on having a default 4Kb page size

------------------------------------------------------------------------
[2016-02-16 21:57:27] basu at us dot ibm dot com

Since linux on POWER supports huge page of size 16MB, it appears that this
hard coded value of 2MB in ZendAccelerator.c is letting the mmap()/madvise()/munmap()
fail with EINVAL due to invalid argument.

This routine below with 2MB constant is only valid for promoting opcode cache to huge page.. This
routine is not controlling the huge page semantics for PHP data allocations. However, there is a
CHUNKSIZE buckets that are being managed by PHP 7.0.2
that does not have a size for huge page (max size for chunk size is only 2MB) I changed that to 16MB
and was able to eliminate the mmap/madvise/munmap errors. Basically 
the chunk size management code should include huge page support on POWER.

------------------------------------------------------------------------
[2016-01-12 23:06:34] jocelyn dot fournier at softizy dot com

Description:
------------
Hi,

It seems huge page size is hardcoded in the php src code : 

In ZendAccelerator.c for example, you have :

static void accel_move_code_to_huge_pages(void)
{
	FILE *f;
	long unsigned int huge_page_size = 2 * 1024 * 1024;

However on IBM Power8 on linux, the default page size is 64KB ( http://www.redbooks.ibm.com/redbooks/pdfs/sg248171.pdf
).
Hence when huge pages are enabled, php displays the following warning : 


munmap() failed: [22] Invalid argument

strace output :

[...]
mmap(NULL, 2097152, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS|0x40000, -1, 0) = 0x3effff000000
madvise(0x3effff000000, 2097152, MADV_HUGEPAGE) = -1 EINVAL (Invalid argument)
[...]
open("/usr/local/lib/php/extensions/no-debug-non-zts-20151012/apcu.so",
O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0\25\0\1\0\0\0\0`\0\0\0\0\0\0"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0644, st_size=121864, ...}) = 0
mmap(NULL, 158952, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x3fff8e140000
mmap(0x3fff8e160000, 65536, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x10000) =
0x3fff8e160000
close(3)                                = 0
[...]
munmap(0x3efff7000000, 134217728)       = 0
close(3)                                = 0
munmap(0x3fff962c0000, 185272)          = 0
munmap(0x3fff96240000, 82352)           = 0
munmap(0x3fff96260000, 328760)          = 0
munmap(0x3fff94210000, 33554432)        = 0
munmap(0x3fff962f0000, 158952)          = 0
brk(0x1001a8d0000)                      = 0x1001a8d0000
munmap(0x3fff96320000, 301576)          = 0
munmap(0x3fff96210000, 196608)          = 0
munmap(0x3effff000000, 2097152)         = -1 EINVAL (Invalid argument)
write(2, "\nmunmap() failed: [22] Invalid a"..., 40
munmap() failed: [22] Invalid argument
) = 40
munmap(0x3fff96370000, 327680)          = 0
exit_group(0)                           = ?
+++ exited with 0 +++


To fix the issue, the default page size should not be hardcoded, but should depend on the platform.

Thanks and regards,
  Jocelyn Fournier


Expected result:
----------------
No warning

Actual result:
--------------
munmap() failed: [22] Invalid argument


------------------------------------------------------------------------



--
Edit this bug report at https://bugs.php.net/bug.php?id=71355&edit=1


Thread (7 messages)

« previous php.bugs (#200030) next »