wafer-cli 0.2.29__py3-none-any.whl → 0.2.31__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
wafer/evaluate.py CHANGED
@@ -78,9 +78,10 @@ def _build_docker_run_command(
78
78
  for cap in cap_add:
79
79
  parts.extend(["--cap-add", cap])
80
80
 
81
- # GPU access - use single quotes for the device spec to avoid shell escaping issues
81
+ # GPU access - use --runtime=nvidia alongside --gpus for compatibility
82
+ # with newer NVIDIA drivers (580+) where --gpus alone may not initialize CUDA
82
83
  if gpus:
83
- parts.extend(["--gpus", f"'{gpus}'"])
84
+ parts.extend(["--runtime=nvidia", "--gpus", f"'{gpus}'"])
84
85
 
85
86
  # Volume mounts
86
87
  if volumes:
@@ -379,18 +380,6 @@ def _build_docker_pip_install_cmd(target: BaremetalTarget | VMTarget) -> str:
379
380
  return " && ".join(commands)
380
381
 
381
382
 
382
- def _get_wafer_root() -> Path:
383
- """Get wafer monorepo root directory.
384
-
385
- Walks up from this file to find the wafer repo root (contains apps/, packages/).
386
- """
387
- current = Path(__file__).resolve()
388
- for parent in [current] + list(current.parents):
389
- if (parent / "apps").is_dir() and (parent / "packages").is_dir():
390
- return parent
391
- raise RuntimeError(f"Could not find wafer root from {__file__}")
392
-
393
-
394
383
  async def run_evaluate_docker(
395
384
  args: EvaluateArgs,
396
385
  target: BaremetalTarget | VMTarget,
@@ -2033,54 +2022,13 @@ async def run_evaluate_runpod(
2033
2022
  error_message=f"Failed to setup Python environment: {e}",
2034
2023
  )
2035
2024
 
2036
- # Upload wafer-core to remote
2037
- try:
2038
- wafer_root = _get_wafer_root()
2039
- wafer_core_path = wafer_root / "packages" / "wafer-core"
2040
- print(f"Uploading wafer-core from {wafer_core_path}...")
2041
-
2042
- wafer_core_remote = f"{REMOTE_WORKSPACE}/wafer-core"
2043
- await client.exec(f"mkdir -p {wafer_core_remote}")
2044
- wafer_core_workspace = await client.expand_path(wafer_core_remote)
2045
-
2046
- upload_result = await client.upload_files(
2047
- str(wafer_core_path), wafer_core_workspace, recursive=True
2048
- )
2049
-
2050
- # Wide event logging for upload result
2051
- upload_event = {
2052
- "event": "wafer_core_upload",
2053
- "target": target.name,
2054
- "target_type": "runpod",
2055
- "ssh_host": f"{client.user}@{client.host}:{client.port}",
2056
- "local_path": str(wafer_core_path),
2057
- "remote_path": wafer_core_workspace,
2058
- "success": upload_result.success,
2059
- "files_copied": upload_result.files_copied,
2060
- "duration_seconds": upload_result.duration_seconds,
2061
- "error_message": upload_result.error_message,
2062
- }
2063
- if upload_result.debug_info:
2064
- upload_event["debug_info"] = upload_result.debug_info
2065
- logger.info(json.dumps(upload_event))
2066
-
2067
- # Fail fast if upload failed
2068
- if not upload_result.success:
2069
- print(f"ERROR: Upload failed: {upload_result.error_message}")
2070
- if upload_result.debug_info:
2071
- print(f"Debug info: {json.dumps(upload_result.debug_info, indent=2)}")
2072
- return EvaluateResult(
2073
- success=False,
2074
- all_correct=False,
2075
- correctness_score=0.0,
2076
- geomean_speedup=0.0,
2077
- passed_tests=0,
2078
- total_tests=0,
2079
- error_message=f"Failed to upload wafer-core: {upload_result.error_message}",
2080
- )
2081
-
2082
- print(f"Uploaded {upload_result.files_copied} files")
2083
- except Exception as e:
2025
+ # Install wafer-core in remote venv
2026
+ print("Installing wafer-core...")
2027
+ install_result = await client.exec(
2028
+ f'export PATH="$HOME/.local/bin:$HOME/.cargo/bin:$PATH" && '
2029
+ f"uv pip install --python {python_exe} wafer-core"
2030
+ )
2031
+ if install_result.exit_code != 0:
2084
2032
  return EvaluateResult(
2085
2033
  success=False,
2086
2034
  all_correct=False,
@@ -2088,7 +2036,7 @@ async def run_evaluate_runpod(
2088
2036
  geomean_speedup=0.0,
2089
2037
  passed_tests=0,
2090
2038
  total_tests=0,
2091
- error_message=f"Failed to upload wafer-core: {e}",
2039
+ error_message=f"Failed to install wafer-core: {install_result.stderr}",
2092
2040
  )
2093
2041
 
2094
2042
  # Select GPU (RunPod pods typically have GPU 0)
@@ -2229,11 +2177,18 @@ async def run_evaluate_runpod(
2229
2177
  error_message=f"Evaluation timed out after {target.eval_timeout}s",
2230
2178
  )
2231
2179
 
2232
- # Parse output
2180
+ # Show output to user
2233
2181
  stdout = result.stdout
2234
2182
  stderr = result.stderr
2183
+ if stdout:
2184
+ print(stdout)
2235
2185
 
2236
2186
  if result.exit_code != 0:
2187
+ error_parts = [f"Evaluation failed (exit code {result.exit_code}):"]
2188
+ if stdout:
2189
+ error_parts.append(f"stdout: {stdout}")
2190
+ if stderr:
2191
+ error_parts.append(f"stderr: {stderr}")
2237
2192
  return EvaluateResult(
2238
2193
  success=False,
2239
2194
  all_correct=False,
@@ -2241,20 +2196,27 @@ async def run_evaluate_runpod(
2241
2196
  geomean_speedup=0.0,
2242
2197
  passed_tests=0,
2243
2198
  total_tests=0,
2244
- error_message=f"Evaluation failed:\nstdout: {stdout}\nstderr: {stderr}",
2199
+ error_message="\n".join(error_parts),
2245
2200
  )
2246
2201
 
2247
- # Find JSON result in output
2248
- result_json = None
2249
- for line in reversed(stdout.strip().split("\n")):
2250
- if line.startswith("{"):
2251
- try:
2252
- result_json = json.loads(line)
2253
- break
2254
- except json.JSONDecodeError:
2255
- continue
2256
-
2257
- if result_json is None:
2202
+ # Read results from results.json file written by evaluate module
2203
+ results_path = f"{run_path}/results.json"
2204
+ cat_result = await client.exec(f"cat {results_path}")
2205
+
2206
+ if cat_result.exit_code != 0:
2207
+ return EvaluateResult(
2208
+ success=False,
2209
+ all_correct=False,
2210
+ correctness_score=0.0,
2211
+ geomean_speedup=0.0,
2212
+ passed_tests=0,
2213
+ total_tests=0,
2214
+ error_message=f"Failed to read results: {cat_result.stderr}",
2215
+ )
2216
+
2217
+ try:
2218
+ results_data = json.loads(cat_result.stdout)
2219
+ except json.JSONDecodeError as e:
2258
2220
  return EvaluateResult(
2259
2221
  success=False,
2260
2222
  all_correct=False,
@@ -2262,10 +2224,12 @@ async def run_evaluate_runpod(
2262
2224
  geomean_speedup=0.0,
2263
2225
  passed_tests=0,
2264
2226
  total_tests=0,
2265
- error_message=f"No JSON result in output:\n{stdout}",
2227
+ error_message=f"Invalid JSON in results: {e}",
2266
2228
  )
2267
2229
 
2268
- if "error" in result_json:
2230
+ # Extract backend results (same format as DigitalOcean/SSH path)
2231
+ backends = results_data.get("backends", [])
2232
+ if not backends:
2269
2233
  return EvaluateResult(
2270
2234
  success=False,
2271
2235
  all_correct=False,
@@ -2273,18 +2237,20 @@ async def run_evaluate_runpod(
2273
2237
  geomean_speedup=0.0,
2274
2238
  passed_tests=0,
2275
2239
  total_tests=0,
2276
- error_message=result_json["error"],
2240
+ error_message="No backend results found",
2277
2241
  )
2278
2242
 
2279
- passed = result_json.get("passed", 0)
2280
- total = result_json.get("total", 0)
2243
+ backend = backends[0]
2244
+ correctness_tests = backend.get("correctness_tests", [])
2245
+ passed = sum(1 for t in correctness_tests if t.get("is_correct", False))
2246
+ total = len(correctness_tests)
2281
2247
  correctness = passed / total if total > 0 else 0.0
2282
2248
 
2283
2249
  return EvaluateResult(
2284
2250
  success=True,
2285
- all_correct=result_json.get("all_correct", False),
2251
+ all_correct=backend.get("all_correct", False),
2286
2252
  correctness_score=correctness,
2287
- geomean_speedup=result_json.get("speedup", 0.0),
2253
+ geomean_speedup=backend.get("geomean_speedup", 0.0),
2288
2254
  passed_tests=passed,
2289
2255
  total_tests=total,
2290
2256
  )
@@ -2385,61 +2351,13 @@ async def run_evaluate_digitalocean(
2385
2351
  error_message=f"Failed to setup Python environment: {e}",
2386
2352
  )
2387
2353
 
2388
- # Upload wafer-core to remote
2389
- try:
2390
- wafer_root = _get_wafer_root()
2391
- wafer_core_path = wafer_root / "packages" / "wafer-core"
2392
- print(f"Uploading wafer-core from {wafer_core_path}...")
2393
-
2394
- wafer_core_remote = f"{REMOTE_WORKSPACE}/wafer-core"
2395
- await client.exec(f"mkdir -p {wafer_core_remote}")
2396
- wafer_core_workspace = await client.expand_path(wafer_core_remote)
2397
-
2398
- # Use SFTP instead of rsync to avoid SSH subprocess timeout issues
2399
- # (DigitalOcean may rate-limit new SSH connections)
2400
- upload_result = await client.upload_files(
2401
- str(wafer_core_path),
2402
- wafer_core_workspace,
2403
- recursive=True,
2404
- use_sftp=True,
2405
- )
2406
-
2407
- # Wide event logging for upload result
2408
- upload_event = {
2409
- "event": "wafer_core_upload",
2410
- "target": target.name,
2411
- "target_type": "digitalocean",
2412
- "ssh_host": f"{client.user}@{client.host}:{client.port}",
2413
- "local_path": str(wafer_core_path),
2414
- "remote_path": wafer_core_workspace,
2415
- "success": upload_result.success,
2416
- "files_copied": upload_result.files_copied,
2417
- "duration_seconds": upload_result.duration_seconds,
2418
- "error_message": upload_result.error_message,
2419
- }
2420
- if upload_result.debug_info:
2421
- upload_event["debug_info"] = upload_result.debug_info
2422
- logger.info(json.dumps(upload_event))
2423
-
2424
- # Fail fast if upload failed
2425
- if not upload_result.success:
2426
- print(f"ERROR: Upload failed: {upload_result.error_message}")
2427
- if upload_result.debug_info:
2428
- print(
2429
- f"Debug info: {json.dumps(upload_result.debug_info, indent=2)}"
2430
- )
2431
- return EvaluateResult(
2432
- success=False,
2433
- all_correct=False,
2434
- correctness_score=0.0,
2435
- geomean_speedup=0.0,
2436
- passed_tests=0,
2437
- total_tests=0,
2438
- error_message=f"Failed to upload wafer-core: {upload_result.error_message}",
2439
- )
2440
-
2441
- print(f"Uploaded {upload_result.files_copied} files")
2442
- except Exception as e:
2354
+ # Install wafer-core in remote venv
2355
+ print("Installing wafer-core...")
2356
+ install_result = await client.exec(
2357
+ f'export PATH="$HOME/.local/bin:$HOME/.cargo/bin:$PATH" && '
2358
+ f"uv pip install --python {python_exe} wafer-core"
2359
+ )
2360
+ if install_result.exit_code != 0:
2443
2361
  return EvaluateResult(
2444
2362
  success=False,
2445
2363
  all_correct=False,
@@ -2447,7 +2365,7 @@ async def run_evaluate_digitalocean(
2447
2365
  geomean_speedup=0.0,
2448
2366
  passed_tests=0,
2449
2367
  total_tests=0,
2450
- error_message=f"Failed to upload wafer-core: {e}",
2368
+ error_message=f"Failed to install wafer-core: {install_result.stderr}",
2451
2369
  )
2452
2370
 
2453
2371
  # Select GPU (DigitalOcean droplets typically have GPU 0)
@@ -3242,15 +3160,35 @@ def main():
3242
3160
  inputs = [x.cuda() if isinstance(x, torch.Tensor) else x for x in inputs]
3243
3161
 
3244
3162
  if run_defense and defense_module is not None:
3245
- # Use full defense suite
3163
+ # Use extended defense suite (Makora taxonomy + CUDA-L2)
3246
3164
  print("[KernelBench] Running defense checks on implementation...")
3247
- run_all_defenses = defense_module.run_all_defenses
3165
+ run_extended = defense_module.run_all_defenses_extended
3248
3166
  time_with_defenses = defense_module.time_execution_with_defenses
3249
3167
 
3250
- # Run defense checks on implementation
3251
- all_passed, defense_results, _ = run_all_defenses(
3168
+ # Read source code for LLM adversarial evaluator
3169
+ _problem_code = None
3170
+ _kernel_code = None
3171
+ try:
3172
+ _problem_code = Path(args.reference).read_text()
3173
+ _kernel_code = Path(args.impl).read_text()
3174
+ except Exception:
3175
+ pass
3176
+
3177
+ # Input generator for caching/multi-input checks
3178
+ def _input_generator():
3179
+ _ins = get_inputs()
3180
+ return tuple(x.cuda() if isinstance(x, torch.Tensor) else x for x in _ins)
3181
+
3182
+ # Run all defense checks (original + extended)
3183
+ all_passed, defense_results, _ = run_extended(
3252
3184
  lambda *x: new_model(*x),
3253
3185
  *inputs,
3186
+ reference_fn=lambda *x: ref_model(*x),
3187
+ input_generator=_input_generator,
3188
+ test_shapes=[(128, 128), (256, 256), (512, 512)],
3189
+ check_precision_ulp=True,
3190
+ problem_code=_problem_code,
3191
+ kernel_code=_kernel_code,
3254
3192
  )
3255
3193
  results["defense_results"] = {
3256
3194
  name: {"passed": passed, "message": msg}
@@ -35,7 +35,8 @@ Strategy:
35
35
  Commands:
36
36
  - `wafer evaluate --impl <file> --reference <ref> --test-cases <tests>` - Run evaluation
37
37
  - `wafer evaluate --impl <file> --reference <ref> --test-cases <tests> --profile` - With NCU profiling
38
- - `wafer remote-run "<command>"` - Run arbitrary commands on remote GPU
38
+ - `wafer workspaces exec -- <command>` - Run arbitrary commands on remote GPU
39
+ - `wafer targets exec <target> -- <command>` - Run commands on a configured target via SSH
39
40
 
40
41
  Output:
41
42
  - Summary of optimizations applied
@@ -48,7 +49,8 @@ IMPORTANT: Always verify correctness with wafer evaluate before claiming success
48
49
  tools=["read", "write", "edit", "glob", "grep", "bash"],
49
50
  bash_allowlist=[
50
51
  "wafer evaluate",
51
- "wafer remote-run",
52
+ "wafer workspaces exec",
53
+ "wafer targets exec",
52
54
  "wafer nvidia ncu",
53
55
  "wafer nvidia nsys",
54
56
  "wafer nvidia perfetto",
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: wafer-cli
3
- Version: 0.2.29
3
+ Version: 0.2.31
4
4
  Summary: CLI for running GPU workloads, managing remote workspaces, and evaluating/optimizing kernels
5
5
  Requires-Python: >=3.11
6
6
  Description-Content-Type: text/markdown
@@ -5,12 +5,13 @@ wafer/analytics.py,sha256=qLY6Z16usVHFD8TCv7XBuz7l47vXVdXk-qhOzA-hW_8,8179
5
5
  wafer/api_client.py,sha256=i_Az2b2llC3DSW8yOL-BKqa7LSKuxOr8hSN40s-oQXY,6313
6
6
  wafer/auth.py,sha256=dwss_se5P-FFc9IN38q4kh_dBrA6k-CguDBkivgcdj0,14003
7
7
  wafer/autotuner.py,sha256=41WYP41pTDvMijv2h42vm89bcHtDMJXObDlWmn6xpFU,44416
8
+ wafer/baseline.py,sha256=OrGCAut_xtkH9Ogx4mMU5-94Q0oClIXqac94YRwqERY,21534
8
9
  wafer/billing.py,sha256=hEEwtrtIsbPQ3lLJNcyTLMsapUbcuvcVW_e9_0SxzVo,7199
9
- wafer/cli.py,sha256=zuVZhPdML5AOBtLUqLwAwjl8XMNe9EwQkffZxtBGLx4,282748
10
+ wafer/cli.py,sha256=9wpLZlrKC3_DtkYuNWH42H1x9gJJOkJ32X2bNECG0rY,273013
10
11
  wafer/cli_instructions.py,sha256=bziUKDNDAXABVMvKPLEMXm-hFSD2TcFSh-FKRYa949k,4693
11
12
  wafer/config.py,sha256=h5Eo9_yfWqWGoPNdVQikI9GoZVUeysunSYiixf1mKcw,3411
12
13
  wafer/corpus.py,sha256=CY9T7wXENNDJxnrtI-XsQmXeptrFfKG4x-lngrc9_3s,24748
13
- wafer/evaluate.py,sha256=HMFQD-uwC6Wky1t_0JxYZaoHWgLaTBkjxOxgpZVnGrc,190519
14
+ wafer/evaluate.py,sha256=i15PliAVI3W04_4eju46PBDdh2BwSToLME5n7yGu7dU,187355
14
15
  wafer/global_config.py,sha256=iu1HbTDr1695tSeDG2NfkK7PiY7XD6vjCk37w1wHbgk,11920
15
16
  wafer/gpu_run.py,sha256=TwqXy72T7f2I7e6n5WWod3xgxCPnDhU0BgLsB4CUoQY,9716
16
17
  wafer/inference.py,sha256=tZCO5i05FKY27ewis3CSBHFBeFbXY3xwj0DSjdoMY9s,4314
@@ -36,12 +37,12 @@ wafer/workspaces.py,sha256=J-TXGwHXSZlzRWCew63KNvk6HLJ-zTSELRgzjryTkMk,35710
36
37
  wafer/skills/wafer-guide/SKILL.md,sha256=UDsXCD5Kb-lDParKCTf2WkE3kodVs-rja8XeumSBO5U,3934
37
38
  wafer/templates/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
38
39
  wafer/templates/ask_docs.py,sha256=15t1Aa4WBMwMox8XmFdzyosOZfBLMdXyaxo3GDb7nTE,2254
39
- wafer/templates/optimize_kernel.py,sha256=4-MaKm_C9BQHQEllrNLLYkcdhJpcj6D-8zbJ4FdLUEY,2444
40
+ wafer/templates/optimize_kernel.py,sha256=Q4FA_8ECEegW_3DS51mkLCX6Vk1dcWWzY3A_RQ4NW8U,2576
40
41
  wafer/templates/optimize_kernelbench.py,sha256=T3co9Y9eSLWDrZG66gwQVFMdnGVoyUQos-TxnMMBLL8,3747
41
42
  wafer/templates/trace_analyze.py,sha256=B7CiRlsokERzBjLL-k49kGjpU2zlJZqzTE05xbRS1WI,2878
42
43
  wafer/tests/test_eval_cli_parity.py,sha256=SGmaj2NGBZ7GdDF53bXsECvQbV21iHZw8YeL_MJOLk0,7206
43
- wafer_cli-0.2.29.dist-info/METADATA,sha256=Cqwe6AdROCtQG3Xo6BzyICS2n5Rvtk-ex85P_s0PSIU,2799
44
- wafer_cli-0.2.29.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
45
- wafer_cli-0.2.29.dist-info/entry_points.txt,sha256=WqB7hB__WhtPY8y1cO2sZiUz7fCq6Ik-usAigpeFvWE,41
46
- wafer_cli-0.2.29.dist-info/top_level.txt,sha256=2MK1IVMWfpLL8BZCQ3E9aG6L6L666gSA_teYlwan4fs,6
47
- wafer_cli-0.2.29.dist-info/RECORD,,
44
+ wafer_cli-0.2.31.dist-info/METADATA,sha256=rrIOyDKT02oelCRNJTTdlCvidNgVXmNSlE2vXmRsa-U,2799
45
+ wafer_cli-0.2.31.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
46
+ wafer_cli-0.2.31.dist-info/entry_points.txt,sha256=WqB7hB__WhtPY8y1cO2sZiUz7fCq6Ik-usAigpeFvWE,41
47
+ wafer_cli-0.2.31.dist-info/top_level.txt,sha256=2MK1IVMWfpLL8BZCQ3E9aG6L6L666gSA_teYlwan4fs,6
48
+ wafer_cli-0.2.31.dist-info/RECORD,,