Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
96 changes: 94 additions & 2 deletions arraycontext/impl/pytato/__init__.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -54,15 +54,21 @@
from arraycontext.container.traversal import (rec_map_array_container,
with_array_context)
from arraycontext.metadata import NameHint
from pytools import memoize_method

if TYPE_CHECKING:
import pytato
import pyopencl as cl
import loopy as lp

if getattr(sys, "_BUILDING_SPHINX_DOCS", False):
import pyopencl as cl # noqa: F811


import logging
logger = logging.getLogger(__name__)


# {{{ tag conversion

def _preprocess_array_tags(tags: ToTagSetConvertible) -> FrozenSet[Tag]:
Expand DownExpand Up@@ -203,13 +209,30 @@ def supports_nonscalar_broadcasting(self):
def permits_advanced_indexing(self):
return True

def get_target(self):
return None

# }}}

# }}}


# {{{ PytatoPyOpenCLArrayContext

from pytato.target.loopy import LoopyPyOpenCLTarget


class _ArgSizeLimitingPytatoLoopyPyOpenCLTarget(LoopyPyOpenCLTarget):
def __init__(self, limit_arg_size_nbytes: int) -> None:
super().__init__()
self.limit_arg_size_nbytes = limit_arg_size_nbytes

@memoize_method
def get_loopy_target(self) -> Optional["lp.PyOpenCLTarget"]:
from loopy import PyOpenCLTarget
return PyOpenCLTarget(limit_arg_size_nbytes=self.limit_arg_size_nbytes)


class PytatoPyOpenCLArrayContext(_BasePytatoArrayContext):
"""
A :class:`ArrayContext` that uses :mod:`pytato` data types to represent
Expand All@@ -232,7 +255,11 @@ class PytatoPyOpenCLArrayContext(_BasePytatoArrayContext):
"""
def __init__(
self, queue: "cl.CommandQueue", allocator=None, *,
compile_trace_callback: Optional[Callable[[Any, str, Any], None]] = None
use_memory_pool: Optional[bool] = None,
compile_trace_callback: Optional[Callable[[Any, str, Any], None]] = None,

# do not use: only for testing
_force_svm_arg_limit: Optional[int] = None,
) -> None:
"""
:arg compile_trace_callback: A function of three arguments
Expand All@@ -242,16 +269,57 @@ def __init__(
representation. This interface should be considered
unstable.
"""
if allocator is not None and use_memory_pool is not None:
raise TypeError("may not specify both allocator and use_memory_pool")

self.using_svm = None

if allocator is None:
from pyopencl.characterize import has_coarse_grain_buffer_svm
has_svm = has_coarse_grain_buffer_svm(queue.device)
if has_svm:
self.using_svm = True

from pyopencl.tools import SVMAllocator
allocator = SVMAllocator(queue.context, queue=queue)

if use_memory_pool:
from pyopencl.tools import SVMPool
allocator = SVMPool(allocator)
else:
self.using_svm = False

from pyopencl.tools import ImmediateAllocator
allocator = ImmediateAllocator(queue.context)

if use_memory_pool:
from pyopencl.tools import MemoryPool
allocator = MemoryPool(allocator)
else:
# Check whether the passed allocator allocates SVM
try:
from pyopencl import SVMPointer
mem = allocator(4)
if isinstance(mem, SVMPointer):
self.using_svm = True
else:
self.using_svm = False
except ImportError:
self.using_svm = False

import pytato as pt
import pyopencl.array as cla
super().__init__(compile_trace_callback=compile_trace_callback)
self.queue = queue

self.allocator = allocator
self.array_types = (pt.Array, cla.Array)

# unused, but necessary to keep the context alive
self.context = self.queue.context

self._force_svm_arg_limit = _force_svm_arg_limit

@property
def _frozen_array_types(self) -> Tuple[Type, ...]:
import pyopencl.array as cla
Expand DownExpand Up@@ -321,6 +389,29 @@ def _to_numpy(ary):
self._rec_map_container(_to_numpy, self.freeze(array)),
actx=None)

@memoize_method
def get_target(self):
import pyopencl as cl
import pyopencl.characterize as cl_char

dev = self.queue.device

if (
self._force_svm_arg_limit is not None
or (
self.using_svm and dev.type & cl.device_type.GPU
and cl_char.has_coarse_grain_buffer_svm(dev))):

limit = dev.max_parameter_size
if self._force_svm_arg_limit is not None:
limit = self._force_svm_arg_limit

logger.info(f"limiting argument buffer size for {dev} to {limit} bytes")

return _ArgSizeLimitingPytatoLoopyPyOpenCLTarget(limit)
else:
return super().get_target()

def freeze(self, array):
if np.isscalar(array):
return array
Expand DownExpand Up@@ -415,7 +506,8 @@ def _record_leaf_ary_in_dict(
pt_prg = pt.generate_loopy(transformed_dag,
options=_DEFAULT_LOOPY_OPTIONS,
cl_device=self.queue.device,
function_name=function_name)
function_name=function_name,
target=self.get_target())
pt_prg = pt_prg.with_transformed_program(self.transform_loopy_program)
self._freeze_prg_cache[normalized_expr] = pt_prg
else:
Expand Down
4 changes: 3 additions & 1 deletion arraycontext/impl/pytato/compile.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -420,7 +420,9 @@ def _dag_to_transformed_pytato_prg(self, dict_of_named_arrays, *, prg_id=None):
options=lp.Options(
return_dict=True,
no_numpy=True),
function_name=_prg_id_to_kernel_name(prg_id))
function_name=_prg_id_to_kernel_name(prg_id),
Comment thread
inducer marked this conversation as resolved.
target=self.actx.get_target(),
)
assert isinstance(pytato_program, BoundPyOpenCLProgram)

