decentriq_util 0.1.0.dev11__tar.gz → 0.1.0.dev13__tar.gz

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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: decentriq_util
3
- Version: 0.1.0.dev11
3
+ Version: 0.1.0.dev13
4
4
  Summary: Utility functions for Python code run in Decentriq workers
5
5
  Author: hafenr
6
6
  Author-email: robin.hafen@gmail.com
@@ -11,7 +11,7 @@ import pyarrow.parquet as pq
11
11
  from pyspark.sql import SparkSession
12
12
 
13
13
 
14
- _DEFAULT_HEAP_SIZE_EXTRA_ROOM = 2 * 512 * 1024 * 1024
14
+ _DEFAULT_HEAP_SIZE_EXTRA_ROOM_PER_CORE = 268435456
15
15
 
16
16
 
17
17
  def _get_cgroup_memory() -> int:
@@ -101,7 +101,7 @@ def _get_num_partitions(
101
101
 
102
102
  # Try to make partitions as big as possible s.t. each CPU is saturated,
103
103
  # while accounting for 50% overhead in spark.
104
- task_per_cpu = 3 # try to get at least this many tasks/partitions per CPU
104
+ task_per_cpu = 2 # try to get at least this many tasks/partitions per CPU
105
105
  max_target_partition_size = max(
106
106
  int(0.5 * available_memory / (task_per_cpu * cpu_count)) // megabyte_in_bytes * megabyte_in_bytes,
107
107
  min_partition_size
@@ -129,16 +129,25 @@ def _get_num_partitions(
129
129
 
130
130
  def _determine_optimal_spark_settings(
131
131
  files: list[str],
132
- heap_size_extra_room = _DEFAULT_HEAP_SIZE_EXTRA_ROOM
132
+ heap_size: Optional[int] = None,
133
+ heap_size_extra_room: Optional[int] = None,
134
+ heap_size_extra_room_per_core: Optional[int] = None
133
135
  ) -> list[Tuple[str, str]]:
134
- def get_spark_memory() -> int:
135
- """Determine the amount of memory available to spark"""
136
+ cpu_count = multiprocessing.cpu_count()
137
+
138
+ if heap_size is not None:
139
+ spark_memory = heap_size
140
+ else:
136
141
  cgroup_memory = _get_cgroup_memory()
137
- spark_memory = cgroup_memory - heap_size_extra_room
138
- return spark_memory
142
+ two_gb_in_bytes = 2147483648
143
+ if heap_size_extra_room is not None:
144
+ pass
145
+ elif heap_size_extra_room_per_core is not None:
146
+ heap_size_extra_room = heap_size_extra_room_per_core * cpu_count
147
+ else:
148
+ heap_size_extra_room = _DEFAULT_HEAP_SIZE_EXTRA_ROOM_PER_CORE * cpu_count
149
+ spark_memory = max(cgroup_memory - heap_size_extra_room, two_gb_in_bytes)
139
150
 
140
- cpu_count = multiprocessing.cpu_count()
141
- spark_memory = get_spark_memory()
142
151
  spark_memory_4096 = (spark_memory // 4096) * 4096
143
152
  num_partitions = _get_num_partitions(files, spark_memory, cpu_count)
144
153
 
@@ -155,34 +164,20 @@ def _determine_optimal_spark_settings(
155
164
  def _create_spark_session(
156
165
  name: str = "local_spark_session",
157
166
  parallelism: int = 8,
158
- heap_size: Optional[int] = None,
159
- heap_size_extra_room: int = _DEFAULT_HEAP_SIZE_EXTRA_ROOM,
160
167
  config: list[Tuple[str, Any]] = [],
161
- java_tmp_dir = "/output",
168
+ java_temp_dir: str = "/scratch",
169
+ java_user_home_dir: str = "/scratch",
162
170
  ) -> SparkSession:
163
171
  """
164
172
  :param name: The name of the spark session.
165
173
  :param parallelism: The size of the executor pool computing internal spark tasks.
166
- :param heap_size: If set then this determines the JVM heap size. Note that not all the heap size is used by spark.
167
- :param heap_size_extra_room: If heap_size is unset then it is determined by the available memory in the current
168
- cgroup. Then heap_size_extra_room is subtracted to arrive at the final heap size. This number should account for
169
- the python runtime itself as well as other structures that may be needed during spark compute.
170
174
  :param config: Additional config settings to set on the spark config.
171
- :param java_tmp_dir: Location for the JVM to store temp files.
175
+ :param java_temp_dir: Location for the JVM to store temp files.
176
+ :param java_user_home_dir: Location for the user home directory as seen by the JVM.
172
177
  :return: The spark session.
173
178
  """
174
179
  os.environ["SPARK_EXECUTOR_POOL_SIZE"] = str(parallelism)
175
- os.environ["JDK_JAVA_OPTIONS"] = f'-Duser.home=/output -Djava.io.tmpdir="{java_tmp_dir}"'
176
- spark_memory = None
177
- if heap_size is None:
178
- cgroup_memory = _get_cgroup_memory()
179
- spark_memory = cgroup_memory - heap_size_extra_room
180
- else:
181
- spark_memory = heap_size
182
-
183
- spark_memory_4096 = (spark_memory // 4096) * 4096
184
- if "spark.driver.memory" not in dict(config):
185
- config.append(("spark.driver.memory", str(spark_memory_4096)))
180
+ os.environ["JDK_JAVA_OPTIONS"] = f'-Duser.home="{java_user_home_dir}" -Djava.io.tmpdir="{java_temp_dir}"'
186
181
 
187
182
  ss = (
188
183
  SparkSession.builder
@@ -198,15 +193,28 @@ def _create_spark_session(
198
193
 
199
194
 
200
195
  @contextmanager
201
- def spark_session(temp_dir: str = "/scratch", input_files: list[str] = None, **kwargs):
196
+ def spark_session(
197
+ temp_dir: str = "/scratch",
198
+ name: str = "Spark",
199
+ input_files: list[str] = None,
200
+ heap_size: Optional[int] = None,
201
+ heap_size_extra_room: Optional[int] = None,
202
+ heap_size_extra_room_per_core: Optional[int] = None,
203
+ config: list[Tuple[str, str]] = [],
204
+ ):
202
205
  """
203
206
  Create a spark session and configure it according to the enclave environment.
204
207
 
205
208
  **Parameters**:
206
209
  - `temp_dir`: Where to store temporary data such as persisted data frames
207
210
  or shuffle data.
211
+ - `name`: An optional name for this spark session.
208
212
  - `input_files`: A list of input files on the basis of which the partition
209
213
  size is determined.
214
+ - `heap_size`: The heap size to use for Spark. If not set, sensible defaults are chosen.
215
+ - `heap_size_extra_room`: How much extra room to leave for non-JVM tasks. If not set, sensible defaults are chosen.
216
+ - `heap_size_extra_room_per_core`: Same as `heap_size_extra_room` but scaled with the number of cores. This is the default behavior.
217
+ - `config`: Extra settings to pass to the Spark session builder.
210
218
 
211
219
  **Example**:
212
220
 
@@ -232,14 +240,13 @@ def spark_session(temp_dir: str = "/scratch", input_files: list[str] = None, **k
232
240
  """
233
241
  with tempfile.TemporaryDirectory(dir=temp_dir, prefix="java-") as java_tmp:
234
242
  with tempfile.TemporaryDirectory(dir=temp_dir, prefix="spark-") as spark_tmp:
235
- config = kwargs.get("config", [])
236
243
  config_dict = dict(config)
237
244
  if input_files is not None and input_files:
238
245
  optimal_settings = _determine_optimal_spark_settings(
239
246
  input_files,
240
- heap_size_extra_room=kwargs.get(
241
- "heap_size_extra_room", _DEFAULT_HEAP_SIZE_EXTRA_ROOM
242
- )
247
+ heap_size=heap_size,
248
+ heap_size_extra_room=heap_size_extra_room,
249
+ heap_size_extra_room_per_core=heap_size_extra_room_per_core,
243
250
  )
244
251
  for key, value in optimal_settings:
245
252
  if key not in config_dict:
@@ -248,10 +255,7 @@ def spark_session(temp_dir: str = "/scratch", input_files: list[str] = None, **k
248
255
  config.append(
249
256
  ("spark.local.dir", spark_tmp)
250
257
  )
251
- kwargs["config"] = config
252
- if "java_tmp_dir" not in kwargs:
253
- kwargs["java_tmp_dir"] = java_tmp
254
- ss = _create_spark_session(**kwargs)
258
+ ss = _create_spark_session(name=name, java_temp_dir=java_tmp, java_user_home_dir=java_tmp, config=config)
255
259
  try:
256
260
  yield ss
257
261
  finally:
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "decentriq_util"
3
- version = "0.1.0-dev11"
3
+ version = "0.1.0-dev13"
4
4
  description = "Utility functions for Python code run in Decentriq workers"
5
5
  authors = ["hafenr <robin.hafen@gmail.com>"]
6
6