Skip to content

Commit dc62e03

Browse files
committed
instruction coverage update
1 parent f28deff commit dc62e03

File tree

11 files changed

+104
-74
lines changed

11 files changed

+104
-74
lines changed

utbot-python-executor/src/main/python/utbot_executor/pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[tool.poetry]
22
name = "utbot-executor"
3-
version = "1.7.0.dev13"
3+
version = "1.8.0"
44
description = ""
55
authors = ["Vyacheslav Tamarin <vyacheslav.tamarin@yandex.ru>"]
66
readme = "README.md"

utbot-python-executor/src/main/python/utbot_executor/utbot_executor/__main__.py

Lines changed: 32 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -2,35 +2,45 @@
22
import logging
33

44
from utbot_executor.listener import PythonExecuteServer
5+
from utbot_executor.utils import TraceMode
56

67

7-
def main(hostname: str, port: int, coverage_hostname: str, coverage_port: str):
8-
server = PythonExecuteServer(hostname, port, coverage_hostname, coverage_port)
8+
def main(hostname: str, port: int, coverage_hostname: str, coverage_port: int, trace_mode: TraceMode):
9+
server = PythonExecuteServer(hostname, port, coverage_hostname, coverage_port, trace_mode)
910
server.run()
1011

1112

12-
if __name__ == '__main__':
13+
if __name__ == "__main__":
1314
parser = argparse.ArgumentParser(
14-
prog='UtBot Python Executor',
15-
description='Listen socket stream and execute function value',
16-
)
17-
parser.add_argument('hostname')
18-
parser.add_argument('port', type=int)
19-
parser.add_argument('--logfile', default=None)
15+
prog="UtBot Python Executor",
16+
description="Listen socket stream and execute function value",
17+
)
18+
parser.add_argument("hostname")
19+
parser.add_argument("port", type=int)
20+
parser.add_argument("--logfile", default=None)
2021
parser.add_argument(
21-
'--loglevel',
22-
choices=["DEBUG", "INFO", "ERROR"],
23-
default="ERROR",
24-
)
25-
parser.add_argument('coverage_hostname')
26-
parser.add_argument('coverage_port', type=int)
22+
"--loglevel",
23+
choices=["DEBUG", "INFO", "WARNING", "ERROR"],
24+
default="ERROR",
25+
)
26+
parser.add_argument("coverage_hostname")
27+
parser.add_argument("coverage_port", type=int)
28+
parser.add_argument(
29+
"--coverage_type", choices=["lines", "instructions"], default="instructions"
30+
)
2731
args = parser.parse_args()
2832

29-
loglevel = {"DEBUG": logging.DEBUG, "INFO": logging.INFO, "ERROR": logging.ERROR}[args.loglevel]
33+
loglevel = {
34+
"DEBUG": logging.DEBUG,
35+
"INFO": logging.INFO,
36+
"WARNING": logging.WARNING,
37+
"ERROR": logging.ERROR,
38+
}[args.loglevel]
3039
logging.basicConfig(
31-
filename=args.logfile,
32-
format='%(asctime)s | %(levelname)s | %(funcName)s - %(message)s',
33-
datefmt='%m/%d/%Y %H:%M:%S',
34-
level=loglevel,
35-
)
36-
main(args.hostname, args.port, args.coverage_hostname, args.coverage_port)
40+
filename=args.logfile,
41+
format="%(asctime)s | %(levelname)s | %(funcName)s - %(message)s",
42+
datefmt="%m/%d/%Y %H:%M:%S",
43+
level=loglevel,
44+
)
45+
trace_mode = TraceMode.Lines if args.coverage_type == "lines" else TraceMode.Instructions
46+
main(args.hostname, args.port, args.coverage_hostname, args.coverage_port, trace_mode)

utbot-python-executor/src/main/python/utbot_executor/utbot_executor/executor.py

Lines changed: 21 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,12 @@
1515
from utbot_executor.memory_compressor import compress_memory
1616
from utbot_executor.parser import ExecutionRequest, ExecutionResponse, ExecutionFailResponse, ExecutionSuccessResponse
1717
from utbot_executor.ut_tracer import UtTracer, UtCoverageSender
18-
from utbot_executor.utils import suppress_stdout as __suppress_stdout, get_instructions
18+
from utbot_executor.utils import (
19+
suppress_stdout as __suppress_stdout,
20+
get_instructions,
21+
filter_instructions,
22+
TraceMode,
23+
)
1924

2025
__all__ = ['PythonExecutor']
2126

@@ -38,9 +43,10 @@ def _load_objects(objs: List[Any]) -> MemoryDump:
3843

3944

4045
class PythonExecutor:
41-
def __init__(self, coverage_hostname: str, coverage_port: int):
46+
def __init__(self, coverage_hostname: str, coverage_port: int, trace_mode: TraceMode):
4247
self.coverage_hostname = coverage_hostname
4348
self.coverage_port = coverage_port
49+
self.trace_mode = trace_mode
4450

4551
@staticmethod
4652
def add_syspaths(syspaths: Iterable[str]):
@@ -108,24 +114,21 @@ def run_function(self, request: ExecutionRequest) -> ExecutionResponse:
108114
state_init = _update_states(loader.reload_id(), state_init_memory)
109115
serialized_state_init = serialize_memory_dump(state_init)
110116

111-
# def _coverage_sender(info: typing.Tuple[str, int]):
112-
# if pathlib.Path(info[0]) == pathlib.Path(request.filepath):
113-
# sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
114-
# logging.debug("Coverage message: %s:%d", request.coverage_id, info[1])
115-
# logging.debug("Port: %d", self.coverage_port)
116-
# message = bytes(f'{request.coverage_id}:{info[1]}', encoding='utf-8')
117-
# sock.sendto(message, (self.coverage_hostname, self.coverage_port))
118-
# logging.debug("ID: %s, Coverage: %s", request.coverage_id, info)
119117
_coverage_sender = UtCoverageSender(request.coverage_id, self.coverage_hostname, self.coverage_port)
120118

121119
value = _run_calculate_function_value(
122-
function,
123-
args,
124-
kwargs,
125-
request.filepath,
126-
serialized_state_init,
127-
tracer=UtTracer(pathlib.Path(request.filepath), [sys.prefix, sys.exec_prefix], _coverage_sender)
128-
)
120+
function,
121+
args,
122+
kwargs,
123+
request.filepath,
124+
serialized_state_init,
125+
tracer=UtTracer(
126+
pathlib.Path(request.filepath),
127+
[sys.prefix, sys.exec_prefix],
128+
_coverage_sender,
129+
self.trace_mode,
130+
),
131+
)
129132
except Exception as _:
130133
logging.debug("Error \n%s", traceback.format_exc())
131134
return ExecutionFailResponse("fail", traceback.format_exc())
@@ -170,7 +173,7 @@ def _run_calculate_function_value(
170173

171174
__is_exception = False
172175

173-
__all_code_lines = list(get_instructions(function))
176+
__all_code_lines = filter_instructions(get_instructions(function), tracer.mode)
174177
__start = min([op[0] for op in __all_code_lines])
175178

176179
__tracer = tracer
@@ -196,7 +199,6 @@ def _run_calculate_function_value(
196199

197200
args_ids, kwargs_ids, result_id, state_after, serialized_state_after = _serialize_state(args, kwargs, __result)
198201
ids = args_ids + list(kwargs_ids.values())
199-
# state_before, state_after = compress_memory(ids, state_before, state_after)
200202
diff_ids = compress_memory(ids, state_before, state_after)
201203

202204
return ExecutionSuccessResponse(

utbot-python-executor/src/main/python/utbot_executor/utbot_executor/listener.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
from utbot_executor.deep_serialization.memory_objects import PythonSerializer
77
from utbot_executor.parser import parse_request, serialize_response, ExecutionFailResponse
88
from utbot_executor.executor import PythonExecutor
9-
9+
from utbot_executor.utils import TraceMode
1010

1111
RECV_SIZE = 2**15
1212

@@ -17,12 +17,13 @@ def __init__(
1717
hostname: str,
1818
port: int,
1919
coverage_hostname: str,
20-
coverage_port: str,
20+
coverage_port: int,
21+
trace_mode: TraceMode,
2122
):
2223
logging.info('PythonExecutor is creating...')
2324
self.clientsocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
2425
self.clientsocket.connect((hostname, port))
25-
self.executor = PythonExecutor(coverage_hostname, coverage_port)
26+
self.executor = PythonExecutor(coverage_hostname, coverage_port, trace_mode)
2627

2728
def run(self) -> None:
2829
logging.info('PythonExecutor is ready...')

utbot-python-executor/src/main/python/utbot_executor/utbot_executor/ut_tracer.py

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,14 @@
1-
import dis
2-
import inspect
31
import logging
42
import os
53
import pathlib
64
import queue
75
import socket
86
import sys
9-
import threading
107
import typing
118
from concurrent.futures import ThreadPoolExecutor
129

10+
from utbot_executor.utils import TraceMode
11+
1312

1413
def _modname(path):
1514
base = os.path.basename(path)
@@ -55,13 +54,20 @@ def put_message(self, key: str):
5554

5655

5756
class UtTracer:
58-
def __init__(self, tested_file: pathlib.Path, ignore_dirs: typing.List[str], sender: UtCoverageSender):
57+
def __init__(
58+
self,
59+
tested_file: pathlib.Path,
60+
ignore_dirs: typing.List[str],
61+
sender: UtCoverageSender,
62+
mode: TraceMode = TraceMode.Instructions,
63+
):
5964
self.tested_file = tested_file
6065
self.counts = {}
6166
self.localtrace = self.localtrace_count
6267
self.globaltrace = self.globaltrace_lt
6368
self.ignore_dirs = ignore_dirs
6469
self.sender = sender
70+
self.mode = mode
6571

6672
def runfunc(self, func, /, *args, **kw):
6773
result = None
@@ -80,15 +86,13 @@ def localtrace_count(self, frame, why, arg):
8086
filename = frame.f_code.co_filename
8187
if pathlib.Path(filename) == self.tested_file:
8288
lineno = frame.f_lineno
83-
offset = 0
89+
offset = lineno * 2
8490
if why == "opcode":
8591
offset = frame.f_lasti
8692
key = (lineno, offset)
87-
logging.debug(filename, key)
8893
if key not in self.counts:
8994
message = ":".join(map(str, key))
9095
try:
91-
# self.sender.send_message(message)
9296
self.sender.put_message(message)
9397
except Exception:
9498
pass
@@ -97,8 +101,9 @@ def localtrace_count(self, frame, why, arg):
97101

98102
def globaltrace_lt(self, frame, why, arg):
99103
if why == 'call':
100-
frame.f_trace_opcodes = True
101-
frame.f_trace_lines = False
104+
if self.mode == TraceMode.Instructions:
105+
frame.f_trace_opcodes = True
106+
frame.f_trace_lines = False
102107
filename = frame.f_globals.get('__file__', None)
103108
if filename and all(not filename.startswith(d + os.sep) for d in self.ignore_dirs):
104109
modulename = _modname(filename)
@@ -127,5 +132,5 @@ def f(x):
127132

128133

129134
if __name__ in "__main__":
130-
tracer = UtTracer(pathlib.Path(__file__), [], UtCoverageSender("1", "localhost", 0, use_thread=False))
135+
tracer = UtTracer(pathlib.Path(__file__), [], UtCoverageSender("1", "localhost", 0, use_thread=False), mode=TraceMode.Lines)
131136
tracer.runfunc(f, 6)

utbot-python-executor/src/main/python/utbot_executor/utbot_executor/utils.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,17 @@
11
import dis
2+
import enum
3+
import inspect
24
import os
35
import sys
46
import typing
57
from contextlib import contextmanager
68

79

10+
class TraceMode(enum.Enum):
11+
Lines = 1
12+
Instructions = 2
13+
14+
815
@contextmanager
916
def suppress_stdout():
1017
with open(os.devnull, "w") as devnull:
@@ -25,3 +32,13 @@ def inner_get_instructions(x, current_line):
2532
if "<class 'code'>" in str(type(el.argval)):
2633
inner_get_instructions(el.argval, current_line)
2734
return inner_get_instructions(obj, None)
35+
36+
37+
def filter_instructions(
38+
instructions: typing.Iterable[tuple[int, int]],
39+
mode: TraceMode = TraceMode.Instructions,
40+
) -> list[tuple[int, int]]:
41+
if mode == TraceMode.Lines:
42+
return [(it, it) for it in {line for line, op in instructions}]
43+
return list(instructions)
44+
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
1.7.0.dev13
1+
1.8.0
Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,14 @@
1-
import time
2-
3-
41
def check_interval(x: float, left: float, right: float) -> str:
52
if left < x < right or right < x < left:
6-
print(1)
7-
time.sleep(4)
83
return "between"
94
elif x < left and x < right:
10-
print(1)
11-
time.sleep(4)
125
return "less"
136
elif x > left and x > right:
14-
print(1)
15-
time.sleep(4)
167
return "more"
178
elif left == right:
18-
print(1)
19-
time.sleep(4)
209
return "all equals"
2110
elif x == left:
22-
print(1)
23-
time.sleep(4)
2411
return "left"
2512
elif x == right:
26-
print(1)
27-
time.sleep(4)
2813
return "right"
29-
print(1)
30-
time.sleep(4)
3114
return "what?"

utbot-python/samples/test_configuration.json

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,17 @@
248248
"coverage": 75
249249
}
250250
]
251+
},
252+
{
253+
"name": "multi_conditions",
254+
"groups": [
255+
{
256+
"classes": null,
257+
"methods": null,
258+
"timeout": 15,
259+
"coverage": 100
260+
}
261+
]
251262
}
252263
]
253264
},

utbot-python/src/main/kotlin/org/utbot/python/evaluation/PythonCodeSocketExecutor.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,7 @@ class PythonCodeSocketExecutor(
166166
it.offset
167167
)
168168
},
169-
instructionsCount = statements.size.toLong(),
169+
instructionsCount = (covered.size + missedStatements.size).toLong(),
170170
missedInstructions = missedStatements.map {
171171
Instruction(
172172
method.containingPythonClass?.pythonTypeRepresentation() ?: pythonAnyClassId.name,

0 commit comments

Comments
 (0)