Commit 006c1ce8 authored by Roman Alifanov's avatar Roman Alifanov

Unify benchmark files for accurate AWK vs Bash comparison

Made bench_heavy_awk.ct and bench_heavy_bash.ct identical except for @awk decorator. Fixed compound assignment with method calls that was causing different results.
parent 2abf5fbb
......@@ -100,6 +100,19 @@ class DispatchMixin:
else:
self.emit(f'{target}=("${{__CT_RET[@]}}")')
def _emit_assign_with_op(self, target: str, value: str, operator: str):
"""Emit assignment with compound operator support."""
if operator == "=":
self.emit_var_assign(target, value)
elif operator == "+=":
self.emit(f'{target}=$((${{target}} + {value}))'.replace('target', target))
elif operator == "-=":
self.emit(f'{target}=$((${{target}} - {value}))'.replace('target', target))
elif operator == "*=":
self.emit(f'{target}=$((${{target}} * {value}))'.replace('target', target))
elif operator == "/=":
self.emit(f'{target}=$((${{target}} / {value}))'.replace('target', target))
def generate_assignment(self, stmt: Assignment):
if isinstance(stmt.target, MemberAccess):
if isinstance(stmt.target.object, ThisExpr):
......@@ -245,7 +258,7 @@ class DispatchMixin:
method = callee.member
args_str = " ".join([f'"{a}"' for a in args])
self.emit(f'__ct_class_{self.current_class}_{method} "$this" {args_str} >/dev/null')
self.emit_var_assign(target, '$__CT_RET')
self._emit_assign_with_op(target, '$__CT_RET', stmt.operator)
return True
if isinstance(callee.object, MemberAccess) and isinstance(callee.object.object, ThisExpr):
......@@ -258,7 +271,7 @@ class DispatchMixin:
if method in ARR_METHODS:
arr_name = f'"${{this}}_{field_name}"'
self.emit(f'{ARR_METHODS[method]} {arr_name} {args_str} >/dev/null'.strip())
self.emit_var_assign(target, '$__CT_RET')
self._emit_assign_with_op(target, '$__CT_RET', stmt.operator)
return True
else:
self._validate_type_method("array", method, location)
......@@ -266,14 +279,14 @@ class DispatchMixin:
if method in DICT_METHODS:
dict_ref = f'"${{__CT_OBJ[\\"$this.{field_name}\\"]}}"'
self.emit(f'{DICT_METHODS[method]} {dict_ref} {args_str} >/dev/null'.strip())
self.emit_var_assign(target, '$__CT_RET')
self._emit_assign_with_op(target, '$__CT_RET', stmt.operator)
return True
else:
self._validate_type_method("dict", method, location)
if field_type == "object":
obj_ref = f'${{__CT_OBJ["$this.{field_name}"]}}'
self.emit(f'__ct_call_method "{obj_ref}" "{method}" {args_str} >/dev/null')
self.emit_var_assign(target, '$__CT_RET')
self._emit_assign_with_op(target, '$__CT_RET', stmt.operator)
return True
return False
......@@ -293,7 +306,7 @@ class DispatchMixin:
func_name = ARR_METHODS[method]
if method == "push" and len(args) == 1:
self.emit(f'{obj_name}+=("{args[0]}")')
self.emit_var_assign(target, '$__CT_RET')
self._emit_assign_with_op(target, '$__CT_RET', stmt.operator)
elif method in ("map", "filter") and len(stmt.value.arguments) >= 1:
first_arg = stmt.value.arguments[0]
if isinstance(first_arg, Lambda):
......@@ -305,7 +318,7 @@ class DispatchMixin:
self._emit_array_assign(target)
else:
self.emit(f'{func_name} "{obj_name}" {args_str} >/dev/null'.replace(' ', ' '))
self.emit_var_assign(target, '$__CT_RET')
self._emit_assign_with_op(target, '$__CT_RET', stmt.operator)
return True
else:
self._validate_type_method("array", method, location)
......@@ -314,7 +327,7 @@ class DispatchMixin:
if method in DICT_METHODS:
func_name = DICT_METHODS[method]
self.emit(f'{func_name} "{obj_name}" {args_str} >/dev/null'.replace(' ', ' '))
self.emit_var_assign(target, '$__CT_RET')
self._emit_assign_with_op(target, '$__CT_RET', stmt.operator)
return True
else:
self._validate_type_method("dict", method, location)
......@@ -323,7 +336,7 @@ class DispatchMixin:
if method in FILE_HANDLE_METHODS:
func_name = FILE_HANDLE_METHODS[method]
self.emit(f'{func_name} "${obj_name}" {args_str} >/dev/null'.replace(' ', ' '))
self.emit_var_assign(target, '$__CT_RET')
self._emit_assign_with_op(target, '$__CT_RET', stmt.operator)
return True
else:
self._validate_type_method("file_handle", method, location)
......@@ -332,12 +345,12 @@ class DispatchMixin:
obj = self.generate_expr(callee.object)
func_name = STR_METHODS[method]
self.emit(f'{func_name} "{obj}" {args_str} >/dev/null'.replace(' ', ' '))
self.emit_var_assign(target, '$__CT_RET')
self._emit_assign_with_op(target, '$__CT_RET', stmt.operator)
return True
obj = self.generate_expr(callee.object)
self.emit(f'__ct_call_method "{obj}" "{method}" {args_str} >/dev/null')
self.emit_var_assign(target, '$__CT_RET')
self._emit_assign_with_op(target, '$__CT_RET', stmt.operator)
return True
return False
......
# Heavy string benchmark - AWK only
@awk
func awk_process_lines (n) {
func process_lines (n) {
result = ""
for i in range (n) {
line = "item_" .. i .. "_data_" .. (i * 7) .. "_end"
......@@ -14,14 +14,12 @@ func awk_process_lines (n) {
}
@awk
func awk_word_stats (n) {
func word_stats (n) {
total_len = 0
word_count = 0
for i in range (n) {
words = "alpha beta gamma delta epsilon zeta eta theta"
num = words.split (" ")
for j in range (1, num + 1) {
word = __split_arr[j]
foreach word in words.split (" ") {
total_len += word.len ()
word_count += 1
}
......@@ -30,7 +28,7 @@ func awk_word_stats (n) {
}
@awk
func awk_build_csv (rows, cols) {
func build_csv (rows, cols) {
result = ""
for r in range (rows) {
for c in range (cols) {
......@@ -46,7 +44,7 @@ func awk_build_csv (rows, cols) {
}
@awk
func awk_search_pattern (n) {
func search_pattern (n) {
count = 0
for i in range (n) {
text = "error_log_" .. i .. "_warning_" .. (i % 100) .. "_info"
......@@ -64,7 +62,7 @@ func awk_search_pattern (n) {
}
@awk
func awk_concat_heavy (n) {
func concat_heavy (n) {
s = ""
for i in range (n) {
s = s .. "x"
......@@ -73,9 +71,9 @@ func awk_concat_heavy (n) {
}
print ("=== AWK String Benchmark ===")
print ("process_lines(5000): {awk_process_lines (5000)}")
print ("word_stats(3000): {awk_word_stats (3000)}")
print ("build_csv(200,50): {awk_build_csv (200, 50)}")
print ("search_pattern(10000): {awk_search_pattern (10000)}")
print ("concat_heavy(10000): {awk_concat_heavy (10000)}")
print ("process_lines(5000): {process_lines (5000)}")
print ("word_stats(3000): {word_stats (3000)}")
print ("build_csv(200,50): {build_csv (200, 50)}")
print ("search_pattern(10000): {search_pattern (10000)}")
print ("concat_heavy(10000): {concat_heavy (10000)}")
print ("Done!")
# Heavy string benchmark - BASH only
func bash_process_lines (n) {
func process_lines (n) {
result = ""
for i in range (n) {
line = "item_" .. i .. "_data_" .. (i * 7) .. "_end"
......@@ -12,20 +12,20 @@ func bash_process_lines (n) {
return result.len ()
}
func bash_word_stats (n) {
func word_stats (n) {
total_len = 0
word_count = 0
for i in range (n) {
words = "alpha beta gamma delta epsilon zeta eta theta"
foreach word in words.split (" ") {
total_len = total_len + word.len ()
word_count = word_count + 1
total_len += word.len ()
word_count += 1
}
}
return total_len
}
func bash_build_csv (rows, cols) {
func build_csv (rows, cols) {
result = ""
for r in range (rows) {
for c in range (cols) {
......@@ -40,24 +40,24 @@ func bash_build_csv (rows, cols) {
return result.len ()
}
func bash_search_pattern (n) {
func search_pattern (n) {
count = 0
for i in range (n) {
text = "error_log_" .. i .. "_warning_" .. (i % 100) .. "_info"
if text.contains ("warning") {
count = count + 1
count += 1
}
if text.contains ("error") {
count = count + 1
count += 1
}
if text.contains ("info") {
count = count + 1
count += 1
}
}
return count
}
func bash_concat_heavy (n) {
func concat_heavy (n) {
s = ""
for i in range (n) {
s = s .. "x"
......@@ -66,9 +66,9 @@ func bash_concat_heavy (n) {
}
print ("=== BASH String Benchmark ===")
print ("process_lines(5000): {bash_process_lines (5000)}")
print ("word_stats(3000): {bash_word_stats (3000)}")
print ("build_csv(200,50): {bash_build_csv (200, 50)}")
print ("search_pattern(10000): {bash_search_pattern (10000)}")
print ("concat_heavy(10000): {bash_concat_heavy (10000)}")
print ("process_lines(5000): {process_lines (5000)}")
print ("word_stats(3000): {word_stats (3000)}")
print ("build_csv(200,50): {build_csv (200, 50)}")
print ("search_pattern(10000): {search_pattern (10000)}")
print ("concat_heavy(10000): {concat_heavy (10000)}")
print ("Done!")
......@@ -125,6 +125,48 @@ class TestArithmetic:
assert "1" in stdout
class TestCompoundAssignment:
def test_plus_assign_simple(self):
code, stdout, _ = run_ct('''
x = 5
x += 3
print (x)
''')
assert code == 0
assert "8" in stdout
def test_plus_assign_with_method_call(self):
code, stdout, _ = run_ct('''
total = 0
word = "hello"
total += word.len ()
print (total)
''')
assert code == 0
assert "5" in stdout
def test_plus_assign_in_loop(self):
code, stdout, _ = run_ct('''
total = 0
foreach word in "ab cde f".split (" ") {
total += word.len ()
}
print (total)
''')
assert code == 0
assert "6" in stdout
def test_minus_assign_with_method(self):
code, stdout, _ = run_ct('''
x = 10
s = "abc"
x -= s.len ()
print (x)
''')
assert code == 0
assert "7" in stdout
class TestFunctions:
def test_function_call(self):
code, stdout, _ = run_ct('''
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment