{"action":"created","comment":{"url":"https://api.github.com/repos/numba/numba/pulls/comments/53042911","id":53042911,"diff_hunk":"@@ -0,0 +1,177 @@\n+from numba.tracing import trace\n+import numpy\n+import sys\n+\n+def _o2s(dtype, shape, order):\n+    # convert order parameter to strides\n+\n+    if dtype is None or shape is None or order is None:\n+        return None\n+\n+    if order == 'F':\n+        shape = list(shape)\n+        shape.reverse()\n+    strides = []\n+    itemsize = dtype.itemsize\n+    for i in range(len(shape), 0, -1):\n+        strides.append(itemsize)\n+        itemsize *= shape[i - 1]\n+    if order in ('C', None):\n+        strides.reverse()\n+    return tuple(strides)\n+\n+def _s2o(dtype, shape, strides):\n+    # convert strides parameter to order\n+    # Note: strides must correspond to contiguous data layout\n+\n+    if strides is None or strides[-1] == dtype.itemsize:\n+        order = 'C'\n+    elif strides[0] == dtype.itemsize:\n+        order = 'F'\n+    else:\n+        raise Error('strides do not correspond to contiguous data layout')\n+    s2 = _o2s(dtype, shape, order)\n+    if strides != s2:\n+        raise Error('strides do not correspond to contiguous data layout')\n+    return order\n+\n+class Array:\n+    \"\"\"An array type that supports host and GPU storage.\"\"\"\n+\n+    def __init__(self, obj=None, copy=True,\n+                 shape=None, dtype=None, order=None, where='host'):\n+        \"\"\"Construct an Array in the memory space defined by 'where'.\"\"\"\n+\n+        assert where in ('host', 'gpu')\n+        # we need either a prototype or proper type info\n+        assert obj is not None or (shape and dtype)\n+        self._host = self._gpu = None\n+        self._host_valid = self._gpu_valid = False\n+        self._allocate(where, obj, dtype, shape, _o2s(dtype, shape, order), copy)\n+        if where == 'host':\n+            self._host_valid = True\n+            t = self._host\n+        else:\n+            self._gpu_valid = True\n+            t = self._gpu\n+        self.shape = t.shape\n+        self.strides = t.strides\n+        self.dtype = t.dtype\n+        self.ndim = t.ndim\n+        self.size = t.size\n+\n+    def host(self):\n+        \"\"\"Get a host array.\"\"\"\n+\n+        self._sync('host')\n+        #self._invalidate('gpu') # only if write-access is requested !\n+        return self._host\n+\n+    def host_changed(self):\n+        \"\"\"Mark the host array as changed, broadcast updates if needed.\"\"\"\n+\n+        self._invalidate('gpu')\n+        # only sync if there are active views\n+        if self._gpu is not None and sys.getrefcount(self._gpu) > 2:\n+            self._sync('gpu')\n+\n+    def gpu(self):\n+        \"\"\"Get a GPU array.\"\"\"\n+\n+        self._sync('gpu')\n+        #self._invalidate('host') # only if write-access is requested !\n+        return self._gpu\n+\n+    def gpu_changed(self):\n+        \"\"\"Mark the gpu array as changed, broadcast updates if needed.\"\"\"\n+\n+        self._invalidate('host')\n+        # only sync if there are active views\n+        if self._host is not None and sys.getrefcount(self._host) > 2:\n+            self._sync('host')\n+\n+    def __array__(self, *args):\n+\n+        self._sync('host')\n+        return numpy.array(self._host, *args)\n+\n+    def _sync(self, where):\n+        \"\"\"Sync the data in one memory space with the other.\"\"\"\n+\n+        if where == 'gpu':\n+            if self._gpu is None:\n+                self._allocate('gpu', None, self.dtype, self.shape, self.strides)\n+            if not self._gpu_valid:\n+                self._copy_to_gpu()\n+        else:\n+            if self._host is None:\n+                self._allocate('host', None, self.dtype, self.shape, self.strides)\n+            if not self._host_valid:\n+                self._copy_to_host()\n+\n+    @trace\n+    def _invalidate(self, where):\n+        \"\"\"Mark the host / device array as out-of-date.\"\"\"\n+\n+        if where == 'gpu':\n+            self._gpu_valid = False\n+        else:\n+            self._host_valid = False\n+\n+    @trace\n+    def _allocate(self, where, obj=None, dtype=None, shape=None, strides=None,\n+                  copy=True):\n+        if dtype:\n+            dtype = numpy.dtype(dtype)\n+        if where == 'host':\n+            if obj is not None:\n+                self._host = numpy.array(obj, dtype, copy=copy)\n+            else:\n+                self._host = numpy.empty(shape, dtype, _s2o(dtype, shape, strides))\n+        else:\n+            # Don't import this at module-scope as it may not be available\n+            # in all environments (e.g., CUDASIM)\n+            from numba.cuda.cudadrv import devicearray as da\n+            if obj is not None:\n+                # If 'obj' is an array-like object but not an ndarray,\n+                # construct an ndarray first to extract all the parameters we need.\n+                if not isinstance(obj, numpy.ndarray):\n+                    obj = numpy.array(obj, copy=False)\n+                self._gpu = da.from_array_like(obj)\n+            else:\n+                if strides is None:\n+                    strides = _o2s(dtype, shape, 'C')\n+                self._gpu = da.DeviceNDArray(shape, strides, dtype)\n+\n+    @trace\n+    def _copy_to_gpu(self):\n+        self._gpu.copy_to_device(self._host)\n+        self._gpu_valid = True\n+\n+    @trace\n+    def _copy_to_host(self):\n+        self._gpu.copy_to_host(self._host)\n+        self._host_valid = True\n+\n+    #def __hasattr__(self, attr):#\n+\n+    #    # forward all normal operations to the host array\n+    #    return self.host().__hasattr__(attr)\n+\n+    @trace\n+    def __getattr__(self, name):\n+        \"\"\"Transparently forward attribute access to the host array.\"\"\"\n+\n+        if self._host is None:\n+            self._allocate('host', None, self.dtype, self.shape, self.strides)\n+\n+        # FIXME: for some attributes we need to sync first !\n+        return getattr(self._host, name)\n+\n+    def __len__(self, *args): return self.size\n+    def __eq__(self, other):\n+        if type(self) is not type(other): return False\n+        # FIXME: If both arrays have valid GPU data, compare there.","path":"numba/array.py","position":174,"original_position":174,"commit_id":"2175d59a52954826871c2dd5916cffa256c14fe4","original_commit_id":"2175d59a52954826871c2dd5916cffa256c14fe4","user":{"login":"stuartarchibald","id":907717,"avatar_url":"https://avatars.githubusercontent.com/u/907717?v=3","gravatar_id":"","url":"https://api.github.com/users/stuartarchibald","html_url":"https://github.com/stuartarchibald","followers_url":"https://api.github.com/users/stuartarchibald/followers","following_url":"https://api.github.com/users/stuartarchibald/following{/other_user}","gists_url":"https://api.github.com/users/stuartarchibald/gists{/gist_id}","starred_url":"https://api.github.com/users/stuartarchibald/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/stuartarchibald/subscriptions","organizations_url":"https://api.github.com/users/stuartarchibald/orgs","repos_url":"https://api.github.com/users/stuartarchibald/repos","events_url":"https://api.github.com/users/stuartarchibald/events{/privacy}","received_events_url":"https://api.github.com/users/stuartarchibald/received_events","type":"User","site_admin":false},"body":"Ok. Great. I wasn't sure if `host()` implicitly caused the synchronisation.","created_at":"2016-02-16T17:11:39Z","updated_at":"2016-02-16T17:11:39Z","html_url":"https://github.com/numba/numba/pull/1676#discussion_r53042911","pull_request_url":"https://api.github.com/repos/numba/numba/pulls/1676","_links":{"self":{"href":"https://api.github.com/repos/numba/numba/pulls/comments/53042911"},"html":{"href":"https://github.com/numba/numba/pull/1676#discussion_r53042911"},"pull_request":{"href":"https://api.github.com/repos/numba/numba/pulls/1676"}}},"pull_request":{"url":"https://api.github.com/repos/numba/numba/pulls/1676","id":57505874,"html_url":"https://github.com/numba/numba/pull/1676","diff_url":"https://github.com/numba/numba/pull/1676.diff","patch_url":"https://github.com/numba/numba/pull/1676.patch","issue_url":"https://api.github.com/repos/numba/numba/issues/1676","number":1676,"state":"open","locked":false,"title":"First prototype.","user":{"login":"stefanseefeld","id":1243351,"avatar_url":"https://avatars.githubusercontent.com/u/1243351?v=3","gravatar_id":"","url":"https://api.github.com/users/stefanseefeld","html_url":"https://github.com/stefanseefeld","followers_url":"https://api.github.com/users/stefanseefeld/followers","following_url":"https://api.github.com/users/stefanseefeld/following{/other_user}","gists_url":"https://api.github.com/users/stefanseefeld/gists{/gist_id}","starred_url":"https://api.github.com/users/stefanseefeld/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/stefanseefeld/subscriptions","organizations_url":"https://api.github.com/users/stefanseefeld/orgs","repos_url":"https://api.github.com/users/stefanseefeld/repos","events_url":"https://api.github.com/users/stefanseefeld/events{/privacy}","received_events_url":"https://api.github.com/users/stefanseefeld/received_events","type":"User","site_admin":false},"body":"This is Work In Progress.\r\n\r\nThis is a prototype of a higher-level array type that encapsulates data allocation and movement between host and device. Data can thus be moved on-demand, to reduce overhead.","created_at":"2016-01-28T14:04:40Z","updated_at":"2016-02-16T17:11:39Z","closed_at":null,"merged_at":null,"merge_commit_sha":"9075d76a465c0acfea0e23a40a3362785a5f906a","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/numba/numba/pulls/1676/commits","review_comments_url":"https://api.github.com/repos/numba/numba/pulls/1676/comments","review_comment_url":"https://api.github.com/repos/numba/numba/pulls/comments{/number}","comments_url":"https://api.github.com/repos/numba/numba/issues/1676/comments","statuses_url":"https://api.github.com/repos/numba/numba/statuses/2175d59a52954826871c2dd5916cffa256c14fe4","head":{"label":"stefanseefeld:array","ref":"array","sha":"2175d59a52954826871c2dd5916cffa256c14fe4","user":{"login":"stefanseefeld","id":1243351,"avatar_url":"https://avatars.githubusercontent.com/u/1243351?v=3","gravatar_id":"","url":"https://api.github.com/users/stefanseefeld","html_url":"https://github.com/stefanseefeld","followers_url":"https://api.github.com/users/stefanseefeld/followers","following_url":"https://api.github.com/users/stefanseefeld/following{/other_user}","gists_url":"https://api.github.com/users/stefanseefeld/gists{/gist_id}","starred_url":"https://api.github.com/users/stefanseefeld/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/stefanseefeld/subscriptions","organizations_url":"https://api.github.com/users/stefanseefeld/orgs","repos_url":"https://api.github.com/users/stefanseefeld/repos","events_url":"https://api.github.com/users/stefanseefeld/events{/privacy}","received_events_url":"https://api.github.com/users/stefanseefeld/received_events","type":"User","site_admin":false},"repo":{"id":41437445,"name":"numba","full_name":"stefanseefeld/numba","owner":{"login":"stefanseefeld","id":1243351,"avatar_url":"https://avatars.githubusercontent.com/u/1243351?v=3","gravatar_id":"","url":"https://api.github.com/users/stefanseefeld","html_url":"https://github.com/stefanseefeld","followers_url":"https://api.github.com/users/stefanseefeld/followers","following_url":"https://api.github.com/users/stefanseefeld/following{/other_user}","gists_url":"https://api.github.com/users/stefanseefeld/gists{/gist_id}","starred_url":"https://api.github.com/users/stefanseefeld/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/stefanseefeld/subscriptions","organizations_url":"https://api.github.com/users/stefanseefeld/orgs","repos_url":"https://api.github.com/users/stefanseefeld/repos","events_url":"https://api.github.com/users/stefanseefeld/events{/privacy}","received_events_url":"https://api.github.com/users/stefanseefeld/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/stefanseefeld/numba","description":"NumPy aware dynamic Python compiler using LLVM","fork":true,"url":"https://api.github.com/repos/stefanseefeld/numba","forks_url":"https://api.github.com/repos/stefanseefeld/numba/forks","keys_url":"https://api.github.com/repos/stefanseefeld/numba/keys{/key_id}","collaborators_url":"https://api.github.com/repos/stefanseefeld/numba/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/stefanseefeld/numba/teams","hooks_url":"https://api.github.com/repos/stefanseefeld/numba/hooks","issue_events_url":"https://api.github.com/repos/stefanseefeld/numba/issues/events{/number}","events_url":"https://api.github.com/repos/stefanseefeld/numba/events","assignees_url":"https://api.github.com/repos/stefanseefeld/numba/assignees{/user}","branches_url":"https://api.github.com/repos/stefanseefeld/numba/branches{/branch}","tags_url":"https://api.github.com/repos/stefanseefeld/numba/tags","blobs_url":"https://api.github.com/repos/stefanseefeld/numba/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/stefanseefeld/numba/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/stefanseefeld/numba/git/refs{/sha}","trees_url":"https://api.github.com/repos/stefanseefeld/numba/git/trees{/sha}","statuses_url":"https://api.github.com/repos/stefanseefeld/numba/statuses/{sha}","languages_url":"https://api.github.com/repos/stefanseefeld/numba/languages","stargazers_url":"https://api.github.com/repos/stefanseefeld/numba/stargazers","contributors_url":"https://api.github.com/repos/stefanseefeld/numba/contributors","subscribers_url":"https://api.github.com/repos/stefanseefeld/numba/subscribers","subscription_url":"https://api.github.com/repos/stefanseefeld/numba/subscription","commits_url":"https://api.github.com/repos/stefanseefeld/numba/commits{/sha}","git_commits_url":"https://api.github.com/repos/stefanseefeld/numba/git/commits{/sha}","comments_url":"https://api.github.com/repos/stefanseefeld/numba/comments{/number}","issue_comment_url":"https://api.github.com/repos/stefanseefeld/numba/issues/comments{/number}","contents_url":"https://api.github.com/repos/stefanseefeld/numba/contents/{+path}","compare_url":"https://api.github.com/repos/stefanseefeld/numba/compare/{base}...{head}","merges_url":"https://api.github.com/repos/stefanseefeld/numba/merges","archive_url":"https://api.github.com/repos/stefanseefeld/numba/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/stefanseefeld/numba/downloads","issues_url":"https://api.github.com/repos/stefanseefeld/numba/issues{/number}","pulls_url":"https://api.github.com/repos/stefanseefeld/numba/pulls{/number}","milestones_url":"https://api.github.com/repos/stefanseefeld/numba/milestones{/number}","notifications_url":"https://api.github.com/repos/stefanseefeld/numba/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/stefanseefeld/numba/labels{/name}","releases_url":"https://api.github.com/repos/stefanseefeld/numba/releases{/id}","deployments_url":"https://api.github.com/repos/stefanseefeld/numba/deployments","created_at":"2015-08-26T16:42:33Z","updated_at":"2016-01-22T01:37:01Z","pushed_at":"2016-02-16T13:40:29Z","git_url":"git://github.com/stefanseefeld/numba.git","ssh_url":"git@github.com:stefanseefeld/numba.git","clone_url":"https://github.com/stefanseefeld/numba.git","svn_url":"https://github.com/stefanseefeld/numba","homepage":"http://numba.pydata.org/","size":27098,"stargazers_count":0,"watchers_count":0,"language":"Python","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":"numba:master","ref":"master","sha":"656ae59668fd8a06af0c363b1ab017afc906bbc7","user":{"login":"numba","id":1628082,"avatar_url":"https://avatars.githubusercontent.com/u/1628082?v=3","gravatar_id":"","url":"https://api.github.com/users/numba","html_url":"https://github.com/numba","followers_url":"https://api.github.com/users/numba/followers","following_url":"https://api.github.com/users/numba/following{/other_user}","gists_url":"https://api.github.com/users/numba/gists{/gist_id}","starred_url":"https://api.github.com/users/numba/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/numba/subscriptions","organizations_url":"https://api.github.com/users/numba/orgs","repos_url":"https://api.github.com/users/numba/repos","events_url":"https://api.github.com/users/numba/events{/privacy}","received_events_url":"https://api.github.com/users/numba/received_events","type":"Organization","site_admin":false},"repo":{"id":3659275,"name":"numba","full_name":"numba/numba","owner":{"login":"numba","id":1628082,"avatar_url":"https://avatars.githubusercontent.com/u/1628082?v=3","gravatar_id":"","url":"https://api.github.com/users/numba","html_url":"https://github.com/numba","followers_url":"https://api.github.com/users/numba/followers","following_url":"https://api.github.com/users/numba/following{/other_user}","gists_url":"https://api.github.com/users/numba/gists{/gist_id}","starred_url":"https://api.github.com/users/numba/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/numba/subscriptions","organizations_url":"https://api.github.com/users/numba/orgs","repos_url":"https://api.github.com/users/numba/repos","events_url":"https://api.github.com/users/numba/events{/privacy}","received_events_url":"https://api.github.com/users/numba/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/numba/numba","description":"NumPy aware dynamic Python compiler using LLVM","fork":false,"url":"https://api.github.com/repos/numba/numba","forks_url":"https://api.github.com/repos/numba/numba/forks","keys_url":"https://api.github.com/repos/numba/numba/keys{/key_id}","collaborators_url":"https://api.github.com/repos/numba/numba/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/numba/numba/teams","hooks_url":"https://api.github.com/repos/numba/numba/hooks","issue_events_url":"https://api.github.com/repos/numba/numba/issues/events{/number}","events_url":"https://api.github.com/repos/numba/numba/events","assignees_url":"https://api.github.com/repos/numba/numba/assignees{/user}","branches_url":"https://api.github.com/repos/numba/numba/branches{/branch}","tags_url":"https://api.github.com/repos/numba/numba/tags","blobs_url":"https://api.github.com/repos/numba/numba/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/numba/numba/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/numba/numba/git/refs{/sha}","trees_url":"https://api.github.com/repos/numba/numba/git/trees{/sha}","statuses_url":"https://api.github.com/repos/numba/numba/statuses/{sha}","languages_url":"https://api.github.com/repos/numba/numba/languages","stargazers_url":"https://api.github.com/repos/numba/numba/stargazers","contributors_url":"https://api.github.com/repos/numba/numba/contributors","subscribers_url":"https://api.github.com/repos/numba/numba/subscribers","subscription_url":"https://api.github.com/repos/numba/numba/subscription","commits_url":"https://api.github.com/repos/numba/numba/commits{/sha}","git_commits_url":"https://api.github.com/repos/numba/numba/git/commits{/sha}","comments_url":"https://api.github.com/repos/numba/numba/comments{/number}","issue_comment_url":"https://api.github.com/repos/numba/numba/issues/comments{/number}","contents_url":"https://api.github.com/repos/numba/numba/contents/{+path}","compare_url":"https://api.github.com/repos/numba/numba/compare/{base}...{head}","merges_url":"https://api.github.com/repos/numba/numba/merges","archive_url":"https://api.github.com/repos/numba/numba/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/numba/numba/downloads","issues_url":"https://api.github.com/repos/numba/numba/issues{/number}","pulls_url":"https://api.github.com/repos/numba/numba/pulls{/number}","milestones_url":"https://api.github.com/repos/numba/numba/milestones{/number}","notifications_url":"https://api.github.com/repos/numba/numba/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/numba/numba/labels{/name}","releases_url":"https://api.github.com/repos/numba/numba/releases{/id}","deployments_url":"https://api.github.com/repos/numba/numba/deployments","created_at":"2012-03-08T11:12:43Z","updated_at":"2016-02-16T13:02:03Z","pushed_at":"2016-02-16T16:33:57Z","git_url":"git://github.com/numba/numba.git","ssh_url":"git@github.com:numba/numba.git","clone_url":"https://github.com/numba/numba.git","svn_url":"https://github.com/numba/numba","homepage":"http://numba.pydata.org/","size":27797,"stargazers_count":1730,"watchers_count":1730,"language":"Python","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":true,"forks_count":189,"mirror_url":null,"open_issues_count":194,"forks":189,"open_issues":194,"watchers":1730,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/numba/numba/pulls/1676"},"html":{"href":"https://github.com/numba/numba/pull/1676"},"issue":{"href":"https://api.github.com/repos/numba/numba/issues/1676"},"comments":{"href":"https://api.github.com/repos/numba/numba/issues/1676/comments"},"review_comments":{"href":"https://api.github.com/repos/numba/numba/pulls/1676/comments"},"review_comment":{"href":"https://api.github.com/repos/numba/numba/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/numba/numba/pulls/1676/commits"},"statuses":{"href":"https://api.github.com/repos/numba/numba/statuses/2175d59a52954826871c2dd5916cffa256c14fe4"}}}}