self.actx._compile_trace_callback(
Expand Down
21 changes: 21 additions & 0 deletions test/test_pytato_arraycontext.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -100,6 +100,27 @@ def test_tags_preserved_after_freeze(actx_factory):
assert foo.axes[1].tags_of_type(BazTag)


def test_arg_size_limit(actx_factory):
ran_callback = False

def my_ctc(what, stage, ir):
if stage == "final":
assert ir.target.limit_arg_size_nbytes == 42
nonlocal ran_callback
ran_callback = True

def twice(x):
return 2 * x

actx = _PytatoPyOpenCLArrayContextForTests(
actx_factory().queue, compile_trace_callback=my_ctc, _force_svm_arg_limit=42)

f = actx.compile(twice)
f(99)

assert ran_callback


if __name__ == "__main__":
import sys
if len(sys.argv) > 1:
Expand Down
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all \u003cpre\u003e\u003ccode\u003e blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks"); } } catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); } })(); (function(){ try { var __m = "github.com"; var __re = new RegExp('^' + "github\\.com" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
96 changes: 94 additions & 2 deletions arraycontext/impl/pytato/__init__.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -54,15 +54,21 @@
from arraycontext.container.traversal import (rec_map_array_container,
with_array_context)
from arraycontext.metadata import NameHint
from pytools import memoize_method

if TYPE_CHECKING:
import pytato
import pyopencl as cl
import loopy as lp

if getattr(sys, "_BUILDING_SPHINX_DOCS", False):
import pyopencl as cl # noqa: F811


import logging
logger = logging.getLogger(__name__)


# {{{ tag conversion

def _preprocess_array_tags(tags: ToTagSetConvertible) -> FrozenSet[Tag]:
Expand DownExpand Up@@ -203,13 +209,30 @@ def supports_nonscalar_broadcasting(self):
def permits_advanced_indexing(self):
return True

def get_target(self):
return None

# }}}

# }}}


# {{{ PytatoPyOpenCLArrayContext

from pytato.target.loopy import LoopyPyOpenCLTarget


class _ArgSizeLimitingPytatoLoopyPyOpenCLTarget(LoopyPyOpenCLTarget):
def __init__(self, limit_arg_size_nbytes: int) -> None:
super().__init__()
self.limit_arg_size_nbytes = limit_arg_size_nbytes

@memoize_method
def get_loopy_target(self) -> Optional["lp.PyOpenCLTarget"]:
from loopy import PyOpenCLTarget
return PyOpenCLTarget(limit_arg_size_nbytes=self.limit_arg_size_nbytes)


class PytatoPyOpenCLArrayContext(_BasePytatoArrayContext):
"""
A :class:`ArrayContext` that uses :mod:`pytato` data types to represent
Expand All@@ -232,7 +255,11 @@ class PytatoPyOpenCLArrayContext(_BasePytatoArrayContext):
"""
def __init__(
self, queue: "cl.CommandQueue", allocator=None, *,
compile_trace_callback: Optional[Callable[[Any, str, Any], None]] = None
use_memory_pool: Optional[bool] = None,
compile_trace_callback: Optional[Callable[[Any, str, Any], None]] = None,

# do not use: only for testing
_force_svm_arg_limit: Optional[int] = None,
) -> None:
"""
:arg compile_trace_callback: A function of three arguments
Expand All@@ -242,16 +269,57 @@ def __init__(
representation. This interface should be considered
unstable.
"""
if allocator is not None and use_memory_pool is not None:
raise TypeError("may not specify both allocator and use_memory_pool")

self.using_svm = None

if allocator is None:
from pyopencl.characterize import has_coarse_grain_buffer_svm
has_svm = has_coarse_grain_buffer_svm(queue.device)
if has_svm:
self.using_svm = True

from pyopencl.tools import SVMAllocator
allocator = SVMAllocator(queue.context, queue=queue)

if use_memory_pool:
from pyopencl.tools import SVMPool
allocator = SVMPool(allocator)
else:
self.using_svm = False

from pyopencl.tools import ImmediateAllocator
allocator = ImmediateAllocator(queue.context)

if use_memory_pool:
from pyopencl.tools import MemoryPool
allocator = MemoryPool(allocator)
else:
# Check whether the passed allocator allocates SVM
try:
from pyopencl import SVMPointer
mem = allocator(4)
if isinstance(mem, SVMPointer):
self.using_svm = True
else:
self.using_svm = False
except ImportError:
self.using_svm = False

import pytato as pt
import pyopencl.array as cla
super().__init__(compile_trace_callback=compile_trace_callback)
self.queue = queue

self.allocator = allocator
self.array_types = (pt.Array, cla.Array)

# unused, but necessary to keep the context alive
self.context = self.queue.context

self._force_svm_arg_limit = _force_svm_arg_limit

@property
def _frozen_array_types(self) -> Tuple[Type, ...]:
import pyopencl.array as cla
Expand DownExpand Up@@ -321,6 +389,29 @@ def _to_numpy(ary):
self._rec_map_container(_to_numpy, self.freeze(array)),
actx=None)

@memoize_method
def get_target(self):
import pyopencl as cl
import pyopencl.characterize as cl_char

dev = self.queue.device

if (
self._force_svm_arg_limit is not None
or (
self.using_svm and dev.type & cl.device_type.GPU
and cl_char.has_coarse_grain_buffer_svm(dev))):

limit = dev.max_parameter_size
if self._force_svm_arg_limit is not None:
limit = self._force_svm_arg_limit

logger.info(f"limiting argument buffer size for {dev} to {limit} bytes")

return _ArgSizeLimitingPytatoLoopyPyOpenCLTarget(limit)
else:
return super().get_target()

def freeze(self, array):
if np.isscalar(array):
return array
Expand DownExpand Up@@ -415,7 +506,8 @@ def _record_leaf_ary_in_dict(
pt_prg = pt.generate_loopy(transformed_dag,
options=_DEFAULT_LOOPY_OPTIONS,
cl_device=self.queue.device,
function_name=function_name)
function_name=function_name,
target=self.get_target())
pt_prg = pt_prg.with_transformed_program(self.transform_loopy_program)
self._freeze_prg_cache[normalized_expr] = pt_prg
else:
Expand Down
4 changes: 3 additions & 1 deletion arraycontext/impl/pytato/compile.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -420,7 +420,9 @@ def _dag_to_transformed_pytato_prg(self, dict_of_named_arrays, *, prg_id=None):
options=lp.Options(
return_dict=True,
no_numpy=True),
function_name=_prg_id_to_kernel_name(prg_id))
function_name=_prg_id_to_kernel_name(prg_id),
Comment thread
inducer marked this conversation as resolved.
target=self.actx.get_target(),
)
assert isinstance(pytato_program, BoundPyOpenCLProgram)

