Repository navigation
Read every on-premise value by name, because the engine class is built on every request - #71
Closed
jwrosewell wants to merge 2 commits into
Closed
jwrosewell wants to merge 2 commits into
jwrosewell wants to merge 2 commits into
Conversation
PHP builds DeviceDetectionOnPremise and IpIntelligenceOnPremise on every request, so the index table from #66 is built on every request. The stub tests now say every value accessor is handed the property's name. The tests of the index table itself go, and the IP Intelligence test that an engine built with names reads the values an engine with no names reads stays, without its check of the table.
Takes out the read path #66 added. DeviceDetectionOnPremise and IpIntelligenceOnPremise no longer build a table from names to indexes, SwigData hands every value accessor the property's name, and PROPERTY_NOT_BUILT, getPropertyIndex and the IP Intelligence startupSetting go with them. PHP builds both classes on every request, so the table was built on every request, and a whole request timed on a runner with the TAC file was no faster by index than by name with 1, 5 or 15 names. Device Detection still reads required_properties as it was when PHP started, which #66 also fixed.
This was referenced Nov 11, 2026
Build property metadata only when something asks for it, and read every on-premise value by name
#72
Merged
Merged
Contributor
Author
|
Closing unmerged. #72 supersedes this draft and is in rc. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Takes out the read path that #66 added, so the on-premise Device Detection and IP Intelligence engines read every value by the property's name again, as they did before #66.
Problem
#66 made both on-premise engines read every value by its index in the list of names the engine was built with, through a table from names to indexes. The table is built when
DeviceDetectionOnPremiseorIpIntelligenceOnPremiseis constructed, and PHP constructs them on every request, so the table is built on every request. A read by index is faster than a read by name, but the table has to be built before the first read, and the question is whether a whole request is faster.Measurement
One runner job, run 43064604148, built the Device Detection extension from cxx 7c4ac436 with PHP 8.3 and loaded the TAC file (109 MB). It timed two trees of PHP code against the same extension.
rcas it is now (d876e75, whose tree is the tree the job checked out).DeviceDetectionOnPremise, so the table stays empty andreadKeyhands every accessor the name, which is Read every on-premise value by its build-time property index #66's read path reverted.A request builds
DeviceDetectionOnPremiseand a pipeline with no JavaScript or set-header elements, processes one User-Agent and reads each name once through$flowData->device->get. Each figure is 3,000 requests after 100 to warm up, in its own PHP process withrequired_propertiesset to the first 1, 5 or 15 of IsMobile, BrowserName, PlatformName, DeviceType, HardwareVendor, BrowserVersion, PlatformVersion, HardwareModel, HardwareName, ScreenPixelsWidth, ScreenPixelsHeight, IsTablet, IsSmartPhone, BrowserVendor and PlatformVendor. There were 10 rounds, and the order of the two trees was swapped each round. The two trees read the same values at every size. The scripts wereci/tmp-timing/request.phpandci/tmp-timing/run.pyon a temporary branch, at 15f59f0d, which has since been deleted.Medians of the 10 rounds, with the lowest and highest.
By index was slower at every size, and slower in 23 of the 30 rounds. The differences are smaller than the spread of each column, so the measurement shows that reading by index makes a whole request no faster, rather than putting a number on how much slower it is. The table alone took 1,345 to 2,563 ns for 15 names with the Lite file in run 43059409861 on the php#46 branch, and a read by index saved 24 to 70 ns there, so a request would need tens of reads before the time saved covered the table. A whole request took about 5.6 ms with the TAC file, so a difference of that size is lost in the spread of the rest of the request.
Specification
Finding Properties at 927ac677 says "Every read MUST use the position", and that the table "is built once, when the Engine is created". In PHP the Engine, the native engine of the extension, is created once when PHP starts, while the class that would hold the table is built on every request, so PHP cannot build the table once per Engine today. This draft is the faster approach, which James's rule says is used, and is a departure from that sentence of the specification for PHP until the table can be built once per process.
What changed
device-detection/onpremise/tests/SwigDataIndexTests.phpbecomesSwigDataReadTests.php, whose stub tests say every value accessor is handed the property's name, a read throughSwigDataagrees with a native read by name, and a metric property is not read through a value accessor. Inip-intelligence/tests/SwigDataTests.php,testEveryReadGoesByNamereplaces the three index tests.PropertyIndexTests.phpand the IP Intelligence tests of the table (testANameGivenTwiceKeepsItsFirstIndexandtestASettingForTheRequestDoesNotTurnOnIndexes) go.testAnEngineBuiltWithNamesReadsTheSameValuesstays, without its check of the table, so an engine built with names in an order of its own still reads the values an engine with no names reads.SwigData.php,Messages.php,IpIntelligenceOnPremise.phpand the IP IntelligenceStubSwigEngine.phpare as they were before Read every on-premise value by its build-time property index #66 (90c3bdb~1), and none of them changed onrcafter Read every on-premise value by its build-time property index #66. That takes out the table,getPropertyIndex,readKey,PROPERTY_NOT_BUILTand the IP IntelligencestartupSetting.DeviceDetectionOnPremise.phploses the table,getPropertyIndexandbuildPropertyIndexes, and keepsstartupSetting, so Device Detection's restricted properties still come fromrequired_propertiesas it was when PHP started, which Read every on-premise value by its build-time property index #66 also fixed and which is not about reading. The Device Detection stub engine loses its table.Runs
SwigDataReadTests::testEveryReadGoesByNameandtestMetricPropertiesAreNotReadThroughTheValueAccessorsin Device Detection (2 of 53) andSwigDataTests::testEveryReadGoesByNamein IP Intelligence (1 of 17), each because the accessors were handed0,1and2where the names were expected, and the other jobs were cancelled when it failed. ItsSetting 'PullRequestSha'line gives 128b439.Setting 'PullRequestSha'lines gives 98489b1, and Configure printed "Left out 5 macOS entries".What remains
macOS was left out of this draft's full build under the 9 November decision. The rc head is built with macOS before it merges into main.