Skip to content

Commit cd58070

Browse files
griftがCを出力できるように、castとlongestも出力するように
1 parent cc543a3 commit cd58070

10 files changed

Lines changed: 125 additions & 71 deletions

File tree

Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ RUN apt-get update && apt-get install -y \
99
curl git make gcc g++ m4 unzip pkg-config libgmp-dev \
1010
racket llvm-11-dev clang-11 \
1111
python3 python3-pip \
12-
opam \
12+
opam nano \
1313
lsb-release wget software-properties-common gnupg \
1414
libgc-dev libcjson-dev \
1515
&& rm -rf /var/lib/apt/lists/*

benchC/run_grift.py

Lines changed: 124 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -155,37 +155,73 @@ def parse_all_grift_times(stdout_str):
155155
matches = re.findall(r"time \(sec\):\s*([\d\.]+)", stdout_str)
156156
return [float(m) for m in matches]
157157

158-
def run_benchmark(config_dir, source_filename, input_content_multiplied):
159-
# 1. ファイルの場所を「絶対パス(/app/.../fib.grift)」で確実に指定する
158+
def parse_grift_profiler(stdout_str):
159+
"""Griftの --cast-profiler 出力からキャスト関連の数値を抽出する"""
160+
cast_total = None
161+
longest_data = None
162+
163+
for line in stdout_str.split('\n'):
164+
# "total casts:" の行を探す
165+
if "total casts:" in line:
166+
# "total casts:" 以降の文字列を取得して空白で分割
167+
parts = line.split("total casts:")[1].split()
168+
169+
# 数値に変換できるもの(N/Aなどを除く)をすべて合計する
170+
total = 0
171+
for p in parts:
172+
if p.isdigit():
173+
total += int(p)
174+
cast_total = total
175+
176+
# "longest proxy chain:" の行を探す
177+
elif "longest proxy chain:" in line:
178+
parts = line.split("longest proxy chain:")[1].split()
179+
if parts and parts[0].isdigit():
180+
longest_data = int(parts[0])
181+
182+
return cast_total, longest_data
183+
184+
def run_benchmark(config_dir, source_filename, input_content, enable_profiler=False):
160185
import os
161186
abs_source_path = os.path.abspath(os.path.join(config_dir, source_filename))
162-
abs_output_path = os.path.abspath(os.path.join(config_dir, "bench"))
163-
164-
# 2. コマンドに絶対パスを渡す
165-
compile_cmd = [
166-
GRIFT_CMD, "-O", "3", "-o", abs_output_path, abs_source_path
167-
]
187+
output_bin = "bench_prof" if enable_profiler else "bench_perf"
188+
abs_output_path = os.path.abspath(os.path.join(config_dir, output_bin))
189+
190+
# コンパイルコマンドの構築
191+
compile_cmd = [GRIFT_CMD, "-O", "3"]
192+
if enable_profiler:
193+
compile_cmd.append("--cast-profiler")
194+
compile_cmd.extend(["-o", abs_output_path, abs_source_path])
168195

169196
try:
170-
# cwd=config_dir を追加(Griftが中間ファイルなどを正しい場所に置けるようにするため)
171197
subprocess.run(compile_cmd, cwd=config_dir, check=True, capture_output=True, text=True)
172198
except subprocess.CalledProcessError as e:
173199
print(f"\n[Compile Error in {source_filename}]\n{e.stderr}")
174-
return {"status": "Compile Failed", "times": [], "stderr": e.stderr}
200+
return {"status": "Compile Failed", "times": [], "cast": None, "longest": None, "stderr": e.stderr}
175201

176-
# 3. 実行時も絶対パスでバイナリを叩く
177202
run_cmd = [abs_output_path]
178203

179204
try:
180-
# ここでも cwd=config_dir を追加します
181-
proc = subprocess.run(run_cmd, input=input_content_multiplied, cwd=config_dir, check=True, capture_output=True, text=True)
205+
proc = subprocess.run(run_cmd, input=input_content, cwd=config_dir, check=True, capture_output=True, text=True)
182206
stdout_str = proc.stdout.strip()
183-
times = parse_all_grift_times(stdout_str)
184-
status = "Success" if len(times) > 0 else "No Output"
185-
return {"status": status, "times": times, "stdout": stdout_str}
207+
208+
result = {"status": "Success"}
209+
if enable_profiler:
210+
# プロファイルON時はキャスト情報のみパース
211+
cast_data, longest_data = parse_grift_profiler(stdout_str)
212+
result["cast"] = cast_data
213+
result["longest"] = longest_data
214+
else:
215+
# プロファイルOFF時は実行時間のみパース
216+
times = parse_all_grift_times(stdout_str)
217+
result["status"] = "Success" if len(times) > 0 else "No Output"
218+
result["times"] = times
219+
220+
return result
186221
except subprocess.CalledProcessError as e:
187222
print(f"\n[Runtime Error]\n{e.stderr}")
188-
return {"status": "Run Failed", "times": [], "stderr": e.stderr}
223+
return {"status": "Run Failed", "times": [], "cast": None, "longest": None, "stderr": e.stderr}
224+
189225

190226
def get_latest_log_dir():
191227
log_base = os.path.expanduser(LOG_BASE_DIR)
@@ -198,6 +234,34 @@ def get_latest_log_dir():
198234
raise FileNotFoundError(f"No timestamped directories found in {log_base}")
199235
return os.path.join(log_base, valid_subdirs[-1])
200236

237+
def generate_c_code(config_dir, source_filename, dest_dir, dest_filename):
238+
"""GriftでCコードを生成し、指定したディレクトリに保存する"""
239+
import os
240+
import shutil
241+
242+
# 修正: --keep-ir <出力ファイル名> <入力ファイル名> の順番に変更
243+
cmd = [GRIFT_CMD, "--backend", "C", "--keep-ir", dest_filename, source_filename]
244+
245+
try:
246+
# config_dir内でコマンドを実行し、Cコードを生成
247+
subprocess.run(cmd, cwd=config_dir, check=True, capture_output=True, text=True)
248+
249+
# config_dir内に生成されたCコードを、目的のログディレクトリへ移動
250+
src_c = os.path.join(config_dir, dest_filename)
251+
dest_c = os.path.join(dest_dir, dest_filename)
252+
253+
# 指定した名前で正しくファイルが生成されていれば移動
254+
if os.path.exists(src_c):
255+
shutil.move(src_c, dest_c)
256+
else:
257+
# 万が一、Grift側が自動で別の名前(元のファイル名.cなど)をつけてしまった場合の保険
258+
c_files = [f for f in os.listdir(config_dir) if f.endswith(".c")]
259+
if c_files:
260+
shutil.move(os.path.join(config_dir, c_files[0]), dest_c)
261+
262+
except subprocess.CalledProcessError as e:
263+
print(f"\n[C Code Generation Error in {source_filename}]\n{e.stderr}")
264+
201265
def main():
202266
parser = argparse.ArgumentParser(description="Run Grift Lattice Benchmark.")
203267
parser.add_argument("grift_path", help="Path to the .grift file")
@@ -222,6 +286,8 @@ def main():
222286
latest_log_dir = get_latest_log_dir()
223287
suffix = "_fs" if args.static else ""
224288
output_jsonl_path = os.path.join(latest_log_dir, f"GRIFT_{filename_no_ext}{suffix}.jsonl")
289+
c_code_dir = os.path.join(latest_log_dir, "GRIFT")
290+
os.makedirs(c_code_dir, exist_ok=True)
225291
except Exception as e:
226292
print(f"Error setting up log directory: {e}")
227293
return
@@ -232,8 +298,8 @@ def main():
232298
if not base_input:
233299
print(f"\n[Warning] Input file {input_path} is empty!")
234300

235-
# args.iter ぴったりではなく、余裕を持たせて +10 回分連結する
236-
multiplied_input = (base_input + "\n") * (args.iter + 10)
301+
multiplied_input_perf = (base_input + "\n") * (args.iter + 10)
302+
multiplied_input_prof = (base_input + "\n") * (1 + 10)
237303

238304
# AST解析
239305
with open(grift_path, 'r') as f:
@@ -288,37 +354,65 @@ def main():
288354
node.is_mutable_type = is_dyn
289355

290356
base_code = "\n".join([serialize(c) for c in ast_root.children])
291-
full_code = base_code + get_grift_driver_code(args.iter)
292357

293358
variant_dir = os.path.join(work_dir, f"config_{i}")
294359
os.makedirs(variant_dir, exist_ok=True)
295-
with open(os.path.join(variant_dir, filename), 'w') as f:
296-
f.write(full_code)
360+
mutant_index = seq_idx + 1
297361

298-
print(f"[{seq_idx + 1}/{total_variants}] {config_id} ... ", end="", flush=True)
299-
result = run_benchmark(variant_dir, filename, multiplied_input)
300-
301-
times = result.get("times", [])
362+
print(f"[{mutant_index}/{total_variants}] {config_id} ... ", end="", flush=True)
363+
364+
# ---------------------------------------------------------------------
365+
# Phase 1: 実行時間の計測 (プロファイラ OFF, args.iter 回ループ)
366+
# ---------------------------------------------------------------------
367+
filename_perf = f"perf_{filename}"
368+
full_code_perf = base_code + get_grift_driver_code(args.iter)
369+
with open(os.path.join(variant_dir, filename_perf), 'w') as f:
370+
f.write(full_code_perf)
371+
372+
res_perf = run_benchmark(variant_dir, filename_perf, multiplied_input_perf, enable_profiler=False)
373+
times = res_perf.get("times", [])
302374
avg_time = sum(times) / len(times) if times else 0.0
303-
print(f"{result['status']} (Avg: {avg_time:.4f}s)")
375+
376+
# Cコード生成 (純粋な実行用コードを元に生成)
377+
dest_c_filename = f"{filename_no_ext}{mutant_index}.c"
378+
generate_c_code(variant_dir, filename_perf, c_code_dir, dest_c_filename)
379+
380+
# ---------------------------------------------------------------------
381+
# Phase 2: キャストプロファイルの取得 (プロファイラ ON, 1回のみ実行)
382+
# ---------------------------------------------------------------------
383+
filename_prof = f"prof_{filename}"
384+
full_code_prof = base_code + get_grift_driver_code(1)
385+
with open(os.path.join(variant_dir, filename_prof), 'w') as f:
386+
f.write(full_code_prof)
387+
388+
res_prof = run_benchmark(variant_dir, filename_prof, multiplied_input_prof, enable_profiler=True)
389+
390+
print(f"{res_perf['status']} (Avg: {avg_time:.4f}s)")
304391

392+
# ---------------------------------------------------------------------
393+
# 結果の統合とJSON出力
394+
# ---------------------------------------------------------------------
305395
output_obj = {
306396
"mode": "GRIFT",
307-
"mutant_index": seq_idx + 1,
397+
"mutant_index": mutant_index,
308398
"after_mutate": base_code,
309399
"after_insertion": None,
310400
"after_translation": None,
311401
"times_sec": times,
312402
"mem": None,
313-
"cast": None,
403+
"cast": res_prof.get("cast"), # Phase 2 の結果を利用
314404
"inference": None,
315-
"longest": None
405+
"longest": res_prof.get("longest") # Phase 2 の結果を利用
316406
}
317407

318408
with open(output_jsonl_path, 'a') as f:
319409
f.write(json.dumps(output_obj) + "\n")
320410

321411
print(f"Done! Saved to: {output_jsonl_path}")
322412

413+
if os.path.exists(work_dir):
414+
shutil.rmtree(work_dir)
415+
print(f"Cleaned up temporary directory: {work_dir}")
416+
323417
if __name__ == "__main__":
324418
main()
-836 KB
Binary file not shown.

samples/src_grift/experiments_fib/config_0/fib.grift

Lines changed: 0 additions & 10 deletions
This file was deleted.
-836 KB
Binary file not shown.

samples/src_grift/experiments_fib/config_1/fib.grift

Lines changed: 0 additions & 10 deletions
This file was deleted.
-837 KB
Binary file not shown.

samples/src_grift/experiments_fib/config_2/fib.grift

Lines changed: 0 additions & 10 deletions
This file was deleted.
-837 KB
Binary file not shown.

samples/src_grift/experiments_fib/config_3/fib.grift

Lines changed: 0 additions & 10 deletions
This file was deleted.

0 commit comments

Comments
 (0)