self.actx._compile_trace_callback(
Expand Down
21 changes: 21 additions & 0 deletions test/test_pytato_arraycontext.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -100,6 +100,27 @@ def test_tags_preserved_after_freeze(actx_factory):
assert foo.axes[1].tags_of_type(BazTag)


def test_arg_size_limit(actx_factory):
ran_callback = False

def my_ctc(what, stage, ir):
if stage == "final":
assert ir.target.limit_arg_size_nbytes == 42
nonlocal ran_callback
ran_callback = True

def twice(x):
return 2 * x

actx = _PytatoPyOpenCLArrayContextForTests(
actx_factory().queue, compile_trace_callback=my_ctc, _force_svm_arg_limit=42)

f = actx.compile(twice)
f(99)

assert ran_callback


if __name__ == "__main__":
import sys
if len(sys.argv) > 1:
Expand Down
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
96 changes: 94 additions & 2 deletions arraycontext/impl/pytato/__init__.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -54,15 +54,21 @@
from arraycontext.container.traversal import (rec_map_array_container,
with_array_context)
from arraycontext.metadata import NameHint
from pytools import memoize_method

if TYPE_CHECKING:
import pytato
import pyopencl as cl
import loopy as lp

if getattr(sys, "_BUILDING_SPHINX_DOCS", False):
import pyopencl as cl # noqa: F811


import logging
logger = logging.getLogger(__name__)


# {{{ tag conversion

def _preprocess_array_tags(tags: ToTagSetConvertible) -> FrozenSet[Tag]:
Expand DownExpand Up@@ -203,13 +209,30 @@ def supports_nonscalar_broadcasting(self):
def permits_advanced_indexing(self):
return True

def get_target(self):
return None

# }}}

# }}}


# {{{ PytatoPyOpenCLArrayContext

from pytato.target.loopy import LoopyPyOpenCLTarget


class _ArgSizeLimitingPytatoLoopyPyOpenCLTarget(LoopyPyOpenCLTarget):
def __init__(self, limit_arg_size_nbytes: int) -> None:
super().__init__()
self.limit_arg_size_nbytes = limit_arg_size_nbytes

@memoize_method
def get_loopy_target(self) -> Optional["lp.PyOpenCLTarget"]:
from loopy import PyOpenCLTarget
return PyOpenCLTarget(limit_arg_size_nbytes=self.limit_arg_size_nbytes)


class PytatoPyOpenCLArrayContext(_BasePytatoArrayContext):
"""
A :class:`ArrayContext` that uses :mod:`pytato` data types to represent
Expand All@@ -232,7 +255,11 @@ class PytatoPyOpenCLArrayContext(_BasePytatoArrayContext):
"""
def __init__(
self, queue: "cl.CommandQueue", allocator=None, *,
compile_trace_callback: Optional[Callable[[Any, str, Any], None]] = None
use_memory_pool: Optional[bool] = None,
compile_trace_callback: Optional[Callable[[Any, str, Any], None]] = None,

# do not use: only for testing
_force_svm_arg_limit: Optional[int] = None,
) -> None:
"""
:arg compile_trace_callback: A function of three arguments
Expand All@@ -242,16 +269,57 @@ def __init__(
representation. This interface should be considered
unstable.
"""
if allocator is not None and use_memory_pool is not None:
raise TypeError("may not specify both allocator and use_memory_pool")

self.using_svm = None

if allocator is None:
from pyopencl.characterize import has_coarse_grain_buffer_svm
has_svm = has_coarse_grain_buffer_svm(queue.device)
if has_svm:
self.using_svm = True

from pyopencl.tools import SVMAllocator
allocator = SVMAllocator(queue.context, queue=queue)

if use_memory_pool:
from pyopencl.tools import SVMPool
allocator = SVMPool(allocator)
else:
self.using_svm = False

from pyopencl.tools import ImmediateAllocator
allocator = ImmediateAllocator(queue.context)

if use_memory_pool:
from pyopencl.tools import MemoryPool
allocator = MemoryPool(allocator)
else:
# Check whether the passed allocator allocates SVM
try:
from pyopencl import SVMPointer
mem = allocator(4)
if isinstance(mem, SVMPointer):
self.using_svm = True
else:
self.using_svm = False
except ImportError:
self.using_svm = False

import pytato as pt
import pyopencl.array as cla
super().__init__(compile_trace_callback=compile_trace_callback)
self.queue = queue

self.allocator = allocator
self.array_types = (pt.Array, cla.Array)

# unused, but necessary to keep the context alive
self.context = self.queue.context

self._force_svm_arg_limit = _force_svm_arg_limit

@property
def _frozen_array_types(self) -> Tuple[Type, ...]:
import pyopencl.array as cla
Expand DownExpand Up@@ -321,6 +389,29 @@ def _to_numpy(ary):
self._rec_map_container(_to_numpy, self.freeze(array)),
actx=None)

@memoize_method
def get_target(self):
import pyopencl as cl
import pyopencl.characterize as cl_char

dev = self.queue.device

if (
self._force_svm_arg_limit is not None
or (
self.using_svm and dev.type & cl.device_type.GPU
and cl_char.has_coarse_grain_buffer_svm(dev))):

limit = dev.max_parameter_size
if self._force_svm_arg_limit is not None:
limit = self._force_svm_arg_limit

logger.info(f"limiting argument buffer size for {dev} to {limit} bytes")

return _ArgSizeLimitingPytatoLoopyPyOpenCLTarget(limit)
else:
return super().get_target()

def freeze(self, array):
if np.isscalar(array):
return array
Expand DownExpand Up@@ -415,7 +506,8 @@ def _record_leaf_ary_in_dict(
pt_prg = pt.generate_loopy(transformed_dag,
options=_DEFAULT_LOOPY_OPTIONS,
cl_device=self.queue.device,
function_name=function_name)
function_name=function_name,
target=self.get_target())
pt_prg = pt_prg.with_transformed_program(self.transform_loopy_program)
self._freeze_prg_cache[normalized_expr] = pt_prg
else:
Expand Down
4 changes: 3 additions & 1 deletion arraycontext/impl/pytato/compile.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -420,7 +420,9 @@ def _dag_to_transformed_pytato_prg(self, dict_of_named_arrays, *, prg_id=None):
options=lp.Options(
return_dict=True,
no_numpy=True),
function_name=_prg_id_to_kernel_name(prg_id))
function_name=_prg_id_to_kernel_name(prg_id),
Comment thread
inducer marked this conversation as resolved.
target=self.actx.get_target(),
)
assert isinstance(pytato_program, BoundPyOpenCLProgram)

