ABAO77 commited on
Commit
3485015
·
verified ·
1 Parent(s): 8257fba

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +114 -23
app.py CHANGED
@@ -19,6 +19,7 @@ import json
19
  import resource
20
  import platform
21
  from loguru import logger
 
22
 
23
  app = FastAPI(title="Code Execution and Input Analysis API", docs_url="/")
24
 
@@ -62,6 +63,68 @@ class CodeExecutor:
62
  "java": "javac",
63
  "python": "python3",
64
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
65
 
66
  def set_resource_limits(self):
67
  """Set resource limits for subprocess (Unix only)"""
@@ -72,6 +135,32 @@ class CodeExecutor:
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:
@@ -564,41 +653,38 @@ class CodeExecutor:
564
 
565
  # Try different JVM configurations
566
  jvm_configs = [
567
- # Config 1: Minimal memory with explicit small code cache
568
  [
569
- "-XX:+UseSerialGC",
570
  "-Xmx32m",
571
- "-Xms4m",
572
- "-XX:ReservedCodeCacheSize=16m",
573
- "-XX:InitialCodeCacheSize=4m",
574
- "-XX:MaxMetaspaceSize=32m",
575
- "-XX:CompressedClassSpaceSize=8m",
576
- "-XX:-TieredCompilation",
577
- "-XX:CICompilerCount=1",
578
- "-Xss256k",
579
- "-XX:+UseStringDeduplication",
580
- "-XX:MaxDirectMemorySize=16m",
581
  "-Djava.awt.headless=true",
582
- "-Dfile.encoding=UTF-8",
583
  ],
584
- # Config 2: Even more minimal
585
  [
586
- "-Xmx16m",
587
- "-Xms2m",
 
588
  "-XX:ReservedCodeCacheSize=8m",
589
- "-XX:MaxMetaspaceSize=16m",
 
590
  "-XX:-TieredCompilation",
591
  "-Djava.awt.headless=true",
592
  ],
593
- # Config 3: Absolute minimum
594
  [
595
- "-Xmx8m",
596
- "-XX:ReservedCodeCacheSize=4m",
 
 
 
597
  "-Djava.awt.headless=true",
598
  ],
599
- # Config 4: Let JVM decide with hints
600
  [
601
- "-XX:+UseSerialGC",
 
602
  "-XX:-TieredCompilation",
603
  "-Djava.awt.headless=true",
604
  ],
@@ -610,7 +696,12 @@ class CodeExecutor:
610
  logger.info(f"Trying JVM config {config_idx + 1} for {class_name}")
611
  start_time = asyncio.get_event_loop().time()
612
 
613
- java_cmd = ["java"] + jvm_opts + [class_name]
 
 
 
 
 
614
 
615
  stdout, stderr, returncode = await self._execute_with_input(
616
  java_cmd, workspace, input_data
 
19
  import resource
20
  import platform
21
  from loguru import logger
22
+ import subprocess
23
 
24
  app = FastAPI(title="Code Execution and Input Analysis API", docs_url="/")
25
 
 
63
  "java": "javac",
64
  "python": "python3",
65
  }
66
+ # Check and log ulimits on startup
67
+ self._check_ulimits()
68
+
69
+ def _check_ulimits(self):
70
+ """Check current ulimits and log them"""
71
+ try:
72
+ # Check various ulimits
73
+ limits = {
74
+ "RLIMIT_NOFILE": resource.RLIMIT_NOFILE, # file descriptors
75
+ "RLIMIT_NPROC": resource.RLIMIT_NPROC, # processes
76
+ "RLIMIT_STACK": resource.RLIMIT_STACK, # stack size
77
+ }
78
+
79
+ logger.info("Current ulimits:")
80
+ for name, limit_type in limits.items():
81
+ try:
82
+ soft, hard = resource.getrlimit(limit_type)
83
+ logger.info(f"{name}: soft={soft}, hard={hard}")
84
+ except:
85
+ pass
86
+
87
+ # Try to increase limits if they're too low
88
+ try:
89
+ # Increase file descriptors
90
+ resource.setrlimit(resource.RLIMIT_NOFILE, (65536, 65536))
91
+ except:
92
+ try:
93
+ # Try a lower value if the high one fails
94
+ resource.setrlimit(resource.RLIMIT_NOFILE, (4096, 4096))
95
+ except:
96
+ pass
97
+
98
+ except Exception as e:
99
+ logger.warning(f"Could not check/set ulimits: {e}")
100
+
101
+ async def _create_java_wrapper(self, workspace: str, jvm_opts: List[str]) -> str:
102
+ """Create a wrapper script for Java execution with ulimit settings"""
103
+
104
+ wrapper_content = f"""#!/bin/bash
105
+ # Set ulimits to prevent memory allocation issues
106
+ ulimit -n 65536 2>/dev/null || ulimit -n 4096
107
+ ulimit -u 32768 2>/dev/null || ulimit -u 2048
108
+ ulimit -s 8192 2>/dev/null || ulimit -s 4096
109
+ ulimit -v unlimited 2>/dev/null || true
110
+ ulimit -m unlimited 2>/dev/null || true
111
+
112
+ # Log current ulimits for debugging
113
+ echo "Current ulimits:" >&2
114
+ ulimit -a >&2
115
+
116
+ # Execute Java with the provided options
117
+ exec java {' '.join(jvm_opts)} "$@"
118
+ """
119
+
120
+ wrapper_path = os.path.join(workspace, "java_wrapper.sh")
121
+ with open(wrapper_path, 'w') as f:
122
+ f.write(wrapper_content)
123
+
124
+ # Make executable
125
+ os.chmod(wrapper_path, 0o755)
126
+
127
+ return wrapper_path
128
 
129
  def set_resource_limits(self):
130
  """Set resource limits for subprocess (Unix only)"""
 
135
  resource.setrlimit(resource.RLIMIT_AS, (MAX_MEMORY, MAX_MEMORY))
136
 
137
  def check_available_memory(self) -> int:
138
+ """Create a wrapper script for Java execution with ulimit settings"""
139
+
140
+ wrapper_content = f"""#!/bin/bash
141
+ # Set ulimits to prevent memory allocation issues
142
+ ulimit -n 65536 2>/dev/null || ulimit -n 4096
143
+ ulimit -u 32768 2>/dev/null || ulimit -u 2048
144
+ ulimit -s 8192 2>/dev/null || ulimit -s 4096
145
+ ulimit -v unlimited 2>/dev/null || true
146
+ ulimit -m unlimited 2>/dev/null || true
147
+
148
+ # Log current ulimits for debugging
149
+ echo "Current ulimits:" >&2
150
+ ulimit -a >&2
151
+
152
+ # Execute Java with the provided options
153
+ exec java {' '.join(jvm_opts)} "$@"
154
+ """
155
+
156
+ wrapper_path = os.path.join(workspace, "java_wrapper.sh")
157
+ with open(wrapper_path, 'w') as f:
158
+ f.write(wrapper_content)
159
+
160
+ # Make executable
161
+ os.chmod(wrapper_path, 0o755)
162
+
163
+ return wrapper_path
164
  """Check available memory in MB"""
165
  try:
166
  with open('/proc/meminfo', 'r') as f:
 
653
 
654
  # Try different JVM configurations
655
  jvm_configs = [
656
+ # Config 1: Ultra minimal with no code cache reservation
657
  [
658
+ "-Xint", # Interpreter only mode (no JIT)
659
  "-Xmx32m",
660
+ "-Xms2m",
661
+ "-XX:MaxMetaspaceSize=16m",
 
 
 
 
 
 
 
 
662
  "-Djava.awt.headless=true",
 
663
  ],
664
+ # Config 2: Minimal with small code cache
665
  [
666
+ "-XX:+UseSerialGC",
667
+ "-Xmx32m",
668
+ "-Xms4m",
669
  "-XX:ReservedCodeCacheSize=8m",
670
+ "-XX:InitialCodeCacheSize=2m",
671
+ "-XX:MaxMetaspaceSize=24m",
672
  "-XX:-TieredCompilation",
673
  "-Djava.awt.headless=true",
674
  ],
675
+ # Config 3: Slightly more memory
676
  [
677
+ "-Xmx48m",
678
+ "-Xms8m",
679
+ "-XX:ReservedCodeCacheSize=16m",
680
+ "-XX:MaxMetaspaceSize=32m",
681
+ "-XX:-TieredCompilation",
682
  "-Djava.awt.headless=true",
683
  ],
684
+ # Config 4: Use container support
685
  [
686
+ "-XX:+UseContainerSupport",
687
+ "-XX:MaxRAMPercentage=25.0",
688
  "-XX:-TieredCompilation",
689
  "-Djava.awt.headless=true",
690
  ],
 
696
  logger.info(f"Trying JVM config {config_idx + 1} for {class_name}")
697
  start_time = asyncio.get_event_loop().time()
698
 
699
+ # For first two configs, try with wrapper script
700
+ if config_idx < 2:
701
+ wrapper_path = await self._create_java_wrapper(workspace, jvm_opts)
702
+ java_cmd = [wrapper_path, class_name]
703
+ else:
704
+ java_cmd = ["java"] + jvm_opts + [class_name]
705
 
706
  stdout, stderr, returncode = await self._execute_with_input(
707
  java_cmd, workspace, input_data