Skip to content

Commit e22e6f7

Browse files
committed
added misc
1 parent 4a8ca52 commit e22e6f7

3 files changed

Lines changed: 251 additions & 0 deletions

File tree

misc/benchmark_utils.py

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
# here are all regex templates
2+
import re
3+
from typing import List
4+
5+
# labels
6+
"""
7+
NOTE: there is often overlap between labels. However, you also often have 2 constraints
8+
with the same overlapping labels eg. constraint_A = (lable_AS, label_IT) and constraint_B = (label_AS, label_IT).
9+
Simply use your judgement to assign the best combination eg. constraint_A = (lable_AS) and constraint_B = (label_IT).
10+
11+
Try to use single labels as much as possible
12+
"""
13+
label_AL = "Action Location" # UMBRELLA label: checks for action at location eg. exists goto startloc
14+
label_OWK = "Open World Knowledge"
15+
label_M = "Manipulation at Location"
16+
label_EO = "Event Ordering" # checks for before/after
17+
label_IT = "Correct Initial/Terminal" # checks for the first or last event in a trace
18+
label_L = "Location" # simple checks for robot location eg. exists goto startloc
19+
label_ES = "Exhaustive Search" # "ForAll" style checks
20+
label_A = "Ask Statement at Location"
21+
label_S = "Say Statement at Location"
22+
label_CE = "Check Entity Statements at Location"
23+
24+
labels = [
25+
label_OWK,
26+
label_M,
27+
label_EO,
28+
label_IT,
29+
label_L,
30+
label_ES,
31+
label_AL,
32+
label_A,
33+
label_S,
34+
label_CE,
35+
]
36+
"""
37+
providing (a|b|c) matches for subword
38+
providing a matches for whole word
39+
"""
40+
41+
42+
def contain_words(words: List[str]) -> str:
43+
return r"^(?=.*" + r")(?=.*".join(words) + r").*$"
44+
45+
46+
def contain_words_and_exlude_words(
47+
contained_words: List[str], excluded_words: List[str]
48+
) -> str:
49+
excluded_pattern = r"|".join(
50+
r"\b" + re.escape(word) + r"\b" for word in excluded_words
51+
)
52+
return (
53+
r"^(?!.*"
54+
+ excluded_pattern
55+
+ r")(?=.*"
56+
+ r")(?=.*".join(contained_words)
57+
+ r").*$"
58+
)
59+
60+
61+
def print_debug(check_name: str, check_output: bool, labels: list[str] = []):
62+
print(f"{check_name}: {check_output}. Labels: {labels}")

misc/bounded_subprocess.py

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
import os
2+
import signal
3+
import fcntl
4+
import time
5+
import subprocess
6+
from typing import List
7+
8+
MAX_BYTES_PER_READ = 1024
9+
SLEEP_BETWEEN_READS = 0.1
10+
11+
12+
class Result:
13+
timeout: int
14+
exit_code: int
15+
stdout: str
16+
stderr: str
17+
18+
def __init__(self, timeout, exit_code, stdout, stderr):
19+
self.timeout = timeout
20+
self.exit_code = exit_code
21+
self.stdout = stdout
22+
self.stderr = stderr
23+
24+
25+
def set_nonblocking(reader):
26+
fd = reader.fileno()
27+
fl = fcntl.fcntl(fd, fcntl.F_GETFL)
28+
fcntl.fcntl(fd, fcntl.F_SETFL, fl | os.O_NONBLOCK)
29+
30+
31+
def run(
32+
args: List[str],
33+
timeout_seconds: int = 15,
34+
max_output_size: int = 2048,
35+
env=None,
36+
) -> Result:
37+
"""
38+
Runs the given program with arguments. After the timeout elapses, kills the process
39+
and all other processes in the process group. Captures at most max_output_size bytes
40+
of stdout and stderr each, and discards any output beyond that.
41+
"""
42+
p = subprocess.Popen(
43+
args,
44+
env=env,
45+
stdin=subprocess.DEVNULL,
46+
stdout=subprocess.PIPE,
47+
stderr=subprocess.PIPE,
48+
start_new_session=True,
49+
bufsize=MAX_BYTES_PER_READ,
50+
)
51+
set_nonblocking(p.stdout)
52+
set_nonblocking(p.stderr)
53+
54+
process_group_id = os.getpgid(p.pid)
55+
56+
# We sleep for 0.1 seconds in each iteration.
57+
max_iterations = timeout_seconds * 10
58+
stdout_saved_bytes = []
59+
stderr_saved_bytes = []
60+
stdout_bytes_read = 0
61+
stderr_bytes_read = 0
62+
63+
for _ in range(max_iterations):
64+
this_stdout_read = p.stdout.read(MAX_BYTES_PER_READ)
65+
this_stderr_read = p.stderr.read(MAX_BYTES_PER_READ)
66+
# this_stdout_read and this_stderr_read may be None if stdout or stderr
67+
# are closed. Without these checks, test_close_output fails.
68+
if this_stdout_read is not None and stdout_bytes_read < max_output_size:
69+
stdout_saved_bytes.append(this_stdout_read)
70+
stdout_bytes_read += len(this_stdout_read)
71+
if this_stderr_read is not None and stderr_bytes_read < max_output_size:
72+
stderr_saved_bytes.append(this_stderr_read)
73+
stderr_bytes_read += len(this_stderr_read)
74+
75+
exit_code = p.poll()
76+
if exit_code is not None:
77+
# finish reading output
78+
this_stdout_read = p.stdout.read(max_output_size - stdout_bytes_read)
79+
this_stderr_read = p.stderr.read(max_output_size - stderr_bytes_read)
80+
if this_stdout_read is not None:
81+
stdout_saved_bytes.append(this_stdout_read)
82+
if this_stderr_read is not None:
83+
stderr_saved_bytes.append(this_stderr_read)
84+
break
85+
86+
time.sleep(SLEEP_BETWEEN_READS)
87+
88+
try:
89+
# Kills the process group. Without this line, test_fork_once fails.
90+
os.killpg(process_group_id, signal.SIGKILL)
91+
except ProcessLookupError:
92+
pass
93+
94+
timeout = exit_code is None
95+
exit_code = exit_code if exit_code is not None else -1
96+
stdout = b"".join(stdout_saved_bytes).decode("utf-8", errors="ignore")
97+
stderr = b"".join(stderr_saved_bytes).decode("utf-8", errors="ignore")
98+
return Result(timeout=timeout, exit_code=exit_code, stdout=stdout, stderr=stderr)