self.actx._compile_trace_callback(
Expand Down
21 changes: 21 additions & 0 deletions test/test_pytato_arraycontext.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -100,6 +100,27 @@ def test_tags_preserved_after_freeze(actx_factory):
assert foo.axes[1].tags_of_type(BazTag)


def test_arg_size_limit(actx_factory):
ran_callback = False

def my_ctc(what, stage, ir):
if stage == "final":
assert ir.target.limit_arg_size_nbytes == 42
nonlocal ran_callback
ran_callback = True

def twice(x):
return 2 * x

actx = _PytatoPyOpenCLArrayContextForTests(
actx_factory().queue, compile_trace_callback=my_ctc, _force_svm_arg_limit=42)

f = actx.compile(twice)
f(99)

assert ran_callback


if __name__ == "__main__":
import sys
if len(sys.argv) > 1:
Expand Down
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length \u003e 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
96 changes: 94 additions & 2 deletions arraycontext/impl/pytato/__init__.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -54,15 +54,21 @@
from arraycontext.container.traversal import (rec_map_array_container,
with_array_context)
from arraycontext.metadata import NameHint
from pytools import memoize_method

if TYPE_CHECKING:
import pytato
import pyopencl as cl
import loopy as lp

if getattr(sys, "_BUILDING_SPHINX_DOCS", False):
import pyopencl as cl # noqa: F811


import logging
logger = logging.getLogger(__name__)


# {{{ tag conversion

def _preprocess_array_tags(tags: ToTagSetConvertible) -> FrozenSet[Tag]:
Expand DownExpand Up@@ -203,13 +209,30 @@ def supports_nonscalar_broadcasting(self):
def permits_advanced_indexing(self):
return True

def get_target(self):
return None

# }}}

# }}}


# {{{ PytatoPyOpenCLArrayContext

from pytato.target.loopy import LoopyPyOpenCLTarget


class _ArgSizeLimitingPytatoLoopyPyOpenCLTarget(LoopyPyOpenCLTarget):
def __init__(self, limit_arg_size_nbytes: int) -> None:
super().__init__()
self.limit_arg_size_nbytes = limit_arg_size_nbytes

@memoize_method
def get_loopy_target(self) -> Optional["lp.PyOpenCLTarget"]:
from loopy import PyOpenCLTarget
return PyOpenCLTarget(limit_arg_size_nbytes=self.limit_arg_size_nbytes)


class PytatoPyOpenCLArrayContext(_BasePytatoArrayContext):
"""
A :class:`ArrayContext` that uses :mod:`pytato` data types to represent
Expand All@@ -232,7 +255,11 @@ class PytatoPyOpenCLArrayContext(_BasePytatoArrayContext):
"""
def __init__(
self, queue: "cl.CommandQueue", allocator=None, *,
compile_trace_callback: Optional[Callable[[Any, str, Any], None]] = None
use_memory_pool: Optional[bool] = None,
compile_trace_callback: Optional[Callable[[Any, str, Any], None]] = None,

# do not use: only for testing
_force_svm_arg_limit: Optional[int] = None,
) -> None:
"""
:arg compile_trace_callback: A function of three arguments
Expand All@@ -242,16 +269,57 @@ def __init__(
representation. This interface should be considered
unstable.
"""
if allocator is not None and use_memory_pool is not None:
raise TypeError("may not specify both allocator and use_memory_pool")

self.using_svm = None

if allocator is None:
from pyopencl.characterize import has_coarse_grain_buffer_svm
has_svm = has_coarse_grain_buffer_svm(queue.device)
if has_svm:
self.using_svm = True

from pyopencl.tools import SVMAllocator
allocator = SVMAllocator(queue.context, queue=queue)

if use_memory_pool:
from pyopencl.tools import SVMPool
allocator = SVMPool(allocator)
else:
self.using_svm = False

from pyopencl.tools import ImmediateAllocator
allocator = ImmediateAllocator(queue.context)

if use_memory_pool:
from pyopencl.tools import MemoryPool
allocator = MemoryPool(allocator)
else:
# Check whether the passed allocator allocates SVM
try:
from pyopencl import SVMPointer
mem = allocator(4)
if isinstance(mem, SVMPointer):
self.using_svm = True
else:
self.using_svm = False
except ImportError:
self.using_svm = False

import pytato as pt
import pyopencl.array as cla
super().__init__(compile_trace_callback=compile_trace_callback)
self.queue = queue

self.allocator = allocator
self.array_types = (pt.Array, cla.Array)

# unused, but necessary to keep the context alive
self.context = self.queue.context

self._force_svm_arg_limit = _force_svm_arg_limit

@property
def _frozen_array_types(self) -> Tuple[Type, ...]:
import pyopencl.array as cla
Expand DownExpand Up@@ -321,6 +389,29 @@ def _to_numpy(ary):
self._rec_map_container(_to_numpy, self.freeze(array)),
actx=None)

@memoize_method
def get_target(self):
import pyopencl as cl
import pyopencl.characterize as cl_char

dev = self.queue.device

if (
self._force_svm_arg_limit is not None
or (
self.using_svm and dev.type & cl.device_type.GPU
and cl_char.has_coarse_grain_buffer_svm(dev))):

limit = dev.max_parameter_size
if self._force_svm_arg_limit is not None:
limit = self._force_svm_arg_limit

logger.info(f"limiting argument buffer size for {dev} to {limit} bytes")

return _ArgSizeLimitingPytatoLoopyPyOpenCLTarget(limit)
else:
return super().get_target()

def freeze(self, array):
if np.isscalar(array):
return array
Expand DownExpand Up@@ -415,7 +506,8 @@ def _record_leaf_ary_in_dict(
pt_prg = pt.generate_loopy(transformed_dag,
options=_DEFAULT_LOOPY_OPTIONS,
cl_device=self.queue.device,
function_name=function_name)
function_name=function_name,
target=self.get_target())
pt_prg = pt_prg.with_transformed_program(self.transform_loopy_program)
self._freeze_prg_cache[normalized_expr] = pt_prg
else:
Expand Down
4 changes: 3 additions & 1 deletion arraycontext/impl/pytato/compile.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -420,7 +420,9 @@ def _dag_to_transformed_pytato_prg(self, dict_of_named_arrays, *, prg_id=None):
options=lp.Options(
return_dict=True,
no_numpy=True),
function_name=_prg_id_to_kernel_name(prg_id))
function_name=_prg_id_to_kernel_name(prg_id),
Comment thread
inducer marked this conversation as resolved.
target=self.actx.get_target(),
)
assert isinstance(pytato_program, BoundPyOpenCLProgram)

