Many customers running WinCache reported seeing different cache statistics on consecutive requests to wincache.php. Specifically, cache uptime and opcode cache summary returned second time by wincache.php was completely different than the data returned first time. Occasionally data shown in the opcode cache summary table didn’t match the chart displayed on its side. Many customers correctly guessed that this happens because there are multiple cache instances present in different php-cgi processes but thought that none of the PHP processes are sharing cache data and were worried about excessive memory usage by WinCache. I have been replying to many customers personally and posting on forums explaining why they see this behavior but as more and more customers are using WinCache, this question is becoming more common. Ruslan who is PM for WinCache suggested writing a blog post to help customers understand the reason. So here you go.
WinCache creates many memory segments which are shared among all the php-cgi processes launched by a particular IIS worker process. For simplicity sake I will use the term “all php processes” to refer to “all php processes launched by one IIS worker process”. In version 1.0, WinCache creates 5 shared memory segments. Mostly these segments are shared successfully among all the php processes. In fact 4 shared segments are always shared but memory segment for opcode cache is sometimes not shared. Reason for this is that 4 of the 5 memory segments store data structures which are completely defined by us. Anytime we need to store a pointer in the shared segment which points to some other data in the shared segment, we define pointer as simple integer which is then set to offset from start of memory segment. This way other processes can reach the data pointed by this pointer even when absolute address of the data might be different. In contrast, data stored in opcode cache is defined by the PHP engine and include many absolute pointers. These pointer values cannot be changed to offsets without incurring a very heavy performance penalty which will totally defy the purpose of WinCache. For this reason, we try to map the global opcode cache segment at same address in all processes using MapViewOfFileEx which can possibly fail if the address is already occupied. All other caches doesn’t have this restriction and are mapped anywhere which mostly succeed. If we fail to map the opcode cache at a particular address, we create another opcode cache in process’s local memory so that requests processed by this process are also very fast. Typically this happens for 5%-10% of php processes. Below figures illustrates state of the caches in a normal php process (figure 1) and in a process which ends up creating a local cache (figure 2). For more information on these caches, read my previous blog.
Now that you understand this design, all the anomalies seen in responses of wincache.php can be explained. If the process which processes request to wincache.php has a local cache, opcode cache data will be different from the one shown when request is handled by a process which is using global opcode cache. Also since cache uptime in wincache.php is picked from opcode cache (ocache_fileinfo), it will be age of either global opcode cache or local opcode cache. Reason why chart sometimes didn’t match opcode cache summary is because request to draw the chart is sent separately. If the chart draw request reaches a process which has different cache structure than the one which returned summary data, there can be a mismatch.
Improvements in WinCache 1.0.1
In WinCache 1.0.1, we have made few changes to wincache.php which will make all this a little less confusing. Since cache uptime can be different for file cache and opcode cache, we have moved the cache uptime field to opcode cache and file cache summary tables. So you will now see two cache uptimes. File cache uptime will reflect age of global file cache and opcode cache uptime will reflect age of global or local opcode cache. We also added cache scope property in opcode cache summary table which will be either “global” or “local”. This will indicate if the opcode cache data you are looking at is for global cache or a local cache. To fix the chart discrepancy, we now send data required to draw the chart in the request itself so that chart always matches the data in the summary table. All these changes were made based on feedback from you. So keep sending your feature requests and feedback so that we can keep improving WinCache.
Hope this helps.