ABAO77 commited on
Commit
0f90aa0
·
verified ·
1 Parent(s): c52a700

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +165 -85
app.py CHANGED
@@ -71,6 +71,72 @@ class CodeExecutor:
71
  )
72
  resource.setrlimit(resource.RLIMIT_AS, (MAX_MEMORY, MAX_MEMORY))
73
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
74
  def analyze_input_patterns(
75
  self, language: str, file_contents: Dict[str, str]
76
  ) -> InputAnalysisResult:
@@ -459,28 +525,12 @@ class CodeExecutor:
459
  java_files = list(Path(workspace).glob("*.java"))
460
  needs_compilation = len(java_files) > 0
461
 
462
- # JVM options for very limited container environment (HuggingFace)
463
- jvm_opts = [
464
- "-Xms8m", # Minimal initial heap
465
- "-Xmx64m", # Very small max heap
466
- "-XX:ReservedCodeCacheSize=8m", # Minimal code cache
467
- "-XX:InitialCodeCacheSize=1m", # Tiny initial code cache
468
- "-XX:+UseSerialGC", # Simple GC
469
- "-XX:NewRatio=3", # Small young generation
470
- "-XX:SurvivorRatio=4", # Optimize survivor space
471
- "-XX:MaxMetaspaceSize=32m", # Limit metaspace
472
- "-XX:CompressedClassSpaceSize=8m", # Compress class space
473
- "-Xss256k", # Small stack size
474
- "-XX:-TieredCompilation", # Disable tiered compilation to save memory
475
- "-Djava.awt.headless=true", # Headless mode
476
- ]
477
-
478
  # If we have .java files, compile them
479
  if needs_compilation:
480
  logger.info(f"Found {len(java_files)} Java source files, compiling...")
481
 
482
- # Compile with minimal memory for javac
483
- compile_cmd = ["javac", "-J-Xmx32m", "-J-Xms8m"] + [str(f) for f in java_files]
484
 