self.actx._compile_trace_callback(
Expand Down
21 changes: 21 additions & 0 deletions test/test_pytato_arraycontext.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -100,6 +100,27 @@ def test_tags_preserved_after_freeze(actx_factory):
assert foo.axes[1].tags_of_type(BazTag)


def test_arg_size_limit(actx_factory):
ran_callback = False

def my_ctc(what, stage, ir):
if stage == "final":
assert ir.target.limit_arg_size_nbytes == 42
nonlocal ran_callback
ran_callback = True

def twice(x):
return 2 * x

actx = _PytatoPyOpenCLArrayContextForTests(
actx_factory().queue, compile_trace_callback=my_ctc, _force_svm_arg_limit=42)

f = actx.compile(twice)
f(99)

assert ran_callback


if __name__ == "__main__":
import sys
if len(sys.argv) > 1:
Expand Down
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
96 changes: 94 additions & 2 deletions arraycontext/impl/pytato/__init__.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -54,15 +54,21 @@
from arraycontext.container.traversal import (rec_map_array_container,
with_array_context)
from arraycontext.metadata import NameHint
from pytools import memoize_method

if TYPE_CHECKING:
import pytato
import pyopencl as cl
import loopy as lp

if getattr(sys, "_BUILDING_SPHINX_DOCS", False):
import pyopencl as cl # noqa: F811


import logging
logger = logging.getLogger(__name__)


# {{{ tag conversion

def _preprocess_array_tags(tags: ToTagSetConvertible) -> FrozenSet[Tag]:
Expand DownExpand Up@@ -203,13 +209,30 @@ def supports_nonscalar_broadcasting(self):
def permits_advanced_indexing(self):
return True

def get_target(self):
return None

# }}}

# }}}


# {{{ PytatoPyOpenCLArrayContext

from pytato.target.loopy import LoopyPyOpenCLTarget


class _ArgSizeLimitingPytatoLoopyPyOpenCLTarget(LoopyPyOpenCLTarget):
def __init__(self, limit_arg_size_nbytes: int) -> None:
super().__init__()
self.limit_arg_size_nbytes = limit_arg_size_nbytes

@memoize_method
def get_loopy_target(self) -> Optional["lp.PyOpenCLTarget"]:
from loopy import PyOpenCLTarget
return PyOpenCLTarget(limit_arg_size_nbytes=self.limit_arg_size_nbytes)


class PytatoPyOpenCLArrayContext(_BasePytatoArrayContext):
"""
A :class:`ArrayContext` that uses :mod:`pytato` data types to represent
Expand All@@ -232,7 +255,11 @@ class PytatoPyOpenCLArrayContext(_BasePytatoArrayContext):
"""
def __init__(
self, queue: "cl.CommandQueue", allocator=None, *,
compile_trace_callback: Optional[Callable[[Any, str, Any], None]] = None
use_memory_pool: Optional[bool] = None,
compile_trace_callback: Optional[Callable[[Any, str, Any], None]] = None,

# do not use: only for testing
_force_svm_arg_limit: Optional[int] = None,
) -> None:
"""
:arg compile_trace_callback: A function of three arguments
Expand All@@ -242,16 +269,57 @@ def __init__(
representation. This interface should be considered
unstable.
"""
if allocator is not None and use_memory_pool is not None:
raise TypeError("may not specify both allocator and use_memory_pool")

self.using_svm = None

if allocator is None:
from pyopencl.characterize import has_coarse_grain_buffer_svm
has_svm = has_coarse_grain_buffer_svm(queue.device)
if has_svm:
self.using_svm = True

from pyopencl.tools import SVMAllocator
allocator = SVMAllocator(queue.context, queue=queue)

if use_memory_pool:
from pyopencl.tools import SVMPool
allocator = SVMPool(allocator)
else:
self.using_svm = False

from pyopencl.tools import ImmediateAllocator
allocator = ImmediateAllocator(queue.context)

if use_memory_pool:
from pyopencl.tools import MemoryPool
allocator = MemoryPool(allocator)
else:
# Check whether the passed allocator allocates SVM
try:
from pyopencl import SVMPointer
mem = allocator(4)
if isinstance(mem, SVMPointer):
self.using_svm = True
else:
self.using_svm = False
except ImportError:
self.using_svm = False

import pytato as pt
import pyopencl.array as cla
super().__init__(compile_trace_callback=compile_trace_callback)
self.queue = queue

self.allocator = allocator
self.array_types = (pt.Array, cla.Array)

# unused, but necessary to keep the context alive
self.context = self.queue.context

self._force_svm_arg_limit = _force_svm_arg_limit

@property
def _frozen_array_types(self) -> Tuple[Type, ...]:
import pyopencl.array as cla
Expand DownExpand Up@@ -321,6 +389,29 @@ def _to_numpy(ary):
self._rec_map_container(_to_numpy, self.freeze(array)),
actx=None)

@memoize_method
def get_target(self):
import pyopencl as cl
import pyopencl.characterize as cl_char

dev = self.queue.device

if (
self._force_svm_arg_limit is not None
or (
self.using_svm and dev.type & cl.device_type.GPU
and cl_char.has_coarse_grain_buffer_svm(dev))):

limit = dev.max_parameter_size
if self._force_svm_arg_limit is not None:
limit = self._force_svm_arg_limit

logger.info(f"limiting argument buffer size for {dev} to {limit} bytes")

return _ArgSizeLimitingPytatoLoopyPyOpenCLTarget(limit)
else:
return super().get_target()

def freeze(self, array):
if np.isscalar(array):
return array
Expand DownExpand Up@@ -415,7 +506,8 @@ def _record_leaf_ary_in_dict(
pt_prg = pt.generate_loopy(transformed_dag,
options=_DEFAULT_LOOPY_OPTIONS,
cl_device=self.queue.device,
function_name=function_name)
function_name=function_name,
target=self.get_target())
pt_prg = pt_prg.with_transformed_program(self.transform_loopy_program)
self._freeze_prg_cache[normalized_expr] = pt_prg
else:
Expand Down
4 changes: 3 additions & 1 deletion arraycontext/impl/pytato/compile.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -420,7 +420,9 @@ def _dag_to_transformed_pytato_prg(self, dict_of_named_arrays, *, prg_id=None):
options=lp.Options(
return_dict=True,
no_numpy=True),
function_name=_prg_id_to_kernel_name(prg_id))
function_name=_prg_id_to_kernel_name(prg_id),
Comment thread
inducer marked this conversation as resolved.
target=self.actx.get_target(),
)
assert isinstance(pytato_program, BoundPyOpenCLProgram)

