{"action":"created","comment":{"url":"https://api.github.com/repos/OP2/PyOP2/pulls/comments/27639599","id":27639599,"diff_hunk":"@@ -436,6 +447,14 @@ def _is_indirect_and_not_read(self):\n         return self._is_indirect and self._access is not READ\n \n     @property\n+    def _is_readonly(self):\n+        return self._access == READ\n+\n+    @property\n+    def _is_written(self):","path":"pyop2/base.py","position":61,"original_position":61,"commit_id":"829faae028818f84fb9f1bdb3e88f7e803852c27","original_commit_id":"829faae028818f84fb9f1bdb3e88f7e803852c27","user":{"login":"FabioLuporini","id":478143,"avatar_url":"https://avatars.githubusercontent.com/u/478143?v=3","gravatar_id":"","url":"https://api.github.com/users/FabioLuporini","html_url":"https://github.com/FabioLuporini","followers_url":"https://api.github.com/users/FabioLuporini/followers","following_url":"https://api.github.com/users/FabioLuporini/following{/other_user}","gists_url":"https://api.github.com/users/FabioLuporini/gists{/gist_id}","starred_url":"https://api.github.com/users/FabioLuporini/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/FabioLuporini/subscriptions","organizations_url":"https://api.github.com/users/FabioLuporini/orgs","repos_url":"https://api.github.com/users/FabioLuporini/repos","events_url":"https://api.github.com/users/FabioLuporini/events{/privacy}","received_events_url":"https://api.github.com/users/FabioLuporini/received_events","type":"User","site_admin":false},"body":"I agree, will change","created_at":"2015-04-02T08:24:31Z","updated_at":"2015-04-02T08:24:31Z","html_url":"https://github.com/OP2/PyOP2/pull/432#discussion_r27639599","pull_request_url":"https://api.github.com/repos/OP2/PyOP2/pulls/432","_links":{"self":{"href":"https://api.github.com/repos/OP2/PyOP2/pulls/comments/27639599"},"html":{"href":"https://github.com/OP2/PyOP2/pull/432#discussion_r27639599"},"pull_request":{"href":"https://api.github.com/repos/OP2/PyOP2/pulls/432"}}},"pull_request":{"url":"https://api.github.com/repos/OP2/PyOP2/pulls/432","id":32307785,"html_url":"https://github.com/OP2/PyOP2/pull/432","diff_url":"https://github.com/OP2/PyOP2/pull/432.diff","patch_url":"https://github.com/OP2/PyOP2/pull/432.patch","issue_url":"https://api.github.com/repos/OP2/PyOP2/issues/432","number":432,"state":"open","locked":false,"title":"Loop Fusion","user":{"login":"FabioLuporini","id":478143,"avatar_url":"https://avatars.githubusercontent.com/u/478143?v=3","gravatar_id":"","url":"https://api.github.com/users/FabioLuporini","html_url":"https://github.com/FabioLuporini","followers_url":"https://api.github.com/users/FabioLuporini/followers","following_url":"https://api.github.com/users/FabioLuporini/following{/other_user}","gists_url":"https://api.github.com/users/FabioLuporini/gists{/gist_id}","starred_url":"https://api.github.com/users/FabioLuporini/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/FabioLuporini/subscriptions","organizations_url":"https://api.github.com/users/FabioLuporini/orgs","repos_url":"https://api.github.com/users/FabioLuporini/repos","events_url":"https://api.github.com/users/FabioLuporini/events{/privacy}","received_events_url":"https://api.github.com/users/FabioLuporini/received_events","type":"User","site_admin":false},"body":"This PR introduces loop fusion in PyOP2. \r\n\r\nBad news:\r\n- It depends on three other branches (in FFC, COFFEE, and Firedrake)\r\n- It obviously passes all tests, including Firedrake ones (with fusion enabled), but of course this should be tested extensively in bigger codes\r\n- It's quite massive...\r\n\r\nGood news:\r\n- ...but the changes are mostly confined in a new module, fusion.py and...\r\n- ...fusion is off by default, but one can switch it on by simply exporting PYOP2_LOOP_FUSION=1. I think this is the best scheme for the moment, so incrementally we can fix bugs and add functionalities. This also ensures no performance regression (if any).\r\n- performance evaluation will be the next step\r\n- anyway, I haven't experienced any tangible overhead due to fusing loops\r\n\r\nOther minor points:\r\n- extrusion and mixed are currently not supported in \"hard fusion mode\" (see below). It's a matter of fixing code generation, which I'll do after some performance experimentation\r\n\r\nHow it works (summary):\r\n- it's all based on lazy evaluation of loops. If fusion is ON, the trace of loops is intercepted prior to execution and analysed\r\n- three sort of fusions are possible, depending on the actual data dependency pattern between loops: \r\n  * if no dependency at all or only \"trivial\" ones are present (e.g., two *direct* loops, write-after-read or read-after-writ), then ``soft fusion`` is performed: that's basically body concatenation, plus a few minor tweaks (e.g. avoiding passing in the same Arg twice, etc.). \r\n  * if dependencies are less trivial, like increment-after-increment in indirect loops (the case of cell/facet integrals in Firedrake), then what I called ``hard fusion`` takes place. Things here get more complicated, because basically one needs to track which elements of the fused loop (e.g. cells) have already been visited to avoid executing the same iteration multiple times. This is not the only issue though -- however, the code is fairly commented, so if interested I invite to have a look at it.\r\n  * if dependencies are \"real dependencies\", like read-after-write between indirect loops. then fusion is implemented through ``split tiling``. For this, an ``inspector-executor scheme`` is implemented exploiting the SLOPE library (accessible at coneoproject/SLOPE).  This is an under-development feature: it currently works if one explicitly enabled it,  but still far we are from actually being able of extensively using it (for example, it lacks MPI support).\r\n\r\nDetails on the implementation:\r\n- Polymorphism is exploited extensively\r\n- Fusion is heavily based on caching. The fused kernels, the data dependency analysis etc, are all performed just once for identical sequences of loops\r\n\r\nRequired branches/PR:\r\n- PR 39 in coneoproject/COFFEE\r\n-  PR 492 in firedrakeproject/firedrake\r\n- PR 72 in bitbucket.org/mapdes/ffc","created_at":"2015-03-31T10:09:03Z","updated_at":"2015-04-02T08:24:31Z","closed_at":null,"merged_at":null,"merge_commit_sha":"cf64c798ef601f87daac8779b6f2073bfc9a7da8","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/OP2/PyOP2/pulls/432/commits","review_comments_url":"https://api.github.com/repos/OP2/PyOP2/pulls/432/comments","review_comment_url":"https://api.github.com/repos/OP2/PyOP2/pulls/comments{/number}","comments_url":"https://api.github.com/repos/OP2/PyOP2/issues/432/comments","statuses_url":"https://api.github.com/repos/OP2/PyOP2/statuses/829faae028818f84fb9f1bdb3e88f7e803852c27","head":{"label":"OP2:loopfusion","ref":"loopfusion","sha":"829faae028818f84fb9f1bdb3e88f7e803852c27","user":{"login":"OP2","id":1544411,"avatar_url":"https://avatars.githubusercontent.com/u/1544411?v=3","gravatar_id":"","url":"https://api.github.com/users/OP2","html_url":"https://github.com/OP2","followers_url":"https://api.github.com/users/OP2/followers","following_url":"https://api.github.com/users/OP2/following{/other_user}","gists_url":"https://api.github.com/users/OP2/gists{/gist_id}","starred_url":"https://api.github.com/users/OP2/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/OP2/subscriptions","organizations_url":"https://api.github.com/users/OP2/orgs","repos_url":"https://api.github.com/users/OP2/repos","events_url":"https://api.github.com/users/OP2/events{/privacy}","received_events_url":"https://api.github.com/users/OP2/received_events","type":"Organization","site_admin":false},"repo":{"id":4648505,"name":"PyOP2","full_name":"OP2/PyOP2","owner":{"login":"OP2","id":1544411,"avatar_url":"https://avatars.githubusercontent.com/u/1544411?v=3","gravatar_id":"","url":"https://api.github.com/users/OP2","html_url":"https://github.com/OP2","followers_url":"https://api.github.com/users/OP2/followers","following_url":"https://api.github.com/users/OP2/following{/other_user}","gists_url":"https://api.github.com/users/OP2/gists{/gist_id}","starred_url":"https://api.github.com/users/OP2/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/OP2/subscriptions","organizations_url":"https://api.github.com/users/OP2/orgs","repos_url":"https://api.github.com/users/OP2/repos","events_url":"https://api.github.com/users/OP2/events{/privacy}","received_events_url":"https://api.github.com/users/OP2/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/OP2/PyOP2","description":"Framework for performance-portable parallel computations on unstructured meshes","fork":false,"url":"https://api.github.com/repos/OP2/PyOP2","forks_url":"https://api.github.com/repos/OP2/PyOP2/forks","keys_url":"https://api.github.com/repos/OP2/PyOP2/keys{/key_id}","collaborators_url":"https://api.github.com/repos/OP2/PyOP2/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/OP2/PyOP2/teams","hooks_url":"https://api.github.com/repos/OP2/PyOP2/hooks","issue_events_url":"https://api.github.com/repos/OP2/PyOP2/issues/events{/number}","events_url":"https://api.github.com/repos/OP2/PyOP2/events","assignees_url":"https://api.github.com/repos/OP2/PyOP2/assignees{/user}","branches_url":"https://api.github.com/repos/OP2/PyOP2/branches{/branch}","tags_url":"https://api.github.com/repos/OP2/PyOP2/tags","blobs_url":"https://api.github.com/repos/OP2/PyOP2/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/OP2/PyOP2/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/OP2/PyOP2/git/refs{/sha}","trees_url":"https://api.github.com/repos/OP2/PyOP2/git/trees{/sha}","statuses_url":"https://api.github.com/repos/OP2/PyOP2/statuses/{sha}","languages_url":"https://api.github.com/repos/OP2/PyOP2/languages","stargazers_url":"https://api.github.com/repos/OP2/PyOP2/stargazers","contributors_url":"https://api.github.com/repos/OP2/PyOP2/contributors","subscribers_url":"https://api.github.com/repos/OP2/PyOP2/subscribers","subscription_url":"https://api.github.com/repos/OP2/PyOP2/subscription","commits_url":"https://api.github.com/repos/OP2/PyOP2/commits{/sha}","git_commits_url":"https://api.github.com/repos/OP2/PyOP2/git/commits{/sha}","comments_url":"https://api.github.com/repos/OP2/PyOP2/comments{/number}","issue_comment_url":"https://api.github.com/repos/OP2/PyOP2/issues/comments{/number}","contents_url":"https://api.github.com/repos/OP2/PyOP2/contents/{+path}","compare_url":"https://api.github.com/repos/OP2/PyOP2/compare/{base}...{head}","merges_url":"https://api.github.com/repos/OP2/PyOP2/merges","archive_url":"https://api.github.com/repos/OP2/PyOP2/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/OP2/PyOP2/downloads","issues_url":"https://api.github.com/repos/OP2/PyOP2/issues{/number}","pulls_url":"https://api.github.com/repos/OP2/PyOP2/pulls{/number}","milestones_url":"https://api.github.com/repos/OP2/PyOP2/milestones{/number}","notifications_url":"https://api.github.com/repos/OP2/PyOP2/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/OP2/PyOP2/labels{/name}","releases_url":"https://api.github.com/repos/OP2/PyOP2/releases{/id}","created_at":"2012-06-13T08:28:09Z","updated_at":"2015-04-01T10:27:17Z","pushed_at":"2015-04-01T10:27:15Z","git_url":"git://github.com/OP2/PyOP2.git","ssh_url":"git@github.com:OP2/PyOP2.git","clone_url":"https://github.com/OP2/PyOP2.git","svn_url":"https://github.com/OP2/PyOP2","homepage":"op2.github.com/PyOP2","size":18316,"stargazers_count":23,"watchers_count":23,"language":"Python","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":true,"forks_count":12,"mirror_url":null,"open_issues_count":32,"forks":12,"open_issues":32,"watchers":23,"default_branch":"master"}},"base":{"label":"OP2:master","ref":"master","sha":"a14e2e71ee7b75216bea6b5d1f466ce762d8acae","user":{"login":"OP2","id":1544411,"avatar_url":"https://avatars.githubusercontent.com/u/1544411?v=3","gravatar_id":"","url":"https://api.github.com/users/OP2","html_url":"https://github.com/OP2","followers_url":"https://api.github.com/users/OP2/followers","following_url":"https://api.github.com/users/OP2/following{/other_user}","gists_url":"https://api.github.com/users/OP2/gists{/gist_id}","starred_url":"https://api.github.com/users/OP2/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/OP2/subscriptions","organizations_url":"https://api.github.com/users/OP2/orgs","repos_url":"https://api.github.com/users/OP2/repos","events_url":"https://api.github.com/users/OP2/events{/privacy}","received_events_url":"https://api.github.com/users/OP2/received_events","type":"Organization","site_admin":false},"repo":{"id":4648505,"name":"PyOP2","full_name":"OP2/PyOP2","owner":{"login":"OP2","id":1544411,"avatar_url":"https://avatars.githubusercontent.com/u/1544411?v=3","gravatar_id":"","url":"https://api.github.com/users/OP2","html_url":"https://github.com/OP2","followers_url":"https://api.github.com/users/OP2/followers","following_url":"https://api.github.com/users/OP2/following{/other_user}","gists_url":"https://api.github.com/users/OP2/gists{/gist_id}","starred_url":"https://api.github.com/users/OP2/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/OP2/subscriptions","organizations_url":"https://api.github.com/users/OP2/orgs","repos_url":"https://api.github.com/users/OP2/repos","events_url":"https://api.github.com/users/OP2/events{/privacy}","received_events_url":"https://api.github.com/users/OP2/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/OP2/PyOP2","description":"Framework for performance-portable parallel computations on unstructured meshes","fork":false,"url":"https://api.github.com/repos/OP2/PyOP2","forks_url":"https://api.github.com/repos/OP2/PyOP2/forks","keys_url":"https://api.github.com/repos/OP2/PyOP2/keys{/key_id}","collaborators_url":"https://api.github.com/repos/OP2/PyOP2/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/OP2/PyOP2/teams","hooks_url":"https://api.github.com/repos/OP2/PyOP2/hooks","issue_events_url":"https://api.github.com/repos/OP2/PyOP2/issues/events{/number}","events_url":"https://api.github.com/repos/OP2/PyOP2/events","assignees_url":"https://api.github.com/repos/OP2/PyOP2/assignees{/user}","branches_url":"https://api.github.com/repos/OP2/PyOP2/branches{/branch}","tags_url":"https://api.github.com/repos/OP2/PyOP2/tags","blobs_url":"https://api.github.com/repos/OP2/PyOP2/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/OP2/PyOP2/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/OP2/PyOP2/git/refs{/sha}","trees_url":"https://api.github.com/repos/OP2/PyOP2/git/trees{/sha}","statuses_url":"https://api.github.com/repos/OP2/PyOP2/statuses/{sha}","languages_url":"https://api.github.com/repos/OP2/PyOP2/languages","stargazers_url":"https://api.github.com/repos/OP2/PyOP2/stargazers","contributors_url":"https://api.github.com/repos/OP2/PyOP2/contributors","subscribers_url":"https://api.github.com/repos/OP2/PyOP2/subscribers","subscription_url":"https://api.github.com/repos/OP2/PyOP2/subscription","commits_url":"https://api.github.com/repos/OP2/PyOP2/commits{/sha}","git_commits_url":"https://api.github.com/repos/OP2/PyOP2/git/commits{/sha}","comments_url":"https://api.github.com/repos/OP2/PyOP2/comments{/number}","issue_comment_url":"https://api.github.com/repos/OP2/PyOP2/issues/comments{/number}","contents_url":"https://api.github.com/repos/OP2/PyOP2/contents/{+path}","compare_url":"https://api.github.com/repos/OP2/PyOP2/compare/{base}...{head}","merges_url":"https://api.github.com/repos/OP2/PyOP2/merges","archive_url":"https://api.github.com/repos/OP2/PyOP2/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/OP2/PyOP2/downloads","issues_url":"https://api.github.com/repos/OP2/PyOP2/issues{/number}","pulls_url":"https://api.github.com/repos/OP2/PyOP2/pulls{/number}","milestones_url":"https://api.github.com/repos/OP2/PyOP2/milestones{/number}","notifications_url":"https://api.github.com/repos/OP2/PyOP2/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/OP2/PyOP2/labels{/name}","releases_url":"https://api.github.com/repos/OP2/PyOP2/releases{/id}","created_at":"2012-06-13T08:28:09Z","updated_at":"2015-04-01T10:27:17Z","pushed_at":"2015-04-01T10:27:15Z","git_url":"git://github.com/OP2/PyOP2.git","ssh_url":"git@github.com:OP2/PyOP2.git","clone_url":"https://github.com/OP2/PyOP2.git","svn_url":"https://github.com/OP2/PyOP2","homepage":"op2.github.com/PyOP2","size":18316,"stargazers_count":23,"watchers_count":23,"language":"Python","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":true,"forks_count":12,"mirror_url":null,"open_issues_count":32,"forks":12,"open_issues":32,"watchers":23,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/OP2/PyOP2/pulls/432"},"html":{"href":"https://github.com/OP2/PyOP2/pull/432"},"issue":{"href":"https://api.github.com/repos/OP2/PyOP2/issues/432"},"comments":{"href":"https://api.github.com/repos/OP2/PyOP2/issues/432/comments"},"review_comments":{"href":"https://api.github.com/repos/OP2/PyOP2/pulls/432/comments"},"review_comment":{"href":"https://api.github.com/repos/OP2/PyOP2/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/OP2/PyOP2/pulls/432/commits"},"statuses":{"href":"https://api.github.com/repos/OP2/PyOP2/statuses/829faae028818f84fb9f1bdb3e88f7e803852c27"}}}}