2025-11-09 14:45:37 +00:00
|
|
|
from copapy import NumLike, iif, variable, sin
|
2025-11-06 14:37:01 +00:00
|
|
|
from copapy.backend import Write, compile_to_dag, add_read_command
|
|
|
|
|
import subprocess
|
|
|
|
|
from copapy import _binwrite
|
|
|
|
|
import copapy.backend as backend
|
|
|
|
|
import warnings
|
|
|
|
|
import re
|
|
|
|
|
import struct
|
2025-11-09 14:45:37 +00:00
|
|
|
import platform
|
|
|
|
|
import copapy as cp
|
2025-11-09 21:53:07 +00:00
|
|
|
import pytest
|
2025-11-06 14:37:01 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
def parse_results(log_text: str) -> dict[int, bytes]:
|
|
|
|
|
regex = r"^READ_DATA offs=(\d*) size=(\d*) data=(.*)$"
|
|
|
|
|
matches = re.finditer(regex, log_text, re.MULTILINE)
|
|
|
|
|
var_dict: dict[int, bytes] = {}
|
|
|
|
|
|
|
|
|
|
for match in matches:
|
|
|
|
|
value_str: list[str] = match.group(3).strip().split(' ')
|
2025-11-07 15:27:39 +00:00
|
|
|
#print('--', value_str)
|
2025-11-06 14:37:01 +00:00
|
|
|
value = bytes(int(v, base=16) for v in value_str)
|
|
|
|
|
if len(value) <= 8:
|
|
|
|
|
var_dict[int(match.group(1))] = value
|
|
|
|
|
|
|
|
|
|
return var_dict
|
|
|
|
|
|
2025-11-09 14:45:37 +00:00
|
|
|
|
2025-11-06 14:37:01 +00:00
|
|
|
def run_command(command: list[str]) -> str:
|
|
|
|
|
result = subprocess.run(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, encoding='utf8', check=False)
|
|
|
|
|
assert result.returncode != 11, f"SIGSEGV (segmentation fault)\n -Error occurred: {result.stderr}\n -Output: {result.stdout}"
|
|
|
|
|
assert result.returncode == 0, f"\n -Error occurred: {result.stderr}\n -Output: {result.stdout}"
|
|
|
|
|
return result.stdout
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def function1(c1: NumLike) -> list[NumLike]:
|
|
|
|
|
return [c1 / 4, c1 / -4, c1 // 4, c1 // -4, (c1 * -1) // 4,
|
|
|
|
|
c1 * 4, c1 * -4,
|
|
|
|
|
c1 + 4, c1 - 4,
|
|
|
|
|
c1 > 2, c1 > 100, c1 < 4, c1 < 100]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def function2(c1: NumLike) -> list[NumLike]:
|
|
|
|
|
return [c1 * 4.44, c1 * -4.44]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def function3(c1: NumLike) -> list[NumLike]:
|
|
|
|
|
return [c1 / 4]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def function4(c1: NumLike) -> list[NumLike]:
|
|
|
|
|
return [c1 == 9, c1 == 4, c1 != 9, c1 != 4]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def function5(c1: NumLike) -> list[NumLike]:
|
|
|
|
|
return [c1 == True, c1 == False, c1 != True, c1 != False, c1 / 2, c1 + 2]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def function6(c1: NumLike) -> list[NumLike]:
|
|
|
|
|
return [c1 == True]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def iiftests(c1: NumLike) -> list[NumLike]:
|
|
|
|
|
return [iif(c1 > 5, 8, 9),
|
|
|
|
|
iif(c1 < 5, 8.5, 9.5),
|
|
|
|
|
iif(1 > 5, 3.3, 8.8) + c1,
|
|
|
|
|
iif(1 < 5, c1 * 3.3, 8.8),
|
|
|
|
|
iif(c1 < 5, c1 * 3.3, 8.8)]
|
|
|
|
|
|
|
|
|
|
|
2025-11-09 21:53:07 +00:00
|
|
|
@pytest.mark.runner
|
2025-11-06 14:37:01 +00:00
|
|
|
def test_compile():
|
2025-11-09 14:45:37 +00:00
|
|
|
t1 = cp.vector([10, 11, 12]) + cp.vector(cp.variable(v) for v in range(3))
|
|
|
|
|
t2 = t1.sum()
|
|
|
|
|
|
|
|
|
|
t3 = cp.vector(cp.variable(1 / (v + 1)) for v in range(3))
|
|
|
|
|
t4 = ((t3 * t1) * 2).sum()
|
|
|
|
|
t5 = ((t3 * t1) * 2).magnitude()
|
|
|
|
|
|
2025-11-07 15:27:39 +00:00
|
|
|
c_i = variable(9)
|
|
|
|
|
c_f = variable(1.111)
|
|
|
|
|
c_b = variable(True)
|
2025-11-06 14:37:01 +00:00
|
|
|
|
2025-11-14 07:56:43 +00:00
|
|
|
#ret_test = function1(c_i) + function1(c_f) + function2(c_i) + function2(c_f) + function3(c_i) + function4(c_i) + function5(c_b) + [c_i % 2, sin(c_f)] + iiftests(c_i) + iiftests(c_f)
|
|
|
|
|
#ret_ref = function1(9) + function1(1.111) + function2(9) + function2(1.111) + function3(9) + function4(9) + function5(True) + [9 % 2, sin(1.111)] + iiftests(9) + iiftests(1.111)
|
|
|
|
|
|
|
|
|
|
#ret_test = [cp.sin(c_i), cp.asin(variable(0.0))]
|
|
|
|
|
#ret_ref = [cp.sin(9), cp.asin(0.0)]
|
|
|
|
|
|
|
|
|
|
ret_test: list[variable[float]] = []
|
|
|
|
|
ret_ref: list[float] = []
|
|
|
|
|
#sval = variable(8.0)
|
|
|
|
|
#tval = 8.0
|
|
|
|
|
#for i in range(20):
|
|
|
|
|
# tval = (10-i) / 12
|
|
|
|
|
# sval = cp.asin(variable(tval))
|
|
|
|
|
# tval = cp.asin(tval)
|
|
|
|
|
# ret_test.append(sval)
|
|
|
|
|
# ret_ref.append(tval)
|
|
|
|
|
|
|
|
|
|
#ret_test = [cp.sin(c_i)]
|
|
|
|
|
#ret_ref = [cp.sin(9)]
|
|
|
|
|
|
|
|
|
|
ret_test = [cp.get_42(c_i)]
|
|
|
|
|
ret_ref = [cp.get_42(9)]
|
2025-11-06 14:37:01 +00:00
|
|
|
|
2025-11-14 07:56:43 +00:00
|
|
|
out = [Write(r) for r in ret_test]
|
2025-11-06 14:37:01 +00:00
|
|
|
|
|
|
|
|
#ret_test += [c_i, v2]
|
|
|
|
|
#ret_ref += [9, 4.44, -4.44]
|
|
|
|
|
|
2025-11-09 14:45:37 +00:00
|
|
|
sdb = backend.stencil_db_from_package('x86')
|
2025-11-06 14:37:01 +00:00
|
|
|
dw, variables = compile_to_dag(out, sdb)
|
|
|
|
|
|
2025-11-07 15:01:22 +00:00
|
|
|
#dw.write_com(_binwrite.Command.READ_DATA)
|
|
|
|
|
#dw.write_int(0)
|
|
|
|
|
#dw.write_int(28)
|
2025-11-06 14:37:01 +00:00
|
|
|
|
|
|
|
|
# run program command
|
|
|
|
|
dw.write_com(_binwrite.Command.RUN_PROG)
|
2025-11-07 15:01:22 +00:00
|
|
|
#dw.write_com(_binwrite.Command.DUMP_CODE)
|
2025-11-06 14:37:01 +00:00
|
|
|
|
|
|
|
|
for net in ret_test:
|
|
|
|
|
assert isinstance(net, backend.Net)
|
|
|
|
|
add_read_command(dw, variables, net)
|
|
|
|
|
|
2025-11-07 15:01:22 +00:00
|
|
|
#dw.write_com(_binwrite.Command.READ_DATA)
|
|
|
|
|
#dw.write_int(0)
|
|
|
|
|
#dw.write_int(28)
|
2025-11-06 14:37:01 +00:00
|
|
|
|
|
|
|
|
dw.write_com(_binwrite.Command.END_COM)
|
|
|
|
|
|
2025-11-14 07:56:43 +00:00
|
|
|
#print('* Data to runner:')
|
|
|
|
|
#dw.print()
|
2025-11-06 14:37:01 +00:00
|
|
|
|
2025-11-12 23:29:48 +00:00
|
|
|
dw.to_file('build/runner/test-x86.copapy')
|
2025-11-06 14:37:01 +00:00
|
|
|
|
2025-11-09 21:53:07 +00:00
|
|
|
if platform.machine() != 'AMD64' and platform.machine() != 'x86_64':
|
2025-11-09 14:45:37 +00:00
|
|
|
warnings.warn(f"Test skipped, {platform.machine()} not supported for this test.", UserWarning)
|
2025-11-06 14:37:01 +00:00
|
|
|
else:
|
2025-11-12 23:29:48 +00:00
|
|
|
command = ['build/runner/coparun-x86', 'build/runner/test-x86.copapy', 'build/runner/test-x86.copapy.bin']
|
2025-11-09 21:53:07 +00:00
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
result = run_command(command)
|
|
|
|
|
except FileNotFoundError:
|
|
|
|
|
warnings.warn(f"Test skipped, executable not found.", UserWarning)
|
|
|
|
|
return
|
|
|
|
|
|
2025-11-06 14:37:01 +00:00
|
|
|
print('* Output from runner:\n--')
|
|
|
|
|
print(result)
|
|
|
|
|
print('--')
|
|
|
|
|
|
|
|
|
|
assert 'Return value: 1' in result
|
|
|
|
|
|
|
|
|
|
result_data = parse_results(result)
|
|
|
|
|
|
|
|
|
|
for test, ref in zip(ret_test, ret_ref):
|
|
|
|
|
assert isinstance(test, variable)
|
|
|
|
|
address = variables[test][0]
|
|
|
|
|
data = result_data[address]
|
|
|
|
|
if test.dtype == 'int':
|
|
|
|
|
val = int.from_bytes(data, sdb.byteorder, signed=True)
|
|
|
|
|
elif test.dtype == 'bool':
|
|
|
|
|
val = bool.from_bytes(data, sdb.byteorder)
|
|
|
|
|
elif test.dtype == 'float':
|
|
|
|
|
en = {'little': '<', 'big': '>'}[sdb.byteorder]
|
|
|
|
|
val = struct.unpack(en + 'f', data)[0]
|
|
|
|
|
assert isinstance(val, float)
|
|
|
|
|
else:
|
|
|
|
|
raise Exception(f"Unknown type: {test.dtype}")
|
|
|
|
|
print('+', val, ref, test.dtype, f" addr={address}")
|
|
|
|
|
#for t in (int, float, bool):
|
|
|
|
|
# assert isinstance(val, t) == isinstance(ref, t), f"Result type does not match for {val} and {ref}"
|
|
|
|
|
#assert val == pytest.approx(ref, 1e-5), f"Result does not match: {val} and reference: {ref}" # pyright: ignore[reportUnknownMemberType]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == "__main__":
|
|
|
|
|
#test_example()
|
|
|
|
|
test_compile()
|