self.actx._compile_trace_callback(
Expand Down
21 changes: 21 additions & 0 deletions test/test_pytato_arraycontext.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -100,6 +100,27 @@ def test_tags_preserved_after_freeze(actx_factory):
assert foo.axes[1].tags_of_type(BazTag)


def test_arg_size_limit(actx_factory):
ran_callback = False

def my_ctc(what, stage, ir):
if stage == "final":
assert ir.target.limit_arg_size_nbytes == 42
nonlocal ran_callback
ran_callback = True

def twice(x):
return 2 * x

actx = _PytatoPyOpenCLArrayContextForTests(
actx_factory().queue, compile_trace_callback=my_ctc, _force_svm_arg_limit=42)

f = actx.compile(twice)
f(99)

assert ran_callback


if __name__ == "__main__":
import sys
if len(sys.argv) > 1:
Expand Down
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
96 changes: 94 additions & 2 deletions arraycontext/impl/pytato/__init__.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -54,15 +54,21 @@
from arraycontext.container.traversal import (rec_map_array_container,
with_array_context)
from arraycontext.metadata import NameHint
from pytools import memoize_method

if TYPE_CHECKING:
import pytato
import pyopencl as cl
import loopy as lp

if getattr(sys, "_BUILDING_SPHINX_DOCS", False):
import pyopencl as cl # noqa: F811


import logging
logger = logging.getLogger(__name__)


# {{{ tag conversion

def _preprocess_array_tags(tags: ToTagSetConvertible) -> FrozenSet[Tag]:
Expand DownExpand Up@@ -203,13 +209,30 @@ def supports_nonscalar_broadcasting(self):
def permits_advanced_indexing(self):
return True

def get_target(self):
return None

# }}}

# }}}


# {{{ PytatoPyOpenCLArrayContext

from pytato.target.loopy import LoopyPyOpenCLTarget


class _ArgSizeLimitingPytatoLoopyPyOpenCLTarget(LoopyPyOpenCLTarget):
def __init__(self, limit_arg_size_nbytes: int) -> None:
super().__init__()
self.limit_arg_size_nbytes = limit_arg_size_nbytes

@memoize_method
def get_loopy_target(self) -> Optional["lp.PyOpenCLTarget"]:
from loopy import PyOpenCLTarget
return PyOpenCLTarget(limit_arg_size_nbytes=self.limit_arg_size_nbytes)


class PytatoPyOpenCLArrayContext(_BasePytatoArrayContext):
"""
A :class:`ArrayContext` that uses :mod:`pytato` data types to represent
Expand All@@ -232,7 +255,11 @@ class PytatoPyOpenCLArrayContext(_BasePytatoArrayContext):
"""
def __init__(
self, queue: "cl.CommandQueue", allocator=None, *,
compile_trace_callback: Optional[Callable[[Any, str, Any], None]] = None
use_memory_pool: Optional[bool] = None,
compile_trace_callback: Optional[Callable[[Any, str, Any], None]] = None,

# do not use: only for testing
_force_svm_arg_limit: Optional[int] = None,
) -> None:
"""
:arg compile_trace_callback: A function of three arguments
Expand All@@ -242,16 +269,57 @@ def __init__(
representation. This interface should be considered
unstable.
"""
if allocator is not None and use_memory_pool is not None:
raise TypeError("may not specify both allocator and use_memory_pool")

self.using_svm = None

if allocator is None:
from pyopencl.characterize import has_coarse_grain_buffer_svm
has_svm = has_coarse_grain_buffer_svm(queue.device)
if has_svm:
self.using_svm = True

from pyopencl.tools import SVMAllocator
allocator = SVMAllocator(queue.context, queue=queue)

if use_memory_pool:
from pyopencl.tools import SVMPool
allocator = SVMPool(allocator)
else:
self.using_svm = False

from pyopencl.tools import ImmediateAllocator
allocator = ImmediateAllocator(queue.context)

if use_memory_pool:
from pyopencl.tools import MemoryPool
allocator = MemoryPool(allocator)
else:
# Check whether the passed allocator allocates SVM
try:
from pyopencl import SVMPointer
mem = allocator(4)
if isinstance(mem, SVMPointer):
self.using_svm = True
else:
self.using_svm = False
except ImportError:
self.using_svm = False

import pytato as pt
import pyopencl.array as cla
super().__init__(compile_trace_callback=compile_trace_callback)
self.queue = queue

self.allocator = allocator
self.array_types = (pt.Array, cla.Array)

# unused, but necessary to keep the context alive
self.context = self.queue.context

self._force_svm_arg_limit = _force_svm_arg_limit

@property
def _frozen_array_types(self) -> Tuple[Type, ...]:
import pyopencl.array as cla
Expand DownExpand Up@@ -321,6 +389,29 @@ def _to_numpy(ary):
self._rec_map_container(_to_numpy, self.freeze(array)),
actx=None)

@memoize_method
def get_target(self):
import pyopencl as cl
import pyopencl.characterize as cl_char

dev = self.queue.device

if (
self._force_svm_arg_limit is not None
or (
self.using_svm and dev.type & cl.device_type.GPU
and cl_char.has_coarse_grain_buffer_svm(dev))):

limit = dev.max_parameter_size
if self._force_svm_arg_limit is not None:
limit = self._force_svm_arg_limit

logger.info(f"limiting argument buffer size for {dev} to {limit} bytes")

return _ArgSizeLimitingPytatoLoopyPyOpenCLTarget(limit)
else:
return super().get_target()

def freeze(self, array):
if np.isscalar(array):
return array
Expand DownExpand Up@@ -415,7 +506,8 @@ def _record_leaf_ary_in_dict(
pt_prg = pt.generate_loopy(transformed_dag,
options=_DEFAULT_LOOPY_OPTIONS,
cl_device=self.queue.device,
function_name=function_name)
function_name=function_name,
target=self.get_target())
pt_prg = pt_prg.with_transformed_program(self.transform_loopy_program)
self._freeze_prg_cache[normalized_expr] = pt_prg
else:
Expand Down
4 changes: 3 additions & 1 deletion arraycontext/impl/pytato/compile.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -420,7 +420,9 @@ def _dag_to_transformed_pytato_prg(self, dict_of_named_arrays, *, prg_id=None):
options=lp.Options(
return_dict=True,
no_numpy=True),
function_name=_prg_id_to_kernel_name(prg_id))
function_name=_prg_id_to_kernel_name(prg_id),
Comment thread
inducer marked this conversation as resolved.
target=self.actx.get_target(),
)
assert isinstance(pytato_program, BoundPyOpenCLProgram)

