php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Request #58885 Use in-process memory for APC cache for multithreaded Web Servers
Submitted: 2009-10-09 20:00 UTC Modified: 2009-10-11 00:31 UTC
From: basantk@php.net Assigned:
Status: Closed Package: APC (PECL)
PHP Version: HEAD CVS-2009-10-09 (dev) OS: all
Private report: No CVE-ID: None
 [2009-10-09 20:00 UTC] basantk@php.net
Description:
------------
On Unix platforms, APC can be compiled with mmap or shared memory. This performs good for multiprocess php. However when we run inside single process multi-threaded Web Servers e.g Sun Web Server or Apache worker mpm with single process, mmap is simply overkill. Reading APC's compiled cache from in-process memory is much efficient than from mmap.

To achieve the above, I introduced a configurable variable apc.single_proc which is set to 0 by default. When apc.single_proc is set to 1, cache is created inside process memory. Also mutex which is used to synchronize the cache can also be created as PTHREAD_PROCESS_PRIVATE. apc.single_proc can only be set to 1 when ZTS is enabled.

Expected result:
----------------
Better performance for single process multi-threaded php servers.


Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2009-10-09 20:07 UTC] basantk@php.net
Attached is the the URL to the patch :
http://blogs.sun.com/basant/resource/apc_mmap_replace_malloc.txt

Also patch is attached here :
---------------------------

Index: php_apc.c
===================================================================
--- php_apc.c	(revision 289375)
+++ php_apc.c	(working copy)
@@ -95,6 +95,7 @@
     apc_globals->report_autofilter = 0;
     apc_globals->include_once = 0;
     apc_globals->apc_optimize_function = NULL;
+    apc_globals->single_proc = 0;
 #ifdef MULTIPART_EVENT_FORMDATA
     apc_globals->rfc1867 = 0;
     memset(&(apc_globals->rfc1867_data), 0, sizeof(apc_rfc1867_data));
@@ -257,6 +258,9 @@
 STD_PHP_INI_BOOLEAN("apc.write_lock", "1",      PHP_INI_SYSTEM, OnUpdateBool,           write_lock,       zend_apc_globals, apc_globals)
 STD_PHP_INI_BOOLEAN("apc.slam_defense", "1",    PHP_INI_SYSTEM, OnUpdateBool,           slam_defense,     zend_apc_globals, apc_globals)
 STD_PHP_INI_BOOLEAN("apc.report_autofilter", "0", PHP_INI_SYSTEM, OnUpdateBool,         report_autofilter,zend_apc_globals, apc_globals)
+#ifdef ZTS
+STD_PHP_INI_BOOLEAN("apc.single_proc", "0",  PHP_INI_ALL, OnUpdateBool,         single_proc, zend_apc_globals, apc_globals)
+#endif
 #ifdef MULTIPART_EVENT_FORMDATA
 STD_PHP_INI_BOOLEAN("apc.rfc1867", "0", PHP_INI_SYSTEM, OnUpdateBool, rfc1867, zend_apc_globals, apc_globals)
 STD_PHP_INI_ENTRY("apc.rfc1867_prefix", "upload_", PHP_INI_SYSTEM, OnUpdateStringUnempty, rfc1867_prefix, zend_apc_globals, apc_globals)
Index: apc_pthreadmutex.c
===================================================================
--- apc_pthreadmutex.c	(revision 289375)
+++ apc_pthreadmutex.c	(working copy)
@@ -20,6 +20,7 @@
 /* $Id$ */
 
 #include "apc_pthreadmutex.h"
+#include "apc_globals.h"
 
 #ifdef APC_PTHREADMUTEX_LOCKS
 
