ABAO77 commited on
Commit
da404fd
·
verified ·
1 Parent(s): e7c0eb0

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +36 -146
app.py CHANGED
@@ -100,60 +100,6 @@ class CodeExecutor:
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 (15% of available, min 8MB, max 16MB)
118
- HEAP_SIZE=$((AVAILABLE_MEM * 15 / 100))
119
- if [ "$HEAP_SIZE" -lt 8 ]; then
120
- HEAP_SIZE=8
121
- elif [ "$HEAP_SIZE" -gt 16 ]; then
122
- HEAP_SIZE=16
123
- fi
124
-
125
- # Calculate code cache (smaller)
126
- CODE_CACHE_SIZE=$((HEAP_SIZE / 4))
127
- if [ "$CODE_CACHE_SIZE" -lt 4 ]; then
128
- CODE_CACHE_SIZE=4
129
- fi
130
-
131
- echo "Using ${HEAP_SIZE}MB heap, ${CODE_CACHE_SIZE}MB code cache (${AVAILABLE_MEM}MB available)" >&2
132
-
133
- # Execute Java with proper stack size and memory limits
134
- exec java \\
135
- -Xms2m \\
136
- -Xmx${HEAP_SIZE}m \\
137
- -XX:ReservedCodeCacheSize=${CODE_CACHE_SIZE}m \\
138
- -XX:InitialCodeCacheSize=1m \\
139
- -XX:+UseSerialGC \\
140
- -XX:MaxMetaspaceSize=16m \\
141
- -XX:CompressedClassSpaceSize=8m \\
142
- -Xss256k \\
143
- -XX:-TieredCompilation \\
144
- -Djava.awt.headless=true \\
145
- "$@"
146
- """
147
-
148
- wrapper_path = os.path.join(workspace, "java_wrapper.sh")
149
- with open(wrapper_path, 'w') as f:
150
- f.write(wrapper_script)
151
-
152
- # Make executable
153
- os.chmod(wrapper_path, 0o755)
154
-
155
- return wrapper_path
156
-
157
  def analyze_input_patterns(
158
  self, language: str, file_contents: Dict[str, str]
159
  ) -> InputAnalysisResult:
@@ -536,18 +482,18 @@ exec java \\
536
  workspace: str,
537
  input_data: Optional[List[str]] = None,
538
  ) -> ExecutionResult:
539
- """Compile and execute Java code with input support and memory optimization"""
540
-
541
  # Check if we have .java files to compile
542
  java_files = list(Path(workspace).glob("*.java"))
543
  needs_compilation = len(java_files) > 0
544
-
545
  # If we have .java files, compile them
546
  if needs_compilation:
547
  logger.info(f"Found {len(java_files)} Java source files, compiling...")
548
-
549
- # Compile with absolute minimal memory for javac
550
- compile_cmd = ["javac", "-J-Xmx16m", "-J-Xms2m"] + [str(f) for f in java_files]
551
 
552
  compile_process = await asyncio.create_subprocess_exec(
553
  *compile_cmd,
@@ -555,9 +501,9 @@ exec java \\
555
  stdout=asyncio.subprocess.PIPE,
556
  stderr=asyncio.subprocess.PIPE,
557
  )
558
-
559
  stdout, stderr = await compile_process.communicate()
560
-
561
  if compile_process.returncode != 0:
562
  return ExecutionResult(
563
  success=False,
@@ -566,20 +512,20 @@ exec java \\
566
  execution_time=0,
567
  exit_code=compile_process.returncode,
568
  )
569
-
570
  logger.info("Java compilation successful")
571
  else:
572
- # Check if we have .class files for the main files
573
  class_files_missing = []
574
  for main_file in main_files:
575
  if main_file.endswith(".class"):
576
  class_file_path = os.path.join(workspace, main_file)
577
  else:
578
  class_file_path = os.path.join(workspace, f"{main_file}.class")
579
-
580
  if not os.path.exists(class_file_path):
581
  class_files_missing.append(main_file)
582
-
583
  if class_files_missing:
584
  return ExecutionResult(
585
  success=False,
@@ -588,72 +534,10 @@ exec java \\
588
  execution_time=0,
589
  exit_code=-1,
590
  )
591
-
592
- logger.info("Using existing .class files, skipping compilation")
593
-
594
- # Use memory-aware wrapper for execution
595
- return await self._execute_java_with_wrapper(main_files, workspace, input_data)
596
-
597
- async def _execute_java_with_wrapper(
598
- self,
599
- main_files: List[str],
600
- workspace: str,
601
- input_data: Optional[List[str]] = None,
602
- ) -> ExecutionResult:
603
- """Execute Java using a memory-aware wrapper script with fallback"""
604
-
605
- # Try wrapper first, then fallback to minimal direct execution
606
- approaches = [
607
- ("wrapper", None),
608
- ("minimal", ["-Xms2m", "-Xmx16m", "-Xss256k", "-Djava.awt.headless=true"]),
609
- ("basic", ["-Xms2m", "-Xmx12m", "-Djava.awt.headless=true"]),
610
- ("simple", ["-Xmx8m", "-Djava.awt.headless=true"]),
611
- ("no_limits", ["-Djava.awt.headless=true"])
612
- ]
613
-
614
- for approach_name, jvm_opts in approaches:
615
- logger.info(f"Trying Java execution approach: {approach_name}")
616
 
617
- try:
618
- if approach_name == "wrapper":
619
- # Create and use wrapper script
620
- wrapper_path = await self._create_java_wrapper(workspace)
621
- result = await self._try_java_direct(main_files, workspace, input_data, wrapper_cmd=wrapper_path)
622
- else:
623
- # Use direct java with specific JVM options
624
- result = await self._try_java_direct(main_files, workspace, input_data, jvm_opts=jvm_opts)
625
-
626
- # If successful or not a memory error, return result
627
- if result.success or "Could not reserve" not in result.stderr:
628
- logger.info(f"Java execution successful with approach: {approach_name}")
629
- return result
630
- else:
631
- logger.warning(f"Approach {approach_name} failed with memory error, trying next...")
632
-
633
- except Exception as e:
634
- logger.warning(f"Approach {approach_name} failed with exception: {e}")
635
- continue
636
-
637
- # If all approaches fail
638
- return ExecutionResult(
639
- success=False,
640
- stdout="",
641
- stderr="Java execution failed with all memory configurations. Container memory too limited for JVM.",
642
- execution_time=0,
643
- exit_code=-1,
644
- error="All JVM memory configurations failed"
645
- )
646
-
647
- async def _try_java_direct(
648
- self,
649
- main_files: List[str],
650
- workspace: str,
651
- input_data: Optional[List[str]],
652
- wrapper_cmd: Optional[str] = None,
653
- jvm_opts: Optional[List[str]] = None
654
- ) -> ExecutionResult:
655
- """Try Java execution with specific configuration"""
656
 
 
657
  results = []
658
  for main_file in main_files:
659
  # Determine class name
@@ -663,7 +547,7 @@ exec java \\
663
  class_name = main_file.replace(".java", "")
664
  else:
665
  class_name = main_file
666
-
667
  # Verify the .class file exists
668
  class_file_path = os.path.join(workspace, f"{class_name}.class")
669
  if not os.path.exists(class_file_path):
@@ -677,24 +561,31 @@ exec java \\
677
  )
678
  )
679
  continue
680
-
681
  try:
682
  start_time = asyncio.get_event_loop().time()
683
-
684
- # Build command
685
- if wrapper_cmd:
686
- java_cmd = [wrapper_cmd, class_name]
687
- elif jvm_opts:
688
- java_cmd = ["java"] + jvm_opts + [class_name]
689
- else:
690
- java_cmd = ["java", class_name]
 
 
 
 
 
 
 
691
 
692
  stdout, stderr, returncode = await self._execute_with_input(
693
  java_cmd, workspace, input_data
694
  )
695
-
696
  execution_time = asyncio.get_event_loop().time() - start_time
697
-
698
  results.append(
699
  ExecutionResult(
700
  success=returncode == 0,
@@ -704,7 +595,7 @@ exec java \\
704
  exit_code=returncode,
705
  )
706
  )
707
-
708
  except asyncio.TimeoutError:
709
  results.append(
710
  ExecutionResult(
@@ -716,6 +607,7 @@ exec java \\
716
  )
717
  )
718
  except Exception as e:
 
719
  results.append(
720
  ExecutionResult(
721
  success=False,
@@ -726,7 +618,7 @@ exec java \\
726
  error=str(e),
727
  )
728
  )
729
-
730
  return self._combine_results(results, main_files)
731
 
732
  async def _execute_c_cpp(
@@ -1007,8 +899,6 @@ async def analyze_inputs(code_content: str = Form(...), language: str = Form(...
1007
  )
1008
  result_dict = analysis_result.model_dump()
1009
 
1010
- # Cache the result
1011
-
1012
  logger.info(f"Input analysis completed for {language} code")
1013
  return JSONResponse(content=result_dict)
1014
 
 
100
 
101
  return 0 # Unknown
102
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
103
  def analyze_input_patterns(
104
  self, language: str, file_contents: Dict[str, str]
105
  ) -> InputAnalysisResult:
 
482
  workspace: str,
483
  input_data: Optional[List[str]] = None,
484
  ) -> ExecutionResult:
485
+ """Compile and execute Java code with optimized memory settings"""
486
+
487
  # Check if we have .java files to compile
488
  java_files = list(Path(workspace).glob("*.java"))
489
  needs_compilation = len(java_files) > 0
490
+
491
  # If we have .java files, compile them
492
  if needs_compilation:
493
  logger.info(f"Found {len(java_files)} Java source files, compiling...")
494
+
495
+ # Compile with minimal memory
496
+ compile_cmd = ["javac", "-J-Xmx32m"] + [str(f) for f in java_files]
497
 
498
  compile_process = await asyncio.create_subprocess_exec(
499
  *compile_cmd,
 
501
  stdout=asyncio.subprocess.PIPE,
502
  stderr=asyncio.subprocess.PIPE,
503
  )
504
+
505
  stdout, stderr = await compile_process.communicate()
506
+
507
  if compile_process.returncode != 0:
508
  return ExecutionResult(
509
  success=False,
 
512
  execution_time=0,
513
  exit_code=compile_process.returncode,
514
  )
515
+
516
  logger.info("Java compilation successful")
517
  else:
518
+ # Check if we have .class files
519
  class_files_missing = []
520
  for main_file in main_files:
521
  if main_file.endswith(".class"):
522
  class_file_path = os.path.join(workspace, main_file)
523
  else:
524
  class_file_path = os.path.join(workspace, f"{main_file}.class")
525
+
526
  if not os.path.exists(class_file_path):
527
  class_files_missing.append(main_file)
528
+
529
  if class_files_missing:
530
  return ExecutionResult(
531
  success=False,
 
534
  execution_time=0,
535
  exit_code=-1,
536
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
537
 
538
+ logger.info("Using existing .class files, skipping compilation")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
539
 
540
+ # Execute Java with optimized settings
541
  results = []
542
  for main_file in main_files:
543
  # Determine class name
 
547
  class_name = main_file.replace(".java", "")
548
  else:
549
  class_name = main_file
550
+
551
  # Verify the .class file exists
552
  class_file_path = os.path.join(workspace, f"{class_name}.class")
553
  if not os.path.exists(class_file_path):
 
561
  )
562
  )
563
  continue
564
+
565
  try:
566
  start_time = asyncio.get_event_loop().time()
567
+
568
+ # Optimized JVM settings for container environments
569
+ java_cmd = [
570
+ "java",
571
+ "-XX:+UseSerialGC", # Use simple GC for small heap
572
+ "-Xmx64m", # Max heap 64MB
573
+ "-Xms8m", # Initial heap 8MB
574
+ "-XX:MaxMetaspaceSize=64m", # Limit metaspace
575
+ "-XX:MaxDirectMemorySize=32m", # Limit direct memory
576
+ "-XX:-TieredCompilation", # Disable tiered compilation
577
+ "-XX:CICompilerCount=1", # Single compiler thread
578
+ "-Djava.awt.headless=true", # Headless mode
579
+ "-Dfile.encoding=UTF-8", # UTF-8 encoding
580
+ class_name
581
+ ]
582
 
583
  stdout, stderr, returncode = await self._execute_with_input(
584
  java_cmd, workspace, input_data
585
  )
586
+
587
  execution_time = asyncio.get_event_loop().time() - start_time
588
+
589
  results.append(
590
  ExecutionResult(
591
  success=returncode == 0,
 
595
  exit_code=returncode,
596
  )
597
  )
598
+
599
  except asyncio.TimeoutError:
600
  results.append(
601
  ExecutionResult(
 
607
  )
608
  )
609
  except Exception as e:
610
+ logger.error(f"Java execution error: {str(e)}")
611
  results.append(
612
  ExecutionResult(
613
  success=False,
 
618
  error=str(e),
619
  )
620
  )
621
+
622
  return self._combine_results(results, main_files)
623
 
624
  async def _execute_c_cpp(
 
899
  )
900
  result_dict = analysis_result.model_dump()
901
 
 
 
902
  logger.info(f"Input analysis completed for {language} code")
903
  return JSONResponse(content=result_dict)
904