self.actx._compile_trace_callback(
Expand Down
21 changes: 21 additions & 0 deletions test/test_pytato_arraycontext.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -100,6 +100,27 @@ def test_tags_preserved_after_freeze(actx_factory):
assert foo.axes[1].tags_of_type(BazTag)


def test_arg_size_limit(actx_factory):
ran_callback = False

def my_ctc(what, stage, ir):
if stage == "final":
assert ir.target.limit_arg_size_nbytes == 42
nonlocal ran_callback
ran_callback = True

def twice(x):
return 2 * x

actx = _PytatoPyOpenCLArrayContextForTests(
actx_factory().queue, compile_trace_callback=my_ctc, _force_svm_arg_limit=42)

f = actx.compile(twice)
f(99)

assert ran_callback


if __name__ == "__main__":
import sys
if len(sys.argv) > 1:
Expand Down
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
96 changes: 94 additions & 2 deletions arraycontext/impl/pytato/__init__.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -54,15 +54,21 @@
from arraycontext.container.traversal import (rec_map_array_container,
with_array_context)
from arraycontext.metadata import NameHint
from pytools import memoize_method

if TYPE_CHECKING:
import pytato
import pyopencl as cl
import loopy as lp

if getattr(sys, "_BUILDING_SPHINX_DOCS", False):
import pyopencl as cl # noqa: F811


import logging
logger = logging.getLogger(__name__)


# {{{ tag conversion

def _preprocess_array_tags(tags: ToTagSetConvertible) -> FrozenSet[Tag]:
Expand DownExpand Up@@ -203,13 +209,30 @@ def supports_nonscalar_broadcasting(self):
def permits_advanced_indexing(self):
return True

def get_target(self):
return None

# }}}

# }}}


# {{{ PytatoPyOpenCLArrayContext

from pytato.target.loopy import LoopyPyOpenCLTarget


class _ArgSizeLimitingPytatoLoopyPyOpenCLTarget(LoopyPyOpenCLTarget):
def __init__(self, limit_arg_size_nbytes: int) -> None:
super().__init__()
self.limit_arg_size_nbytes = limit_arg_size_nbytes

@memoize_method
def get_loopy_target(self) -> Optional["lp.PyOpenCLTarget"]:
from loopy import PyOpenCLTarget
return PyOpenCLTarget(limit_arg_size_nbytes=self.limit_arg_size_nbytes)


class PytatoPyOpenCLArrayContext(_BasePytatoArrayContext):
"""
A :class:`ArrayContext` that uses :mod:`pytato` data types to represent
Expand All@@ -232,7 +255,11 @@ class PytatoPyOpenCLArrayContext(_BasePytatoArrayContext):
"""
def __init__(
self, queue: "cl.CommandQueue", allocator=None, *,
compile_trace_callback: Optional[Callable[[Any, str, Any], None]] = None
use_memory_pool: Optional[bool] = None,
compile_trace_callback: Optional[Callable[[Any, str, Any], None]] = None,

# do not use: only for testing
_force_svm_arg_limit: Optional[int] = None,
) -> None:
"""
:arg compile_trace_callback: A function of three arguments
Expand All@@ -242,16 +269,57 @@ def __init__(
representation. This interface should be considered
unstable.
"""
if allocator is not None and use_memory_pool is not None:
raise TypeError("may not specify both allocator and use_memory_pool")

self.using_svm = None

if allocator is None:
from pyopencl.characterize import has_coarse_grain_buffer_svm
has_svm = has_coarse_grain_buffer_svm(queue.device)
if has_svm:
self.using_svm = True

from pyopencl.tools import SVMAllocator
allocator = SVMAllocator(queue.context, queue=queue)

if use_memory_pool:
from pyopencl.tools import SVMPool
allocator = SVMPool(allocator)
else:
self.using_svm = False

from pyopencl.tools import ImmediateAllocator
allocator = ImmediateAllocator(queue.context)

if use_memory_pool:
from pyopencl.tools import MemoryPool
allocator = MemoryPool(allocator)
else:
# Check whether the passed allocator allocates SVM
try:
from pyopencl import SVMPointer
mem = allocator(4)
if isinstance(mem, SVMPointer):
self.using_svm = True
else:
self.using_svm = False
except ImportError:
self.using_svm = False

import pytato as pt
import pyopencl.array as cla
super().__init__(compile_trace_callback=compile_trace_callback)
self.queue = queue

self.allocator = allocator
self.array_types = (pt.Array, cla.Array)

# unused, but necessary to keep the context alive
self.context = self.queue.context

self._force_svm_arg_limit = _force_svm_arg_limit

@property
def _frozen_array_types(self) -> Tuple[Type, ...]:
import pyopencl.array as cla
Expand DownExpand Up@@ -321,6 +389,29 @@ def _to_numpy(ary):
self._rec_map_container(_to_numpy, self.freeze(array)),
actx=None)

@memoize_method
def get_target(self):
import pyopencl as cl
import pyopencl.characterize as cl_char

dev = self.queue.device

if (
self._force_svm_arg_limit is not None
or (
self.using_svm and dev.type & cl.device_type.GPU
and cl_char.has_coarse_grain_buffer_svm(dev))):

limit = dev.max_parameter_size
if self._force_svm_arg_limit is not None:
limit = self._force_svm_arg_limit

logger.info(f"limiting argument buffer size for {dev} to {limit} bytes")

return _ArgSizeLimitingPytatoLoopyPyOpenCLTarget(limit)
else:
return super().get_target()

def freeze(self, array):
if np.isscalar(array):
return array
Expand DownExpand Up@@ -415,7 +506,8 @@ def _record_leaf_ary_in_dict(
pt_prg = pt.generate_loopy(transformed_dag,
options=_DEFAULT_LOOPY_OPTIONS,
cl_device=self.queue.device,
function_name=function_name)
function_name=function_name,
target=self.get_target())
pt_prg = pt_prg.with_transformed_program(self.transform_loopy_program)
self._freeze_prg_cache[normalized_expr] = pt_prg
else:
Expand Down
4 changes: 3 additions & 1 deletion arraycontext/impl/pytato/compile.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -420,7 +420,9 @@ def _dag_to_transformed_pytato_prg(self, dict_of_named_arrays, *, prg_id=None):
options=lp.Options(
return_dict=True,
no_numpy=True),
function_name=_prg_id_to_kernel_name(prg_id))
function_name=_prg_id_to_kernel_name(prg_id),
Comment thread
inducer marked this conversation as resolved.
target=self.actx.get_target(),
)
assert isinstance(pytato_program, BoundPyOpenCLProgram)

