Spaces:
Runtime error
Runtime error
File size: 3,836 Bytes
1359055 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 |
import datetime
import gc
import multiprocessing as mp
import pathlib
import subprocess
from dataclasses import dataclass
from typing import Dict, List
from tqdm import tqdm
@dataclass
class CommandResult:
return_code: int
runtime: float
stdout: str
stderr: str
timed_out: bool
def safe_execute(
command_to_run: List[str],
working_dir: pathlib.Path,
timeout: int = 10,
) -> CommandResult:
"""Executes a list of commands safely.
Args:
command_to_run: The command to run.
working_dir: The working directory to run them in.
timeout Timeout.
Returns:
The result of executing the command.
"""
timed_out = False
return_code = -1
runtime = timeout
stderr = None
stdout = None
start_time = datetime.datetime.now()
execution_process = subprocess.Popen(
command_to_run,
cwd=str(working_dir),
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
)
try:
outputs = execution_process.communicate(timeout=timeout)
stdout, stderr = outputs
stdout = stdout.decode('utf-8')
stderr = stderr.decode('utf-8')
runtime = (datetime.datetime.now() - start_time).total_seconds()
return_code = execution_process.returncode
except subprocess.TimeoutExpired:
timed_out = True
runtime = timeout
finally:
execution_process.kill()
return CommandResult(
return_code=return_code,
runtime=runtime,
stderr=stderr,
stdout=stdout,
timed_out=timed_out,
)
def execute_code(sample: Dict):
"""Execute a file of code.
Args:
sample: The sample to run.
Returns:
The execution result.
"""
file_path = sample["cwd"]
working_dir_for_execution = (
file_path.parent if file_path.is_file() else file_path
)
working_dir_for_execution = working_dir_for_execution.resolve().absolute()
timed_out = False
failed = False
results = []
for command in sample['commands']:
res = safe_execute(command['command'], working_dir=working_dir_for_execution, timeout=command['timeout'])
results.append(res)
if res.timed_out:
timed_out = True
break
if res.return_code != 0:
failed = True
break
return {
"qid":sample['qid'],
"idx": sample["idx"],
"file_path": str(file_path.absolute().resolve()),
"results": results,
"failed":failed,
"timed_out": timed_out,
}
def execute_predictions(
predictions: List[Dict],
num_workers: int = 1,
max_task_per_child: int = 1,
garbage_collection_freq: int = 500,
):
"""Execute a list of predictions in a specific language.
Args:
predictions: List of predictions.
num_workers: The number of workers to use.
max_task_per_child: The maximum tasks ran per child before it is killed.
garbage_collection_freq: How often to run garbage collection.
Returns:
The the array of raw execution results and the total runtime.
"""
# Make the arguments to submit to the ThreadPoolExecutor. Do it here so we
# can have a progress bar as well.
num_to_complete = len(predictions)
num_completed = 0
results = []
with mp.Pool(num_workers, maxtasksperchild=max_task_per_child) as pool:
for result in tqdm(
pool.imap_unordered(execute_code, predictions),
total=num_to_complete,
desc="Executing",
):
num_completed += 1
results.append(result)
if num_completed % garbage_collection_freq == 0:
gc.collect()
# Cleanup pool
pool.close()
pool.terminate()
return results
|