APC Quick-Start Braindump
This is a rapidly written braindump of how APC currently works in the
form of a quick-start guide to start hacking on APC.
1. Install and use APC a bit so you know what it does from the end-user's
perspective.
user-space functions are all explained here:
2. Grab the current APC code from CVS:
cvs -d:pserver:cvsread@cvs.php.net:/repository login
Password: phpfi
cvs -d:pserver:cvsread@cvs.php.net:/repository co pecl/apc
apc/php_apc.c has most of the code for the user-visible stuff. It is
also a regular PHP extension in the sense that there are MINIT, MINFO,
MSHUTDOWN, RSHUTDOWN, etc. functions.
3. Build it.
cd pecl/apc
phpize
./configure --enable-apc --enable-mmap
make
cp modules/apc.so /usr/local/lib/php
apachectl restart
4. Debugging Hints
apachectl stop
gdb /usr/bin/httpd
break ??
run -X
Grab the .gdbinit from the PHP source tree and have a look at the macros.
5. Look through apc/apc_sma.c
It is a pretty standard memory allocator.
apc_sma_malloc, apc_sma_realloc, apc_sma_strdup and apc_sma_free behave to the
caller just like malloc, realloc, strdup and free
On server startup the MINIT hook in php_apc.c calls apc_module_init() in
apc_main.c which in turn calls apc_sma_init(). apc_sma_init calls into
apc_mmap.c to mmap the specified sized segment (I tend to just use a single
segment). apc_mmap.c should be self-explanatory. It mmaps a temp file and
then unlinks that file right after the mmap to provide automatic shared memory
cleanup in case the process dies.
Once the region has been initialized we stick a header_t at the beginning
of the region. It contains the total size in header->segsize and the number
of bytes available in header->avail.
After the header comes a bit of a hack. A zero-sized block is inserted just
to make things easier later on. And then a huge block that is basically
the size of the entire segment minus the two (for the 0-sized block, and this one)
block headers.
The code for this is:
header = (header_t*) shmaddr;
header->segsize = sma_segsize;
header->avail = sma_segsize - sizeof(header_t) - sizeof(block_t) - alignword(sizeof(int));
memset(&header->lock,0,sizeof(header->lock));
sma_lock = &header->lock;
block = BLOCKAT(sizeof(header_t));
block->size = 0;
block->next = sizeof(header_t) + sizeof(block_t);
block = BLOCKAT(block->next);
block->size = header->avail;
block->next = 0;
So the shared memory looks like this:
+--------+-------+---------------------------------+
| header | block | block |
+--------+-------+---------------------------------+
sma_shmaddrs[0] gives you the address of header
The blocks are just a simple offset-based linked list (so no pointers):
typedef struct block_t block_t;
struct block_t {
size_t size; /* size of this block */
size_t next; /* offset in segment of next free block */
size_t canary; /* canary to check for memory overwrites */
#ifdef __APC_SMA_DEBUG__
int id; /* identifier for the memory block */
#endif
};
The BLOCKAT macro turns an offset into an actual address for you:
#define BLOCKAT(offset) ((block_t*)((char *)shmaddr + offset))
where shmaddr = sma_shaddrs[0]
And the OFFSET macro goes the other way:
#define OFFSET(block) ((int)(((char*)block) - (char*)shmaddr))
Allocating a block with a call to apc_sma_allocate() walks through the
linked list of blocks until it finds one that is >= to the requested size.
The first call to apc_sma_allocate() will hit the second block. We then
chop up that block so it looks like this:
+--------+-------+-------+-------------------------+
| header | block | block | block |
+--------+-------+-------+-------------------------+
Then we unlink that block from the linked list so it won't show up
as an available block on the next allocate. So we actually have:
+--------+-------+ +-------------------------+
| header | block |------>| block |
+--------+-------+ +-------------------------+
And header->avail along with block->size of the remaining large
block are updated accordingly. The arrow there representing the
link which now points to a block with an offset further along in
the segment.
When the block is freed using apc_sma_deallocate() the steps are
basically just reversed. The block is put back and then the deallocate
code looks at the block before and after to see if the block immediately
before and after are free and if so the blocks are combined. So you never
have 2 free blocks next to each other, apart from at the front with that
0-sized dummy block. This mostly prevents fragmentation. I have been
toying with the idea of always allocating block at 2^n boundaries to make
it more likely that they will be re-used to cut down on fragmentation further.
That's what the POWER_OF_TWO_BLOCKSIZE you see in apc_sma.c is all about.
Of course, anytime we fiddle with our shared memory segment we lock using
the locking macros, LOCK() and UNLOCK().
That should mostly take care of the low-level shared memory handling.
6. Next up is apc_main.c and apc_cache.c which implement the meat of the
cache logic.
The apc_main.c file mostly calls functions in apc_sma.c to allocate memory
and apc_cache.c for actual cache manipulation.
After the shared memory segment is created and the caches are initialized,
apc_module_init() installs the my_compile_file() function overriding Zend's
version. I'll talk about my_compile_file() and the rest of apc_compile.c
in the next section. For now I will stick with apc_main.c and apc_cache.c
and talk about the actual caches. A cache consists of a block of shared
memory returned by apc_sma_allocate() via apc_sma_malloc(). You will
notice references to apc_emalloc(). apc_emalloc() is just a thin wrapper
around PHP's own emalloc() function which allocates per-process memory from
PHP's pool-based memory allocator. Don't confuse apc_emalloc() and
apc_sma_malloc() as the first is per-process and the second is shared memory.
The cache is stored in/described by this struct allocated locally using
emalloc():
struct apc_cache_t {
void* shmaddr; /* process (local) address of shared cache */
header_t* header; /* cache header (stored in SHM) */
slot_t** slots; /* array of cache slots (stored in SHM) */
int num_slots; /* number of slots in cache */
int gc_ttl; /* maximum time on GC list for a slot */
int ttl; /* if slot is needed and entry's access time is older than this ttl, remove it */
};
Whenever you see functions that take a 'cache' argument, this is what they
take. And apc_cache_create() returns a pointer to this populated struct.
At the beginning of the cache we have a header. Remember, we are down a level now
from the sma stuff. The sma stuff is the low-level shared-memory allocator which
has its own header which is completely separate and invisible to apc_cache.c.
As far as apc_cache.c is concerned the block of memory it is working with could
have come from a call to malloc().
The header looks like this:
typedef struct header_t header_t;
struct header_t {
int num_hits; /* total successful hits in cache */
int num_misses; /* total unsuccessful hits in cache */
slot_t* deleted_list; /* linked list of to-be-deleted slots */
};
Since this is at the start of the shared memory segment, these values are acces
没有合适的资源?快使用搜索试试~ 我知道了~
php5.4 Non Thread Safe (NTS) x86 apc加速器
共9个文件
install:1个
pdb:1个
license:1个
需积分: 9 10 下载量 42 浏览量
2014-06-11
08:06:50
上传
评论
收藏 234KB ZIP 举报
温馨提示
重命名为php_apc.dll 2.复制php_apc.dll到你的PHP的模块文件夹里,比如c:/php/extensions (PHP4.X)或者c:/php/ext(PHP5.X) 3.打开php.ini.搜索;extension=php_zip.dll 在这一行下面加上 extension=php_apc.dll apc.enabled = 1 apc.shm_segments = 1 apc.shm_size = 64 apc.optimization = 0 apc.num_files_hint = 1000 apc.ttl = 0 apc.gc_ttl = 3600 apc.cache_by_default = On apc.slam_defense = 0 apc.file_update_protection = 2 apc.enable_cli = 0 apc.stat=0 4.保存php.ini,重新启动你的IIS
资源推荐
资源详情
资源评论
收起资源包目录
php_apc-3.1.13-5.4-nts-vc9-x86.zip (9个子文件)
php_apc.dll 106KB
INSTALL 19KB
LICENSE 3KB
php_apc.pdb 643KB
LICENSE.PHP.APC 3KB
NOTICE 2KB
TODO 1KB
TECHNOTES.txt 16KB
CHANGELOG 9KB
共 9 条
- 1
资源评论
Knowvision
- 粉丝: 57
- 资源: 14
上传资源 快速赚钱
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功