From 69217d9f460c4110128085063f6f23764a22204f Mon Sep 17 00:00:00 2001 From: Antonio Cuni Date: Wed, 2 Feb 2022 18:13:16 +0000 Subject: [PATCH 01/25] add a compiler pass which tries to detect suspicious cases of possible memory leaks and warns the user --- rbc/omnisci_backend/omnisci_pipeline.py | 69 ++++++++++++++++++++++++- rbc/tests/test_compiler_pipeline.py | 60 +++++++++++++++++++++ 2 files changed, 127 insertions(+), 2 deletions(-) create mode 100644 rbc/tests/test_compiler_pipeline.py diff --git a/rbc/omnisci_backend/omnisci_pipeline.py b/rbc/omnisci_backend/omnisci_pipeline.py index be6d2784..45d4720e 100644 --- a/rbc/omnisci_backend/omnisci_pipeline.py +++ b/rbc/omnisci_backend/omnisci_pipeline.py @@ -1,7 +1,8 @@ import operator +import warnings from rbc.errors import NumbaTypeError -from .omnisci_buffer import BufferMeta, free_all_other_buffers +from .omnisci_buffer import BufferMeta, BufferPointer, free_all_other_buffers, free_buffer from numba.core import ir, types from numba.core.compiler import CompilerBase, DefaultPassBuilder from numba.core.compiler_machinery import FunctionPass, register_pass @@ -9,7 +10,9 @@ RewriteSemanticConstants, ReconstructSSA, DeadBranchPrune,) -from numba.core.typed_passes import PartialTypeInference, DeadCodeElimination +from numba.core.typed_passes import (PartialTypeInference, + DeadCodeElimination, + NopythonTypeInference) # Register this pass with the compiler framework, declare that it will not @@ -151,6 +154,67 @@ def run_pass(self, state): return mutated +class MissingFreeWarning(Warning): + + _msg = """ + Possible memory leak detected! + In RBC, arrays and buffers must be freed manually by calling the method + .free() or the function free_buffer(): see the relevant docs. + """ + + def __init__(self): + Warning.__init__(self, self._msg) + + +@register_pass(mutates_CFG=False, analysis_only=True) +class DetectMissingFree(FunctionPass): + _name = "DetectMissingFree" + + def __init__(self): + FunctionPass.__init__(self) + + def iter_calls(self, func_ir): + for block in func_ir.blocks.values(): + for inst in block.find_insts(ir.Assign): + if isinstance(inst.value, ir.Expr) and inst.value.op == 'call': + yield inst + + + def contains_buffer_constructors(self, state): + """ + Check whether the func_ir contains any call which creates a buffer. This + could be either a direct call to e.g. xp.Array() or a call to any + function which returns a BufferPointer: in that case we assume that + the ownership is transfered upon return and that the caller is + responsible to free() it. + """ + func_ir = state.func_ir + for inst in self.iter_calls(func_ir): + ret_type = state.typemap[inst.target.name] + if isinstance(ret_type, BufferPointer): + return True + return False + + def contains_calls_to_free(self, state): + """ + Check whether there is at least an instruction which calls free_buffer() + or BufferPointer.free() + """ + func_ir = state.func_ir + for inst in self.iter_calls(func_ir): + rhs = func_ir.get_definition(inst.value.func) + if isinstance(rhs, ir.Global) and rhs.value is free_buffer: + return True + return False + + def run_pass(self, state): + if (self.contains_buffer_constructors(state) and + not self.contains_calls_to_free(state)): + warnings.warn(MissingFreeWarning()) + + return False # we didn't modify the IR + + class OmnisciCompilerPipeline(CompilerBase): def define_pipelines(self): # define a new set of pipelines (just one in this case) and for ease @@ -161,6 +225,7 @@ def define_pipelines(self): pm.add_pass_after(AutoFreeBuffers, IRProcessing) pm.add_pass_after(CheckRaiseStmts, IRProcessing) pm.add_pass_after(DTypeComparison, ReconstructSSA) + pm.add_pass_after(DetectMissingFree, NopythonTypeInference) # finalize pm.finalize() # return as an iterable, any number of pipelines may be defined! diff --git a/rbc/tests/test_compiler_pipeline.py b/rbc/tests/test_compiler_pipeline.py new file mode 100644 index 00000000..2423527a --- /dev/null +++ b/rbc/tests/test_compiler_pipeline.py @@ -0,0 +1,60 @@ +import pytest +import contextlib +import warnings +from rbc.remotejit import RemoteJIT +from rbc.omnisci_backend.omnisci_buffer import free_buffer +from rbc.omnisci_backend.omnisci_pipeline import MissingFreeWarning +from rbc.stdlib import array_api as xp + +@pytest.fixture +def rjit(): + return RemoteJIT(local=True) + + +@contextlib.contextmanager +def no_warnings(warning_cls): + with pytest.warns(None) as wlist: + yield + + wlist = [w.message for w in wlist if isinstance(w.message, warning_cls)] + if wlist: + raise AssertionError( + "Warnings were raised: " + ", ".join([str(w) for w in wlist]) + ) + +def test_no_warnings_decorator(): + with no_warnings(MissingFreeWarning): + pass + + with no_warnings(MissingFreeWarning): + warnings.warn('hello') + + with pytest.raises(AssertionError, match='Warnings were raised'): + with no_warnings(MissingFreeWarning): + warnings.warn(MissingFreeWarning()) + + + +class TestDetectMissingFree: + + def test_missing_free(self, rjit): + # basic case: we are creating an array but we don't call .free() + @rjit('int32(int32)') + def fn(size): + a = xp.Array(size, xp.float64) + return size + + with pytest.warns(MissingFreeWarning): + res = fn(10) + assert res == 10 + + def test_detect_call_to_free_buffer(self, rjit): + @rjit('int32(int32)') + def fn(size): + a = xp.Array(size, xp.float64) + free_buffer(a) + return size + + with no_warnings(MissingFreeWarning): + res = fn(10) + assert res == 10 From bc38bb3583a1253aadb42bb08a3e2f600166bef2 Mon Sep 17 00:00:00 2001 From: Antonio Cuni Date: Thu, 3 Feb 2022 15:27:06 +0000 Subject: [PATCH 02/25] detect calls to BufferPointer.free() --- rbc/omnisci_backend/omnisci_pipeline.py | 8 ++++++++ rbc/tests/test_compiler_pipeline.py | 11 +++++++++++ 2 files changed, 19 insertions(+) diff --git a/rbc/omnisci_backend/omnisci_pipeline.py b/rbc/omnisci_backend/omnisci_pipeline.py index 45d4720e..affa1463 100644 --- a/rbc/omnisci_backend/omnisci_pipeline.py +++ b/rbc/omnisci_backend/omnisci_pipeline.py @@ -195,6 +195,12 @@ def contains_buffer_constructors(self, state): return True return False + def is_BufferPoint_dot_free(self, state, expr): + return (isinstance(expr, ir.Expr) and + expr.op == 'getattr' and + isinstance(state.typemap[expr.value.name], BufferPointer) and + expr.attr == 'free') + def contains_calls_to_free(self, state): """ Check whether there is at least an instruction which calls free_buffer() @@ -205,6 +211,8 @@ def contains_calls_to_free(self, state): rhs = func_ir.get_definition(inst.value.func) if isinstance(rhs, ir.Global) and rhs.value is free_buffer: return True + elif self.is_BufferPoint_dot_free(state, rhs): + return True return False def run_pass(self, state): diff --git a/rbc/tests/test_compiler_pipeline.py b/rbc/tests/test_compiler_pipeline.py index 2423527a..e22cd75d 100644 --- a/rbc/tests/test_compiler_pipeline.py +++ b/rbc/tests/test_compiler_pipeline.py @@ -58,3 +58,14 @@ def fn(size): with no_warnings(MissingFreeWarning): res = fn(10) assert res == 10 + + def test_detect_call_to_method_free(self, rjit): + @rjit('int32(int32)') + def fn(size): + a = xp.Array(size, xp.float64) + a.free() + return size + + with no_warnings(MissingFreeWarning): + res = fn(10) + assert res == 10 From d250ecfc16fdbe8208243a57d13807f1f110d6f0 Mon Sep 17 00:00:00 2001 From: Antonio Cuni Date: Thu, 3 Feb 2022 16:06:23 +0000 Subject: [PATCH 03/25] kill the AutoFreeBuffers pass --- rbc/omnisci_backend/omnisci_buffer.py | 48 ------------------- rbc/omnisci_backend/omnisci_pipeline.py | 61 +------------------------ 2 files changed, 1 insertion(+), 108 deletions(-) diff --git a/rbc/omnisci_backend/omnisci_buffer.py b/rbc/omnisci_backend/omnisci_buffer.py index a69ced60..819592c3 100644 --- a/rbc/omnisci_backend/omnisci_buffer.py +++ b/rbc/omnisci_backend/omnisci_buffer.py @@ -193,54 +193,6 @@ def omnisci_buffer_constructor(context, builder, sig, args): return fa._getpointer() -@extending.intrinsic -def free_all_other_buffers(typingctx, value_to_keep_alive): - """ - Black magic function which automatically frees all the buffers which were - allocated in the function apart the given one. - - value_to_keep_alive can be of any type: - - if it's of a Buffer type, it will be kept alive and not freed - - if it's of any other type, all buffers will be freed unconditionally - - The end user should never call this function explicitly: it is - automatically inserted by omnisci_pipeline.AutoFreeBuffers. - """ - - sig = types.void(value_to_keep_alive) - - def codegen(context, builder, signature, args): - buffers = builder_buffers[builder] - - # TODO: using stdlib `free` that works only for CPU. For CUDA - # devices, we need to use omniscidb provided deallocator. - target_info = TargetInfo() - try: - free_buffer_fn_name = target_info.info['fn_free_buffer'] - except KeyError as msg: - raise UnsupportedError(f'{target_info} does not provide {msg}') - free_buffer_fnty = llvm_ir.FunctionType(void_t, [int8_t.as_pointer()]) - free_buffer_fn = irutils.get_or_insert_function( - builder.module, free_buffer_fnty, free_buffer_fn_name) - - if isinstance(value_to_keep_alive, BufferPointer): - # free all the buffers apart value_to_keep_alive - [keep_alive] = args - keep_alive_ptr = builder.load(builder.gep(keep_alive, [int32_t(0), int32_t(0)])) - keep_alive_ptr = builder.bitcast(keep_alive_ptr, int8_t.as_pointer()) - for ptr8 in buffers: - with builder.if_then(builder.icmp_signed('!=', keep_alive_ptr, ptr8)): - builder.call(free_buffer_fn, [ptr8]) - else: - # free all the buffers unconditionally - for ptr8 in buffers: - builder.call(free_buffer_fn, [ptr8]) - - del builder_buffers[builder] - - return sig, codegen - - @extending.intrinsic def free_buffer(typingctx, buf): """ diff --git a/rbc/omnisci_backend/omnisci_pipeline.py b/rbc/omnisci_backend/omnisci_pipeline.py index affa1463..790363fa 100644 --- a/rbc/omnisci_backend/omnisci_pipeline.py +++ b/rbc/omnisci_backend/omnisci_pipeline.py @@ -2,7 +2,7 @@ import warnings from rbc.errors import NumbaTypeError -from .omnisci_buffer import BufferMeta, BufferPointer, free_all_other_buffers, free_buffer +from .omnisci_buffer import BufferMeta, BufferPointer, free_buffer from numba.core import ir, types from numba.core.compiler import CompilerBase, DefaultPassBuilder from numba.core.compiler_machinery import FunctionPass, register_pass @@ -15,64 +15,6 @@ NopythonTypeInference) -# Register this pass with the compiler framework, declare that it will not -# mutate the control flow graph and that it is not an analysis_only pass (it -# potentially mutates the IR). -@register_pass(mutates_CFG=False, analysis_only=False) -class AutoFreeBuffers(FunctionPass): - """ - Black magic at work. - - The goal of this pass is to "automagically" free all the buffers which - were allocated, apart the one which is used as a return value (if any). - - NOTE: at the moment of writing there are very few tests for this and it's - likely that it is broken and/or does not work properly in the general - case. [Remove this note once we are confident that it works well] - """ - _name = "auto_free_buffers" # the common name for the pass - - def __init__(self): - FunctionPass.__init__(self) - - # implement method to do the work, "state" is the internal compiler - # state from the CompilerBase instance. - def run_pass(self, state): - func_ir = state.func_ir # get the FunctionIR object - - for blk in func_ir.blocks.values(): - for stmt in blk.find_insts(ir.Assign): - if ( - isinstance(stmt.value, ir.FreeVar) - and stmt.value.name in BufferMeta.class_names - ): - break - else: - continue - break - else: - return False # one does not changes the IR - - for blk in func_ir.blocks.values(): - loc = blk.loc - scope = blk.scope - for ret in blk.find_insts(ir.Return): - - name = "free_all_other_buffers_fn" - value = ir.Global(name, free_all_other_buffers, loc) - target = scope.make_temp(loc) - stmt = ir.Assign(value, target, loc) - blk.insert_before_terminator(stmt) - - fn_call = ir.Expr.call(func=target, args=[ret.value], kws=(), loc=loc) - lhs = scope.make_temp(loc) - var = ir.Assign(fn_call, lhs, blk.loc) - blk.insert_before_terminator(var) - break - - return True # we changed the IR - - @register_pass(mutates_CFG=False, analysis_only=False) class CheckRaiseStmts(FunctionPass): _name = "check_raise_stmts" @@ -230,7 +172,6 @@ def define_pipelines(self): # namely the "nopython" pipeline pm = DefaultPassBuilder.define_nopython_pipeline(self.state) # Add the new pass to run after IRProcessing - pm.add_pass_after(AutoFreeBuffers, IRProcessing) pm.add_pass_after(CheckRaiseStmts, IRProcessing) pm.add_pass_after(DTypeComparison, ReconstructSSA) pm.add_pass_after(DetectMissingFree, NopythonTypeInference) From be49a3d8b986ad0e62095e37a1bf0191214591c2 Mon Sep 17 00:00:00 2001 From: Antonio Cuni Date: Thu, 3 Feb 2022 16:12:26 +0000 Subject: [PATCH 04/25] fix flake8 --- rbc/omnisci_backend/omnisci_pipeline.py | 9 +++------ rbc/tests/test_compiler_pipeline.py | 5 +++-- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/rbc/omnisci_backend/omnisci_pipeline.py b/rbc/omnisci_backend/omnisci_pipeline.py index 790363fa..d0449f6b 100644 --- a/rbc/omnisci_backend/omnisci_pipeline.py +++ b/rbc/omnisci_backend/omnisci_pipeline.py @@ -2,7 +2,7 @@ import warnings from rbc.errors import NumbaTypeError -from .omnisci_buffer import BufferMeta, BufferPointer, free_buffer +from .omnisci_buffer import BufferPointer, free_buffer from numba.core import ir, types from numba.core.compiler import CompilerBase, DefaultPassBuilder from numba.core.compiler_machinery import FunctionPass, register_pass @@ -121,7 +121,6 @@ def iter_calls(self, func_ir): if isinstance(inst.value, ir.Expr) and inst.value.op == 'call': yield inst - def contains_buffer_constructors(self, state): """ Check whether the func_ir contains any call which creates a buffer. This @@ -158,11 +157,9 @@ def contains_calls_to_free(self, state): return False def run_pass(self, state): - if (self.contains_buffer_constructors(state) and - not self.contains_calls_to_free(state)): + if (self.contains_buffer_constructors(state) and not self.contains_calls_to_free(state)): warnings.warn(MissingFreeWarning()) - - return False # we didn't modify the IR + return False # we didn't modify the IR class OmnisciCompilerPipeline(CompilerBase): diff --git a/rbc/tests/test_compiler_pipeline.py b/rbc/tests/test_compiler_pipeline.py index e22cd75d..14018422 100644 --- a/rbc/tests/test_compiler_pipeline.py +++ b/rbc/tests/test_compiler_pipeline.py @@ -6,6 +6,7 @@ from rbc.omnisci_backend.omnisci_pipeline import MissingFreeWarning from rbc.stdlib import array_api as xp + @pytest.fixture def rjit(): return RemoteJIT(local=True) @@ -22,6 +23,7 @@ def no_warnings(warning_cls): "Warnings were raised: " + ", ".join([str(w) for w in wlist]) ) + def test_no_warnings_decorator(): with no_warnings(MissingFreeWarning): pass @@ -34,14 +36,13 @@ def test_no_warnings_decorator(): warnings.warn(MissingFreeWarning()) - class TestDetectMissingFree: def test_missing_free(self, rjit): # basic case: we are creating an array but we don't call .free() @rjit('int32(int32)') def fn(size): - a = xp.Array(size, xp.float64) + a = xp.Array(size, xp.float64) # noqa: F841 return size with pytest.warns(MissingFreeWarning): From 36505782f2d1bb7be397ee8b9ca9de0a8ef310a1 Mon Sep 17 00:00:00 2001 From: Antonio Cuni Date: Thu, 3 Feb 2022 16:19:15 +0000 Subject: [PATCH 05/25] fix missing import --- rbc/omnisci_backend/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/rbc/omnisci_backend/__init__.py b/rbc/omnisci_backend/__init__.py index fd67c901..706f71b3 100644 --- a/rbc/omnisci_backend/__init__.py +++ b/rbc/omnisci_backend/__init__.py @@ -11,3 +11,4 @@ from .python_operators import * # noqa: F401, F403 from .omnisci_column_list import * # noqa: F401, F403 from .omnisci_table_function_manager import * # noqa: F401, F403 +from .omnisci_buffer import BufferMeta From b7d61dd401e1dd6b947944817ac5f437e30636a6 Mon Sep 17 00:00:00 2001 From: Antonio Cuni Date: Thu, 3 Feb 2022 16:21:44 +0000 Subject: [PATCH 06/25] flake8 again --- rbc/omnisci_backend/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rbc/omnisci_backend/__init__.py b/rbc/omnisci_backend/__init__.py index 706f71b3..ab769465 100644 --- a/rbc/omnisci_backend/__init__.py +++ b/rbc/omnisci_backend/__init__.py @@ -11,4 +11,4 @@ from .python_operators import * # noqa: F401, F403 from .omnisci_column_list import * # noqa: F401, F403 from .omnisci_table_function_manager import * # noqa: F401, F403 -from .omnisci_buffer import BufferMeta +from .omnisci_buffer import BufferMeta # noqa: F401 From 890629b6183666a5827c88c47de8b8da52b05cf7 Mon Sep 17 00:00:00 2001 From: Antonio Cuni Date: Thu, 3 Feb 2022 16:27:35 +0000 Subject: [PATCH 07/25] make sure to detect a call to free_buffer even if it's imported locally --- rbc/omnisci_backend/omnisci_pipeline.py | 7 ++++--- rbc/tests/test_compiler_pipeline.py | 16 ++++++++++++++++ 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/rbc/omnisci_backend/omnisci_pipeline.py b/rbc/omnisci_backend/omnisci_pipeline.py index d0449f6b..b4027662 100644 --- a/rbc/omnisci_backend/omnisci_pipeline.py +++ b/rbc/omnisci_backend/omnisci_pipeline.py @@ -136,6 +136,9 @@ def contains_buffer_constructors(self, state): return True return False + def is_free_buffer(self, rhs): + return isinstance(rhs, (ir.Global, ir.FreeVar)) and rhs.value is free_buffer + def is_BufferPoint_dot_free(self, state, expr): return (isinstance(expr, ir.Expr) and expr.op == 'getattr' and @@ -150,9 +153,7 @@ def contains_calls_to_free(self, state): func_ir = state.func_ir for inst in self.iter_calls(func_ir): rhs = func_ir.get_definition(inst.value.func) - if isinstance(rhs, ir.Global) and rhs.value is free_buffer: - return True - elif self.is_BufferPoint_dot_free(state, rhs): + if self.is_free_buffer(rhs) or self.is_BufferPoint_dot_free(state, rhs): return True return False diff --git a/rbc/tests/test_compiler_pipeline.py b/rbc/tests/test_compiler_pipeline.py index 14018422..5d11099b 100644 --- a/rbc/tests/test_compiler_pipeline.py +++ b/rbc/tests/test_compiler_pipeline.py @@ -60,6 +60,22 @@ def fn(size): res = fn(10) assert res == 10 + def test_detect_call_to_free_buffer_non_global(self, rjit): + # note, this is not a typo: we are aware that free_buffer is already + # imported globally, but here we want to check that we detect the call + # to free_buffer even when it's imported locally + from rbc.omnisci_backend.omnisci_buffer import free_buffer + + @rjit('int32(int32)') + def fn(size): + a = xp.Array(size, xp.float64) + free_buffer(a) + return size + + with no_warnings(MissingFreeWarning): + res = fn(10) + assert res == 10 + def test_detect_call_to_method_free(self, rjit): @rjit('int32(int32)') def fn(size): From 50ff854895ab94329555bcd4ec3de58385223c0d Mon Sep 17 00:00:00 2001 From: Antonio Cuni Date: Thu, 3 Feb 2022 16:44:19 +0000 Subject: [PATCH 08/25] make it possible to silence the memory leaks warnings --- rbc/irtools.py | 13 +++++++++--- rbc/omnisci_backend/omnisci_pipeline.py | 3 ++- rbc/remotejit.py | 28 ++++++++++++++++++++----- rbc/tests/test_compiler_pipeline.py | 10 +++++++++ 4 files changed, 45 insertions(+), 9 deletions(-) diff --git a/rbc/irtools.py b/rbc/irtools.py index 3795d9d9..e194b525 100644 --- a/rbc/irtools.py +++ b/rbc/irtools.py @@ -249,7 +249,8 @@ def compile_instance(func, sig, target_context, pipeline_class, main_library, - debug=False): + debug=False, + disable_leak_warnings=False): """Compile a function with given signature. Return function name when succesful. """ @@ -258,10 +259,12 @@ def compile_instance(func, sig, flags.no_compile = True flags.no_cpython_wrapper = True flags.no_cfunc_wrapper = True + flags.disable_leak_warnings = disable_leak_warnings else: flags.set('no_compile') flags.set('no_cpython_wrapper') flags.set('no_cfunc_wrapper') + flags.set('disable_leak_warnings', disable_leak_warnings) fname = func.__name__ + sig.mangling() args, return_type = sigutils.normalize_signature( @@ -333,7 +336,8 @@ def compile_to_LLVM(functions_and_signatures, target_info: TargetInfo, pipeline_class=compiler.Compiler, user_defined_llvm_ir=None, - debug=False): + debug=False, + disable_leak_warnings=False): """Compile functions with given signatures to target specific LLVM IR. Parameters @@ -346,6 +350,8 @@ def compile_to_LLVM(functions_and_signatures, Specify user-defined LLVM IR module that is linked in to the returned module. debug : bool + disable_leak_warnings: bool + Disable warnings about possible memory leaks when using Arrays Returns ------- @@ -379,7 +385,8 @@ def compile_to_LLVM(functions_and_signatures, fname = compile_instance(func, sig, target_info, typing_context, target_context, pipeline_class, main_library, - debug=debug) + debug=debug, + disable_leak_warnings=disable_leak_warnings) if fname is not None: succesful_fids.append(fid) function_names.append(fname) diff --git a/rbc/omnisci_backend/omnisci_pipeline.py b/rbc/omnisci_backend/omnisci_pipeline.py index b4027662..1e17dc1b 100644 --- a/rbc/omnisci_backend/omnisci_pipeline.py +++ b/rbc/omnisci_backend/omnisci_pipeline.py @@ -172,7 +172,8 @@ def define_pipelines(self): # Add the new pass to run after IRProcessing pm.add_pass_after(CheckRaiseStmts, IRProcessing) pm.add_pass_after(DTypeComparison, ReconstructSSA) - pm.add_pass_after(DetectMissingFree, NopythonTypeInference) + if not self.state.flags.disable_leak_warnings: + pm.add_pass_after(DetectMissingFree, NopythonTypeInference) # finalize pm.finalize() # return as an iterable, any number of pipelines may be defined! diff --git a/rbc/remotejit.py b/rbc/remotejit.py index 2bf0c653..e5122749 100644 --- a/rbc/remotejit.py +++ b/rbc/remotejit.py @@ -51,7 +51,7 @@ def extract_templates(options): correspond to a concrete type. """ - known_options = ['devices', 'local'] + known_options = ['devices', 'local', 'disable_leak_warnings'] new_options = {} templates = options.get('templates') if templates is not None: @@ -104,6 +104,7 @@ def __init__(self, remotejit): self.signatures = [] self.signature_devices = {} self.signature_templates = {} + self.disable_leak_warnings = False @property def debug(self): @@ -135,6 +136,9 @@ def __call__(self, obj, **options): Specify device names for the given set of signatures. templates : dict Specify template types mapping. + disable_leak_warnings : bool + When True, disable the compile-time warnings about missing calls to Array.free. + Default is False Returns ------- @@ -155,9 +159,14 @@ def __call__(self, obj, **options): return self options, templates = extract_templates(options) devices = options.get('devices') + # if we specifiy disable_leak_warnings, override the previous settings + if 'disable_leak_warnings' in options: + self.disable_leak_warnings = options['disable_leak_warnings'] if isinstance(obj, Signature): self.signatures.extend(obj.signatures) self.signature_devices.update(obj.signature_devices) + # propagate this option from the original signature + self.disable_leak_warnings = obj.disable_leak_warnings self.remotejit.discard_last_compile() if devices is not None: for s in obj.signatures: @@ -386,7 +395,8 @@ def __call__(self, *arguments, **options): ftype = self.signature.best_match(self.func, atypes) key = self.func.__name__, ftype if key not in self._is_compiled: - self.remotejit.remote_compile(self.func, ftype, target_info) + self.remotejit.remote_compile(self.func, ftype, target_info, + self.signature.disable_leak_warnings) self._is_compiled.add(key) return self.remotejit.remote_call(self.func, ftype, arguments) @@ -597,6 +607,9 @@ def __call__(self, *signatures, **options): Specify device names for the given set of signatures. templates : dict Specify template types mapping. + disable_leak_warnings : bool + When True, disable the compile-time warnings about missing calls to Array.free. + Default is False Returns ------- @@ -617,9 +630,12 @@ def __call__(self, *signatures, **options): else: s = Signature(self) devices = options.get('devices') + disable_leak_warnings = options.get('disable_leak_warnings', False) options, templates = extract_templates(options) + for sig in signatures: - s = s(sig, devices=devices, templates=templates) + s = s(sig, devices=devices, disable_leak_warnings=disable_leak_warnings, + templates=templates) return s def start_server(self, background=False): @@ -666,7 +682,8 @@ def client(self): socket_timeout=60000) return self._client - def remote_compile(self, func, ftype: Type, target_info: TargetInfo): + def remote_compile(self, func, ftype: Type, target_info: TargetInfo, + disable_leak_warnings=False): """Remote compile function and signatures to machine code. The input function `func` is compiled to LLVM IR module, the @@ -682,7 +699,8 @@ def remote_compile(self, func, ftype: Type, target_info: TargetInfo): [(func, {0: ftype})], target_info, pipeline_class=OmnisciCompilerPipeline, - debug=self.debug) + debug=self.debug, + disable_leak_warnings=disable_leak_warnings,) ir = str(llvm_module) mangled_signatures = ';'.join([s.mangle() for s in [ftype]]) response = self.client(remotejit=dict( diff --git a/rbc/tests/test_compiler_pipeline.py b/rbc/tests/test_compiler_pipeline.py index 5d11099b..3abe44ad 100644 --- a/rbc/tests/test_compiler_pipeline.py +++ b/rbc/tests/test_compiler_pipeline.py @@ -49,6 +49,16 @@ def fn(size): res = fn(10) assert res == 10 + def test_disable_leak_warnings(self, rjit): + @rjit('int32(int32)', disable_leak_warnings=True) + def fn(size): + a = xp.Array(size, xp.float64) # noqa: F841 + return size + + with no_warnings(MissingFreeWarning): + res = fn(10) + assert res == 10 + def test_detect_call_to_free_buffer(self, rjit): @rjit('int32(int32)') def fn(size): From 3bbd923f8c2a575fb8fd7da5b80a5df7566ea447 Mon Sep 17 00:00:00 2001 From: Antonio Cuni Date: Fri, 4 Feb 2022 15:36:12 +0000 Subject: [PATCH 09/25] use another approach to propagate the disable_leak_warning function, because the old one didn't work with @omnisci --- rbc/irtools.py | 12 ++++-------- rbc/remotejit.py | 11 +++++------ 2 files changed, 9 insertions(+), 14 deletions(-) diff --git a/rbc/irtools.py b/rbc/irtools.py index 33964a7e..20b90a7b 100644 --- a/rbc/irtools.py +++ b/rbc/irtools.py @@ -263,11 +263,11 @@ def compile_instance(func, sig, target_context, pipeline_class, main_library, - debug=False, - disable_leak_warnings=False): + debug=False): """Compile a function with given signature. Return function name when succesful. """ + disable_leak_warnings = getattr(func, '__disable_leak_warnings__', False) flags = compiler.Flags() if get_version('numba') >= (0, 54): flags.no_compile = True @@ -350,8 +350,7 @@ def compile_to_LLVM(functions_and_signatures, target_info: TargetInfo, pipeline_class=compiler.Compiler, user_defined_llvm_ir=None, - debug=False, - disable_leak_warnings=False): + debug=False): """Compile functions with given signatures to target specific LLVM IR. Parameters @@ -364,8 +363,6 @@ def compile_to_LLVM(functions_and_signatures, Specify user-defined LLVM IR module that is linked in to the returned module. debug : bool - disable_leak_warnings: bool - Disable warnings about possible memory leaks when using Arrays Returns ------- @@ -399,8 +396,7 @@ def compile_to_LLVM(functions_and_signatures, fname = compile_instance(func, sig, target_info, typing_context, target_context, pipeline_class, main_library, - debug=debug, - disable_leak_warnings=disable_leak_warnings) + debug=debug) if fname is not None: succesful_fids.append(fid) function_names.append(fname) diff --git a/rbc/remotejit.py b/rbc/remotejit.py index fef80dcf..d49a3a86 100644 --- a/rbc/remotejit.py +++ b/rbc/remotejit.py @@ -199,6 +199,8 @@ def __call__(self, obj, **options): assert not templates return Caller(obj.func, final) if isfunctionlike(obj): + if self.disable_leak_warnings: + obj.__disable_leak_warnings__ = True final = Signature(self.remotejit) final(self) # copies the signatures from self to final assert devices is None @@ -499,8 +501,7 @@ def execute(self, hold=False): key = self.caller.func.__name__, self.ftype if key not in self.caller._is_compiled: self.caller.remotejit.remote_compile( - self.caller.func, self.ftype, self.target_info, - self.caller.signature.disable_leak_warnings) + self.caller.func, self.ftype, self.target_info) self.caller._is_compiled.add(key) result = self.caller.remotejit.remote_call(self.caller.func, self.ftype, self.arguments, hold=hold) @@ -811,8 +812,7 @@ def client(self): socket_timeout=60000) return self._client - def remote_compile(self, func, ftype: Type, target_info: TargetInfo, - disable_leak_warnings=False): + def remote_compile(self, func, ftype: Type, target_info: TargetInfo): """Remote compile function and signatures to machine code. The input function `func` is compiled to LLVM IR module, the @@ -829,8 +829,7 @@ def remote_compile(self, func, ftype: Type, target_info: TargetInfo, [(func, {0: ftype})], target_info, pipeline_class=OmnisciCompilerPipeline, - debug=self.debug, - disable_leak_warnings=disable_leak_warnings,) + debug=self.debug) ir = str(llvm_module) mangled_signatures = ';'.join([s.mangle() for s in [ftype]]) response = self.client(remotejit=dict( From aac9aab77622500c1c0d8a8c09d14960d567fd72 Mon Sep 17 00:00:00 2001 From: Pearu Peterson Date: Sat, 5 Feb 2022 21:35:02 +0200 Subject: [PATCH 10/25] Include the function location to the missing free warning message. --- rbc/omnisci_backend/omnisci_pipeline.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/rbc/omnisci_backend/omnisci_pipeline.py b/rbc/omnisci_backend/omnisci_pipeline.py index 1e17dc1b..de23e3a7 100644 --- a/rbc/omnisci_backend/omnisci_pipeline.py +++ b/rbc/omnisci_backend/omnisci_pipeline.py @@ -99,13 +99,14 @@ def run_pass(self, state): class MissingFreeWarning(Warning): _msg = """ - Possible memory leak detected! + Possible memory leak detected in function `{}` defined in {}#{}! + In RBC, arrays and buffers must be freed manually by calling the method .free() or the function free_buffer(): see the relevant docs. """ - def __init__(self): - Warning.__init__(self, self._msg) + def __init__(self, functionname, filename, firstlineno): + Warning.__init__(self, self._msg.format(functionname, filename, firstlineno)) @register_pass(mutates_CFG=False, analysis_only=True) @@ -159,7 +160,8 @@ def contains_calls_to_free(self, state): def run_pass(self, state): if (self.contains_buffer_constructors(state) and not self.contains_calls_to_free(state)): - warnings.warn(MissingFreeWarning()) + warnings.warn(MissingFreeWarning( + state.func_id.func_name, state.func_id.filename, state.func_id.firstlineno)) return False # we didn't modify the IR From 5fc872ef647d068ad0f93abfb44aecc150691ba1 Mon Sep 17 00:00:00 2001 From: Pearu Peterson Date: Sat, 5 Feb 2022 22:03:15 +0200 Subject: [PATCH 11/25] Fix test_no_warnings_decorator --- rbc/tests/test_compiler_pipeline.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rbc/tests/test_compiler_pipeline.py b/rbc/tests/test_compiler_pipeline.py index 3abe44ad..10216dea 100644 --- a/rbc/tests/test_compiler_pipeline.py +++ b/rbc/tests/test_compiler_pipeline.py @@ -16,7 +16,6 @@ def rjit(): def no_warnings(warning_cls): with pytest.warns(None) as wlist: yield - wlist = [w.message for w in wlist if isinstance(w.message, warning_cls)] if wlist: raise AssertionError( @@ -33,7 +32,8 @@ def test_no_warnings_decorator(): with pytest.raises(AssertionError, match='Warnings were raised'): with no_warnings(MissingFreeWarning): - warnings.warn(MissingFreeWarning()) + c = test_no_warnings_decorator.__code__ + warnings.warn(MissingFreeWarning(c.co_name, c.co_filename, c.co_firstlineno)) class TestDetectMissingFree: From b4707a5e0254a0c5f6d6da688e72f0cd254b1fef Mon Sep 17 00:00:00 2001 From: Antonio Cuni Date: Mon, 7 Feb 2022 10:04:45 +0000 Subject: [PATCH 12/25] change disable_leak_warnings into on_missing_free, which now can be 'warn', 'fail' or 'ignore' --- rbc/irtools.py | 19 ++++++---- rbc/omnisci_backend/omnisci_pipeline.py | 16 +++++++-- rbc/remotejit.py | 48 ++++++++++++++----------- rbc/tests/test_compiler_pipeline.py | 29 ++++++++++++--- 4 files changed, 80 insertions(+), 32 deletions(-) diff --git a/rbc/irtools.py b/rbc/irtools.py index 20b90a7b..bbcf6daf 100644 --- a/rbc/irtools.py +++ b/rbc/irtools.py @@ -263,22 +263,25 @@ def compile_instance(func, sig, target_context, pipeline_class, main_library, - debug=False): + debug=False, + on_missing_free='warn'): """Compile a function with given signature. Return function name when succesful. """ - disable_leak_warnings = getattr(func, '__disable_leak_warnings__', False) + # individual functions can override the global settig + if hasattr(func, '__on_missing_free__'): + on_missing_free = func.__on_missing_free__ flags = compiler.Flags() if get_version('numba') >= (0, 54): flags.no_compile = True flags.no_cpython_wrapper = True flags.no_cfunc_wrapper = True - flags.disable_leak_warnings = disable_leak_warnings + flags.on_missing_free = on_missing_free else: flags.set('no_compile') flags.set('no_cpython_wrapper') flags.set('no_cfunc_wrapper') - flags.set('disable_leak_warnings', disable_leak_warnings) + flags.set('on_missing_free', on_missing_free) fname = func.__name__ + sig.mangling() args, return_type = sigutils.normalize_signature( @@ -350,7 +353,8 @@ def compile_to_LLVM(functions_and_signatures, target_info: TargetInfo, pipeline_class=compiler.Compiler, user_defined_llvm_ir=None, - debug=False): + debug=False, + on_missing_free='warn'): """Compile functions with given signatures to target specific LLVM IR. Parameters @@ -363,6 +367,8 @@ def compile_to_LLVM(functions_and_signatures, Specify user-defined LLVM IR module that is linked in to the returned module. debug : bool + on_missing_free: str + 'warn', 'fail' or 'ignore'. Returns ------- @@ -396,7 +402,8 @@ def compile_to_LLVM(functions_and_signatures, fname = compile_instance(func, sig, target_info, typing_context, target_context, pipeline_class, main_library, - debug=debug) + debug=debug, + on_missing_free=on_missing_free) if fname is not None: succesful_fids.append(fid) function_names.append(fname) diff --git a/rbc/omnisci_backend/omnisci_pipeline.py b/rbc/omnisci_backend/omnisci_pipeline.py index 1e17dc1b..892860f5 100644 --- a/rbc/omnisci_backend/omnisci_pipeline.py +++ b/rbc/omnisci_backend/omnisci_pipeline.py @@ -108,6 +108,12 @@ def __init__(self): Warning.__init__(self, self._msg) +class MissingFreeError(Exception): + + def __init__(self): + Exception.__init__(self, MissingFreeWarning._msg) + + @register_pass(mutates_CFG=False, analysis_only=True) class DetectMissingFree(FunctionPass): _name = "DetectMissingFree" @@ -158,8 +164,14 @@ def contains_calls_to_free(self, state): return False def run_pass(self, state): + on_missing_free= state.flags.on_missing_free if (self.contains_buffer_constructors(state) and not self.contains_calls_to_free(state)): - warnings.warn(MissingFreeWarning()) + if on_missing_free == 'warn': + warnings.warn(MissingFreeWarning()) + elif on_missing_free == 'fail': + raise MissingFreeError() + else: + raise ValueError(f"Unexpected value for on_missing_free: got {on_missing_free:r}, expected 'warn', 'fail' or 'ignore'") return False # we didn't modify the IR @@ -172,7 +184,7 @@ def define_pipelines(self): # Add the new pass to run after IRProcessing pm.add_pass_after(CheckRaiseStmts, IRProcessing) pm.add_pass_after(DTypeComparison, ReconstructSSA) - if not self.state.flags.disable_leak_warnings: + if self.state.flags.on_missing_free != 'ignore': pm.add_pass_after(DetectMissingFree, NopythonTypeInference) # finalize pm.finalize() diff --git a/rbc/remotejit.py b/rbc/remotejit.py index d49a3a86..722a27de 100644 --- a/rbc/remotejit.py +++ b/rbc/remotejit.py @@ -18,7 +18,7 @@ from .rbclib import tracing_allocator # XXX WIP: the OmnisciCompilerPipeline is no longer omnisci-specific because # we support Arrays even without omnisci, so it must be renamed and moved -# somewhere elsef +# somewhere else from .omnisci_backend import OmnisciCompilerPipeline @@ -52,7 +52,7 @@ def extract_templates(options): correspond to a concrete type. """ - known_options = ['devices', 'local', 'disable_leak_warnings'] + known_options = ['devices', 'local', 'on_missing_free'] new_options = {} templates = options.get('templates') if templates is not None: @@ -105,7 +105,7 @@ def __init__(self, remotejit): self.signatures = [] self.signature_devices = {} self.signature_templates = {} - self.disable_leak_warnings = False + self.on_missing_free = None @property def debug(self): @@ -148,9 +148,10 @@ def __call__(self, obj, **options): Specify device names for the given set of signatures. templates : dict Specify template types mapping. - disable_leak_warnings : bool - When True, disable the compile-time warnings about missing calls to Array.free. - Default is False + on_missing_free : str + Determine what to do if we detect a missing call to Array.free. + Can be None, 'warn', 'fail' or 'ignore. Default is None, which + means to use the default setting Returns ------- @@ -171,14 +172,14 @@ def __call__(self, obj, **options): return self options, templates = extract_templates(options) devices = options.get('devices') - # if we specifiy disable_leak_warnings, override the previous settings - if 'disable_leak_warnings' in options: - self.disable_leak_warnings = options['disable_leak_warnings'] + # if we specifiy on_missing_free, override the previous settings + if 'on_missing_free' in options: + self.on_missing_free = options['on_missing_free'] if isinstance(obj, Signature): self.signatures.extend(obj.signatures) self.signature_devices.update(obj.signature_devices) # propagate this option from the original signature - self.disable_leak_warnings = obj.disable_leak_warnings + self.on_missing_free = obj.on_missing_free self.remotejit.discard_last_compile() if devices is not None: for s in obj.signatures: @@ -199,8 +200,8 @@ def __call__(self, obj, **options): assert not templates return Caller(obj.func, final) if isfunctionlike(obj): - if self.disable_leak_warnings: - obj.__disable_leak_warnings__ = True + if self.on_missing_free is not None: + obj.__on_missing_free__ = self.on_missing_free final = Signature(self.remotejit) final(self) # copies the signatures from self to final assert devices is None @@ -552,7 +553,8 @@ def bar(a, b): default_remote_call_hold = False def __init__(self, host='localhost', port=11532, - local=False, debug=False, use_tracing_allocator=False): + local=False, debug=False, use_tracing_allocator=False, + on_missing_free='warn'): """Construct remote JIT function decorator. The decorator is re-usable for different functions. @@ -569,13 +571,17 @@ def __init__(self, host='localhost', port=11532, When True, output debug messages. use_tracing_allocator : bool When True, enable the automatic detection of memory leaks. + on_missing_free: str + Determine what to do if we statically determine a possible missing call to + Array.free(): can be 'warn', 'fail' or 'ignore'. """ if host == 'localhost': host = get_local_ip() if use_tracing_allocator and not local: raise ValueError('use_tracing_allocator=True can be used only with local=True') - + assert on_missing_free in ('warn', 'fail', 'ignore') + self.on_missing_free = on_missing_free self.debug = debug self.use_tracing_allocator = use_tracing_allocator self.host = host @@ -737,9 +743,10 @@ def __call__(self, *signatures, **options): Specify device names for the given set of signatures. templates : dict Specify template types mapping. - disable_leak_warnings : bool - When True, disable the compile-time warnings about missing calls to Array.free. - Default is False + on_missing_free : str + Determine what to do if we detect a missing call to Array.free. + Can be None, 'warn', 'fail' or 'ignore. Default is None, which means + to use the global settings which is set on the RemoteJIT. Returns ------- @@ -760,11 +767,11 @@ def __call__(self, *signatures, **options): else: s = Signature(self) devices = options.get('devices') - disable_leak_warnings = options.get('disable_leak_warnings', False) + on_missing_free = options.get('on_missing_free', None) options, templates = extract_templates(options) for sig in signatures: - s = s(sig, devices=devices, disable_leak_warnings=disable_leak_warnings, + s = s(sig, devices=devices, on_missing_free=on_missing_free, templates=templates) return s @@ -829,7 +836,8 @@ def remote_compile(self, func, ftype: Type, target_info: TargetInfo): [(func, {0: ftype})], target_info, pipeline_class=OmnisciCompilerPipeline, - debug=self.debug) + debug=self.debug, + on_missing_free=self.on_missing_free) ir = str(llvm_module) mangled_signatures = ';'.join([s.mangle() for s in [ftype]]) response = self.client(remotejit=dict( diff --git a/rbc/tests/test_compiler_pipeline.py b/rbc/tests/test_compiler_pipeline.py index 3abe44ad..b9979f72 100644 --- a/rbc/tests/test_compiler_pipeline.py +++ b/rbc/tests/test_compiler_pipeline.py @@ -3,7 +3,7 @@ import warnings from rbc.remotejit import RemoteJIT from rbc.omnisci_backend.omnisci_buffer import free_buffer -from rbc.omnisci_backend.omnisci_pipeline import MissingFreeWarning +from rbc.omnisci_backend.omnisci_pipeline import MissingFreeWarning, MissingFreeError from rbc.stdlib import array_api as xp @@ -38,7 +38,7 @@ def test_no_warnings_decorator(): class TestDetectMissingFree: - def test_missing_free(self, rjit): + def test_on_missing_free_warn(self, rjit): # basic case: we are creating an array but we don't call .free() @rjit('int32(int32)') def fn(size): @@ -49,8 +49,17 @@ def fn(size): res = fn(10) assert res == 10 - def test_disable_leak_warnings(self, rjit): - @rjit('int32(int32)', disable_leak_warnings=True) + def test_on_missing_free_fail(self, rjit): + @rjit('int32(int32)', on_missing_free='fail') + def fn(size): + a = xp.Array(size, xp.float64) # noqa: F841 + return size + + with pytest.raises(MissingFreeError): + res = fn(10) + + def test_on_missing_free_ignore(self, rjit): + @rjit('int32(int32)', on_missing_free='ignore') def fn(size): a = xp.Array(size, xp.float64) # noqa: F841 return size @@ -59,6 +68,18 @@ def fn(size): res = fn(10) assert res == 10 + def test_set_on_missing_globally(self): + my_rjit = RemoteJIT(local=True, on_missing_free='fail') + @my_rjit('int32(int32)') + def fn(size): + a = xp.Array(size, xp.float64) # noqa: F841 + return size + + # this raises because on_missing_free='fail' it set globablly on the + # RemoteJIT instance + with pytest.raises(MissingFreeError): + res = fn(10) + def test_detect_call_to_free_buffer(self, rjit): @rjit('int32(int32)') def fn(size): From 957a958432e9e080652cd9a90c1d70938a2fc23c Mon Sep 17 00:00:00 2001 From: Antonio Cuni Date: Mon, 7 Feb 2022 10:12:49 +0000 Subject: [PATCH 13/25] make sure that test_omnisci_array and test_omnisci_array_functions don't emit MissingFree warnings --- rbc/omniscidb.py | 3 ++- rbc/tests/test_omnisci_array.py | 27 ++++++++++++++++------- rbc/tests/test_omnisci_array_functions.py | 7 +++--- 3 files changed, 25 insertions(+), 12 deletions(-) diff --git a/rbc/omniscidb.py b/rbc/omniscidb.py index 901a204c..370a5486 100644 --- a/rbc/omniscidb.py +++ b/rbc/omniscidb.py @@ -1175,7 +1175,8 @@ def _register(self): target_info, pipeline_class=OmnisciCompilerPipeline, user_defined_llvm_ir=self.user_defined_llvm_ir.get(device), - debug=self.debug) + debug=self.debug, + on_missing_free=self.on_missing_free) assert llvm_module.triple == target_info.triple assert llvm_module.data_layout == target_info.datalayout diff --git a/rbc/tests/test_omnisci_array.py b/rbc/tests/test_omnisci_array.py index 69647116..13e66a13 100644 --- a/rbc/tests/test_omnisci_array.py +++ b/rbc/tests/test_omnisci_array.py @@ -14,7 +14,7 @@ def omnisci(): # TODO: use omnisci_fixture from rbc/tests/__init__.py config = rbc_omnisci.get_client_config(debug=not True) - m = rbc_omnisci.RemoteOmnisci(**config) + m = rbc_omnisci.RemoteOmnisci(on_missing_free='fail', **config) table_name = os.path.splitext(os.path.basename(__file__))[0] m.sql_execute(f'DROP TABLE IF EXISTS {table_name}') @@ -288,6 +288,9 @@ def array_noreturn(size): s = 0.0 for i in range(size): s += a[i] + b[i] + c[i] - a[i] * b[i] + a.free() + b.free() + c.free() return s query = 'select array_noreturn(10)' @@ -313,8 +316,10 @@ def array_return(size): b[i] = float(size - i - 1) if size % 2: c = a + b.free() else: c = b + a.free() printf("returning array with length %i\n", len(c)) return c @@ -335,7 +340,9 @@ def test_array_constructor_len(omnisci): @omnisci('int64(int32)') def array_len(size): a = Array(size, types.float64) - return len(a) + res = len(a) + a.free() + return res query = 'select array_len(30)' _, result = omnisci.sql_execute(query) @@ -354,7 +361,9 @@ def array_ptr(size, pos): a = Array(size, np.double) for i in range(size): a[i] = i + 0.0 - return a[pos] + res = a[pos] + a.free() + return res query = 'select array_ptr(5, 3)' _, result = omnisci.sql_execute(query) @@ -370,7 +379,9 @@ def test_array_constructor_is_null(omnisci): @omnisci('int8(int64)') def array_is_null(size): a = Array(size, 'double') - return a.is_null() + res = a.is_null() + a.free() + return res query = 'select array_is_null(3);' _, result = omnisci.sql_execute(query) @@ -407,7 +418,7 @@ def fn_issue197(x): fn_name = f"fn_issue197_{typ}_{suffix}" fn_issue197.__name__ = fn_name - omnisci(f'{typ}[]({typ}[])')(fn_issue197) + omnisci(f'{typ}[]({typ}[])', on_missing_free='ignore')(fn_issue197) _, result = omnisci.sql_execute( f'SELECT {col}, {fn_name}({col}) FROM {omnisci.table_name};' @@ -423,7 +434,7 @@ def test_issue197_bool(omnisci): import rbc.omnisci_backend as np - @omnisci('bool[](bool[])') + @omnisci('bool[](bool[])', on_missing_free='ignore') def fn_issue197_bool(x): y = np.zeros_like(x) for i in range(len(x)): @@ -444,7 +455,7 @@ def fn_issue197_bool(x): def test_issue109(omnisci): - @omnisci('double[](int32)') + @omnisci('double[](int32)', on_missing_free='ignore') def issue109(size): a = Array(5, 'double') for i in range(5): @@ -457,7 +468,7 @@ def issue109(size): def test_issue77(omnisci): - @omnisci('int64[]()') + @omnisci('int64[]()', on_missing_free='ignore') def issue77(): a = Array(5, 'int64') a.fill(1) diff --git a/rbc/tests/test_omnisci_array_functions.py b/rbc/tests/test_omnisci_array_functions.py index a784d8ee..82bf818f 100644 --- a/rbc/tests/test_omnisci_array_functions.py +++ b/rbc/tests/test_omnisci_array_functions.py @@ -13,7 +13,7 @@ def omnisci(): # TODO: use omnisci_fixture from rbc/tests/__init__.py config = rbc_omnisci.get_client_config(debug=not True) - m = rbc_omnisci.RemoteOmnisci(**config) + m = rbc_omnisci.RemoteOmnisci(on_missing_free='fail', **config) table_name = 'rbc_test_omnisci_array' m.sql_execute(f'DROP TABLE IF EXISTS {table_name}') @@ -130,7 +130,7 @@ def np_cumsum(sz): def test_array_methods(omnisci, method, signature, args, expected): omnisci.reset() - fn = omnisci(signature)(eval('np_{}'.format(method))) + fn = omnisci(signature, on_missing_free='ignore')(eval('np_{}'.format(method))) query = 'select np_{method}'.format(**locals()) + \ '(' + ', '.join(map(str, args)) + ')' + \ @@ -146,7 +146,8 @@ def test_array_methods(omnisci, method, signature, args, expected): def test_dtype(omnisci, col): omnisci.reset() - @omnisci('T[](T[])', T=['int32', 'int64', 'float32'], devices=['cpu']) + @omnisci('T[](T[])', T=['int32', 'int64', 'float32'], devices=['cpu'], + on_missing_free='ignore') def zeros_like(x): z = omni.zeros(len(x), x.dtype) return z From ddc9e4849bf7822500ad98f60819d49374085603 Mon Sep 17 00:00:00 2001 From: Antonio Cuni Date: Mon, 7 Feb 2022 10:29:32 +0000 Subject: [PATCH 14/25] fix warnings --- rbc/tests/test_omnisci_array_math.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/rbc/tests/test_omnisci_array_math.py b/rbc/tests/test_omnisci_array_math.py index 2fb86e45..0b150c02 100644 --- a/rbc/tests/test_omnisci_array_math.py +++ b/rbc/tests/test_omnisci_array_math.py @@ -12,7 +12,7 @@ def omnisci(): # TODO: use omnisci_fixture from rbc/tests/__init__.py config = rbc_omnisci.get_client_config(debug=not True) - m = rbc_omnisci.RemoteOmnisci(**config) + m = rbc_omnisci.RemoteOmnisci(on_missing_free='fail', **config) table_name = 'rbc_test_omnisci_array' m.sql_execute(f'DROP TABLE IF EXISTS {table_name}') @@ -116,7 +116,7 @@ def test_omnisci_array_binary_math(omnisci, method, signature, columns): s = f'def np_{method}(a, b): return omni.{method}(a, b)' exec(s, globals()) - omnisci(signature)(eval('np_{}'.format(method))) + omnisci(signature, on_missing_free='ignore')(eval('np_{}'.format(method))) ca, cb = columns.split(',') @@ -178,7 +178,7 @@ def test_omnisci_array_binary_math_scalar(omnisci, method, signature, args): s = f'def np_{method}(a, b): return omni.{method}(a, b)' exec(s, globals()) - omnisci(signature)(eval('np_{}'.format(method))) + omnisci(signature, on_missing_free='ignore')(eval('np_{}'.format(method))) t = tuple(args.split(',')) a, b = t[0], t[1] @@ -261,7 +261,7 @@ def test_omnisci_array_unary_math_fns(omnisci, method, signature, column): s = f'def np_{method}(a): return omni.{method}(a)' exec(s, globals()) - omnisci(signature)(eval('np_{}'.format(method))) + omnisci(signature, on_missing_free='ignore')(eval('np_{}'.format(method))) query = f'select {column}, ' + \ f'np_{method}({column})' + \ @@ -280,7 +280,7 @@ def test_omnisci_array_unary_math_fns(omnisci, method, signature, column): def test_heaviside(omnisci): - @omnisci('double[](int64[], int64)') + @omnisci('double[](int64[], int64)', on_missing_free='ignore') def heaviside(x1, x2): return omni.heaviside(x1, x2) From 1ad3b1cde8093cd3ef440cb0b29f489f5956b31c Mon Sep 17 00:00:00 2001 From: Antonio Cuni Date: Mon, 7 Feb 2022 10:34:16 +0000 Subject: [PATCH 15/25] fix MissingFree warnings/errors in test_omnisci_array_methods --- rbc/tests/__init__.py | 2 +- rbc/tests/test_omnisci_array_methods.py | 42 ++++++++++++++++++------- 2 files changed, 32 insertions(+), 12 deletions(-) diff --git a/rbc/tests/__init__.py b/rbc/tests/__init__.py index 7bd4c461..438fe240 100644 --- a/rbc/tests/__init__.py +++ b/rbc/tests/__init__.py @@ -164,7 +164,7 @@ def require_version(version, message=None, label=None): table_name = os.path.splitext(os.path.basename(filename))[0] config = rbc_omnisci.get_client_config(debug=debug) - m = rbc_omnisci.RemoteOmnisci(**config) + m = rbc_omnisci.RemoteOmnisci(on_missing_free='fail', **config) sqltypes = ['FLOAT', 'DOUBLE', 'TINYINT', 'SMALLINT', 'INT', 'BIGINT', 'BOOLEAN'] diff --git a/rbc/tests/test_omnisci_array_methods.py b/rbc/tests/test_omnisci_array_methods.py index ddedc4bf..1f087665 100644 --- a/rbc/tests/test_omnisci_array_methods.py +++ b/rbc/tests/test_omnisci_array_methods.py @@ -54,7 +54,7 @@ def omnisci(): def define(omnisci): - @omnisci('double[](int64, double)') + @omnisci('double[](int64, double)', on_missing_free='ignore') def ndarray_fill(size, v): a = Array(size, 'double') a.fill(v) @@ -64,14 +64,18 @@ def ndarray_fill(size, v): def ndarray_max(size, v): a = Array(size, 'double') a.fill(v) - return a.max() + res = a.max() + a.free() + return res for retty in NUMERIC_TYPES: for op in ('min', 'max', 'mean'): fn_name = f'ndarray_{op}_empty_{retty}' fn = (f'def {fn_name}(size):\n' f' a = Array(size, "{retty}")\n' - f' return a.{op}()\n') + f' res = a.{op}()\n' + f' a.free()\n' + f' return res') exec(fn) fn = locals()[fn_name] if op == 'mean': @@ -83,49 +87,65 @@ def ndarray_max(size, v): def ndarray_max_initial(size, v, initial): a = Array(size, 'double') a.fill(v) - return a.max(initial=initial) + res = a.max(initial=initial) + a.free() + return res @omnisci('double(int64, double)') def ndarray_mean(size, v): a = Array(size, 'double') a.fill(v) - return a.mean() + res = a.mean() + a.free() + return res @omnisci('double(int64, double)') def ndarray_min(size, v): a = Array(size, 'double') a.fill(v) - return a.min() + res = a.min() + a.free() + return res @omnisci('double(int64, double, double)') def ndarray_min_initial(size, v, initial): a = Array(size, 'double') a.fill(v) - return a.min(initial=initial) + res = a.min(initial=initial) + a.free() + return res @omnisci('double(int64, double)') def ndarray_sum(size, v): a = Array(size, 'double') a.fill(v) - return a.sum() + res = a.sum() + a.free() + return res @omnisci('double(int64, double, double)') def ndarray_sum_initial(size, v, initial): a = Array(size, 'double') a.fill(v) - return a.sum(initial=initial) + res = a.sum(initial=initial) + a.free() + return res @omnisci('double(int64, double)') def ndarray_prod(size, v): a = Array(size, 'double') a.fill(v) - return a.prod() + res = a.prod() + a.free() + return res @omnisci('double(int64, double, double)') def ndarray_prod_initial(size, v, initial): a = Array(size, 'double') a.fill(v) - return a.prod(initial=initial) + res = a.prod(initial=initial) + a.free() + return res @pytest.mark.parametrize("method, args, expected", ndarray_methods, From 482d8ef00af4acf86ffccb7becb8beeb5aeadbbf Mon Sep 17 00:00:00 2001 From: Antonio Cuni Date: Mon, 7 Feb 2022 10:42:32 +0000 Subject: [PATCH 16/25] fix MissingFree warnings/errors in test_omnisci_array_operators and test_omnisci_caller --- rbc/tests/test_omnisci_array_operators.py | 182 ++++++++++++++++------ rbc/tests/test_omnisci_caller.py | 2 +- 2 files changed, 134 insertions(+), 50 deletions(-) diff --git a/rbc/tests/test_omnisci_array_operators.py b/rbc/tests/test_omnisci_array_operators.py index 521487d9..0a272482 100644 --- a/rbc/tests/test_omnisci_array_operators.py +++ b/rbc/tests/test_omnisci_array_operators.py @@ -79,7 +79,9 @@ def operator_abs(size): a = Array(size, 'int32') for i in range(size): a[i] = nb_types.int32(-i) - return abs(a) + res = abs(a) + a.free() + return res @omnisci('int32[](int64)') def operator_add(size): @@ -88,7 +90,9 @@ def operator_add(size): for i in range(size): a[i] = nb_types.int32(i) b[i] = nb_types.int32(size-i-1) - return operator.add(a, b) + res = operator.add(a, b) + a.free() + return res @omnisci('int32[](int64)') def operator_and_bw(size): @@ -97,28 +101,36 @@ def operator_and_bw(size): for i in range(size): a[i] = nb_types.int32(i) b[i] = nb_types.int32(size-i-1) - return operator.and_(a, b) + res = operator.and_(a, b) + a.free() + return res @omnisci('int64(int64, int64, int64)') def operator_countOf(size, fill_value, b): a = Array(size, 'int64') for i in range(size): a[i] = fill_value - return operator.countOf(a, b) + res = operator.countOf(a, b) + a.free() + return res @omnisci('int8[](int64, int32)') def operator_eq(size, v): a = Array(size, 'int32') for i in range(size): a[i] = nb_types.int32(i) - return a == v + res = a == v + a.free() + return res @omnisci('bool(int64, int32)') def operator_eq_array(size, v): a = Array(size, 'int32') for i in range(size): a[i] = nb_types.int32(i) - return a == a + res = a == a + a.free() + return res @omnisci('int32[](int64)') def operator_floordiv(size): @@ -127,7 +139,9 @@ def operator_floordiv(size): for i in range(size): a[i] = nb_types.int32(i+10) b[i] = nb_types.int32(i+3) - return operator.floordiv(a, b) + res = operator.floordiv(a, b) + a.free() + return res @omnisci('double[](int64)') def operator_floordiv2(size): @@ -136,37 +150,47 @@ def operator_floordiv2(size): for i in range(size): a[i] = nb_types.double(i+10) b[i] = nb_types.double(i+3) - return operator.floordiv(a, b) + res = operator.floordiv(a, b) + a.free() + return res @omnisci('int8[](int64, int32)') def operator_ge(size, v): a = Array(size, 'int32') for i in range(size): a[i] = nb_types.int32(i) - return a >= v + res = a >= v + a.free() + return res @omnisci('bool(int64, int32)') def operator_ge_array(size, v): a = Array(size, 'int32') for i in range(size): a[i] = nb_types.int32(i) - return a >= a + res = a >= a + a.free() + return res @omnisci('int8[](int64, int32)') def operator_gt(size, v): a = Array(size, 'int32') for i in range(size): a[i] = nb_types.int32(i) - return a > v + res = a > v + a.free() + return res @omnisci('bool(int64, int32)') def operator_gt_array(size, v): a = Array(size, 'int32') for i in range(size): a[i] = nb_types.int32(i) - return a > a + res = a > a + a.free() + return res - @omnisci('int32[](int64)') + @omnisci('int32[](int64)', on_missing_free='ignore') def operator_iadd(size): a = Array(size, 'int32') b = Array(size, 'int32') @@ -174,9 +198,10 @@ def operator_iadd(size): a[i] = nb_types.int32(i) b[i] = nb_types.int32(1) operator.iadd(a, b) + b.free() return a - @omnisci('int32[](int64)') + @omnisci('int32[](int64)', on_missing_free='ignore') def operator_iand(size): a = Array(size, 'int32') b = Array(size, 'int32') @@ -184,9 +209,10 @@ def operator_iand(size): a[i] = nb_types.int32(i) b[i] = nb_types.int32(size-i-1) operator.iand(a, b) + b.free() return a - @omnisci('int32[](int64)') + @omnisci('int32[](int64)', on_missing_free='ignore') def operator_ifloordiv(size): a = Array(size, 'int32') b = Array(size, 'int32') @@ -194,9 +220,10 @@ def operator_ifloordiv(size): a[i] = nb_types.int32(i+10) b[i] = nb_types.int32(i+3) operator.ifloordiv(a, b) + b.free() return a - @omnisci('double[](int64)') + @omnisci('double[](int64)', on_missing_free='ignore') def operator_ifloordiv2(size): a = Array(size, 'double') b = Array(size, 'double') @@ -204,9 +231,10 @@ def operator_ifloordiv2(size): a[i] = nb_types.double(i+10) b[i] = nb_types.double(i+3) operator.ifloordiv(a, b) + b.free() return a - @omnisci('int32[](int64)') + @omnisci('int32[](int64)', on_missing_free='ignore') def operator_ilshift(size): a = Array(size, 'int32') b = Array(size, 'int32') @@ -214,9 +242,10 @@ def operator_ilshift(size): a[i] = nb_types.int32(i) b[i] = nb_types.int32(size-i-1) operator.ilshift(a, b) + b.free() return a - @omnisci('int32[](int64)') + @omnisci('int32[](int64)', on_missing_free='ignore') def operator_imul(size): a = Array(size, 'int32') b = Array(size, 'int32') @@ -224,9 +253,10 @@ def operator_imul(size): a[i] = nb_types.int32(i) b[i] = nb_types.int32(size-i-1) operator.imul(a, b) + b.free() return a - @omnisci('int32[](int64)') + @omnisci('int32[](int64)', on_missing_free='ignore') def operator_ior(size): a = Array(size, 'int32') b = Array(size, 'int32') @@ -234,9 +264,10 @@ def operator_ior(size): a[i] = nb_types.int32(i) b[i] = nb_types.int32(size-i-1) operator.ior(a, b) + b.free() return a - @omnisci('int32[](int64)') + @omnisci('int32[](int64)', on_missing_free='ignore') def operator_isub(size): a = Array(size, 'int32') b = Array(size, 'int32') @@ -244,9 +275,10 @@ def operator_isub(size): a[i] = nb_types.int32(i) b[i] = nb_types.int32(size-i-1) operator.isub(a, b) + b.free() return a - @omnisci('int32[](int64)') + @omnisci('int32[](int64)', on_missing_free='ignore') def operator_ipow(size): a = Array(size, 'int32') b = Array(size, 'int32') @@ -254,9 +286,10 @@ def operator_ipow(size): a[i] = nb_types.int32(i+1) b[i] = nb_types.int32(size-i) operator.ipow(a, b) + b.free() return a - @omnisci('int32[](int64)') + @omnisci('int32[](int64)', on_missing_free='ignore') def operator_irshift(size): a = Array(size, 'int32') b = Array(size, 'int32') @@ -264,9 +297,10 @@ def operator_irshift(size): a[i] = nb_types.int32(i) b[i] = nb_types.int32(size-i-1) operator.irshift(a, b) + b.free() return a - @omnisci('int32[](int64)') + @omnisci('int32[](int64)', on_missing_free='ignore') def operator_itruediv(size): a = Array(size, 'int32') b = Array(size, 'int32') @@ -274,9 +308,10 @@ def operator_itruediv(size): a[i] = nb_types.int32(i+10) b[i] = nb_types.int32(i+3) operator.itruediv(a, b) + b.free() return a - @omnisci('double[](int64)') + @omnisci('double[](int64)', on_missing_free='ignore') def operator_itruediv2(size): a = Array(size, 'double') b = Array(size, 'double') @@ -284,9 +319,10 @@ def operator_itruediv2(size): a[i] = nb_types.double(i+10) b[i] = nb_types.double(i+3) operator.itruediv(a, b) + b.free() return a - @omnisci('int32[](int64)') + @omnisci('int32[](int64)', on_missing_free='ignore') def operator_imod(size): a = Array(size, 'int32') b = Array(size, 'int32') @@ -294,9 +330,10 @@ def operator_imod(size): a[i] = nb_types.int32(i * 123) b[i] = nb_types.int32(7) operator.imod(a, b) + b.free() return a - @omnisci('int32[](int64)') + @omnisci('int32[](int64)', on_missing_free='ignore') def operator_ixor(size): a = Array(size, 'int32') b = Array(size, 'int32') @@ -304,6 +341,7 @@ def operator_ixor(size): a[i] = nb_types.int32(i) b[i] = nb_types.int32(size-i-1) operator.ixor(a, b) + b.free() return a @omnisci('int8(int64, int32)') @@ -311,19 +349,25 @@ def operator_in(size, v): a = Array(size, 'int32') for i in range(size): a[i] = nb_types.int32(i) - return v in a + res = v in a + a.free() + return res @omnisci('int8(int64, int32)') def operator_is(size, v): a = Array(size, 'int32') a.fill(v) - return a is a + res = a is a + a.free() + return res @omnisci('int8(int64, int32)') def operator_is_not(size, v): a = Array(size, 'int32') a.fill(v) - return a is not a + res = a is not a + a.free() + return res @omnisci('int8(int64, int32)') def operator_is_not2(size, v): @@ -331,21 +375,27 @@ def operator_is_not2(size, v): a.fill(v) b = Array(size, 'int32') b.fill(v) - return a is not b + res = a is not b + a.free() + return res @omnisci('int8[](int64, int32)') def operator_le(size, v): a = Array(size, 'int32') for i in range(size): a[i] = nb_types.int32(i) - return a <= v + res = a <= v + a.free() + return res @omnisci('bool(int64, int32)') def operator_le_array(size, v): a = Array(size, 'int32') for i in range(size): a[i] = nb_types.int32(i) - return a <= a + res = a <= a + a.free() + return res @omnisci('int32[](int64)') def operator_lshift(size): @@ -354,21 +404,27 @@ def operator_lshift(size): for i in range(size): a[i] = nb_types.int32(i) b[i] = nb_types.int32(size-i-1) - return operator.lshift(a, b) + res = operator.lshift(a, b) + a.free() + return res @omnisci('int8[](int64, int32)') def operator_lt(size, v): a = Array(size, 'int32') for i in range(size): a[i] = nb_types.int32(i) - return a < v + res = a < v + a.free() + return res @omnisci('bool(int64, int32)') def operator_lt_array(size, v): a = Array(size, 'int32') for i in range(size): a[i] = nb_types.int32(i) - return a < a + res = a < a + a.free() + return res @omnisci('int32[](int64)') def operator_mul(size): @@ -377,7 +433,9 @@ def operator_mul(size): for i in range(size): a[i] = nb_types.int32(i) b[i] = nb_types.int32(size-i-1) - return operator.mul(a, b) + res = operator.mul(a, b) + a.free() + return res @omnisci('int32[](int64)') def operator_mod(size): @@ -386,35 +444,45 @@ def operator_mod(size): for i in range(size): a[i] = nb_types.int32(i * 123) b[i] = nb_types.int32(7) - return operator.mod(a, b) + res = operator.mod(a, b) + a.free() + return res @omnisci('int8[](int64, int32)') def operator_ne(size, v): a = Array(size, 'int32') for i in range(size): a[i] = nb_types.int32(i) - return a != v + res = a != v + a.free() + return res @omnisci('bool(int64, int32)') def operator_ne_array(size, v): a = Array(size, 'int32') for i in range(size): a[i] = nb_types.int32(i) - return a != a + res = a != a + a.free() + return res @omnisci('int32[](int64)') def operator_neg(size): a = Array(size, 'int32') for i in range(size): a[i] = nb_types.int32(i) - return operator.neg(a) + res = operator.neg(a) + a.free() + return res @omnisci('int8(int64, int32)') def operator_not_in(size, v): a = Array(size, 'int32') for i in range(size): a[i] = nb_types.int32(i) - return v not in a + res = v not in a + a.free() + return res @omnisci('int32[](int64)') def operator_or_bw(size): @@ -423,14 +491,18 @@ def operator_or_bw(size): for i in range(size): a[i] = nb_types.int32(i) b[i] = nb_types.int32(size-i-1) - return operator.or_(a, b) + res = operator.or_(a, b) + a.free() + return res @omnisci('int32[](int64)') def operator_pos(size): a = Array(size, 'int32') for i in range(size): a[i] = nb_types.int32(-i) - return operator.pos(a) + res = operator.pos(a) + a.free() + return res @omnisci('int32[](int64)') def operator_pow(size): @@ -439,7 +511,9 @@ def operator_pow(size): for i in range(size): a[i] = nb_types.int32(i+1) b[i] = nb_types.int32(size-i) - return operator.pow(a, b) + res = operator.pow(a, b) + a.free() + return res @omnisci('int32[](int64)') def operator_rshift(size): @@ -448,7 +522,9 @@ def operator_rshift(size): for i in range(size): a[i] = nb_types.int32(i) b[i] = nb_types.int32(size-i-1) - return operator.rshift(a, b) + res = operator.rshift(a, b) + a.free() + return res @omnisci('int32[](int64)') def operator_sub(size): @@ -457,7 +533,9 @@ def operator_sub(size): for i in range(size): a[i] = nb_types.int32(i) b[i] = nb_types.int32(size-i-1) - return operator.sub(a, b) + res = operator.sub(a, b) + a.free() + return res @omnisci('int32[](int64)') def operator_truediv(size): @@ -466,7 +544,9 @@ def operator_truediv(size): for i in range(size): a[i] = nb_types.int32(i+10) b[i] = nb_types.int32(i+3) - return operator.truediv(a, b) + res = operator.truediv(a, b) + a.free() + return res @omnisci('double[](int64)') def operator_truediv2(size): @@ -475,7 +555,9 @@ def operator_truediv2(size): for i in range(size): a[i] = nb_types.double(i+10) b[i] = nb_types.double(i+3) - return operator.truediv(a, b) + res = operator.truediv(a, b) + a.free() + return res @omnisci('int32[](int64)') def operator_xor(size): @@ -484,7 +566,9 @@ def operator_xor(size): for i in range(size): a[i] = nb_types.int32(i) b[i] = nb_types.int32(size-i-1) - return operator.xor(a, b) + res = operator.xor(a, b) + a.free() + return res @pytest.mark.parametrize("suffix, args, expected", operator_methods, diff --git a/rbc/tests/test_omnisci_caller.py b/rbc/tests/test_omnisci_caller.py index 1a680da0..5ea497d9 100644 --- a/rbc/tests/test_omnisci_caller.py +++ b/rbc/tests/test_omnisci_caller.py @@ -37,7 +37,7 @@ def aincr(x, dx, y): y[i] = x[i] + dx return size - @omnisci('Bytes(Bytes)') + @omnisci('Bytes(Bytes)', on_missing_free='ignore') def myupper(s): r = Bytes(len(s)) for i in range(len(s)): From 2df5c0930f375ae44399884a3b27beac2d223080 Mon Sep 17 00:00:00 2001 From: Antonio Cuni Date: Mon, 7 Feb 2022 10:54:43 +0000 Subject: [PATCH 17/25] make sure to report the name of the function which actually contains the missing free --- rbc/omnisci_backend/omnisci_pipeline.py | 25 +++++++++++++++++-------- rbc/tests/test_compiler_pipeline.py | 14 +++++++------- 2 files changed, 24 insertions(+), 15 deletions(-) diff --git a/rbc/omnisci_backend/omnisci_pipeline.py b/rbc/omnisci_backend/omnisci_pipeline.py index 892860f5..4260e267 100644 --- a/rbc/omnisci_backend/omnisci_pipeline.py +++ b/rbc/omnisci_backend/omnisci_pipeline.py @@ -100,18 +100,26 @@ class MissingFreeWarning(Warning): _msg = """ Possible memory leak detected! - In RBC, arrays and buffers must be freed manually by calling the method - .free() or the function free_buffer(): see the relevant docs. + + Arrays or buffers are allocated by function {func_name} but the function + never calls .free() or free_buffer(). + In RBC, arrays and buffers must be freed manually: the relevant docs. """ - def __init__(self): - Warning.__init__(self, self._msg) + def __init__(self, func_name): + msg = self.make_message(func_name) + Warning.__init__(self, msg) + + @classmethod + def make_message(cls, func_name): + return cls._msg.format(func_name=func_name) class MissingFreeError(Exception): - def __init__(self): - Exception.__init__(self, MissingFreeWarning._msg) + def __init__(self, func_name): + msg = MissingFreeWarning.make_message(func_name) + Exception.__init__(self, msg) @register_pass(mutates_CFG=False, analysis_only=True) @@ -166,10 +174,11 @@ def contains_calls_to_free(self, state): def run_pass(self, state): on_missing_free= state.flags.on_missing_free if (self.contains_buffer_constructors(state) and not self.contains_calls_to_free(state)): + func_name = state.func_id.func.__name__ if on_missing_free == 'warn': - warnings.warn(MissingFreeWarning()) + warnings.warn(MissingFreeWarning(func_name)) elif on_missing_free == 'fail': - raise MissingFreeError() + raise MissingFreeError(func_name) else: raise ValueError(f"Unexpected value for on_missing_free: got {on_missing_free:r}, expected 'warn', 'fail' or 'ignore'") return False # we didn't modify the IR diff --git a/rbc/tests/test_compiler_pipeline.py b/rbc/tests/test_compiler_pipeline.py index b9979f72..4a48aeda 100644 --- a/rbc/tests/test_compiler_pipeline.py +++ b/rbc/tests/test_compiler_pipeline.py @@ -33,7 +33,7 @@ def test_no_warnings_decorator(): with pytest.raises(AssertionError, match='Warnings were raised'): with no_warnings(MissingFreeWarning): - warnings.warn(MissingFreeWarning()) + warnings.warn(MissingFreeWarning('hello')) class TestDetectMissingFree: @@ -41,22 +41,22 @@ class TestDetectMissingFree: def test_on_missing_free_warn(self, rjit): # basic case: we are creating an array but we don't call .free() @rjit('int32(int32)') - def fn(size): + def my_func(size): a = xp.Array(size, xp.float64) # noqa: F841 return size - with pytest.warns(MissingFreeWarning): - res = fn(10) + with pytest.warns(MissingFreeWarning, match='by function my_func'): + res = my_func(10) assert res == 10 def test_on_missing_free_fail(self, rjit): @rjit('int32(int32)', on_missing_free='fail') - def fn(size): + def my_func(size): a = xp.Array(size, xp.float64) # noqa: F841 return size - with pytest.raises(MissingFreeError): - res = fn(10) + with pytest.raises(MissingFreeError, match='by function my_func'): + res = my_func(10) def test_on_missing_free_ignore(self, rjit): @rjit('int32(int32)', on_missing_free='ignore') From 8c2269c6dbe4fe31dbf21908bf936abc453e3c3c Mon Sep 17 00:00:00 2001 From: Antonio Cuni Date: Mon, 7 Feb 2022 10:56:05 +0000 Subject: [PATCH 18/25] fix MissingFree warnings/errors in test_omnisci_text --- rbc/tests/test_omnisci_text.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/rbc/tests/test_omnisci_text.py b/rbc/tests/test_omnisci_text.py index fb506dfc..f021257f 100644 --- a/rbc/tests/test_omnisci_text.py +++ b/rbc/tests/test_omnisci_text.py @@ -11,7 +11,7 @@ def omnisci(): # TODO: use omnisci_fixture from rbc/tests/__init__.py config = rbc_omnisci.get_client_config(debug=not True) - m = rbc_omnisci.RemoteOmnisci(**config) + m = rbc_omnisci.RemoteOmnisci(on_missing_free='fail', **config) table_name = os.path.splitext(os.path.basename(__file__))[0] m.sql_execute(f'DROP TABLE IF EXISTS {table_name}') @@ -103,7 +103,7 @@ def test_bytes_return(omnisci): from rbc.omnisci_backend import Bytes - @omnisci('Bytes(int32, int32)') + @omnisci('Bytes(int32, int32)', on_missing_free='ignore') def make_abc(first, n): r = Bytes(n) for i in range(n): @@ -122,7 +122,7 @@ def test_bytes_upper(omnisci): from rbc.omnisci_backend import Bytes - @omnisci('Bytes(Bytes)') + @omnisci('Bytes(Bytes)', on_missing_free='ignore') def myupper(s): r = Bytes(len(s)) for i in range(len(s)): From 8cbcf90a5dd2c6dbae083c0212ddb18484fe7d44 Mon Sep 17 00:00:00 2001 From: Antonio Cuni Date: Mon, 7 Feb 2022 10:59:23 +0000 Subject: [PATCH 19/25] fix flake8 --- rbc/omnisci_backend/omnisci_pipeline.py | 7 ++- rbc/tests/test_compiler_pipeline.py | 5 +- rbc/tests/test_omnisci_array_operators.py | 70 +++++++++++------------ 3 files changed, 43 insertions(+), 39 deletions(-) diff --git a/rbc/omnisci_backend/omnisci_pipeline.py b/rbc/omnisci_backend/omnisci_pipeline.py index 4260e267..73b2adb4 100644 --- a/rbc/omnisci_backend/omnisci_pipeline.py +++ b/rbc/omnisci_backend/omnisci_pipeline.py @@ -172,7 +172,7 @@ def contains_calls_to_free(self, state): return False def run_pass(self, state): - on_missing_free= state.flags.on_missing_free + on_missing_free = state.flags.on_missing_free if (self.contains_buffer_constructors(state) and not self.contains_calls_to_free(state)): func_name = state.func_id.func.__name__ if on_missing_free == 'warn': @@ -180,7 +180,10 @@ def run_pass(self, state): elif on_missing_free == 'fail': raise MissingFreeError(func_name) else: - raise ValueError(f"Unexpected value for on_missing_free: got {on_missing_free:r}, expected 'warn', 'fail' or 'ignore'") + raise ValueError( + f"Unexpected value for on_missing_free: " + f"got {on_missing_free:r}, expected 'warn', 'fail' or 'ignore'" + ) return False # we didn't modify the IR diff --git a/rbc/tests/test_compiler_pipeline.py b/rbc/tests/test_compiler_pipeline.py index 4a48aeda..59b2d723 100644 --- a/rbc/tests/test_compiler_pipeline.py +++ b/rbc/tests/test_compiler_pipeline.py @@ -56,7 +56,7 @@ def my_func(size): return size with pytest.raises(MissingFreeError, match='by function my_func'): - res = my_func(10) + my_func(10) def test_on_missing_free_ignore(self, rjit): @rjit('int32(int32)', on_missing_free='ignore') @@ -70,6 +70,7 @@ def fn(size): def test_set_on_missing_globally(self): my_rjit = RemoteJIT(local=True, on_missing_free='fail') + @my_rjit('int32(int32)') def fn(size): a = xp.Array(size, xp.float64) # noqa: F841 @@ -78,7 +79,7 @@ def fn(size): # this raises because on_missing_free='fail' it set globablly on the # RemoteJIT instance with pytest.raises(MissingFreeError): - res = fn(10) + fn(10) def test_detect_call_to_free_buffer(self, rjit): @rjit('int32(int32)') diff --git a/rbc/tests/test_omnisci_array_operators.py b/rbc/tests/test_omnisci_array_operators.py index 0a272482..b5ac0f1c 100644 --- a/rbc/tests/test_omnisci_array_operators.py +++ b/rbc/tests/test_omnisci_array_operators.py @@ -79,7 +79,7 @@ def operator_abs(size): a = Array(size, 'int32') for i in range(size): a[i] = nb_types.int32(-i) - res = abs(a) + res = abs(a) a.free() return res @@ -90,7 +90,7 @@ def operator_add(size): for i in range(size): a[i] = nb_types.int32(i) b[i] = nb_types.int32(size-i-1) - res = operator.add(a, b) + res = operator.add(a, b) a.free() return res @@ -101,7 +101,7 @@ def operator_and_bw(size): for i in range(size): a[i] = nb_types.int32(i) b[i] = nb_types.int32(size-i-1) - res = operator.and_(a, b) + res = operator.and_(a, b) a.free() return res @@ -110,7 +110,7 @@ def operator_countOf(size, fill_value, b): a = Array(size, 'int64') for i in range(size): a[i] = fill_value - res = operator.countOf(a, b) + res = operator.countOf(a, b) a.free() return res @@ -119,7 +119,7 @@ def operator_eq(size, v): a = Array(size, 'int32') for i in range(size): a[i] = nb_types.int32(i) - res = a == v + res = a == v a.free() return res @@ -128,7 +128,7 @@ def operator_eq_array(size, v): a = Array(size, 'int32') for i in range(size): a[i] = nb_types.int32(i) - res = a == a + res = a == a a.free() return res @@ -139,7 +139,7 @@ def operator_floordiv(size): for i in range(size): a[i] = nb_types.int32(i+10) b[i] = nb_types.int32(i+3) - res = operator.floordiv(a, b) + res = operator.floordiv(a, b) a.free() return res @@ -150,7 +150,7 @@ def operator_floordiv2(size): for i in range(size): a[i] = nb_types.double(i+10) b[i] = nb_types.double(i+3) - res = operator.floordiv(a, b) + res = operator.floordiv(a, b) a.free() return res @@ -159,7 +159,7 @@ def operator_ge(size, v): a = Array(size, 'int32') for i in range(size): a[i] = nb_types.int32(i) - res = a >= v + res = a >= v a.free() return res @@ -168,7 +168,7 @@ def operator_ge_array(size, v): a = Array(size, 'int32') for i in range(size): a[i] = nb_types.int32(i) - res = a >= a + res = a >= a a.free() return res @@ -177,7 +177,7 @@ def operator_gt(size, v): a = Array(size, 'int32') for i in range(size): a[i] = nb_types.int32(i) - res = a > v + res = a > v a.free() return res @@ -186,7 +186,7 @@ def operator_gt_array(size, v): a = Array(size, 'int32') for i in range(size): a[i] = nb_types.int32(i) - res = a > a + res = a > a a.free() return res @@ -349,7 +349,7 @@ def operator_in(size, v): a = Array(size, 'int32') for i in range(size): a[i] = nb_types.int32(i) - res = v in a + res = v in a a.free() return res @@ -357,7 +357,7 @@ def operator_in(size, v): def operator_is(size, v): a = Array(size, 'int32') a.fill(v) - res = a is a + res = a is a a.free() return res @@ -365,7 +365,7 @@ def operator_is(size, v): def operator_is_not(size, v): a = Array(size, 'int32') a.fill(v) - res = a is not a + res = a is not a a.free() return res @@ -375,7 +375,7 @@ def operator_is_not2(size, v): a.fill(v) b = Array(size, 'int32') b.fill(v) - res = a is not b + res = a is not b a.free() return res @@ -384,7 +384,7 @@ def operator_le(size, v): a = Array(size, 'int32') for i in range(size): a[i] = nb_types.int32(i) - res = a <= v + res = a <= v a.free() return res @@ -393,7 +393,7 @@ def operator_le_array(size, v): a = Array(size, 'int32') for i in range(size): a[i] = nb_types.int32(i) - res = a <= a + res = a <= a a.free() return res @@ -404,7 +404,7 @@ def operator_lshift(size): for i in range(size): a[i] = nb_types.int32(i) b[i] = nb_types.int32(size-i-1) - res = operator.lshift(a, b) + res = operator.lshift(a, b) a.free() return res @@ -413,7 +413,7 @@ def operator_lt(size, v): a = Array(size, 'int32') for i in range(size): a[i] = nb_types.int32(i) - res = a < v + res = a < v a.free() return res @@ -422,7 +422,7 @@ def operator_lt_array(size, v): a = Array(size, 'int32') for i in range(size): a[i] = nb_types.int32(i) - res = a < a + res = a < a a.free() return res @@ -433,7 +433,7 @@ def operator_mul(size): for i in range(size): a[i] = nb_types.int32(i) b[i] = nb_types.int32(size-i-1) - res = operator.mul(a, b) + res = operator.mul(a, b) a.free() return res @@ -444,7 +444,7 @@ def operator_mod(size): for i in range(size): a[i] = nb_types.int32(i * 123) b[i] = nb_types.int32(7) - res = operator.mod(a, b) + res = operator.mod(a, b) a.free() return res @@ -453,7 +453,7 @@ def operator_ne(size, v): a = Array(size, 'int32') for i in range(size): a[i] = nb_types.int32(i) - res = a != v + res = a != v a.free() return res @@ -462,7 +462,7 @@ def operator_ne_array(size, v): a = Array(size, 'int32') for i in range(size): a[i] = nb_types.int32(i) - res = a != a + res = a != a a.free() return res @@ -471,7 +471,7 @@ def operator_neg(size): a = Array(size, 'int32') for i in range(size): a[i] = nb_types.int32(i) - res = operator.neg(a) + res = operator.neg(a) a.free() return res @@ -480,7 +480,7 @@ def operator_not_in(size, v): a = Array(size, 'int32') for i in range(size): a[i] = nb_types.int32(i) - res = v not in a + res = v not in a a.free() return res @@ -491,7 +491,7 @@ def operator_or_bw(size): for i in range(size): a[i] = nb_types.int32(i) b[i] = nb_types.int32(size-i-1) - res = operator.or_(a, b) + res = operator.or_(a, b) a.free() return res @@ -500,7 +500,7 @@ def operator_pos(size): a = Array(size, 'int32') for i in range(size): a[i] = nb_types.int32(-i) - res = operator.pos(a) + res = operator.pos(a) a.free() return res @@ -511,7 +511,7 @@ def operator_pow(size): for i in range(size): a[i] = nb_types.int32(i+1) b[i] = nb_types.int32(size-i) - res = operator.pow(a, b) + res = operator.pow(a, b) a.free() return res @@ -522,7 +522,7 @@ def operator_rshift(size): for i in range(size): a[i] = nb_types.int32(i) b[i] = nb_types.int32(size-i-1) - res = operator.rshift(a, b) + res = operator.rshift(a, b) a.free() return res @@ -533,7 +533,7 @@ def operator_sub(size): for i in range(size): a[i] = nb_types.int32(i) b[i] = nb_types.int32(size-i-1) - res = operator.sub(a, b) + res = operator.sub(a, b) a.free() return res @@ -544,7 +544,7 @@ def operator_truediv(size): for i in range(size): a[i] = nb_types.int32(i+10) b[i] = nb_types.int32(i+3) - res = operator.truediv(a, b) + res = operator.truediv(a, b) a.free() return res @@ -555,7 +555,7 @@ def operator_truediv2(size): for i in range(size): a[i] = nb_types.double(i+10) b[i] = nb_types.double(i+3) - res = operator.truediv(a, b) + res = operator.truediv(a, b) a.free() return res @@ -566,7 +566,7 @@ def operator_xor(size): for i in range(size): a[i] = nb_types.int32(i) b[i] = nb_types.int32(size-i-1) - res = operator.xor(a, b) + res = operator.xor(a, b) a.free() return res From fd6836c0910bc1af57928ca028d817158bee2a31 Mon Sep 17 00:00:00 2001 From: Antonio Cuni Date: Mon, 7 Feb 2022 14:38:18 +0000 Subject: [PATCH 20/25] TEMP: disable fast fail --- .github/workflows/rbc_test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/rbc_test.yml b/.github/workflows/rbc_test.yml index 1bf81e1c..f19e2dea 100644 --- a/.github/workflows/rbc_test.yml +++ b/.github/workflows/rbc_test.yml @@ -35,7 +35,7 @@ jobs: name: ${{ matrix.os }} - Python v${{ matrix.python-version }} - Numba v${{ matrix.numba-version }} runs-on: ${{ matrix.os }} strategy: - fail-fast: true + #fail-fast: true matrix: os: [ubuntu-latest, windows-latest, macos-latest] python-version: ['3.9', '3.8', '3.7'] From 561df762f9c608489219f443f5fe2826d4a9e004 Mon Sep 17 00:00:00 2001 From: Antonio Cuni Date: Mon, 7 Feb 2022 14:54:36 +0000 Subject: [PATCH 21/25] TEMP: disable fast fail --- .github/workflows/rbc_test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/rbc_test.yml b/.github/workflows/rbc_test.yml index f19e2dea..5785b407 100644 --- a/.github/workflows/rbc_test.yml +++ b/.github/workflows/rbc_test.yml @@ -104,7 +104,7 @@ jobs: runs-on: ${{ matrix.os }} timeout-minutes: 20 strategy: - fail-fast: true + #fail-fast: true matrix: os: [ubuntu-latest] python-version: ['3.9', '3.8', '3.7'] From 321d18e70094b76628bd15f166d658e33111610f Mon Sep 17 00:00:00 2001 From: Antonio Cuni Date: Mon, 7 Feb 2022 18:00:37 +0000 Subject: [PATCH 22/25] try this --- .github/workflows/rbc_test.yml | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/.github/workflows/rbc_test.yml b/.github/workflows/rbc_test.yml index 5785b407..d87c6ce4 100644 --- a/.github/workflows/rbc_test.yml +++ b/.github/workflows/rbc_test.yml @@ -111,19 +111,19 @@ jobs: numba-version: ['0.55', '0.54'] omniscidb-version: ['5.10', '5.9', '5.8', '5.7'] omniscidb-from: [conda] - include: - - os: ubuntu-latest - python-version: '3.10' - numba-version: '0.55' - omniscidb-version: dev - docker-image: omnisci/core-os-cpu-dev:latest - omniscidb-from: docker - - os: ubuntu-latest - python-version: '3.9' - numba-version: '0.54' - omniscidb-version: dev - docker-image: omnisci/core-os-cpu-dev:latest - omniscidb-from: docker + # include: + # - os: ubuntu-latest + # python-version: '3.10' + # numba-version: '0.55' + # omniscidb-version: dev + # docker-image: omnisci/core-os-cpu-dev:latest + # omniscidb-from: docker + # - os: ubuntu-latest + # python-version: '3.9' + # numba-version: '0.54' + # omniscidb-version: dev + # docker-image: omnisci/core-os-cpu-dev:latest + # omniscidb-from: docker needs: lint From a943884c540252125d7bdf475e0c427560af8970 Mon Sep 17 00:00:00 2001 From: Antonio Cuni Date: Mon, 7 Feb 2022 22:19:05 +0000 Subject: [PATCH 23/25] fix all the memory leaks in test_omnisci_array_operators.py --- rbc/tests/test_omnisci_array_operators.py | 77 ++++++++++++++--------- 1 file changed, 46 insertions(+), 31 deletions(-) diff --git a/rbc/tests/test_omnisci_array_operators.py b/rbc/tests/test_omnisci_array_operators.py index b5ac0f1c..c9fc162d 100644 --- a/rbc/tests/test_omnisci_array_operators.py +++ b/rbc/tests/test_omnisci_array_operators.py @@ -92,6 +92,7 @@ def operator_add(size): b[i] = nb_types.int32(size-i-1) res = operator.add(a, b) a.free() + b.free() return res @omnisci('int32[](int64)') @@ -103,6 +104,7 @@ def operator_and_bw(size): b[i] = nb_types.int32(size-i-1) res = operator.and_(a, b) a.free() + b.free() return res @omnisci('int64(int64, int64, int64)') @@ -119,7 +121,7 @@ def operator_eq(size, v): a = Array(size, 'int32') for i in range(size): a[i] = nb_types.int32(i) - res = a == v + res = (a == v) a.free() return res @@ -128,7 +130,7 @@ def operator_eq_array(size, v): a = Array(size, 'int32') for i in range(size): a[i] = nb_types.int32(i) - res = a == a + res = (a == a) a.free() return res @@ -141,6 +143,7 @@ def operator_floordiv(size): b[i] = nb_types.int32(i+3) res = operator.floordiv(a, b) a.free() + b.free() return res @omnisci('double[](int64)') @@ -152,6 +155,7 @@ def operator_floordiv2(size): b[i] = nb_types.double(i+3) res = operator.floordiv(a, b) a.free() + b.free() return res @omnisci('int8[](int64, int32)') @@ -159,7 +163,7 @@ def operator_ge(size, v): a = Array(size, 'int32') for i in range(size): a[i] = nb_types.int32(i) - res = a >= v + res = (a >= v) a.free() return res @@ -168,7 +172,7 @@ def operator_ge_array(size, v): a = Array(size, 'int32') for i in range(size): a[i] = nb_types.int32(i) - res = a >= a + res = (a >= a) a.free() return res @@ -177,7 +181,7 @@ def operator_gt(size, v): a = Array(size, 'int32') for i in range(size): a[i] = nb_types.int32(i) - res = a > v + res = (a > v) a.free() return res @@ -186,11 +190,11 @@ def operator_gt_array(size, v): a = Array(size, 'int32') for i in range(size): a[i] = nb_types.int32(i) - res = a > a + res = (a > a) a.free() return res - @omnisci('int32[](int64)', on_missing_free='ignore') + @omnisci('int32[](int64)') def operator_iadd(size): a = Array(size, 'int32') b = Array(size, 'int32') @@ -201,7 +205,7 @@ def operator_iadd(size): b.free() return a - @omnisci('int32[](int64)', on_missing_free='ignore') + @omnisci('int32[](int64)') def operator_iand(size): a = Array(size, 'int32') b = Array(size, 'int32') @@ -212,7 +216,7 @@ def operator_iand(size): b.free() return a - @omnisci('int32[](int64)', on_missing_free='ignore') + @omnisci('int32[](int64)') def operator_ifloordiv(size): a = Array(size, 'int32') b = Array(size, 'int32') @@ -223,7 +227,7 @@ def operator_ifloordiv(size): b.free() return a - @omnisci('double[](int64)', on_missing_free='ignore') + @omnisci('double[](int64)') def operator_ifloordiv2(size): a = Array(size, 'double') b = Array(size, 'double') @@ -234,7 +238,7 @@ def operator_ifloordiv2(size): b.free() return a - @omnisci('int32[](int64)', on_missing_free='ignore') + @omnisci('int32[](int64)') def operator_ilshift(size): a = Array(size, 'int32') b = Array(size, 'int32') @@ -245,7 +249,7 @@ def operator_ilshift(size): b.free() return a - @omnisci('int32[](int64)', on_missing_free='ignore') + @omnisci('int32[](int64)') def operator_imul(size): a = Array(size, 'int32') b = Array(size, 'int32') @@ -256,7 +260,7 @@ def operator_imul(size): b.free() return a - @omnisci('int32[](int64)', on_missing_free='ignore') + @omnisci('int32[](int64)') def operator_ior(size): a = Array(size, 'int32') b = Array(size, 'int32') @@ -267,7 +271,7 @@ def operator_ior(size): b.free() return a - @omnisci('int32[](int64)', on_missing_free='ignore') + @omnisci('int32[](int64)') def operator_isub(size): a = Array(size, 'int32') b = Array(size, 'int32') @@ -278,7 +282,7 @@ def operator_isub(size): b.free() return a - @omnisci('int32[](int64)', on_missing_free='ignore') + @omnisci('int32[](int64)') def operator_ipow(size): a = Array(size, 'int32') b = Array(size, 'int32') @@ -289,7 +293,7 @@ def operator_ipow(size): b.free() return a - @omnisci('int32[](int64)', on_missing_free='ignore') + @omnisci('int32[](int64)') def operator_irshift(size): a = Array(size, 'int32') b = Array(size, 'int32') @@ -300,7 +304,7 @@ def operator_irshift(size): b.free() return a - @omnisci('int32[](int64)', on_missing_free='ignore') + @omnisci('int32[](int64)') def operator_itruediv(size): a = Array(size, 'int32') b = Array(size, 'int32') @@ -311,7 +315,7 @@ def operator_itruediv(size): b.free() return a - @omnisci('double[](int64)', on_missing_free='ignore') + @omnisci('double[](int64)') def operator_itruediv2(size): a = Array(size, 'double') b = Array(size, 'double') @@ -322,7 +326,7 @@ def operator_itruediv2(size): b.free() return a - @omnisci('int32[](int64)', on_missing_free='ignore') + @omnisci('int32[](int64)') def operator_imod(size): a = Array(size, 'int32') b = Array(size, 'int32') @@ -333,7 +337,7 @@ def operator_imod(size): b.free() return a - @omnisci('int32[](int64)', on_missing_free='ignore') + @omnisci('int32[](int64)') def operator_ixor(size): a = Array(size, 'int32') b = Array(size, 'int32') @@ -349,7 +353,7 @@ def operator_in(size, v): a = Array(size, 'int32') for i in range(size): a[i] = nb_types.int32(i) - res = v in a + res = (v in a) a.free() return res @@ -357,7 +361,7 @@ def operator_in(size, v): def operator_is(size, v): a = Array(size, 'int32') a.fill(v) - res = a is a + res = (a is a) a.free() return res @@ -365,7 +369,7 @@ def operator_is(size, v): def operator_is_not(size, v): a = Array(size, 'int32') a.fill(v) - res = a is not a + res = (a is not a) a.free() return res @@ -375,8 +379,9 @@ def operator_is_not2(size, v): a.fill(v) b = Array(size, 'int32') b.fill(v) - res = a is not b + res = (a is not b) a.free() + b.free() return res @omnisci('int8[](int64, int32)') @@ -384,7 +389,7 @@ def operator_le(size, v): a = Array(size, 'int32') for i in range(size): a[i] = nb_types.int32(i) - res = a <= v + res = (a <= v) a.free() return res @@ -393,7 +398,7 @@ def operator_le_array(size, v): a = Array(size, 'int32') for i in range(size): a[i] = nb_types.int32(i) - res = a <= a + res = (a <= a) a.free() return res @@ -406,6 +411,7 @@ def operator_lshift(size): b[i] = nb_types.int32(size-i-1) res = operator.lshift(a, b) a.free() + b.free() return res @omnisci('int8[](int64, int32)') @@ -413,7 +419,7 @@ def operator_lt(size, v): a = Array(size, 'int32') for i in range(size): a[i] = nb_types.int32(i) - res = a < v + res = (a < v) a.free() return res @@ -422,7 +428,7 @@ def operator_lt_array(size, v): a = Array(size, 'int32') for i in range(size): a[i] = nb_types.int32(i) - res = a < a + res = (a < a) a.free() return res @@ -435,6 +441,7 @@ def operator_mul(size): b[i] = nb_types.int32(size-i-1) res = operator.mul(a, b) a.free() + b.free() return res @omnisci('int32[](int64)') @@ -446,6 +453,7 @@ def operator_mod(size): b[i] = nb_types.int32(7) res = operator.mod(a, b) a.free() + b.free() return res @omnisci('int8[](int64, int32)') @@ -453,7 +461,7 @@ def operator_ne(size, v): a = Array(size, 'int32') for i in range(size): a[i] = nb_types.int32(i) - res = a != v + res = (a != v) a.free() return res @@ -462,7 +470,7 @@ def operator_ne_array(size, v): a = Array(size, 'int32') for i in range(size): a[i] = nb_types.int32(i) - res = a != a + res = (a != a) a.free() return res @@ -480,7 +488,7 @@ def operator_not_in(size, v): a = Array(size, 'int32') for i in range(size): a[i] = nb_types.int32(i) - res = v not in a + res = (v not in a) a.free() return res @@ -493,6 +501,7 @@ def operator_or_bw(size): b[i] = nb_types.int32(size-i-1) res = operator.or_(a, b) a.free() + b.free() return res @omnisci('int32[](int64)') @@ -513,6 +522,7 @@ def operator_pow(size): b[i] = nb_types.int32(size-i) res = operator.pow(a, b) a.free() + b.free() return res @omnisci('int32[](int64)') @@ -524,6 +534,7 @@ def operator_rshift(size): b[i] = nb_types.int32(size-i-1) res = operator.rshift(a, b) a.free() + b.free() return res @omnisci('int32[](int64)') @@ -535,6 +546,7 @@ def operator_sub(size): b[i] = nb_types.int32(size-i-1) res = operator.sub(a, b) a.free() + b.free() return res @omnisci('int32[](int64)') @@ -546,6 +558,7 @@ def operator_truediv(size): b[i] = nb_types.int32(i+3) res = operator.truediv(a, b) a.free() + b.free() return res @omnisci('double[](int64)') @@ -557,6 +570,7 @@ def operator_truediv2(size): b[i] = nb_types.double(i+3) res = operator.truediv(a, b) a.free() + b.free() return res @omnisci('int32[](int64)') @@ -568,6 +582,7 @@ def operator_xor(size): b[i] = nb_types.int32(size-i-1) res = operator.xor(a, b) a.free() + b.free() return res From 055a0600ce090000ccf3a5d8e093d8d54ecf5d1a Mon Sep 17 00:00:00 2001 From: Antonio Cuni Date: Tue, 8 Feb 2022 15:00:26 +0000 Subject: [PATCH 24/25] temporarily disable all the .free() --- .github/workflows/rbc_test.yml | 4 +- rbc/tests/__init__.py | 2 +- rbc/tests/test_omnisci_array_operators.py | 128 +++++++++++----------- 3 files changed, 67 insertions(+), 67 deletions(-) diff --git a/.github/workflows/rbc_test.yml b/.github/workflows/rbc_test.yml index d87c6ce4..84523e30 100644 --- a/.github/workflows/rbc_test.yml +++ b/.github/workflows/rbc_test.yml @@ -35,7 +35,7 @@ jobs: name: ${{ matrix.os }} - Python v${{ matrix.python-version }} - Numba v${{ matrix.numba-version }} runs-on: ${{ matrix.os }} strategy: - #fail-fast: true + fail-fast: false # XXX matrix: os: [ubuntu-latest, windows-latest, macos-latest] python-version: ['3.9', '3.8', '3.7'] @@ -104,7 +104,7 @@ jobs: runs-on: ${{ matrix.os }} timeout-minutes: 20 strategy: - #fail-fast: true + fail-fast: false # XXX matrix: os: [ubuntu-latest] python-version: ['3.9', '3.8', '3.7'] diff --git a/rbc/tests/__init__.py b/rbc/tests/__init__.py index 438fe240..80736066 100644 --- a/rbc/tests/__init__.py +++ b/rbc/tests/__init__.py @@ -164,7 +164,7 @@ def require_version(version, message=None, label=None): table_name = os.path.splitext(os.path.basename(filename))[0] config = rbc_omnisci.get_client_config(debug=debug) - m = rbc_omnisci.RemoteOmnisci(on_missing_free='fail', **config) + m = rbc_omnisci.RemoteOmnisci(on_missing_free='warn', **config) # XXX should be 'fail' sqltypes = ['FLOAT', 'DOUBLE', 'TINYINT', 'SMALLINT', 'INT', 'BIGINT', 'BOOLEAN'] diff --git a/rbc/tests/test_omnisci_array_operators.py b/rbc/tests/test_omnisci_array_operators.py index c9fc162d..f7a21861 100644 --- a/rbc/tests/test_omnisci_array_operators.py +++ b/rbc/tests/test_omnisci_array_operators.py @@ -80,7 +80,7 @@ def operator_abs(size): for i in range(size): a[i] = nb_types.int32(-i) res = abs(a) - a.free() + # a.free() return res @omnisci('int32[](int64)') @@ -91,8 +91,8 @@ def operator_add(size): a[i] = nb_types.int32(i) b[i] = nb_types.int32(size-i-1) res = operator.add(a, b) - a.free() - b.free() + # a.free() + # b.free() return res @omnisci('int32[](int64)') @@ -103,8 +103,8 @@ def operator_and_bw(size): a[i] = nb_types.int32(i) b[i] = nb_types.int32(size-i-1) res = operator.and_(a, b) - a.free() - b.free() + # a.free() + # b.free() return res @omnisci('int64(int64, int64, int64)') @@ -113,7 +113,7 @@ def operator_countOf(size, fill_value, b): for i in range(size): a[i] = fill_value res = operator.countOf(a, b) - a.free() + # a.free() return res @omnisci('int8[](int64, int32)') @@ -122,7 +122,7 @@ def operator_eq(size, v): for i in range(size): a[i] = nb_types.int32(i) res = (a == v) - a.free() + # a.free() return res @omnisci('bool(int64, int32)') @@ -131,7 +131,7 @@ def operator_eq_array(size, v): for i in range(size): a[i] = nb_types.int32(i) res = (a == a) - a.free() + # a.free() return res @omnisci('int32[](int64)') @@ -142,8 +142,8 @@ def operator_floordiv(size): a[i] = nb_types.int32(i+10) b[i] = nb_types.int32(i+3) res = operator.floordiv(a, b) - a.free() - b.free() + # a.free() + # b.free() return res @omnisci('double[](int64)') @@ -154,8 +154,8 @@ def operator_floordiv2(size): a[i] = nb_types.double(i+10) b[i] = nb_types.double(i+3) res = operator.floordiv(a, b) - a.free() - b.free() + # a.free() + # b.free() return res @omnisci('int8[](int64, int32)') @@ -164,7 +164,7 @@ def operator_ge(size, v): for i in range(size): a[i] = nb_types.int32(i) res = (a >= v) - a.free() + # a.free() return res @omnisci('bool(int64, int32)') @@ -173,7 +173,7 @@ def operator_ge_array(size, v): for i in range(size): a[i] = nb_types.int32(i) res = (a >= a) - a.free() + # a.free() return res @omnisci('int8[](int64, int32)') @@ -182,7 +182,7 @@ def operator_gt(size, v): for i in range(size): a[i] = nb_types.int32(i) res = (a > v) - a.free() + # a.free() return res @omnisci('bool(int64, int32)') @@ -191,7 +191,7 @@ def operator_gt_array(size, v): for i in range(size): a[i] = nb_types.int32(i) res = (a > a) - a.free() + # a.free() return res @omnisci('int32[](int64)') @@ -202,7 +202,7 @@ def operator_iadd(size): a[i] = nb_types.int32(i) b[i] = nb_types.int32(1) operator.iadd(a, b) - b.free() + # b.free() return a @omnisci('int32[](int64)') @@ -213,7 +213,7 @@ def operator_iand(size): a[i] = nb_types.int32(i) b[i] = nb_types.int32(size-i-1) operator.iand(a, b) - b.free() + # b.free() return a @omnisci('int32[](int64)') @@ -224,7 +224,7 @@ def operator_ifloordiv(size): a[i] = nb_types.int32(i+10) b[i] = nb_types.int32(i+3) operator.ifloordiv(a, b) - b.free() + # b.free() return a @omnisci('double[](int64)') @@ -235,7 +235,7 @@ def operator_ifloordiv2(size): a[i] = nb_types.double(i+10) b[i] = nb_types.double(i+3) operator.ifloordiv(a, b) - b.free() + # b.free() return a @omnisci('int32[](int64)') @@ -246,7 +246,7 @@ def operator_ilshift(size): a[i] = nb_types.int32(i) b[i] = nb_types.int32(size-i-1) operator.ilshift(a, b) - b.free() + # b.free() return a @omnisci('int32[](int64)') @@ -257,7 +257,7 @@ def operator_imul(size): a[i] = nb_types.int32(i) b[i] = nb_types.int32(size-i-1) operator.imul(a, b) - b.free() + # b.free() return a @omnisci('int32[](int64)') @@ -268,7 +268,7 @@ def operator_ior(size): a[i] = nb_types.int32(i) b[i] = nb_types.int32(size-i-1) operator.ior(a, b) - b.free() + # b.free() return a @omnisci('int32[](int64)') @@ -279,7 +279,7 @@ def operator_isub(size): a[i] = nb_types.int32(i) b[i] = nb_types.int32(size-i-1) operator.isub(a, b) - b.free() + # b.free() return a @omnisci('int32[](int64)') @@ -290,7 +290,7 @@ def operator_ipow(size): a[i] = nb_types.int32(i+1) b[i] = nb_types.int32(size-i) operator.ipow(a, b) - b.free() + # b.free() return a @omnisci('int32[](int64)') @@ -301,7 +301,7 @@ def operator_irshift(size): a[i] = nb_types.int32(i) b[i] = nb_types.int32(size-i-1) operator.irshift(a, b) - b.free() + # b.free() return a @omnisci('int32[](int64)') @@ -312,7 +312,7 @@ def operator_itruediv(size): a[i] = nb_types.int32(i+10) b[i] = nb_types.int32(i+3) operator.itruediv(a, b) - b.free() + # b.free() return a @omnisci('double[](int64)') @@ -323,7 +323,7 @@ def operator_itruediv2(size): a[i] = nb_types.double(i+10) b[i] = nb_types.double(i+3) operator.itruediv(a, b) - b.free() + # b.free() return a @omnisci('int32[](int64)') @@ -334,7 +334,7 @@ def operator_imod(size): a[i] = nb_types.int32(i * 123) b[i] = nb_types.int32(7) operator.imod(a, b) - b.free() + # b.free() return a @omnisci('int32[](int64)') @@ -345,7 +345,7 @@ def operator_ixor(size): a[i] = nb_types.int32(i) b[i] = nb_types.int32(size-i-1) operator.ixor(a, b) - b.free() + # b.free() return a @omnisci('int8(int64, int32)') @@ -354,7 +354,7 @@ def operator_in(size, v): for i in range(size): a[i] = nb_types.int32(i) res = (v in a) - a.free() + # a.free() return res @omnisci('int8(int64, int32)') @@ -362,7 +362,7 @@ def operator_is(size, v): a = Array(size, 'int32') a.fill(v) res = (a is a) - a.free() + # a.free() return res @omnisci('int8(int64, int32)') @@ -370,7 +370,7 @@ def operator_is_not(size, v): a = Array(size, 'int32') a.fill(v) res = (a is not a) - a.free() + # a.free() return res @omnisci('int8(int64, int32)') @@ -380,8 +380,8 @@ def operator_is_not2(size, v): b = Array(size, 'int32') b.fill(v) res = (a is not b) - a.free() - b.free() + # a.free() + # b.free() return res @omnisci('int8[](int64, int32)') @@ -390,7 +390,7 @@ def operator_le(size, v): for i in range(size): a[i] = nb_types.int32(i) res = (a <= v) - a.free() + # a.free() return res @omnisci('bool(int64, int32)') @@ -399,7 +399,7 @@ def operator_le_array(size, v): for i in range(size): a[i] = nb_types.int32(i) res = (a <= a) - a.free() + # a.free() return res @omnisci('int32[](int64)') @@ -410,8 +410,8 @@ def operator_lshift(size): a[i] = nb_types.int32(i) b[i] = nb_types.int32(size-i-1) res = operator.lshift(a, b) - a.free() - b.free() + # a.free() + # b.free() return res @omnisci('int8[](int64, int32)') @@ -420,7 +420,7 @@ def operator_lt(size, v): for i in range(size): a[i] = nb_types.int32(i) res = (a < v) - a.free() + # a.free() return res @omnisci('bool(int64, int32)') @@ -429,7 +429,7 @@ def operator_lt_array(size, v): for i in range(size): a[i] = nb_types.int32(i) res = (a < a) - a.free() + # a.free() return res @omnisci('int32[](int64)') @@ -440,8 +440,8 @@ def operator_mul(size): a[i] = nb_types.int32(i) b[i] = nb_types.int32(size-i-1) res = operator.mul(a, b) - a.free() - b.free() + # a.free() + # b.free() return res @omnisci('int32[](int64)') @@ -452,8 +452,8 @@ def operator_mod(size): a[i] = nb_types.int32(i * 123) b[i] = nb_types.int32(7) res = operator.mod(a, b) - a.free() - b.free() + # a.free() + # b.free() return res @omnisci('int8[](int64, int32)') @@ -462,7 +462,7 @@ def operator_ne(size, v): for i in range(size): a[i] = nb_types.int32(i) res = (a != v) - a.free() + # a.free() return res @omnisci('bool(int64, int32)') @@ -471,7 +471,7 @@ def operator_ne_array(size, v): for i in range(size): a[i] = nb_types.int32(i) res = (a != a) - a.free() + # a.free() return res @omnisci('int32[](int64)') @@ -480,7 +480,7 @@ def operator_neg(size): for i in range(size): a[i] = nb_types.int32(i) res = operator.neg(a) - a.free() + # a.free() return res @omnisci('int8(int64, int32)') @@ -489,7 +489,7 @@ def operator_not_in(size, v): for i in range(size): a[i] = nb_types.int32(i) res = (v not in a) - a.free() + # a.free() return res @omnisci('int32[](int64)') @@ -500,8 +500,8 @@ def operator_or_bw(size): a[i] = nb_types.int32(i) b[i] = nb_types.int32(size-i-1) res = operator.or_(a, b) - a.free() - b.free() + # a.free() + # b.free() return res @omnisci('int32[](int64)') @@ -510,7 +510,7 @@ def operator_pos(size): for i in range(size): a[i] = nb_types.int32(-i) res = operator.pos(a) - a.free() + # a.free() return res @omnisci('int32[](int64)') @@ -521,8 +521,8 @@ def operator_pow(size): a[i] = nb_types.int32(i+1) b[i] = nb_types.int32(size-i) res = operator.pow(a, b) - a.free() - b.free() + # a.free() + # b.free() return res @omnisci('int32[](int64)') @@ -533,8 +533,8 @@ def operator_rshift(size): a[i] = nb_types.int32(i) b[i] = nb_types.int32(size-i-1) res = operator.rshift(a, b) - a.free() - b.free() + # a.free() + # b.free() return res @omnisci('int32[](int64)') @@ -545,8 +545,8 @@ def operator_sub(size): a[i] = nb_types.int32(i) b[i] = nb_types.int32(size-i-1) res = operator.sub(a, b) - a.free() - b.free() + # a.free() + # b.free() return res @omnisci('int32[](int64)') @@ -557,8 +557,8 @@ def operator_truediv(size): a[i] = nb_types.int32(i+10) b[i] = nb_types.int32(i+3) res = operator.truediv(a, b) - a.free() - b.free() + # a.free() + # b.free() return res @omnisci('double[](int64)') @@ -569,8 +569,8 @@ def operator_truediv2(size): a[i] = nb_types.double(i+10) b[i] = nb_types.double(i+3) res = operator.truediv(a, b) - a.free() - b.free() + # a.free() + # b.free() return res @omnisci('int32[](int64)') @@ -581,8 +581,8 @@ def operator_xor(size): a[i] = nb_types.int32(i) b[i] = nb_types.int32(size-i-1) res = operator.xor(a, b) - a.free() - b.free() + # a.free() + # b.free() return res From 82e54bd5b3708c646132ca5f11f3461e070f57f5 Mon Sep 17 00:00:00 2001 From: Antonio Cuni Date: Wed, 9 Feb 2022 14:44:20 +0000 Subject: [PATCH 25/25] try to run only test_abs --- rbc/tests/test_omnisci_array_operators.py | 1115 +++++++++++---------- 1 file changed, 561 insertions(+), 554 deletions(-) diff --git a/rbc/tests/test_omnisci_array_operators.py b/rbc/tests/test_omnisci_array_operators.py index f7a21861..c4e880ba 100644 --- a/rbc/tests/test_omnisci_array_operators.py +++ b/rbc/tests/test_omnisci_array_operators.py @@ -3,7 +3,7 @@ from rbc.omnisci_backend import Array from rbc.tests import omnisci_fixture from numba import types as nb_types -import operator +# import operator rbc_omnisci = pytest.importorskip('rbc.omniscidb') @@ -20,55 +20,55 @@ def omnisci(): operator_methods = [ ('abs', (6,), np.arange(6)), - ('add', (6,), np.full(6, 5)), - ('and_bw', (6,), [0, 0, 2, 2, 0, 0]), - ('countOf', (6, 3, 4), 0), - ('countOf', (6, 3, 3), 6), - ('eq', (6, 3), [0, 0, 0, 1, 0, 0]), - ('eq_array', (6, 3), True), - ('floordiv', (6,), [3, 2, 2, 2, 2, 1]), - ('floordiv2', (6,), [3.0, 2.0, 2.0, 2.0, 2.0, 1.0]), - ('ge', (6, 3), [0, 0, 0, 1, 1, 1]), - ('ge_array', (6, 3), True), - ('gt', (6, 3), [0, 0, 0, 0, 1, 1]), - ('gt_array', (6, 3), False), - ('iadd', (6,), [1, 2, 3, 4, 5, 6]), - ('iand', (6,), [0, 0, 2, 2, 0, 0]), - ('ifloordiv', (6,), [3, 2, 2, 2, 2, 1]), - ('ifloordiv2', (6,), [3, 2, 2, 2, 2, 1]), - ('ilshift', (6,), [0, 16, 16, 12, 8, 5]), - ('imul', (6,), [0, 4, 6, 6, 4, 0]), - ('ior', (6,), [5, 5, 3, 3, 5, 5]), - ('isub', (6,), [-5, -3, -1, 1, 3, 5]), - ('ipow', (6,), [1, 32, 81, 64, 25, 6]), - ('irshift', (6,), [0, 0, 0, 0, 2, 5]), - ('itruediv', (6,), [3, 2, 2, 2, 2, 1]), - ('itruediv2', (6,), [3.3333333333333335, 2.75, 2.4, 2.1666666666666665, 2.0, 1.875]), # noqa: E501 - ('imod', (6,), [0, 4, 1, 5, 2, 6]), - ('ixor', (6,), [5, 5, 1, 1, 5, 5]), - ('in', (6, 3), True), - ('is', (6, 3), True), - ('is_not', (6, 3), False), - ('is_not2', (6, 3), True), - ('le', (6, 3), [1, 1, 1, 1, 0, 0]), - ('le_array', (6, 3), True), - ('lshift', (6,), [0, 16, 16, 12, 8, 5]), - ('lt', (6, 3), [1, 1, 1, 0, 0, 0]), - ('lt_array', (6, 3), False), - ('mul', (6,), [0, 4, 6, 6, 4, 0]), - ('mod', (6,), [0, 4, 1, 5, 2, 6]), - ('ne', (6, 3), [1, 1, 1, 0, 1, 1]), - ('ne_array', (6, 3), False), - ('neg', (6,), [0, -1, -2, -3, -4, -5]), - ('not_in', (6, 3), False), - ('or_bw', (6,), [5, 5, 3, 3, 5, 5]), - ('pos', (6,), [0, -1, -2, -3, -4, -5]), - ('pow', (6,), [1, 32, 81, 64, 25, 6]), - ('rshift', (6,), [0, 0, 0, 0, 2, 5]), - ('sub', (6,), [-5, -3, -1, 1, 3, 5]), - ('truediv', (6,), [3, 2, 2, 2, 2, 1]), - ('truediv2', (6,), [3.3333333333333335, 2.75, 2.4, 2.1666666666666665, 2.0, 1.875]), # noqa: E501 - ('xor', (6,), [5, 5, 1, 1, 5, 5]), + # ('add', (6,), np.full(6, 5)), + # ('and_bw', (6,), [0, 0, 2, 2, 0, 0]), + # ('countOf', (6, 3, 4), 0), + # ('countOf', (6, 3, 3), 6), + # ('eq', (6, 3), [0, 0, 0, 1, 0, 0]), + # ('eq_array', (6, 3), True), + # ('floordiv', (6,), [3, 2, 2, 2, 2, 1]), + # ('floordiv2', (6,), [3.0, 2.0, 2.0, 2.0, 2.0, 1.0]), + # ('ge', (6, 3), [0, 0, 0, 1, 1, 1]), + # ('ge_array', (6, 3), True), + # ('gt', (6, 3), [0, 0, 0, 0, 1, 1]), + # ('gt_array', (6, 3), False), + # ('iadd', (6,), [1, 2, 3, 4, 5, 6]), + # ('iand', (6,), [0, 0, 2, 2, 0, 0]), + # ('ifloordiv', (6,), [3, 2, 2, 2, 2, 1]), + # ('ifloordiv2', (6,), [3, 2, 2, 2, 2, 1]), + # ('ilshift', (6,), [0, 16, 16, 12, 8, 5]), + # ('imul', (6,), [0, 4, 6, 6, 4, 0]), + # ('ior', (6,), [5, 5, 3, 3, 5, 5]), + # ('isub', (6,), [-5, -3, -1, 1, 3, 5]), + # ('ipow', (6,), [1, 32, 81, 64, 25, 6]), + # ('irshift', (6,), [0, 0, 0, 0, 2, 5]), + # ('itruediv', (6,), [3, 2, 2, 2, 2, 1]), + # ('itruediv2', (6,), [3.3333333333333335, 2.75, 2.4, 2.1666666666666665, 2.0, 1.875]), # noqa: E501 + # ('imod', (6,), [0, 4, 1, 5, 2, 6]), + # ('ixor', (6,), [5, 5, 1, 1, 5, 5]), + # ('in', (6, 3), True), + # ('is', (6, 3), True), + # ('is_not', (6, 3), False), + # ('is_not2', (6, 3), True), + # ('le', (6, 3), [1, 1, 1, 1, 0, 0]), + # ('le_array', (6, 3), True), + # ('lshift', (6,), [0, 16, 16, 12, 8, 5]), + # ('lt', (6, 3), [1, 1, 1, 0, 0, 0]), + # ('lt_array', (6, 3), False), + # ('mul', (6,), [0, 4, 6, 6, 4, 0]), + # ('mod', (6,), [0, 4, 1, 5, 2, 6]), + # ('ne', (6, 3), [1, 1, 1, 0, 1, 1]), + # ('ne_array', (6, 3), False), + # ('neg', (6,), [0, -1, -2, -3, -4, -5]), + # ('not_in', (6, 3), False), + # ('or_bw', (6,), [5, 5, 3, 3, 5, 5]), + # ('pos', (6,), [0, -1, -2, -3, -4, -5]), + # ('pow', (6,), [1, 32, 81, 64, 25, 6]), + # ('rshift', (6,), [0, 0, 0, 0, 2, 5]), + # ('sub', (6,), [-5, -3, -1, 1, 3, 5]), + # ('truediv', (6,), [3, 2, 2, 2, 2, 1]), + # ('truediv2', (6,), [3.3333333333333335, 2.75, 2.4, 2.1666666666666665, 2.0, 1.875]), # noqa: E501 + # ('xor', (6,), [5, 5, 1, 1, 5, 5]), ] @@ -80,510 +80,517 @@ def operator_abs(size): for i in range(size): a[i] = nb_types.int32(-i) res = abs(a) - # a.free() - return res - - @omnisci('int32[](int64)') - def operator_add(size): - a = Array(size, 'int32') - b = Array(size, 'int32') - for i in range(size): - a[i] = nb_types.int32(i) - b[i] = nb_types.int32(size-i-1) - res = operator.add(a, b) - # a.free() - # b.free() - return res - - @omnisci('int32[](int64)') - def operator_and_bw(size): - a = Array(size, 'int32') - b = Array(size, 'int32') - for i in range(size): - a[i] = nb_types.int32(i) - b[i] = nb_types.int32(size-i-1) - res = operator.and_(a, b) - # a.free() - # b.free() - return res - - @omnisci('int64(int64, int64, int64)') - def operator_countOf(size, fill_value, b): - a = Array(size, 'int64') - for i in range(size): - a[i] = fill_value - res = operator.countOf(a, b) - # a.free() - return res - - @omnisci('int8[](int64, int32)') - def operator_eq(size, v): - a = Array(size, 'int32') - for i in range(size): - a[i] = nb_types.int32(i) - res = (a == v) - # a.free() - return res - - @omnisci('bool(int64, int32)') - def operator_eq_array(size, v): - a = Array(size, 'int32') - for i in range(size): - a[i] = nb_types.int32(i) - res = (a == a) - # a.free() - return res - - @omnisci('int32[](int64)') - def operator_floordiv(size): - a = Array(size, 'int32') - b = Array(size, 'int32') - for i in range(size): - a[i] = nb_types.int32(i+10) - b[i] = nb_types.int32(i+3) - res = operator.floordiv(a, b) - # a.free() - # b.free() - return res - - @omnisci('double[](int64)') - def operator_floordiv2(size): - a = Array(size, 'double') - b = Array(size, 'double') - for i in range(size): - a[i] = nb_types.double(i+10) - b[i] = nb_types.double(i+3) - res = operator.floordiv(a, b) - # a.free() - # b.free() - return res - - @omnisci('int8[](int64, int32)') - def operator_ge(size, v): - a = Array(size, 'int32') - for i in range(size): - a[i] = nb_types.int32(i) - res = (a >= v) - # a.free() - return res - - @omnisci('bool(int64, int32)') - def operator_ge_array(size, v): - a = Array(size, 'int32') - for i in range(size): - a[i] = nb_types.int32(i) - res = (a >= a) - # a.free() - return res - - @omnisci('int8[](int64, int32)') - def operator_gt(size, v): - a = Array(size, 'int32') - for i in range(size): - a[i] = nb_types.int32(i) - res = (a > v) - # a.free() - return res - - @omnisci('bool(int64, int32)') - def operator_gt_array(size, v): - a = Array(size, 'int32') - for i in range(size): - a[i] = nb_types.int32(i) - res = (a > a) - # a.free() - return res - - @omnisci('int32[](int64)') - def operator_iadd(size): - a = Array(size, 'int32') - b = Array(size, 'int32') - for i in range(size): - a[i] = nb_types.int32(i) - b[i] = nb_types.int32(1) - operator.iadd(a, b) - # b.free() - return a - - @omnisci('int32[](int64)') - def operator_iand(size): - a = Array(size, 'int32') - b = Array(size, 'int32') - for i in range(size): - a[i] = nb_types.int32(i) - b[i] = nb_types.int32(size-i-1) - operator.iand(a, b) - # b.free() - return a - - @omnisci('int32[](int64)') - def operator_ifloordiv(size): - a = Array(size, 'int32') - b = Array(size, 'int32') - for i in range(size): - a[i] = nb_types.int32(i+10) - b[i] = nb_types.int32(i+3) - operator.ifloordiv(a, b) - # b.free() - return a - - @omnisci('double[](int64)') - def operator_ifloordiv2(size): - a = Array(size, 'double') - b = Array(size, 'double') - for i in range(size): - a[i] = nb_types.double(i+10) - b[i] = nb_types.double(i+3) - operator.ifloordiv(a, b) - # b.free() - return a - - @omnisci('int32[](int64)') - def operator_ilshift(size): - a = Array(size, 'int32') - b = Array(size, 'int32') - for i in range(size): - a[i] = nb_types.int32(i) - b[i] = nb_types.int32(size-i-1) - operator.ilshift(a, b) - # b.free() - return a - - @omnisci('int32[](int64)') - def operator_imul(size): - a = Array(size, 'int32') - b = Array(size, 'int32') - for i in range(size): - a[i] = nb_types.int32(i) - b[i] = nb_types.int32(size-i-1) - operator.imul(a, b) - # b.free() - return a - - @omnisci('int32[](int64)') - def operator_ior(size): - a = Array(size, 'int32') - b = Array(size, 'int32') - for i in range(size): - a[i] = nb_types.int32(i) - b[i] = nb_types.int32(size-i-1) - operator.ior(a, b) - # b.free() - return a - - @omnisci('int32[](int64)') - def operator_isub(size): - a = Array(size, 'int32') - b = Array(size, 'int32') - for i in range(size): - a[i] = nb_types.int32(i) - b[i] = nb_types.int32(size-i-1) - operator.isub(a, b) - # b.free() - return a - - @omnisci('int32[](int64)') - def operator_ipow(size): - a = Array(size, 'int32') - b = Array(size, 'int32') - for i in range(size): - a[i] = nb_types.int32(i+1) - b[i] = nb_types.int32(size-i) - operator.ipow(a, b) - # b.free() - return a - - @omnisci('int32[](int64)') - def operator_irshift(size): - a = Array(size, 'int32') - b = Array(size, 'int32') - for i in range(size): - a[i] = nb_types.int32(i) - b[i] = nb_types.int32(size-i-1) - operator.irshift(a, b) - # b.free() - return a - - @omnisci('int32[](int64)') - def operator_itruediv(size): - a = Array(size, 'int32') - b = Array(size, 'int32') - for i in range(size): - a[i] = nb_types.int32(i+10) - b[i] = nb_types.int32(i+3) - operator.itruediv(a, b) - # b.free() - return a - - @omnisci('double[](int64)') - def operator_itruediv2(size): - a = Array(size, 'double') - b = Array(size, 'double') - for i in range(size): - a[i] = nb_types.double(i+10) - b[i] = nb_types.double(i+3) - operator.itruediv(a, b) - # b.free() - return a - - @omnisci('int32[](int64)') - def operator_imod(size): - a = Array(size, 'int32') - b = Array(size, 'int32') - for i in range(size): - a[i] = nb_types.int32(i * 123) - b[i] = nb_types.int32(7) - operator.imod(a, b) - # b.free() - return a - - @omnisci('int32[](int64)') - def operator_ixor(size): - a = Array(size, 'int32') - b = Array(size, 'int32') - for i in range(size): - a[i] = nb_types.int32(i) - b[i] = nb_types.int32(size-i-1) - operator.ixor(a, b) - # b.free() - return a - - @omnisci('int8(int64, int32)') - def operator_in(size, v): - a = Array(size, 'int32') - for i in range(size): - a[i] = nb_types.int32(i) - res = (v in a) - # a.free() - return res - - @omnisci('int8(int64, int32)') - def operator_is(size, v): - a = Array(size, 'int32') - a.fill(v) - res = (a is a) - # a.free() - return res - - @omnisci('int8(int64, int32)') - def operator_is_not(size, v): - a = Array(size, 'int32') - a.fill(v) - res = (a is not a) - # a.free() - return res - - @omnisci('int8(int64, int32)') - def operator_is_not2(size, v): - a = Array(size, 'int32') - a.fill(v) - b = Array(size, 'int32') - b.fill(v) - res = (a is not b) - # a.free() - # b.free() - return res - - @omnisci('int8[](int64, int32)') - def operator_le(size, v): - a = Array(size, 'int32') - for i in range(size): - a[i] = nb_types.int32(i) - res = (a <= v) - # a.free() - return res - - @omnisci('bool(int64, int32)') - def operator_le_array(size, v): - a = Array(size, 'int32') - for i in range(size): - a[i] = nb_types.int32(i) - res = (a <= a) - # a.free() - return res - - @omnisci('int32[](int64)') - def operator_lshift(size): - a = Array(size, 'int32') - b = Array(size, 'int32') - for i in range(size): - a[i] = nb_types.int32(i) - b[i] = nb_types.int32(size-i-1) - res = operator.lshift(a, b) - # a.free() - # b.free() - return res - - @omnisci('int8[](int64, int32)') - def operator_lt(size, v): - a = Array(size, 'int32') - for i in range(size): - a[i] = nb_types.int32(i) - res = (a < v) - # a.free() - return res - - @omnisci('bool(int64, int32)') - def operator_lt_array(size, v): - a = Array(size, 'int32') - for i in range(size): - a[i] = nb_types.int32(i) - res = (a < a) - # a.free() - return res - - @omnisci('int32[](int64)') - def operator_mul(size): - a = Array(size, 'int32') - b = Array(size, 'int32') - for i in range(size): - a[i] = nb_types.int32(i) - b[i] = nb_types.int32(size-i-1) - res = operator.mul(a, b) - # a.free() - # b.free() - return res - - @omnisci('int32[](int64)') - def operator_mod(size): - a = Array(size, 'int32') - b = Array(size, 'int32') - for i in range(size): - a[i] = nb_types.int32(i * 123) - b[i] = nb_types.int32(7) - res = operator.mod(a, b) - # a.free() - # b.free() - return res - - @omnisci('int8[](int64, int32)') - def operator_ne(size, v): - a = Array(size, 'int32') - for i in range(size): - a[i] = nb_types.int32(i) - res = (a != v) - # a.free() - return res - - @omnisci('bool(int64, int32)') - def operator_ne_array(size, v): - a = Array(size, 'int32') - for i in range(size): - a[i] = nb_types.int32(i) - res = (a != a) - # a.free() - return res - - @omnisci('int32[](int64)') - def operator_neg(size): - a = Array(size, 'int32') - for i in range(size): - a[i] = nb_types.int32(i) - res = operator.neg(a) - # a.free() - return res - - @omnisci('int8(int64, int32)') - def operator_not_in(size, v): - a = Array(size, 'int32') - for i in range(size): - a[i] = nb_types.int32(i) - res = (v not in a) - # a.free() - return res - - @omnisci('int32[](int64)') - def operator_or_bw(size): - a = Array(size, 'int32') - b = Array(size, 'int32') - for i in range(size): - a[i] = nb_types.int32(i) - b[i] = nb_types.int32(size-i-1) - res = operator.or_(a, b) - # a.free() - # b.free() - return res - - @omnisci('int32[](int64)') - def operator_pos(size): - a = Array(size, 'int32') - for i in range(size): - a[i] = nb_types.int32(-i) - res = operator.pos(a) - # a.free() - return res - - @omnisci('int32[](int64)') - def operator_pow(size): - a = Array(size, 'int32') - b = Array(size, 'int32') - for i in range(size): - a[i] = nb_types.int32(i+1) - b[i] = nb_types.int32(size-i) - res = operator.pow(a, b) - # a.free() - # b.free() - return res - - @omnisci('int32[](int64)') - def operator_rshift(size): - a = Array(size, 'int32') - b = Array(size, 'int32') - for i in range(size): - a[i] = nb_types.int32(i) - b[i] = nb_types.int32(size-i-1) - res = operator.rshift(a, b) - # a.free() - # b.free() - return res - - @omnisci('int32[](int64)') - def operator_sub(size): - a = Array(size, 'int32') - b = Array(size, 'int32') - for i in range(size): - a[i] = nb_types.int32(i) - b[i] = nb_types.int32(size-i-1) - res = operator.sub(a, b) - # a.free() - # b.free() - return res - - @omnisci('int32[](int64)') - def operator_truediv(size): - a = Array(size, 'int32') - b = Array(size, 'int32') - for i in range(size): - a[i] = nb_types.int32(i+10) - b[i] = nb_types.int32(i+3) - res = operator.truediv(a, b) - # a.free() - # b.free() - return res - - @omnisci('double[](int64)') - def operator_truediv2(size): - a = Array(size, 'double') - b = Array(size, 'double') - for i in range(size): - a[i] = nb_types.double(i+10) - b[i] = nb_types.double(i+3) - res = operator.truediv(a, b) - # a.free() - # b.free() - return res - - @omnisci('int32[](int64)') - def operator_xor(size): - a = Array(size, 'int32') - b = Array(size, 'int32') - for i in range(size): - a[i] = nb_types.int32(i) - b[i] = nb_types.int32(size-i-1) - res = operator.xor(a, b) - # a.free() - # b.free() - return res + a.free() + return res + + print() + print('*' * 80) + print('LLVM IR DUMP of operator_abs') + print(operator_abs.describe()) + print('*' * 80) + print() + + # @omnisci('int32[](int64)') + # def operator_add(size): + # a = Array(size, 'int32') + # b = Array(size, 'int32') + # for i in range(size): + # a[i] = nb_types.int32(i) + # b[i] = nb_types.int32(size-i-1) + # res = operator.add(a, b) + # # a.free() + # # b.free() + # return res + + # @omnisci('int32[](int64)') + # def operator_and_bw(size): + # a = Array(size, 'int32') + # b = Array(size, 'int32') + # for i in range(size): + # a[i] = nb_types.int32(i) + # b[i] = nb_types.int32(size-i-1) + # res = operator.and_(a, b) + # # a.free() + # # b.free() + # return res + + # @omnisci('int64(int64, int64, int64)') + # def operator_countOf(size, fill_value, b): + # a = Array(size, 'int64') + # for i in range(size): + # a[i] = fill_value + # res = operator.countOf(a, b) + # # a.free() + # return res + + # @omnisci('int8[](int64, int32)') + # def operator_eq(size, v): + # a = Array(size, 'int32') + # for i in range(size): + # a[i] = nb_types.int32(i) + # res = (a == v) + # # a.free() + # return res + + # @omnisci('bool(int64, int32)') + # def operator_eq_array(size, v): + # a = Array(size, 'int32') + # for i in range(size): + # a[i] = nb_types.int32(i) + # res = (a == a) + # # a.free() + # return res + + # @omnisci('int32[](int64)') + # def operator_floordiv(size): + # a = Array(size, 'int32') + # b = Array(size, 'int32') + # for i in range(size): + # a[i] = nb_types.int32(i+10) + # b[i] = nb_types.int32(i+3) + # res = operator.floordiv(a, b) + # # a.free() + # # b.free() + # return res + + # @omnisci('double[](int64)') + # def operator_floordiv2(size): + # a = Array(size, 'double') + # b = Array(size, 'double') + # for i in range(size): + # a[i] = nb_types.double(i+10) + # b[i] = nb_types.double(i+3) + # res = operator.floordiv(a, b) + # # a.free() + # # b.free() + # return res + + # @omnisci('int8[](int64, int32)') + # def operator_ge(size, v): + # a = Array(size, 'int32') + # for i in range(size): + # a[i] = nb_types.int32(i) + # res = (a >= v) + # # a.free() + # return res + + # @omnisci('bool(int64, int32)') + # def operator_ge_array(size, v): + # a = Array(size, 'int32') + # for i in range(size): + # a[i] = nb_types.int32(i) + # res = (a >= a) + # # a.free() + # return res + + # @omnisci('int8[](int64, int32)') + # def operator_gt(size, v): + # a = Array(size, 'int32') + # for i in range(size): + # a[i] = nb_types.int32(i) + # res = (a > v) + # # a.free() + # return res + + # @omnisci('bool(int64, int32)') + # def operator_gt_array(size, v): + # a = Array(size, 'int32') + # for i in range(size): + # a[i] = nb_types.int32(i) + # res = (a > a) + # # a.free() + # return res + + # @omnisci('int32[](int64)') + # def operator_iadd(size): + # a = Array(size, 'int32') + # b = Array(size, 'int32') + # for i in range(size): + # a[i] = nb_types.int32(i) + # b[i] = nb_types.int32(1) + # operator.iadd(a, b) + # # b.free() + # return a + + # @omnisci('int32[](int64)') + # def operator_iand(size): + # a = Array(size, 'int32') + # b = Array(size, 'int32') + # for i in range(size): + # a[i] = nb_types.int32(i) + # b[i] = nb_types.int32(size-i-1) + # operator.iand(a, b) + # # b.free() + # return a + + # @omnisci('int32[](int64)') + # def operator_ifloordiv(size): + # a = Array(size, 'int32') + # b = Array(size, 'int32') + # for i in range(size): + # a[i] = nb_types.int32(i+10) + # b[i] = nb_types.int32(i+3) + # operator.ifloordiv(a, b) + # # b.free() + # return a + + # @omnisci('double[](int64)') + # def operator_ifloordiv2(size): + # a = Array(size, 'double') + # b = Array(size, 'double') + # for i in range(size): + # a[i] = nb_types.double(i+10) + # b[i] = nb_types.double(i+3) + # operator.ifloordiv(a, b) + # # b.free() + # return a + + # @omnisci('int32[](int64)') + # def operator_ilshift(size): + # a = Array(size, 'int32') + # b = Array(size, 'int32') + # for i in range(size): + # a[i] = nb_types.int32(i) + # b[i] = nb_types.int32(size-i-1) + # operator.ilshift(a, b) + # # b.free() + # return a + + # @omnisci('int32[](int64)') + # def operator_imul(size): + # a = Array(size, 'int32') + # b = Array(size, 'int32') + # for i in range(size): + # a[i] = nb_types.int32(i) + # b[i] = nb_types.int32(size-i-1) + # operator.imul(a, b) + # # b.free() + # return a + + # @omnisci('int32[](int64)') + # def operator_ior(size): + # a = Array(size, 'int32') + # b = Array(size, 'int32') + # for i in range(size): + # a[i] = nb_types.int32(i) + # b[i] = nb_types.int32(size-i-1) + # operator.ior(a, b) + # # b.free() + # return a + + # @omnisci('int32[](int64)') + # def operator_isub(size): + # a = Array(size, 'int32') + # b = Array(size, 'int32') + # for i in range(size): + # a[i] = nb_types.int32(i) + # b[i] = nb_types.int32(size-i-1) + # operator.isub(a, b) + # # b.free() + # return a + + # @omnisci('int32[](int64)') + # def operator_ipow(size): + # a = Array(size, 'int32') + # b = Array(size, 'int32') + # for i in range(size): + # a[i] = nb_types.int32(i+1) + # b[i] = nb_types.int32(size-i) + # operator.ipow(a, b) + # # b.free() + # return a + + # @omnisci('int32[](int64)') + # def operator_irshift(size): + # a = Array(size, 'int32') + # b = Array(size, 'int32') + # for i in range(size): + # a[i] = nb_types.int32(i) + # b[i] = nb_types.int32(size-i-1) + # operator.irshift(a, b) + # # b.free() + # return a + + # @omnisci('int32[](int64)') + # def operator_itruediv(size): + # a = Array(size, 'int32') + # b = Array(size, 'int32') + # for i in range(size): + # a[i] = nb_types.int32(i+10) + # b[i] = nb_types.int32(i+3) + # operator.itruediv(a, b) + # # b.free() + # return a + + # @omnisci('double[](int64)') + # def operator_itruediv2(size): + # a = Array(size, 'double') + # b = Array(size, 'double') + # for i in range(size): + # a[i] = nb_types.double(i+10) + # b[i] = nb_types.double(i+3) + # operator.itruediv(a, b) + # # b.free() + # return a + + # @omnisci('int32[](int64)') + # def operator_imod(size): + # a = Array(size, 'int32') + # b = Array(size, 'int32') + # for i in range(size): + # a[i] = nb_types.int32(i * 123) + # b[i] = nb_types.int32(7) + # operator.imod(a, b) + # # b.free() + # return a + + # @omnisci('int32[](int64)') + # def operator_ixor(size): + # a = Array(size, 'int32') + # b = Array(size, 'int32') + # for i in range(size): + # a[i] = nb_types.int32(i) + # b[i] = nb_types.int32(size-i-1) + # operator.ixor(a, b) + # # b.free() + # return a + + # @omnisci('int8(int64, int32)') + # def operator_in(size, v): + # a = Array(size, 'int32') + # for i in range(size): + # a[i] = nb_types.int32(i) + # res = (v in a) + # # a.free() + # return res + + # @omnisci('int8(int64, int32)') + # def operator_is(size, v): + # a = Array(size, 'int32') + # a.fill(v) + # res = (a is a) + # # a.free() + # return res + + # @omnisci('int8(int64, int32)') + # def operator_is_not(size, v): + # a = Array(size, 'int32') + # a.fill(v) + # res = (a is not a) + # # a.free() + # return res + + # @omnisci('int8(int64, int32)') + # def operator_is_not2(size, v): + # a = Array(size, 'int32') + # a.fill(v) + # b = Array(size, 'int32') + # b.fill(v) + # res = (a is not b) + # # a.free() + # # b.free() + # return res + + # @omnisci('int8[](int64, int32)') + # def operator_le(size, v): + # a = Array(size, 'int32') + # for i in range(size): + # a[i] = nb_types.int32(i) + # res = (a <= v) + # # a.free() + # return res + + # @omnisci('bool(int64, int32)') + # def operator_le_array(size, v): + # a = Array(size, 'int32') + # for i in range(size): + # a[i] = nb_types.int32(i) + # res = (a <= a) + # # a.free() + # return res + + # @omnisci('int32[](int64)') + # def operator_lshift(size): + # a = Array(size, 'int32') + # b = Array(size, 'int32') + # for i in range(size): + # a[i] = nb_types.int32(i) + # b[i] = nb_types.int32(size-i-1) + # res = operator.lshift(a, b) + # # a.free() + # # b.free() + # return res + + # @omnisci('int8[](int64, int32)') + # def operator_lt(size, v): + # a = Array(size, 'int32') + # for i in range(size): + # a[i] = nb_types.int32(i) + # res = (a < v) + # # a.free() + # return res + + # @omnisci('bool(int64, int32)') + # def operator_lt_array(size, v): + # a = Array(size, 'int32') + # for i in range(size): + # a[i] = nb_types.int32(i) + # res = (a < a) + # # a.free() + # return res + + # @omnisci('int32[](int64)') + # def operator_mul(size): + # a = Array(size, 'int32') + # b = Array(size, 'int32') + # for i in range(size): + # a[i] = nb_types.int32(i) + # b[i] = nb_types.int32(size-i-1) + # res = operator.mul(a, b) + # # a.free() + # # b.free() + # return res + + # @omnisci('int32[](int64)') + # def operator_mod(size): + # a = Array(size, 'int32') + # b = Array(size, 'int32') + # for i in range(size): + # a[i] = nb_types.int32(i * 123) + # b[i] = nb_types.int32(7) + # res = operator.mod(a, b) + # # a.free() + # # b.free() + # return res + + # @omnisci('int8[](int64, int32)') + # def operator_ne(size, v): + # a = Array(size, 'int32') + # for i in range(size): + # a[i] = nb_types.int32(i) + # res = (a != v) + # # a.free() + # return res + + # @omnisci('bool(int64, int32)') + # def operator_ne_array(size, v): + # a = Array(size, 'int32') + # for i in range(size): + # a[i] = nb_types.int32(i) + # res = (a != a) + # # a.free() + # return res + + # @omnisci('int32[](int64)') + # def operator_neg(size): + # a = Array(size, 'int32') + # for i in range(size): + # a[i] = nb_types.int32(i) + # res = operator.neg(a) + # # a.free() + # return res + + # @omnisci('int8(int64, int32)') + # def operator_not_in(size, v): + # a = Array(size, 'int32') + # for i in range(size): + # a[i] = nb_types.int32(i) + # res = (v not in a) + # # a.free() + # return res + + # @omnisci('int32[](int64)') + # def operator_or_bw(size): + # a = Array(size, 'int32') + # b = Array(size, 'int32') + # for i in range(size): + # a[i] = nb_types.int32(i) + # b[i] = nb_types.int32(size-i-1) + # res = operator.or_(a, b) + # # a.free() + # # b.free() + # return res + + # @omnisci('int32[](int64)') + # def operator_pos(size): + # a = Array(size, 'int32') + # for i in range(size): + # a[i] = nb_types.int32(-i) + # res = operator.pos(a) + # # a.free() + # return res + + # @omnisci('int32[](int64)') + # def operator_pow(size): + # a = Array(size, 'int32') + # b = Array(size, 'int32') + # for i in range(size): + # a[i] = nb_types.int32(i+1) + # b[i] = nb_types.int32(size-i) + # res = operator.pow(a, b) + # # a.free() + # # b.free() + # return res + + # @omnisci('int32[](int64)') + # def operator_rshift(size): + # a = Array(size, 'int32') + # b = Array(size, 'int32') + # for i in range(size): + # a[i] = nb_types.int32(i) + # b[i] = nb_types.int32(size-i-1) + # res = operator.rshift(a, b) + # # a.free() + # # b.free() + # return res + + # @omnisci('int32[](int64)') + # def operator_sub(size): + # a = Array(size, 'int32') + # b = Array(size, 'int32') + # for i in range(size): + # a[i] = nb_types.int32(i) + # b[i] = nb_types.int32(size-i-1) + # res = operator.sub(a, b) + # # a.free() + # # b.free() + # return res + + # @omnisci('int32[](int64)') + # def operator_truediv(size): + # a = Array(size, 'int32') + # b = Array(size, 'int32') + # for i in range(size): + # a[i] = nb_types.int32(i+10) + # b[i] = nb_types.int32(i+3) + # res = operator.truediv(a, b) + # # a.free() + # # b.free() + # return res + + # @omnisci('double[](int64)') + # def operator_truediv2(size): + # a = Array(size, 'double') + # b = Array(size, 'double') + # for i in range(size): + # a[i] = nb_types.double(i+10) + # b[i] = nb_types.double(i+3) + # res = operator.truediv(a, b) + # # a.free() + # # b.free() + # return res + + # @omnisci('int32[](int64)') + # def operator_xor(size): + # a = Array(size, 'int32') + # b = Array(size, 'int32') + # for i in range(size): + # a[i] = nb_types.int32(i) + # b[i] = nb_types.int32(size-i-1) + # res = operator.xor(a, b) + # # a.free() + # # b.free() + # return res @pytest.mark.parametrize("suffix, args, expected", operator_methods,