self.actx._compile_trace_callback(
Expand Down
21 changes: 21 additions & 0 deletions test/test_pytato_arraycontext.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -100,6 +100,27 @@ def test_tags_preserved_after_freeze(actx_factory):
assert foo.axes[1].tags_of_type(BazTag)


def test_arg_size_limit(actx_factory):
ran_callback = False

def my_ctc(what, stage, ir):
if stage == "final":
assert ir.target.limit_arg_size_nbytes == 42
nonlocal ran_callback
ran_callback = True

def twice(x):
return 2 * x

actx = _PytatoPyOpenCLArrayContextForTests(
actx_factory().queue, compile_trace_callback=my_ctc, _force_svm_arg_limit=42)

f = actx.compile(twice)
f(99)

assert ran_callback


if __name__ == "__main__":
import sys
if len(sys.argv) > 1:
Expand Down
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
96 changes: 94 additions & 2 deletions arraycontext/impl/pytato/__init__.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -54,15 +54,21 @@
from arraycontext.container.traversal import (rec_map_array_container,
with_array_context)
from arraycontext.metadata import NameHint
from pytools import memoize_method

if TYPE_CHECKING:
import pytato
import pyopencl as cl
import loopy as lp

if getattr(sys, "_BUILDING_SPHINX_DOCS", False):
import pyopencl as cl # noqa: F811


import logging
logger = logging.getLogger(__name__)


# {{{ tag conversion

def _preprocess_array_tags(tags: ToTagSetConvertible) -> FrozenSet[Tag]:
Expand DownExpand Up@@ -203,13 +209,30 @@ def supports_nonscalar_broadcasting(self):
def permits_advanced_indexing(self):
return True

def get_target(self):
return None

# }}}

# }}}


# {{{ PytatoPyOpenCLArrayContext

from pytato.target.loopy import LoopyPyOpenCLTarget


class _ArgSizeLimitingPytatoLoopyPyOpenCLTarget(LoopyPyOpenCLTarget):
def __init__(self, limit_arg_size_nbytes: int) -> None:
super().__init__()
self.limit_arg_size_nbytes = limit_arg_size_nbytes

@memoize_method
def get_loopy_target(self) -> Optional["lp.PyOpenCLTarget"]:
from loopy import PyOpenCLTarget
return PyOpenCLTarget(limit_arg_size_nbytes=self.limit_arg_size_nbytes)


class PytatoPyOpenCLArrayContext(_BasePytatoArrayContext):
"""
A :class:`ArrayContext` that uses :mod:`pytato` data types to represent
Expand All@@ -232,7 +255,11 @@ class PytatoPyOpenCLArrayContext(_BasePytatoArrayContext):
"""
def __init__(
self, queue: "cl.CommandQueue", allocator=None, *,
compile_trace_callback: Optional[Callable[[Any, str, Any], None]] = None
use_memory_pool: Optional[bool] = None,
compile_trace_callback: Optional[Callable[[Any, str, Any], None]] = None,

# do not use: only for testing
_force_svm_arg_limit: Optional[int] = None,
) -> None:
"""
:arg compile_trace_callback: A function of three arguments
Expand All@@ -242,16 +269,57 @@ def __init__(
representation. This interface should be considered
unstable.
"""
if allocator is not None and use_memory_pool is not None:
raise TypeError("may not specify both allocator and use_memory_pool")

self.using_svm = None

if allocator is None:
from pyopencl.characterize import has_coarse_grain_buffer_svm
has_svm = has_coarse_grain_buffer_svm(queue.device)
if has_svm:
self.using_svm = True

from pyopencl.tools import SVMAllocator
allocator = SVMAllocator(queue.context, queue=queue)

if use_memory_pool:
from pyopencl.tools import SVMPool
allocator = SVMPool(allocator)
else:
self.using_svm = False

from pyopencl.tools import ImmediateAllocator
allocator = ImmediateAllocator(queue.context)

if use_memory_pool:
from pyopencl.tools import MemoryPool
allocator = MemoryPool(allocator)
else:
# Check whether the passed allocator allocates SVM
try:
from pyopencl import SVMPointer
mem = allocator(4)
if isinstance(mem, SVMPointer):
self.using_svm = True
else:
self.using_svm = False
except ImportError:
self.using_svm = False

import pytato as pt
import pyopencl.array as cla
super().__init__(compile_trace_callback=compile_trace_callback)
self.queue = queue

self.allocator = allocator
self.array_types = (pt.Array, cla.Array)

# unused, but necessary to keep the context alive
self.context = self.queue.context

self._force_svm_arg_limit = _force_svm_arg_limit

@property
def _frozen_array_types(self) -> Tuple[Type, ...]:
import pyopencl.array as cla
Expand DownExpand Up@@ -321,6 +389,29 @@ def _to_numpy(ary):
self._rec_map_container(_to_numpy, self.freeze(array)),
actx=None)

@memoize_method
def get_target(self):
import pyopencl as cl
import pyopencl.characterize as cl_char

dev = self.queue.device

if (
self._force_svm_arg_limit is not None
or (
self.using_svm and dev.type & cl.device_type.GPU
and cl_char.has_coarse_grain_buffer_svm(dev))):

limit = dev.max_parameter_size
if self._force_svm_arg_limit is not None:
limit = self._force_svm_arg_limit

logger.info(f"limiting argument buffer size for {dev} to {limit} bytes")

return _ArgSizeLimitingPytatoLoopyPyOpenCLTarget(limit)
else:
return super().get_target()

def freeze(self, array):
if np.isscalar(array):
return array
Expand DownExpand Up@@ -415,7 +506,8 @@ def _record_leaf_ary_in_dict(
pt_prg = pt.generate_loopy(transformed_dag,
options=_DEFAULT_LOOPY_OPTIONS,
cl_device=self.queue.device,
function_name=function_name)
function_name=function_name,
target=self.get_target())
pt_prg = pt_prg.with_transformed_program(self.transform_loopy_program)
self._freeze_prg_cache[normalized_expr] = pt_prg
else:
Expand Down
4 changes: 3 additions & 1 deletion arraycontext/impl/pytato/compile.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -420,7 +420,9 @@ def _dag_to_transformed_pytato_prg(self, dict_of_named_arrays, *, prg_id=None):
options=lp.Options(
return_dict=True,
no_numpy=True),
function_name=_prg_id_to_kernel_name(prg_id))
function_name=_prg_id_to_kernel_name(prg_id),
Comment thread
inducer marked this conversation as resolved.
target=self.actx.get_target(),
)
assert isinstance(pytato_program, BoundPyOpenCLProgram)

self.actx._compile_trace_callback(
Expand Down
21 changes: 21 additions & 0 deletions test/test_pytato_arraycontext.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -100,6 +100,27 @@ def test_tags_preserved_after_freeze(actx_factory):
assert foo.axes[1].tags_of_type(BazTag)


def test_arg_size_limit(actx_factory):
ran_callback = False

def my_ctc(what, stage, ir):
if stage == "final":
assert ir.target.limit_arg_size_nbytes == 42
nonlocal ran_callback
ran_callback = True

def twice(x):
return 2 * x

actx = _PytatoPyOpenCLArrayContextForTests(
actx_factory().queue, compile_trace_callback=my_ctc, _force_svm_arg_limit=42)

f = actx.compile(twice)
f(99)

assert ran_callback


if __name__ == "__main__":
import sys
if len(sys.argv) > 1:
Expand Down