misc/utils.py

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
import importlib.util
2+
import sys
3+
import pandas as pd
4+
import glob
5+
from pathlib import Path
6+
import json
7+
8+
9+
def custom_serializer(obj):
10+
if isinstance(obj, (list, tuple)):
11+
return "__list__", obj
12+
return obj
13+
14+
15+
def custom_sort_key(file_name):
16+
# assume the format is in task_prompt_completion.py
17+
file_name = file_name.split("/")[-1].split(".")[0]
18+
name, seq1, seq2 = file_name.split("_")
19+
return name, int(seq1), int(seq2)
20+
21+
22+
def check_file_exists(f: str):
23+
return Path(f).exists()
24+
25+
26+
def load_module(module_name, module_path):
27+
spec = importlib.util.spec_from_file_location(module_name, module_path)
28+
foo = importlib.util.module_from_spec(spec)
29+
sys.modules[module_name] = foo
30+
spec.loader.exec_module(foo)
31+
return foo
32+
33+
34+
def read_benchmark(p: Path, read_regex: str):
35+
if not p.is_dir():
36+
raise Exception(f"Path {p} is not a directory.")
37+
python_files = glob.glob(str(p) + "/{}.py".format(read_regex))
38+
print("benchmark python files: ", python_files)
39+
benchmarks = []
40+
for idx, f in enumerate(python_files):
41+
program = load_module("p{}".format(idx), f)
42+
benchmark = {
43+
"name": program.name,
44+
"prompts": program.prompts,
45+
"tests": program.tests,
46+
}
47+
benchmarks.append(benchmark)
48+
return pd.DataFrame(benchmarks)
49+
50+
51+
def read_completions(p: Path, read_regex: str):
52+
# TODO: read completions from file
53+
if not p.is_dir():
54+
raise Exception(f"Path {p} is not a directory.")
55+
python_files = sorted(
56+
glob.glob(str(p) + "/{}.py".format(read_regex)), key=custom_sort_key
57+
)
58+
59+
print("completion python files: ", python_files)
60+
benchmarks = []
61+
for idx, f in enumerate(python_files):
62+
program = load_module("p{}".format(idx), f)
63+
benchmark = {
64+
"name": program.name,
65+
"detailed_name": python_files[idx].split(".")[0].split("/")[-1],
66+
"prompt": program.prompt,
67+
"completion": program.completion,
68+
}
69+
benchmarks.append(benchmark)
70+
return pd.DataFrame(benchmarks)
71+
72+
73+
def write_dict_to_python_file(variable_name, data_dict, filename, write_mode="w"):
74+
# Convert the dictionary to a JSON-formatted string with custom serialization
75+
json_str = json.dumps(data_dict, default=custom_serializer, indent=4)
76+
77+
# Create the content of the Python file with the formatted dictionary assignment
78+
content = f"{variable_name} = {json_str}\n\n"
79+
80+
# Write the content to the specified filename
81+
with open(filename, write_mode) as file:
82+
file.write(content)
83+
84+
85+
def write_custom_to_python_file(message, filename, write_mode="w"):
86+
# Create the content of the Python file with the formatted dictionary assignment
87+
content = f"{message}\n\n"
88+
89+
# Write the content to the specified filename
90+
with open(filename, write_mode) as file:
91+
file.write(content)

0 commit comments

Comments
 (0)