@@ -27,6 +28,8 @@
 {
     int result;
     pthread_mutexattr_t* attr;
+    int shared;
+    TSRMLS_FETCH();
     attr = malloc(sizeof(pthread_mutexattr_t));
 
     result = pthread_mutexattr_init(attr);
@@ -46,7 +49,13 @@
 #endif
 
     /* pthread_mutexattr_settype(attr, PTHREAD_MUTEX_ERRORCHECK); */
-    result = pthread_mutexattr_setpshared(attr, PTHREAD_PROCESS_SHARED);
+
+    if (APCG(single_proc))
+        shared = PTHREAD_PROCESS_PRIVATE;
+    else
+        shared = PTHREAD_PROCESS_SHARED;
+
+    result = pthread_mutexattr_setpshared(attr, shared);
     if(result == EINVAL) {
         apc_eprint("pthread mutex error: attr is not an initialized mutex attribute object, or pshared is not a valid process-shared state setting.");
     } else if(result == EFAULT) {
Index: apc_sma.c
===================================================================
--- apc_sma.c	(revision 289375)
+++ apc_sma.c	(working copy)
@@ -336,6 +336,7 @@
 void apc_sma_init(int numseg, size_t segsize, char *mmap_file_mask)
 {
     uint i;
+    TSRMLS_FETCH();
 
     if (sma_initialized) {
         return;
@@ -367,12 +368,17 @@
         block_t*    block;
         void*       shmaddr;
 
+        if (APCG(single_proc)) {
+            sma_segments[i].shmaddr = calloc(1, sma_segsize);
+            sma_segments[i].size = sma_segsize;
+        } else {
 #if APC_MMAP
-        sma_segments[i] = apc_mmap(mmap_file_mask, sma_segsize);
-        if(sma_numseg != 1) memcpy(&mmap_file_mask[strlen(mmap_file_mask)-6], "XXXXXX", 6);
+            sma_segments[i] = apc_mmap(mmap_file_mask, sma_segsize);
+            if(sma_numseg != 1) memcpy(&mmap_file_mask[strlen(mmap_file_mask)-6], "XXXXXX", 6);
 #else
-        sma_segments[i] = apc_shm_attach(apc_shm_create(i, sma_segsize));
+            sma_segments[i] = apc_shm_attach(apc_shm_create(i, sma_segsize));
 #endif
+         }
         
         sma_segments[i].size = sma_segsize;
 
@@ -423,16 +429,21 @@
 void apc_sma_cleanup()
 {
     uint i;
+    TSRMLS_FETCH();
 
     assert(sma_initialized);
 
     for (i = 0; i < sma_numseg; i++) {
         apc_lck_destroy(SMA_LCK(i));
+        if (APCG(single_proc)) {
+            free(sma_segments[i].shmaddr);
+        } else {
 #if APC_MMAP
-        apc_unmap(&sma_segments[i]);
+            apc_unmap(&sma_segments[i]);
 #else
-        apc_shm_detach(&sma_segments[i]);
+            apc_shm_detach(&sma_segments[i]);
 #endif
+        }
     }
     sma_initialized = 0;
     apc_efree(sma_segments);
Index: apc_globals.h
===================================================================
--- apc_globals.h	(revision 289375)
+++ apc_globals.h	(working copy)
@@ -76,6 +76,8 @@
 
     /* module variables */
     zend_bool initialized;       /* true if module was initialized */
+    zend_bool single_proc;       /* true if single process shared the APC cache.
+                                    useful for performance */
     apc_stack_t* cache_stack;    /* the stack of cached executable code */
     zend_bool cache_by_default;  /* true if files should be cached unless filtered out */
                                  /* false if files should only be cached if filtered in */
 [2009-10-09 20:08 UTC] basantk@php.net
There is a discussion thread where I discussed this issue :
http://marc.info/?t=125487674200001&r=1&w=2
 [2009-10-09 20:10 UTC] basantk@php.net
Documentation of apc.single_proc:
--------------------------------
    By default single_proc is set to 0 and APC creates mmap/shared memory
to save cached php file and data. This can be set to 1 only if running inside
single multithreaded server process e.g "ServerLimit 1" for Apache worker mpm
or "MaxProcs 1" for Sun Web Server. When set to 1, instead of mmap/shared
memory, APC creates cache in process memory. This option have no effect on
single threaded multi process php e.g fastcgi.
 [2009-10-11 00:31 UTC] basantk@php.net
This patch has no effect on performance of APC so
closing this bug.

Here is my measurement on Solaris sparc on an ecommerce
workload (using Studio 12)

Excl.     Incl.     Excl.       Incl.       Excl.     Incl.      Name  
User CPU  User CPU  Total LWP   Total LWP   Sys. CPU  Sys. CPU     
    sec.      sec.        sec.        sec.      sec.      sec. 
Using calloc:
   4.243  7656.376       7.145   56560.845     0.610  2095.696   php5_execute
Using mmap:
   3.973  7644.517       6.715   54048.538     0.640  2071.839   php5_execute
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Thu Apr 25 10:01:29 2024 UTC