{"action":"opened","number":479,"pull_request":{"url":"https://api.github.com/repos/AngleSharp/AngleSharp/pulls/479","id":96322462,"html_url":"https://github.com/AngleSharp/AngleSharp/pull/479","diff_url":"https://github.com/AngleSharp/AngleSharp/pull/479.diff","patch_url":"https://github.com/AngleSharp/AngleSharp/pull/479.patch","issue_url":"https://api.github.com/repos/AngleSharp/AngleSharp/issues/479","number":479,"state":"open","locked":false,"title":"Optimize tag name allocations","user":{"login":"HellBrick","id":3703722,"avatar_url":"https://avatars.githubusercontent.com/u/3703722?v=3","gravatar_id":"","url":"https://api.github.com/users/HellBrick","html_url":"https://github.com/HellBrick","followers_url":"https://api.github.com/users/HellBrick/followers","following_url":"https://api.github.com/users/HellBrick/following{/other_user}","gists_url":"https://api.github.com/users/HellBrick/gists{/gist_id}","starred_url":"https://api.github.com/users/HellBrick/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/HellBrick/subscriptions","organizations_url":"https://api.github.com/users/HellBrick/orgs","repos_url":"https://api.github.com/users/HellBrick/repos","events_url":"https://api.github.com/users/HellBrick/events{/privacy}","received_events_url":"https://api.github.com/users/HellBrick/received_events","type":"User","site_admin":false},"body":"The biggest source of ~~all evil~~ parsing allocations is `BaseTokenizer.FlushBuffer`:\r\n\r\n![FlushBuffer memory pressure](http://i.imgur.com/wy7l2RP.png)\r\n\r\nIt's not easy to eliminate allocations here, especially when the public API is designed in a way that forces the tokenizer to allocate strings. However, there's some low-hanging fruit here that can be taken care of. I've temporary introduced a few intermediate methods to see what exactly this memory is allocated for:\r\n\r\n![FlushBuffer memory distribution](http://i.imgur.com/mVZkmRM.png)\r\n\r\nThis PR addresses the 18.4% caused by allocating tag names over and over again. Since HTML tag names almost never deviate from a well-known set, we can cache one instance of the string per known tag and reuse it. In order to make the cache check as fast as possible, the lookup code has been pre-generated to account for all the tags from `TagNames` fields (the generator can be found [here](https://gist.github.com/HellBrick/237cabb59af1307ff759316a9a0b381d)). As the result of this change, those 18.4% of `FlushBuffer` allocations are almost gone (some unique tags happen after all, but they are quite rare):\r\n\r\n![FlashBuffer memory distribution after the optimisation](http://i.imgur.com/UlTMda4.png)\r\n\r\nOptimising away ~18% of a method that's responsible for ~24% allocations is probably not that nice in a grand scheme of things, but that's better than nothing, right? =) And as an additional bonus, the cache lookup is actually faster then creating all those strings:\r\n\r\nBefore:\r\n![FlashTagNameBuffer - before](http://i.imgur.com/D8XYVl8.png)\r\n\r\nAfter:\r\n![FlashTagNameBuffer - after](http://i.imgur.com/1Ds4JmN.png)\r\n\r\nTechnically speaking, adding an optional parameter to a public method, like I did to `FlushBuffer`, is considered a breaking change by some people: it preserves source compatibility, but doesn't preserve binary compatibility (AngleSharp dll can't be swapped for new version without recompiling the calling assembly). I don't know what your policy for this kind of things is, but if it's a problem, it can be solved by adding an overload instead of an optional parameter.","created_at":"2016-12-02T17:44:22Z","updated_at":"2016-12-02T17:44:22Z","closed_at":null,"merged_at":null,"merge_commit_sha":"c32a18078429919743004bbc7c9621492f2ef411","assignee":null,"assignees":[],"milestone":null,"commits_url":"https://api.github.com/repos/AngleSharp/AngleSharp/pulls/479/commits","review_comments_url":"https://api.github.com/repos/AngleSharp/AngleSharp/pulls/479/comments","review_comment_url":"https://api.github.com/repos/AngleSharp/AngleSharp/pulls/comments{/number}","comments_url":"https://api.github.com/repos/AngleSharp/AngleSharp/issues/479/comments","statuses_url":"https://api.github.com/repos/AngleSharp/AngleSharp/statuses/8f5f45363081e73eb86523444e960f18272fd116","head":{"label":"HellBrick:optimize-tag-name-allocations","ref":"optimize-tag-name-allocations","sha":"8f5f45363081e73eb86523444e960f18272fd116","user":{"login":"HellBrick","id":3703722,"avatar_url":"https://avatars.githubusercontent.com/u/3703722?v=3","gravatar_id":"","url":"https://api.github.com/users/HellBrick","html_url":"https://github.com/HellBrick","followers_url":"https://api.github.com/users/HellBrick/followers","following_url":"https://api.github.com/users/HellBrick/following{/other_user}","gists_url":"https://api.github.com/users/HellBrick/gists{/gist_id}","starred_url":"https://api.github.com/users/HellBrick/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/HellBrick/subscriptions","organizations_url":"https://api.github.com/users/HellBrick/orgs","repos_url":"https://api.github.com/users/HellBrick/repos","events_url":"https://api.github.com/users/HellBrick/events{/privacy}","received_events_url":"https://api.github.com/users/HellBrick/received_events","type":"User","site_admin":false},"repo":{"id":75318104,"name":"AngleSharp","full_name":"HellBrick/AngleSharp","owner":{"login":"HellBrick","id":3703722,"avatar_url":"https://avatars.githubusercontent.com/u/3703722?v=3","gravatar_id":"","url":"https://api.github.com/users/HellBrick","html_url":"https://github.com/HellBrick","followers_url":"https://api.github.com/users/HellBrick/followers","following_url":"https://api.github.com/users/HellBrick/following{/other_user}","gists_url":"https://api.github.com/users/HellBrick/gists{/gist_id}","starred_url":"https://api.github.com/users/HellBrick/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/HellBrick/subscriptions","organizations_url":"https://api.github.com/users/HellBrick/orgs","repos_url":"https://api.github.com/users/HellBrick/repos","events_url":"https://api.github.com/users/HellBrick/events{/privacy}","received_events_url":"https://api.github.com/users/HellBrick/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/HellBrick/AngleSharp","description":":angel: The ultimate angle brackets parser library parsing HTML5, MathML, SVG and CSS to construct a DOM based on the official W3C specifications.","fork":true,"url":"https://api.github.com/repos/HellBrick/AngleSharp","forks_url":"https://api.github.com/repos/HellBrick/AngleSharp/forks","keys_url":"https://api.github.com/repos/HellBrick/AngleSharp/keys{/key_id}","collaborators_url":"https://api.github.com/repos/HellBrick/AngleSharp/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/HellBrick/AngleSharp/teams","hooks_url":"https://api.github.com/repos/HellBrick/AngleSharp/hooks","issue_events_url":"https://api.github.com/repos/HellBrick/AngleSharp/issues/events{/number}","events_url":"https://api.github.com/repos/HellBrick/AngleSharp/events","assignees_url":"https://api.github.com/repos/HellBrick/AngleSharp/assignees{/user}","branches_url":"https://api.github.com/repos/HellBrick/AngleSharp/branches{/branch}","tags_url":"https://api.github.com/repos/HellBrick/AngleSharp/tags","blobs_url":"https://api.github.com/repos/HellBrick/AngleSharp/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/HellBrick/AngleSharp/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/HellBrick/AngleSharp/git/refs{/sha}","trees_url":"https://api.github.com/repos/HellBrick/AngleSharp/git/trees{/sha}","statuses_url":"https://api.github.com/repos/HellBrick/AngleSharp/statuses/{sha}","languages_url":"https://api.github.com/repos/HellBrick/AngleSharp/languages","stargazers_url":"https://api.github.com/repos/HellBrick/AngleSharp/stargazers","contributors_url":"https://api.github.com/repos/HellBrick/AngleSharp/contributors","subscribers_url":"https://api.github.com/repos/HellBrick/AngleSharp/subscribers","subscription_url":"https://api.github.com/repos/HellBrick/AngleSharp/subscription","commits_url":"https://api.github.com/repos/HellBrick/AngleSharp/commits{/sha}","git_commits_url":"https://api.github.com/repos/HellBrick/AngleSharp/git/commits{/sha}","comments_url":"https://api.github.com/repos/HellBrick/AngleSharp/comments{/number}","issue_comment_url":"https://api.github.com/repos/HellBrick/AngleSharp/issues/comments{/number}","contents_url":"https://api.github.com/repos/HellBrick/AngleSharp/contents/{+path}","compare_url":"https://api.github.com/repos/HellBrick/AngleSharp/compare/{base}...{head}","merges_url":"https://api.github.com/repos/HellBrick/AngleSharp/merges","archive_url":"https://api.github.com/repos/HellBrick/AngleSharp/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/HellBrick/AngleSharp/downloads","issues_url":"https://api.github.com/repos/HellBrick/AngleSharp/issues{/number}","pulls_url":"https://api.github.com/repos/HellBrick/AngleSharp/pulls{/number}","milestones_url":"https://api.github.com/repos/HellBrick/AngleSharp/milestones{/number}","notifications_url":"https://api.github.com/repos/HellBrick/AngleSharp/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/HellBrick/AngleSharp/labels{/name}","releases_url":"https://api.github.com/repos/HellBrick/AngleSharp/releases{/id}","deployments_url":"https://api.github.com/repos/HellBrick/AngleSharp/deployments","created_at":"2016-12-01T17:54:33Z","updated_at":"2016-12-01T17:54:38Z","pushed_at":"2016-12-02T17:06:55Z","git_url":"git://github.com/HellBrick/AngleSharp.git","ssh_url":"git@github.com:HellBrick/AngleSharp.git","clone_url":"https://github.com/HellBrick/AngleSharp.git","svn_url":"https://github.com/HellBrick/AngleSharp","homepage":"https://anglesharp.github.io","size":22222,"stargazers_count":0,"watchers_count":0,"language":"C#","has_issues":false,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"AngleSharp:devel","ref":"devel","sha":"94a4cfdf3df8c00b695a575bbfe017ecd6f76558","user":{"login":"AngleSharp","id":10828168,"avatar_url":"https://avatars.githubusercontent.com/u/10828168?v=3","gravatar_id":"","url":"https://api.github.com/users/AngleSharp","html_url":"https://github.com/AngleSharp","followers_url":"https://api.github.com/users/AngleSharp/followers","following_url":"https://api.github.com/users/AngleSharp/following{/other_user}","gists_url":"https://api.github.com/users/AngleSharp/gists{/gist_id}","starred_url":"https://api.github.com/users/AngleSharp/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/AngleSharp/subscriptions","organizations_url":"https://api.github.com/users/AngleSharp/orgs","repos_url":"https://api.github.com/users/AngleSharp/repos","events_url":"https://api.github.com/users/AngleSharp/events{/privacy}","received_events_url":"https://api.github.com/users/AngleSharp/received_events","type":"Organization","site_admin":false},"repo":{"id":10501638,"name":"AngleSharp","full_name":"AngleSharp/AngleSharp","owner":{"login":"AngleSharp","id":10828168,"avatar_url":"https://avatars.githubusercontent.com/u/10828168?v=3","gravatar_id":"","url":"https://api.github.com/users/AngleSharp","html_url":"https://github.com/AngleSharp","followers_url":"https://api.github.com/users/AngleSharp/followers","following_url":"https://api.github.com/users/AngleSharp/following{/other_user}","gists_url":"https://api.github.com/users/AngleSharp/gists{/gist_id}","starred_url":"https://api.github.com/users/AngleSharp/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/AngleSharp/subscriptions","organizations_url":"https://api.github.com/users/AngleSharp/orgs","repos_url":"https://api.github.com/users/AngleSharp/repos","events_url":"https://api.github.com/users/AngleSharp/events{/privacy}","received_events_url":"https://api.github.com/users/AngleSharp/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/AngleSharp/AngleSharp","description":":angel: The ultimate angle brackets parser library parsing HTML5, MathML, SVG and CSS to construct a DOM based on the official W3C specifications.","fork":false,"url":"https://api.github.com/repos/AngleSharp/AngleSharp","forks_url":"https://api.github.com/repos/AngleSharp/AngleSharp/forks","keys_url":"https://api.github.com/repos/AngleSharp/AngleSharp/keys{/key_id}","collaborators_url":"https://api.github.com/repos/AngleSharp/AngleSharp/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/AngleSharp/AngleSharp/teams","hooks_url":"https://api.github.com/repos/AngleSharp/AngleSharp/hooks","issue_events_url":"https://api.github.com/repos/AngleSharp/AngleSharp/issues/events{/number}","events_url":"https://api.github.com/repos/AngleSharp/AngleSharp/events","assignees_url":"https://api.github.com/repos/AngleSharp/AngleSharp/assignees{/user}","branches_url":"https://api.github.com/repos/AngleSharp/AngleSharp/branches{/branch}","tags_url":"https://api.github.com/repos/AngleSharp/AngleSharp/tags","blobs_url":"https://api.github.com/repos/AngleSharp/AngleSharp/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/AngleSharp/AngleSharp/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/AngleSharp/AngleSharp/git/refs{/sha}","trees_url":"https://api.github.com/repos/AngleSharp/AngleSharp/git/trees{/sha}","statuses_url":"https://api.github.com/repos/AngleSharp/AngleSharp/statuses/{sha}","languages_url":"https://api.github.com/repos/AngleSharp/AngleSharp/languages","stargazers_url":"https://api.github.com/repos/AngleSharp/AngleSharp/stargazers","contributors_url":"https://api.github.com/repos/AngleSharp/AngleSharp/contributors","subscribers_url":"https://api.github.com/repos/AngleSharp/AngleSharp/subscribers","subscription_url":"https://api.github.com/repos/AngleSharp/AngleSharp/subscription","commits_url":"https://api.github.com/repos/AngleSharp/AngleSharp/commits{/sha}","git_commits_url":"https://api.github.com/repos/AngleSharp/AngleSharp/git/commits{/sha}","comments_url":"https://api.github.com/repos/AngleSharp/AngleSharp/comments{/number}","issue_comment_url":"https://api.github.com/repos/AngleSharp/AngleSharp/issues/comments{/number}","contents_url":"https://api.github.com/repos/AngleSharp/AngleSharp/contents/{+path}","compare_url":"https://api.github.com/repos/AngleSharp/AngleSharp/compare/{base}...{head}","merges_url":"https://api.github.com/repos/AngleSharp/AngleSharp/merges","archive_url":"https://api.github.com/repos/AngleSharp/AngleSharp/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/AngleSharp/AngleSharp/downloads","issues_url":"https://api.github.com/repos/AngleSharp/AngleSharp/issues{/number}","pulls_url":"https://api.github.com/repos/AngleSharp/AngleSharp/pulls{/number}","milestones_url":"https://api.github.com/repos/AngleSharp/AngleSharp/milestones{/number}","notifications_url":"https://api.github.com/repos/AngleSharp/AngleSharp/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/AngleSharp/AngleSharp/labels{/name}","releases_url":"https://api.github.com/repos/AngleSharp/AngleSharp/releases{/id}","deployments_url":"https://api.github.com/repos/AngleSharp/AngleSharp/deployments","created_at":"2013-06-05T12:05:34Z","updated_at":"2016-12-02T15:36:54Z","pushed_at":"2016-12-02T17:44:22Z","git_url":"git://github.com/AngleSharp/AngleSharp.git","ssh_url":"git@github.com:AngleSharp/AngleSharp.git","clone_url":"https://github.com/AngleSharp/AngleSharp.git","svn_url":"https://github.com/AngleSharp/AngleSharp","homepage":"https://anglesharp.github.io","size":26760,"stargazers_count":1066,"watchers_count":1066,"language":"C#","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":132,"mirror_url":null,"open_issues_count":16,"forks":132,"open_issues":16,"watchers":1066,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/AngleSharp/AngleSharp/pulls/479"},"html":{"href":"https://github.com/AngleSharp/AngleSharp/pull/479"},"issue":{"href":"https://api.github.com/repos/AngleSharp/AngleSharp/issues/479"},"comments":{"href":"https://api.github.com/repos/AngleSharp/AngleSharp/issues/479/comments"},"review_comments":{"href":"https://api.github.com/repos/AngleSharp/AngleSharp/pulls/479/comments"},"review_comment":{"href":"https://api.github.com/repos/AngleSharp/AngleSharp/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/AngleSharp/AngleSharp/pulls/479/commits"},"statuses":{"href":"https://api.github.com/repos/AngleSharp/AngleSharp/statuses/8f5f45363081e73eb86523444e960f18272fd116"}},"merged":false,"mergeable":true,"mergeable_state":"clean","merged_by":null,"comments":0,"review_comments":0,"commits":2,"additions":585,"deletions":5,"changed_files":4}}
{"actor":{"display_login":"HellBrick"}}