485
  compile_process = await asyncio.create_subprocess_exec(
486
  *compile_cmd,
@@ -524,76 +574,100 @@ class CodeExecutor:
524
 
525
  logger.info("Using existing .class files, skipping compilation")
526
 
527
- # Execute main files
528
- results = []
529
- for main_file in main_files:
530
- # Determine class name
531
- if main_file.endswith(".class"):
532
- class_name = main_file.replace(".class", "")
533
- elif main_file.endswith(".java"):
534
- class_name = main_file.replace(".java", "")
535
- else:
536
- class_name = main_file
537
-
538
- # Verify the .class file exists
539
- class_file_path = os.path.join(workspace, f"{class_name}.class")
540
- if not os.path.exists(class_file_path):
541
- results.append(
542
- ExecutionResult(
543
- success=False,
544
- stdout="",
545
- stderr=f"Class file not found: {class_name}.class",
546
- execution_time=0,
547
- exit_code=-1,
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
548
  )
549
- )
550
- continue
551
-
552
- try:
553
- start_time = asyncio.get_event_loop().time()
554
-
555
- # Build java command with memory optimization
556
- java_cmd = ["java"] + jvm_opts + [class_name]
557
-
558
- stdout, stderr, returncode = await self._execute_with_input(
559
- java_cmd, workspace, input_data
560
- )
561
-
562
- execution_time = asyncio.get_event_loop().time() - start_time
563
-
564
- results.append(
565
- ExecutionResult(
566
- success=returncode == 0,
567
- stdout=stdout.decode("utf-8", errors="replace"),
568
- stderr=stderr.decode("utf-8", errors="replace"),
569
- execution_time=execution_time,
570
- exit_code=returncode,
571
  )
572
- )
573
-
574
- except asyncio.TimeoutError:
575
- results.append(
576
- ExecutionResult(
577
- success=False,
578
- stdout="",
579
- stderr="Execution timeout exceeded",
580
- execution_time=MAX_EXECUTION_TIME,
581
- exit_code=-1,
 
582
  )
583
- )
584
- except Exception as e:
585
- results.append(
586
- ExecutionResult(
587
- success=False,
588
- stdout="",
589
- stderr=str(e),
590
- execution_time=0,
591
- exit_code=-1,
592
- error=str(e),
 
 
 
 
 
 
 
 
 
 
 
593
  )
594
- )
595
-
596
- return self._combine_results(results, main_files)
 
 
 
 
 
 
 
 
 
597
 
598
  async def _execute_c_cpp(
599
  self,
@@ -836,6 +910,12 @@ def detect_language_from_files(main_files: List[str]) -> str:
836
  return detected_language
837
 
838
 
 
 
 
 
 
 
839
  @app.post("/analyze-inputs")
840
  async def analyze_inputs(code_content: str = Form(...), language: str = Form(...)):
841
  """
@@ -1065,4 +1145,4 @@ input("Press enter to continue...")
1065
  if __name__ == "__main__":
1066
  import uvicorn
1067
 
1068
- uvicorn.run("app_3:app", host="0.0.0.0", port=8000, reload=True)
 
71
  )
72
  resource.setrlimit(resource.RLIMIT_AS, (MAX_MEMORY, MAX_MEMORY))
73
 
74
+ def check_available_memory(self) -> int:
75
+ """Check available memory in MB"""
76
+ try:
77
+ with open('/proc/meminfo', 'r') as f:
78
+ meminfo = f.read()
79
+
80
+ available_match = re.search(r'MemAvailable:\s+(\d+)\s+kB', meminfo)
81
+ if available_match:
82
+ available_kb = int(available_match.group(1))
83
+ available_mb = available_kb // 1024
84
+ logger.info(f"Available memory: {available_mb}MB")
85
+ return available_mb
86
+
87
+ # Fallback to MemFree + Cached
88
+ free_match = re.search(r'MemFree:\s+(\d+)\s+kB', meminfo)
89
+ cached_match = re.search(r'Cached:\s+(\d+)\s+kB', meminfo)
90
+
91
+ if free_match and cached_match:
92
+ free_kb = int(free_match.group(1))
93
+ cached_kb = int(cached_match.group(1))
94
+ available_mb = (free_kb + cached_kb) // 1024
95
+ logger.info(f"Estimated available memory: {available_mb}MB")
96
+ return available_mb
97
+
98
+ except Exception as e:
99
+ logger.warning(f"Could not check memory: {e}")
100
+
101
+ return 0 # Unknown
102
+
103
+ async def _create_java_wrapper(self, workspace: str) -> str:
104
+ """Create a wrapper script for Java execution with better memory handling"""
105
+
106
+ wrapper_script = """#!/bin/bash
107
+ # Java memory wrapper for container environments
108
+
109
+ # Get available memory
110
+ AVAILABLE_MEM=$(awk '/MemAvailable/ {print int($2/1024)}' /proc/meminfo 2>/dev/null || echo "32")
111
+
112
+ if [ "$AVAILABLE_MEM" -lt 20 ]; then
113
+ echo "Error: Insufficient memory available ($AVAILABLE_MEM MB)" >&2
114
+ exit 1
115
+ fi
116
+
117
+ # Calculate heap size (30% of available, min 4MB, max 12MB)
118
+ HEAP_SIZE=$((AVAILABLE_MEM * 30 / 100))
119
+ if [ "$HEAP_SIZE" -lt 4 ]; then
120
+ HEAP_SIZE=4
121
+ elif [ "$HEAP_SIZE" -gt 12 ]; then
122
+ HEAP_SIZE=12
123
+ fi
124
+
125
+ echo "Using ${HEAP_SIZE}MB heap (${AVAILABLE_MEM}MB available)" >&2
126
+
127
+ # Execute Java with calculated settings
128
+ exec java -Xms1m -Xmx${HEAP_SIZE}m -Djava.awt.headless=true "$@"
129
+ """
130
+
131
+ wrapper_path = os.path.join(workspace, "java_wrapper.sh")
132
+ with open(wrapper_path, 'w') as f:
133
+ f.write(wrapper_script)
134
+
135
+ # Make executable
136
+ os.chmod(wrapper_path, 0o755)
137
+
138
+ return wrapper_path
139
+
140
  def analyze_input_patterns(
141
  self, language: str, file_contents: Dict[str, str]
142
  ) -> InputAnalysisResult:
 
525
  java_files = list(Path(workspace).glob("*.java"))
526
  needs_compilation = len(java_files) > 0
527
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
528
  # If we have .java files, compile them
529
  if needs_compilation:
530
  logger.info(f"Found {len(java_files)} Java source files, compiling...")
531
 
532
+ # Compile with absolute minimal memory for javac
533
+ compile_cmd = ["javac", "-J-Xmx16m", "-J-Xms2m"] + [str(f) for f in java_files]
534
 
535
  compile_process = await asyncio.create_subprocess_exec(
536
  *compile_cmd,
 
574
 
575
  logger.info("Using existing .class files, skipping compilation")
576
 
577
+ # Use memory-aware wrapper for execution
578
+ return await self._execute_java_with_wrapper(main_files, workspace, input_data)
579
+
580
+ async def _execute_java_with_wrapper(
581
+ self,
582
+ main_files: List[str],
583
+ workspace: str,
584
+ input_data: Optional[List[str]] = None,
585
+ ) -> ExecutionResult:
586
+ """Execute Java using a memory-aware wrapper script"""
587
+
588
+ try:
589
+ # Create wrapper script
590
+ wrapper_path = await self._create_java_wrapper(workspace)
591
+
592
+ results = []
593
+ for main_file in main_files:
594
+ # Determine class name
595
+ if main_file.endswith(".class"):
596
+ class_name = main_file.replace(".class", "")
597
+ elif main_file.endswith(".java"):
598
+ class_name = main_file.replace(".java", "")
599
+ else:
600
+ class_name = main_file
601
+
602
+ # Verify the .class file exists
603
+ class_file_path = os.path.join(workspace, f"{class_name}.class")
604
+ if not os.path.exists(class_file_path):
605
+ results.append(
606
+ ExecutionResult(
607
+ success=False,
608
+ stdout="",
609
+ stderr=f"Class file not found: {class_name}.class",
610
+ execution_time=0,
611
+ exit_code=-1,
612
+ )
613
  )
614
+ continue
615
+
616
+ try:
617
+ start_time = asyncio.get_event_loop().time()
618
+
619
+ # Use wrapper script instead of direct java
620
+ java_cmd = [wrapper_path, class_name]
621
+
622
+ stdout, stderr, returncode = await self._execute_with_input(
623
+ java_cmd, workspace, input_data
 
 
 
 
 
 
 
 
 
 
 
 
624
  )
625
+
626
+ execution_time = asyncio.get_event_loop().time() - start_time
627
+
628
+ results.append(
629
+ ExecutionResult(
630
+ success=returncode == 0,
631
+ stdout=stdout.decode("utf-8", errors="replace"),
632
+ stderr=stderr.decode("utf-8", errors="replace"),
633
+ execution_time=execution_time,
634
+ exit_code=returncode,
635
+ )
636
  )
637
+
638
+ except asyncio.TimeoutError:
639
+ results.append(
640
+ ExecutionResult(
641
+ success=False,
642
+ stdout="",
643
+ stderr="Execution timeout exceeded",
644
+ execution_time=MAX_EXECUTION_TIME,
645
+ exit_code=-1,
646
+ )
647
+ )
648
+ except Exception as e:
649
+ results.append(
650
+ ExecutionResult(
651
+ success=False,
652
+ stdout="",
653
+ stderr=str(e),
654
+ execution_time=0,
655
+ exit_code=-1,
656
+ error=str(e),
657
+ )
658
  )
659
+
660
+ return self._combine_results(results, main_files)
661
+
662
+ except Exception as e:
663
+ return ExecutionResult(
664
+ success=False,
665
+ stdout="",
666
+ stderr=f"Wrapper execution failed: {str(e)}",
667
+ execution_time=0,
668
+ exit_code=-1,
669
+ error=str(e),
670
+ )
671
 
672
  async def _execute_c_cpp(
673
  self,
 
910
  return detected_language
911
 
912
 
913
+ @app.get("/health")
914
+ async def health_check():
915
+ """Health check endpoint"""
916
+ return {"status": "healthy", "timestamp": asyncio.get_event_loop().time()}
917
+
918
+
919
  @app.post("/analyze-inputs")
920
  async def analyze_inputs(code_content: str = Form(...), language: str = Form(...)):
921
  """
 
1145
  if __name__ == "__main__":
1146
  import uvicorn
1147
 
1148
+ uvicorn.run("app:app", host="0.0.0.0", port=8000, reload=True)