parsl 2024.3.4__tar.gz → 2024.3.18__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.
- {parsl-2024.3.4/parsl.egg-info → parsl-2024.3.18}/PKG-INFO +2 -2
- {parsl-2024.3.4 → parsl-2024.3.18}/README.rst +4 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/addresses.py +3 -1
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/config.py +4 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/dataflow/dflow.py +14 -7
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/dataflow/taskrecord.py +3 -1
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/executors/high_throughput/executor.py +34 -10
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/executors/high_throughput/interchange.py +43 -10
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/executors/high_throughput/manager_record.py +1 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/executors/high_throughput/process_worker_pool.py +48 -7
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/executors/taskvine/executor.py +6 -3
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/executors/taskvine/manager.py +1 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/executors/taskvine/manager_config.py +3 -4
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/jobs/job_status_poller.py +4 -3
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/jobs/strategy.py +2 -1
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/launchers/launchers.py +6 -6
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/log_utils.py +8 -4
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/monitoring/db_manager.py +29 -7
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/monitoring/monitoring.py +15 -54
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/monitoring/remote.py +29 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/monitoring/visualization/models.py +7 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/monitoring/visualization/plots/default/workflow_plots.py +3 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/monitoring/visualization/views.py +2 -1
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/providers/cluster_provider.py +1 -3
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/providers/slurm/slurm.py +13 -2
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/configs/user_opts.py +5 -2
- parsl-2024.3.18/parsl/tests/test_htex/test_drain.py +78 -0
- parsl-2024.3.18/parsl/tests/test_monitoring/test_app_names.py +86 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_scaling/test_scale_down_htex_auto_scale.py +3 -11
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/usage_tracking/usage.py +5 -9
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/utils.py +2 -2
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/version.py +1 -1
- {parsl-2024.3.4 → parsl-2024.3.18/parsl.egg-info}/PKG-INFO +2 -2
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl.egg-info/SOURCES.txt +2 -1
- parsl-2024.3.4/parsl/configs/bluewaters.py +0 -28
- {parsl-2024.3.4 → parsl-2024.3.18}/LICENSE +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/MANIFEST.in +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/__init__.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/app/__init__.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/app/app.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/app/bash.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/app/errors.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/app/futures.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/app/python.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/benchmark/__init__.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/benchmark/perf.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/channels/__init__.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/channels/base.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/channels/errors.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/channels/local/__init__.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/channels/local/local.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/channels/oauth_ssh/__init__.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/channels/oauth_ssh/oauth_ssh.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/channels/ssh/__init__.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/channels/ssh/ssh.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/channels/ssh_il/__init__.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/channels/ssh_il/ssh_il.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/concurrent/__init__.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/configs/ASPIRE1.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/configs/Azure.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/configs/__init__.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/configs/ad_hoc.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/configs/bridges.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/configs/cc_in2p3.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/configs/ec2.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/configs/expanse.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/configs/frontera.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/configs/htex_local.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/configs/illinoiscluster.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/configs/kubernetes.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/configs/local_threads.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/configs/midway.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/configs/osg.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/configs/polaris.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/configs/stampede2.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/configs/summit.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/configs/toss3_llnl.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/configs/vineex_local.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/configs/wqex_local.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/curvezmq.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/data_provider/__init__.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/data_provider/data_manager.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/data_provider/file_noop.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/data_provider/files.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/data_provider/ftp.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/data_provider/globus.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/data_provider/http.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/data_provider/rsync.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/data_provider/staging.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/dataflow/__init__.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/dataflow/errors.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/dataflow/futures.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/dataflow/memoization.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/dataflow/rundirs.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/dataflow/states.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/errors.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/executors/__init__.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/executors/base.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/executors/errors.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/executors/flux/__init__.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/executors/flux/execute_parsl_task.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/executors/flux/executor.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/executors/flux/flux_instance_manager.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/executors/high_throughput/__init__.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/executors/high_throughput/errors.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/executors/high_throughput/monitoring_info.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/executors/high_throughput/mpi_prefix_composer.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/executors/high_throughput/mpi_resource_management.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/executors/high_throughput/probe.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/executors/high_throughput/zmq_pipes.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/executors/radical/__init__.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/executors/radical/executor.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/executors/radical/rpex_master.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/executors/radical/rpex_resources.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/executors/radical/rpex_worker.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/executors/status_handling.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/executors/taskvine/__init__.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/executors/taskvine/errors.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/executors/taskvine/exec_parsl_function.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/executors/taskvine/factory.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/executors/taskvine/factory_config.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/executors/taskvine/utils.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/executors/threads.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/executors/workqueue/__init__.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/executors/workqueue/errors.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/executors/workqueue/exec_parsl_function.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/executors/workqueue/executor.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/executors/workqueue/parsl_coprocess.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/executors/workqueue/parsl_coprocess_stub.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/jobs/__init__.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/jobs/error_handlers.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/jobs/errors.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/jobs/states.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/launchers/__init__.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/launchers/base.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/launchers/errors.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/monitoring/__init__.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/monitoring/message_type.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/monitoring/queries/__init__.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/monitoring/queries/pandas.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/monitoring/radios.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/monitoring/types.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/monitoring/visualization/__init__.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/monitoring/visualization/app.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/monitoring/visualization/plots/__init__.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/monitoring/visualization/plots/default/__init__.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/monitoring/visualization/plots/default/task_plots.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/monitoring/visualization/plots/default/workflow_resource_plots.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/monitoring/visualization/static/parsl-logo-white.png +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/monitoring/visualization/static/parsl-monitor.css +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/monitoring/visualization/templates/app.html +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/monitoring/visualization/templates/dag.html +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/monitoring/visualization/templates/error.html +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/monitoring/visualization/templates/layout.html +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/monitoring/visualization/templates/resource_usage.html +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/monitoring/visualization/templates/task.html +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/monitoring/visualization/templates/workflow.html +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/monitoring/visualization/templates/workflows_summary.html +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/monitoring/visualization/utils.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/monitoring/visualization/version.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/multiprocessing.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/process_loggers.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/providers/__init__.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/providers/ad_hoc/__init__.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/providers/ad_hoc/ad_hoc.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/providers/aws/__init__.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/providers/aws/aws.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/providers/aws/template.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/providers/azure/__init__.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/providers/azure/azure.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/providers/azure/template.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/providers/base.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/providers/cobalt/__init__.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/providers/cobalt/cobalt.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/providers/cobalt/template.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/providers/condor/__init__.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/providers/condor/condor.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/providers/condor/template.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/providers/errors.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/providers/googlecloud/__init__.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/providers/googlecloud/googlecloud.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/providers/grid_engine/__init__.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/providers/grid_engine/grid_engine.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/providers/grid_engine/template.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/providers/kubernetes/__init__.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/providers/kubernetes/kube.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/providers/kubernetes/template.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/providers/local/__init__.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/providers/local/local.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/providers/lsf/__init__.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/providers/lsf/lsf.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/providers/lsf/template.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/providers/pbspro/__init__.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/providers/pbspro/pbspro.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/providers/pbspro/template.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/providers/slurm/__init__.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/providers/slurm/template.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/providers/torque/__init__.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/providers/torque/template.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/providers/torque/torque.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/py.typed +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/serialize/__init__.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/serialize/base.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/serialize/concretes.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/serialize/errors.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/serialize/facade.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/serialize/proxystore.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/__init__.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/callables_helper.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/configs/__init__.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/configs/ad_hoc_cluster_htex.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/configs/azure_single_node.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/configs/bluewaters.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/configs/bridges.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/configs/cc_in2p3.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/configs/comet.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/configs/cooley_htex.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/configs/ec2_single_node.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/configs/ec2_spot.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/configs/frontera.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/configs/htex_ad_hoc_cluster.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/configs/htex_local.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/configs/htex_local_alternate.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/configs/htex_local_intask_staging.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/configs/htex_local_rsync_staging.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/configs/local_adhoc.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/configs/local_radical.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/configs/local_radical_mpi.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/configs/local_threads.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/configs/local_threads_checkpoint.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/configs/local_threads_checkpoint_dfk_exit.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/configs/local_threads_checkpoint_periodic.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/configs/local_threads_checkpoint_task_exit.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/configs/local_threads_ftp_in_task.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/configs/local_threads_globus.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/configs/local_threads_http_in_task.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/configs/local_threads_monitoring.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/configs/local_threads_no_cache.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/configs/midway.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/configs/nscc_singapore.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/configs/osg_htex.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/configs/petrelkube.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/configs/summit.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/configs/swan_htex.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/configs/taskvine_ex.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/configs/theta.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/configs/workqueue_ex.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/conftest.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/integration/__init__.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/integration/latency.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/integration/test_apps/__init__.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/integration/test_channels/__init__.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/integration/test_channels/test_channels.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/integration/test_channels/test_local_channel.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/integration/test_channels/test_scp_1.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/integration/test_channels/test_ssh_1.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/integration/test_channels/test_ssh_errors.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/integration/test_channels/test_ssh_file_transport.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/integration/test_channels/test_ssh_interactive.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/integration/test_parsl_load_default_config.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/integration/test_stress/__init__.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/integration/test_stress/test_python_simple.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/integration/test_stress/test_python_threads.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/manual_tests/__init__.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/manual_tests/htex_local.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/manual_tests/test_ad_hoc_htex.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/manual_tests/test_basic.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/manual_tests/test_fan_in_out_htex_remote.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/manual_tests/test_log_filter.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/manual_tests/test_memory_limits.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/manual_tests/test_oauth_ssh.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/manual_tests/test_regression_220.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/manual_tests/test_udp_simple.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/manual_tests/test_worker_count.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/scaling_tests/__init__.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/scaling_tests/htex_local.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/scaling_tests/local_threads.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/scaling_tests/test_scale.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/scaling_tests/vineex_condor.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/scaling_tests/vineex_local.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/scaling_tests/wqex_condor.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/scaling_tests/wqex_local.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/site_tests/__init__.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/site_tests/site_config_selector.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/site_tests/test_provider.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/site_tests/test_site.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/sites/__init__.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/sites/test_affinity.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/sites/test_concurrent.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/sites/test_dynamic_executor.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/sites/test_ec2.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/sites/test_launchers.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/sites/test_local_adhoc.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/sites/test_mpi/__init__.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/sites/test_worker_info.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_aalst_patterns.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_bash_apps/__init__.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_bash_apps/test_apptimeout.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_bash_apps/test_basic.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_bash_apps/test_error_codes.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_bash_apps/test_keyword_overlaps.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_bash_apps/test_kwarg_storage.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_bash_apps/test_memoize.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_bash_apps/test_memoize_ignore_args.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_bash_apps/test_memoize_ignore_args_regr.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_bash_apps/test_multiline.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_bash_apps/test_pipeline.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_bash_apps/test_stdout.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_callables.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_channels/__init__.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_channels/test_large_output.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_checkpointing/__init__.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_checkpointing/test_periodic.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_checkpointing/test_python_checkpoint_1.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_checkpointing/test_python_checkpoint_2.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_checkpointing/test_python_checkpoint_3.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_checkpointing/test_regression_232.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_checkpointing/test_regression_233.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_checkpointing/test_regression_239.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_checkpointing/test_task_exit.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_curvezmq.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_data/__init__.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_data/test_file.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_data/test_file_apps.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_data/test_file_staging.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_data/test_output_chain_filenames.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_docs/__init__.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_docs/test_from_slides.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_docs/test_kwargs.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_docs/test_tutorial_1.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_docs/test_workflow1.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_docs/test_workflow2.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_docs/test_workflow4.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_error_handling/__init__.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_error_handling/test_fail.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_error_handling/test_python_walltime.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_error_handling/test_rand_fail.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_error_handling/test_resource_spec.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_error_handling/test_retries.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_error_handling/test_retry_handler.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_error_handling/test_retry_handler_failure.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_error_handling/test_serialization_fail.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_error_handling/test_wrap_with_logs.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_flowcontrol/__init__.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_flux.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_htex/__init__.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_htex/test_basic.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_htex/test_connected_blocks.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_htex/test_cpu_affinity_explicit.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_htex/test_disconnected_blocks.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_htex/test_htex.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_htex/test_manager_failure.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_htex/test_missing_worker.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_htex/test_multiple_disconnected_blocks.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_htex/test_worker_failure.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_htex/test_zmq_binding.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_monitoring/__init__.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_monitoring/test_basic.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_monitoring/test_db_locks.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_monitoring/test_fuzz_zmq.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_monitoring/test_incomplete_futures.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_monitoring/test_memoization_representation.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_monitoring/test_viz_colouring.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_mpi_apps/__init__.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_mpi_apps/test_bad_mpi_config.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_mpi_apps/test_mpi_mode_disabled.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_mpi_apps/test_mpi_mode_enabled.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_mpi_apps/test_mpi_prefix.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_mpi_apps/test_mpi_scheduler.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_mpi_apps/test_resource_spec.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_providers/__init__.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_providers/test_cobalt_deprecation_warning.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_providers/test_local_provider.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_providers/test_pbspro_template.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_providers/test_slurm_instantiate.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_providers/test_slurm_template.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_providers/test_submiterror_deprecation.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_python_apps/__init__.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_python_apps/test_arg_input_types.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_python_apps/test_basic.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_python_apps/test_dep_standard_futures.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_python_apps/test_dependencies.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_python_apps/test_depfail_propagation.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_python_apps/test_fail.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_python_apps/test_fibonacci_iterative.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_python_apps/test_fibonacci_recursive.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_python_apps/test_futures.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_python_apps/test_garbage_collect.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_python_apps/test_import_fail.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_python_apps/test_join.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_python_apps/test_lifted.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_python_apps/test_mapred.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_python_apps/test_memoize_1.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_python_apps/test_memoize_2.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_python_apps/test_memoize_4.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_python_apps/test_memoize_bad_id_for_memo.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_python_apps/test_memoize_ignore_args.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_python_apps/test_memoize_joinapp.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_python_apps/test_outputs.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_python_apps/test_overview.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_python_apps/test_pipeline.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_python_apps/test_simple.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_python_apps/test_timeout.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_python_apps/test_type5.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_radical/__init__.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_radical/test_mpi_funcs.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_regression/__init__.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_regression/test_1480.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_regression/test_1606_wait_for_current_tasks.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_regression/test_1653.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_regression/test_221.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_regression/test_226.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_regression/test_2652.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_regression/test_69a.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_regression/test_854.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_regression/test_97_parallelism_0.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_regression/test_98.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_scaling/__init__.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_scaling/test_block_error_handler.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_scaling/test_regression_1621.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_scaling/test_scale_down.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_serialization/__init__.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_serialization/test_2555_caching_deserializer.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_serialization/test_basic.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_serialization/test_htex_code_cache.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_serialization/test_pack_resource_spec.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_serialization/test_proxystore_configured.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_serialization/test_proxystore_impl.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_staging/__init__.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_staging/staging_provider.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_staging/test_1316.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_staging/test_docs_1.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_staging/test_docs_2.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_staging/test_elaborate_noop_file.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_staging/test_staging_ftp.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_staging/test_staging_ftp_in_task.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_staging/test_staging_globus.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_staging/test_staging_https.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_summary.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_thread_parallelism.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_threads/__init__.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_threads/test_configs.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_threads/test_lazy_errors.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_utils/__init__.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_utils/test_representation_mixin.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/utils.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl/usage_tracking/__init__.py +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl.egg-info/dependency_links.txt +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl.egg-info/entry_points.txt +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl.egg-info/requires.txt +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/parsl.egg-info/top_level.txt +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/requirements.txt +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/setup.cfg +0 -0
- {parsl-2024.3.4 → parsl-2024.3.18}/setup.py +0 -0
@@ -1,9 +1,9 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: parsl
|
3
|
-
Version: 2024.3.
|
3
|
+
Version: 2024.3.18
|
4
4
|
Summary: Simple data dependent workflows in Python
|
5
5
|
Home-page: https://github.com/Parsl/parsl
|
6
|
-
Download-URL: https://github.com/Parsl/parsl/archive/2024.03.
|
6
|
+
Download-URL: https://github.com/Parsl/parsl/archive/2024.03.18.tar.gz
|
7
7
|
Author: The Parsl Team
|
8
8
|
Author-email: parsl@googlegroups.com
|
9
9
|
License: Apache 2.0
|
@@ -59,6 +59,10 @@ then explore the `parallel computing patterns <https://parsl.readthedocs.io/en/s
|
|
59
59
|
.. |NSF-1550528| image:: https://img.shields.io/badge/NSF-1550528-blue.svg
|
60
60
|
:target: https://nsf.gov/awardsearch/showAward?AWD_ID=1550528
|
61
61
|
:alt: NSF award info
|
62
|
+
.. |NSF-1550475| image:: https://img.shields.io/badge/NSF-1550475-blue.svg
|
63
|
+
:target: https://nsf.gov/awardsearch/showAward?AWD_ID=1550475
|
64
|
+
:alt: NSF award info
|
65
|
+
|
62
66
|
|
63
67
|
Quickstart
|
64
68
|
==========
|
@@ -81,7 +81,9 @@ def address_by_hostname() -> str:
|
|
81
81
|
def address_by_interface(ifname: str) -> str:
|
82
82
|
"""Returns the IP address of the given interface name, e.g. 'eth0'
|
83
83
|
|
84
|
-
This is taken from a Stack Overflow answer:
|
84
|
+
This is taken from a Stack Overflow answer:
|
85
|
+
https://stackoverflow.com/questions/24196932/how-can-i-get-the-ip-address-of-eth0-in-python#24196955
|
86
|
+
|
85
87
|
|
86
88
|
Parameters
|
87
89
|
----------
|
@@ -55,6 +55,8 @@ class Config(RepresentationMixin):
|
|
55
55
|
or `None`.
|
56
56
|
If 'none' or `None`, dynamic scaling will be disabled. Default is 'simple'. The literal value `None` is
|
57
57
|
deprecated.
|
58
|
+
strategy_period : float or int, optional
|
59
|
+
How often the scaling strategy should be executed. Default is 5 seconds.
|
58
60
|
max_idletime : float, optional
|
59
61
|
The maximum idle time allowed for an executor before strategy could shut down unused blocks. Default is 120.0 seconds.
|
60
62
|
usage_tracking : bool, optional
|
@@ -88,6 +90,7 @@ class Config(RepresentationMixin):
|
|
88
90
|
retry_handler: Optional[Callable[[Exception, TaskRecord], float]] = None,
|
89
91
|
run_dir: str = 'runinfo',
|
90
92
|
strategy: Optional[str] = 'simple',
|
93
|
+
strategy_period: Union[float, int] = 5,
|
91
94
|
max_idletime: float = 120.0,
|
92
95
|
monitoring: Optional[MonitoringHub] = None,
|
93
96
|
usage_tracking: bool = False,
|
@@ -121,6 +124,7 @@ class Config(RepresentationMixin):
|
|
121
124
|
self.retry_handler = retry_handler
|
122
125
|
self.run_dir = run_dir
|
123
126
|
self.strategy = strategy
|
127
|
+
self.strategy_period = strategy_period
|
124
128
|
self.max_idletime = max_idletime
|
125
129
|
self.usage_tracking = usage_tracking
|
126
130
|
self.initialize_logging = initialize_logging
|
@@ -95,7 +95,7 @@ class DataFlowKernel:
|
|
95
95
|
self.checkpoint_lock = threading.Lock()
|
96
96
|
|
97
97
|
self.usage_tracker = UsageTracker(self)
|
98
|
-
self.usage_tracker.
|
98
|
+
self.usage_tracker.send_start_message()
|
99
99
|
|
100
100
|
self.task_state_counts_lock = threading.Lock()
|
101
101
|
self.task_state_counts = {state: 0 for state in States}
|
@@ -178,6 +178,7 @@ class DataFlowKernel:
|
|
178
178
|
# this must be set before executors are added since add_executors calls
|
179
179
|
# job_status_poller.add_executors.
|
180
180
|
self.job_status_poller = JobStatusPoller(strategy=self.config.strategy,
|
181
|
+
strategy_period=self.config.strategy_period,
|
181
182
|
max_idletime=self.config.max_idletime,
|
182
183
|
dfk=self)
|
183
184
|
|
@@ -722,7 +723,10 @@ class DataFlowKernel:
|
|
722
723
|
self._send_task_log_info(task_record)
|
723
724
|
|
724
725
|
if hasattr(exec_fu, "parsl_executor_task_id"):
|
725
|
-
logger.info(
|
726
|
+
logger.info(
|
727
|
+
f"Parsl task {task_id} try {try_id} launched on executor {executor.label} "
|
728
|
+
f"with executor id {exec_fu.parsl_executor_task_id}")
|
729
|
+
|
726
730
|
else:
|
727
731
|
logger.info(f"Parsl task {task_id} try {try_id} launched on executor {executor.label}")
|
728
732
|
|
@@ -730,7 +734,8 @@ class DataFlowKernel:
|
|
730
734
|
|
731
735
|
return exec_fu
|
732
736
|
|
733
|
-
def _add_input_deps(self, executor: str, args: Sequence[Any], kwargs: Dict[str, Any], func: Callable) -> Tuple[Sequence[Any], Dict[str, Any],
|
737
|
+
def _add_input_deps(self, executor: str, args: Sequence[Any], kwargs: Dict[str, Any], func: Callable) -> Tuple[Sequence[Any], Dict[str, Any],
|
738
|
+
Callable]:
|
734
739
|
"""Look for inputs of the app that are files. Give the data manager
|
735
740
|
the opportunity to replace a file with a data future for that file,
|
736
741
|
for example wrapping the result of a staging action.
|
@@ -1142,8 +1147,9 @@ class DataFlowKernel:
|
|
1142
1147
|
|
1143
1148
|
def atexit_cleanup(self) -> None:
|
1144
1149
|
if not self.cleanup_called:
|
1145
|
-
logger.
|
1146
|
-
|
1150
|
+
logger.warning("Python is exiting with a DFK still running. "
|
1151
|
+
"You should call parsl.dfk().cleanup() before "
|
1152
|
+
"exiting to release any resources")
|
1147
1153
|
else:
|
1148
1154
|
logger.info("python process is exiting, but DFK has already been cleaned up")
|
1149
1155
|
|
@@ -1165,7 +1171,8 @@ class DataFlowKernel:
|
|
1165
1171
|
fut = task_record['app_fu']
|
1166
1172
|
if not fut.done():
|
1167
1173
|
fut.exception()
|
1168
|
-
# now app future is done, poll until DFK state is final: a
|
1174
|
+
# now app future is done, poll until DFK state is final: a
|
1175
|
+
# DFK state being final and the app future being done do not imply each other.
|
1169
1176
|
while task_record['status'] not in FINAL_STATES:
|
1170
1177
|
time.sleep(0.1)
|
1171
1178
|
|
@@ -1200,7 +1207,7 @@ class DataFlowKernel:
|
|
1200
1207
|
self._checkpoint_timer.close()
|
1201
1208
|
|
1202
1209
|
# Send final stats
|
1203
|
-
self.usage_tracker.
|
1210
|
+
self.usage_tracker.send_end_message()
|
1204
1211
|
self.usage_tracker.close()
|
1205
1212
|
|
1206
1213
|
logger.info("Closing job status poller")
|
@@ -70,7 +70,9 @@ class TaskRecord(TypedDict, total=False):
|
|
70
70
|
# these three could be more strongly typed perhaps but I'm not thinking about that now
|
71
71
|
func: Callable
|
72
72
|
fn_hash: str
|
73
|
-
args: Sequence[Any]
|
73
|
+
args: Sequence[Any]
|
74
|
+
# in some places we uses a Tuple[Any, ...] and in some places a List[Any].
|
75
|
+
# This is an attempt to correctly type both of those.
|
74
76
|
kwargs: Dict[str, Any]
|
75
77
|
|
76
78
|
time_invoked: Optional[datetime.datetime]
|
@@ -6,6 +6,7 @@ import threading
|
|
6
6
|
import queue
|
7
7
|
import datetime
|
8
8
|
import pickle
|
9
|
+
from dataclasses import dataclass
|
9
10
|
from multiprocessing import Process, Queue
|
10
11
|
from typing import Dict, Sequence
|
11
12
|
from typing import List, Optional, Tuple, Union, Callable
|
@@ -54,6 +55,7 @@ DEFAULT_LAUNCH_CMD = ("process_worker_pool.py {debug} {max_workers_per_node} "
|
|
54
55
|
"--hb_period={heartbeat_period} "
|
55
56
|
"{address_probe_timeout_string} "
|
56
57
|
"--hb_threshold={heartbeat_threshold} "
|
58
|
+
"--drain_period={drain_period} "
|
57
59
|
"--cpu-affinity {cpu_affinity} "
|
58
60
|
"{enable_mpi_mode} "
|
59
61
|
"--mpi-launcher={mpi_launcher} "
|
@@ -200,6 +202,14 @@ class HighThroughputExecutor(BlockProviderExecutor, RepresentationMixin):
|
|
200
202
|
Timeout period to be used by the executor components in milliseconds. Increasing poll_periods
|
201
203
|
trades performance for cpu efficiency. Default: 10ms
|
202
204
|
|
205
|
+
drain_period : int
|
206
|
+
The number of seconds after start when workers will begin to drain
|
207
|
+
and then exit. Set this to a time that is slightly less than the
|
208
|
+
maximum walltime of batch jobs to avoid killing tasks while they
|
209
|
+
execute. For example, you could set this to the walltime minus a grace
|
210
|
+
period for the batch job to start the workers, minus the expected
|
211
|
+
maximum length of an individual task.
|
212
|
+
|
203
213
|
worker_logdir_root : string
|
204
214
|
In case of a remote file system, specify the path to where logs will be kept.
|
205
215
|
|
@@ -239,6 +249,7 @@ class HighThroughputExecutor(BlockProviderExecutor, RepresentationMixin):
|
|
239
249
|
prefetch_capacity: int = 0,
|
240
250
|
heartbeat_threshold: int = 120,
|
241
251
|
heartbeat_period: int = 30,
|
252
|
+
drain_period: Optional[int] = None,
|
242
253
|
poll_period: int = 10,
|
243
254
|
address_probe_timeout: Optional[int] = None,
|
244
255
|
worker_logdir_root: Optional[str] = None,
|
@@ -302,6 +313,7 @@ class HighThroughputExecutor(BlockProviderExecutor, RepresentationMixin):
|
|
302
313
|
self.interchange_port_range = interchange_port_range
|
303
314
|
self.heartbeat_threshold = heartbeat_threshold
|
304
315
|
self.heartbeat_period = heartbeat_period
|
316
|
+
self.drain_period = drain_period
|
305
317
|
self.poll_period = poll_period
|
306
318
|
self.run_dir = '.'
|
307
319
|
self.worker_logdir_root = worker_logdir_root
|
@@ -327,7 +339,7 @@ class HighThroughputExecutor(BlockProviderExecutor, RepresentationMixin):
|
|
327
339
|
def _warn_deprecated(self, old: str, new: str):
|
328
340
|
warnings.warn(
|
329
341
|
f"{old} is deprecated and will be removed in a future release. "
|
330
|
-
"Please use {new} instead.",
|
342
|
+
f"Please use {new} instead.",
|
331
343
|
DeprecationWarning,
|
332
344
|
stacklevel=2
|
333
345
|
)
|
@@ -375,6 +387,7 @@ class HighThroughputExecutor(BlockProviderExecutor, RepresentationMixin):
|
|
375
387
|
nodes_per_block=self.provider.nodes_per_block,
|
376
388
|
heartbeat_period=self.heartbeat_period,
|
377
389
|
heartbeat_threshold=self.heartbeat_threshold,
|
390
|
+
drain_period=self.drain_period,
|
378
391
|
poll_period=self.poll_period,
|
379
392
|
cert_dir=self.cert_dir,
|
380
393
|
logdir=self.worker_logdir,
|
@@ -628,8 +641,8 @@ class HighThroughputExecutor(BlockProviderExecutor, RepresentationMixin):
|
|
628
641
|
"""Submits work to the outgoing_q.
|
629
642
|
|
630
643
|
The outgoing_q is an external process listens on this
|
631
|
-
queue for new work. This method behaves like a
|
632
|
-
|
644
|
+
queue for new work. This method behaves like a submit call as described here `Python docs: <https://docs.python.org/3/
|
645
|
+
library/concurrent.futures.html#concurrent.futures.ThreadPoolExecutor>`_
|
633
646
|
|
634
647
|
Args:
|
635
648
|
- func (callable) : Callable function
|
@@ -694,7 +707,7 @@ class HighThroughputExecutor(BlockProviderExecutor, RepresentationMixin):
|
|
694
707
|
def workers_per_node(self) -> Union[int, float]:
|
695
708
|
return self._workers_per_node
|
696
709
|
|
697
|
-
def scale_in(self, blocks, max_idletime=None):
|
710
|
+
def scale_in(self, blocks: int, max_idletime: Optional[float] = None) -> List[str]:
|
698
711
|
"""Scale in the number of active blocks by specified amount.
|
699
712
|
|
700
713
|
The scale in method here is very rude. It doesn't give the workers
|
@@ -721,25 +734,36 @@ class HighThroughputExecutor(BlockProviderExecutor, RepresentationMixin):
|
|
721
734
|
List of block IDs scaled in
|
722
735
|
"""
|
723
736
|
logger.debug(f"Scale in called, blocks={blocks}")
|
737
|
+
|
738
|
+
@dataclass
|
739
|
+
class BlockInfo:
|
740
|
+
tasks: int # sum of tasks in this block
|
741
|
+
idle: float # shortest idle time of any manager in this block
|
742
|
+
|
724
743
|
managers = self.connected_managers()
|
725
|
-
block_info = {}
|
744
|
+
block_info: Dict[str, BlockInfo] = {}
|
726
745
|
for manager in managers:
|
727
746
|
if not manager['active']:
|
728
747
|
continue
|
729
748
|
b_id = manager['block_id']
|
730
749
|
if b_id not in block_info:
|
731
|
-
block_info[b_id] =
|
732
|
-
block_info[b_id]
|
733
|
-
block_info[b_id]
|
750
|
+
block_info[b_id] = BlockInfo(tasks=0, idle=float('inf'))
|
751
|
+
block_info[b_id].tasks += manager['tasks']
|
752
|
+
block_info[b_id].idle = min(block_info[b_id].idle, manager['idle_duration'])
|
753
|
+
|
754
|
+
# The scaling policy is that longest idle blocks should be scaled down
|
755
|
+
# in preference to least idle (most recently used) blocks.
|
756
|
+
# Other policies could be implemented here.
|
757
|
+
|
758
|
+
sorted_blocks = sorted(block_info.items(), key=lambda item: (-item[1].idle, item[1].tasks))
|
734
759
|
|
735
|
-
sorted_blocks = sorted(block_info.items(), key=lambda item: (item[1][1], item[1][0]))
|
736
760
|
logger.debug(f"Scale in selecting from {len(sorted_blocks)} blocks")
|
737
761
|
if max_idletime is None:
|
738
762
|
block_ids_to_kill = [x[0] for x in sorted_blocks[:blocks]]
|
739
763
|
else:
|
740
764
|
block_ids_to_kill = []
|
741
765
|
for x in sorted_blocks:
|
742
|
-
if x[1]
|
766
|
+
if x[1].idle > max_idletime and x[1].tasks == 0:
|
743
767
|
block_ids_to_kill.append(x[0])
|
744
768
|
if len(block_ids_to_kill) == blocks:
|
745
769
|
break
|
@@ -28,6 +28,7 @@ from parsl.process_loggers import wrap_with_logs
|
|
28
28
|
|
29
29
|
|
30
30
|
PKL_HEARTBEAT_CODE = pickle.dumps((2 ** 32) - 1)
|
31
|
+
PKL_DRAINED_CODE = pickle.dumps((2 ** 32) - 2)
|
31
32
|
|
32
33
|
LOGGER_NAME = "interchange"
|
33
34
|
logger = logging.getLogger(LOGGER_NAME)
|
@@ -101,12 +102,12 @@ class Interchange:
|
|
101
102
|
This is overridden when the worker_ports option is set. Default: (54000, 55000)
|
102
103
|
|
103
104
|
hub_address : str
|
104
|
-
The
|
105
|
-
|
105
|
+
The IP address at which the interchange can send info about managers to when monitoring is enabled.
|
106
|
+
Default: None (meaning monitoring disabled)
|
106
107
|
|
107
108
|
hub_port : str
|
108
109
|
The port at which the interchange can send info about managers to when monitoring is enabled.
|
109
|
-
|
110
|
+
Default: None (meaning monitoring disabled)
|
110
111
|
|
111
112
|
heartbeat_threshold : int
|
112
113
|
Number of seconds since the last heartbeat after which worker is considered lost.
|
@@ -244,19 +245,19 @@ class Interchange:
|
|
244
245
|
|
245
246
|
def _create_monitoring_channel(self) -> Optional[zmq.Socket]:
|
246
247
|
if self.hub_address and self.hub_port:
|
247
|
-
logger.info("Connecting to
|
248
|
+
logger.info("Connecting to MonitoringHub")
|
248
249
|
# This is a one-off because monitoring is unencrypted
|
249
250
|
hub_channel = zmq.Context().socket(zmq.DEALER)
|
250
251
|
hub_channel.set_hwm(0)
|
251
252
|
hub_channel.connect("tcp://{}:{}".format(self.hub_address, self.hub_port))
|
252
|
-
logger.info("
|
253
|
+
logger.info("Connected to MonitoringHub")
|
253
254
|
return hub_channel
|
254
255
|
else:
|
255
256
|
return None
|
256
257
|
|
257
258
|
def _send_monitoring_info(self, hub_channel: Optional[zmq.Socket], manager: ManagerRecord) -> None:
|
258
259
|
if hub_channel:
|
259
|
-
logger.info("Sending message {} to
|
260
|
+
logger.info("Sending message {} to MonitoringHub".format(manager))
|
260
261
|
|
261
262
|
d: Dict = cast(Dict, manager.copy())
|
262
263
|
d['timestamp'] = datetime.datetime.now()
|
@@ -308,7 +309,8 @@ class Interchange:
|
|
308
309
|
'worker_count': m['worker_count'],
|
309
310
|
'tasks': len(m['tasks']),
|
310
311
|
'idle_duration': idle_duration,
|
311
|
-
'active': m['active']
|
312
|
+
'active': m['active'],
|
313
|
+
'draining': m['draining']}
|
312
314
|
reply.append(resp)
|
313
315
|
|
314
316
|
elif command_req.startswith("HOLD_WORKER"):
|
@@ -385,6 +387,7 @@ class Interchange:
|
|
385
387
|
self.process_task_outgoing_incoming(interesting_managers, hub_channel, kill_event)
|
386
388
|
self.process_results_incoming(interesting_managers, hub_channel)
|
387
389
|
self.expire_bad_managers(interesting_managers, hub_channel)
|
390
|
+
self.expire_drained_managers(interesting_managers, hub_channel)
|
388
391
|
self.process_tasks_to_send(interesting_managers)
|
389
392
|
|
390
393
|
self.zmq_context.destroy()
|
@@ -392,7 +395,12 @@ class Interchange:
|
|
392
395
|
logger.info("Processed {} tasks in {} seconds".format(self.count, delta))
|
393
396
|
logger.warning("Exiting")
|
394
397
|
|
395
|
-
def process_task_outgoing_incoming(
|
398
|
+
def process_task_outgoing_incoming(
|
399
|
+
self,
|
400
|
+
interesting_managers: Set[bytes],
|
401
|
+
hub_channel: Optional[zmq.Socket],
|
402
|
+
kill_event: threading.Event
|
403
|
+
) -> None:
|
396
404
|
"""Process one message from manager on the task_outgoing channel.
|
397
405
|
Note that this message flow is in contradiction to the name of the
|
398
406
|
channel - it is not an outgoing message and it is not a task.
|
@@ -426,6 +434,7 @@ class Interchange:
|
|
426
434
|
'max_capacity': 0,
|
427
435
|
'worker_count': 0,
|
428
436
|
'active': True,
|
437
|
+
'draining': False,
|
429
438
|
'tasks': []}
|
430
439
|
self.connected_block_history.append(msg['block_id'])
|
431
440
|
|
@@ -464,10 +473,28 @@ class Interchange:
|
|
464
473
|
self._ready_managers[manager_id]['last_heartbeat'] = time.time()
|
465
474
|
logger.debug("Manager {!r} sent heartbeat via tasks connection".format(manager_id))
|
466
475
|
self.task_outgoing.send_multipart([manager_id, b'', PKL_HEARTBEAT_CODE])
|
476
|
+
elif msg['type'] == 'drain':
|
477
|
+
self._ready_managers[manager_id]['draining'] = True
|
478
|
+
logger.debug(f"Manager {manager_id!r} requested drain")
|
467
479
|
else:
|
468
480
|
logger.error(f"Unexpected message type received from manager: {msg['type']}")
|
469
481
|
logger.debug("leaving task_outgoing section")
|
470
482
|
|
483
|
+
def expire_drained_managers(self, interesting_managers: Set[bytes], hub_channel: Optional[zmq.Socket]) -> None:
|
484
|
+
|
485
|
+
for manager_id in list(interesting_managers):
|
486
|
+
# is it always true that a draining manager will be in interesting managers?
|
487
|
+
# i think so because it will have outstanding capacity?
|
488
|
+
m = self._ready_managers[manager_id]
|
489
|
+
if m['draining'] and len(m['tasks']) == 0:
|
490
|
+
logger.info(f"Manager {manager_id!r} is drained - sending drained message to manager")
|
491
|
+
self.task_outgoing.send_multipart([manager_id, b'', PKL_DRAINED_CODE])
|
492
|
+
interesting_managers.remove(manager_id)
|
493
|
+
self._ready_managers.pop(manager_id)
|
494
|
+
|
495
|
+
m['active'] = False
|
496
|
+
self._send_monitoring_info(hub_channel, m)
|
497
|
+
|
471
498
|
def process_tasks_to_send(self, interesting_managers: Set[bytes]) -> None:
|
472
499
|
# Check if there are tasks that could be sent to managers
|
473
500
|
|
@@ -485,7 +512,7 @@ class Interchange:
|
|
485
512
|
tasks_inflight = len(m['tasks'])
|
486
513
|
real_capacity = m['max_capacity'] - tasks_inflight
|
487
514
|
|
488
|
-
if (real_capacity and m['active']):
|
515
|
+
if (real_capacity and m['active'] and not m['draining']):
|
489
516
|
tasks = self.get_tasks(real_capacity)
|
490
517
|
if tasks:
|
491
518
|
self.task_outgoing.send_multipart([manager_id, b'', pickle.dumps(tasks)])
|
@@ -621,7 +648,13 @@ def start_file_logger(filename: str, level: int = logging.DEBUG, format_string:
|
|
621
648
|
None.
|
622
649
|
"""
|
623
650
|
if format_string is None:
|
624
|
-
format_string =
|
651
|
+
format_string = (
|
652
|
+
|
653
|
+
"%(asctime)s.%(msecs)03d %(name)s:%(lineno)d "
|
654
|
+
"%(processName)s(%(process)d) %(threadName)s "
|
655
|
+
"%(funcName)s [%(levelname)s] %(message)s"
|
656
|
+
|
657
|
+
)
|
625
658
|
|
626
659
|
global logger
|
627
660
|
logger = logging.getLogger(LOGGER_NAME)
|
@@ -36,6 +36,7 @@ from parsl.executors.high_throughput.mpi_resource_management import (
|
|
36
36
|
from parsl.executors.high_throughput.mpi_prefix_composer import compose_all, VALID_LAUNCHERS
|
37
37
|
|
38
38
|
HEARTBEAT_CODE = (2 ** 32) - 1
|
39
|
+
DRAINED_CODE = (2 ** 32) - 2
|
39
40
|
|
40
41
|
|
41
42
|
class Manager:
|
@@ -73,7 +74,8 @@ class Manager:
|
|
73
74
|
enable_mpi_mode: bool = False,
|
74
75
|
mpi_launcher: str = "mpiexec",
|
75
76
|
available_accelerators: Sequence[str],
|
76
|
-
cert_dir: Optional[str]
|
77
|
+
cert_dir: Optional[str],
|
78
|
+
drain_period: Optional[int]):
|
77
79
|
"""
|
78
80
|
Parameters
|
79
81
|
----------
|
@@ -138,6 +140,9 @@ class Manager:
|
|
138
140
|
|
139
141
|
cert_dir : str | None
|
140
142
|
Path to the certificate directory.
|
143
|
+
|
144
|
+
drain_period: int | None
|
145
|
+
Number of seconds to drain after TODO: could be a nicer timespec involving m,s,h qualifiers for user friendliness?
|
141
146
|
"""
|
142
147
|
|
143
148
|
logger.info("Manager initializing")
|
@@ -227,6 +232,14 @@ class Manager:
|
|
227
232
|
self.heartbeat_period = heartbeat_period
|
228
233
|
self.heartbeat_threshold = heartbeat_threshold
|
229
234
|
self.poll_period = poll_period
|
235
|
+
|
236
|
+
self.drain_time: float
|
237
|
+
if drain_period:
|
238
|
+
self.drain_time = self._start_time + drain_period
|
239
|
+
logger.info(f"Will request drain at {self.drain_time}")
|
240
|
+
else:
|
241
|
+
self.drain_time = float('inf')
|
242
|
+
|
230
243
|
self.cpu_affinity = cpu_affinity
|
231
244
|
|
232
245
|
# Define accelerator available, adjust worker count accordingly
|
@@ -262,10 +275,19 @@ class Manager:
|
|
262
275
|
""" Send heartbeat to the incoming task queue
|
263
276
|
"""
|
264
277
|
msg = {'type': 'heartbeat'}
|
278
|
+
# don't need to dumps and encode this every time - could do as a global on import?
|
265
279
|
b_msg = json.dumps(msg).encode('utf-8')
|
266
280
|
self.task_incoming.send(b_msg)
|
267
281
|
logger.debug("Sent heartbeat")
|
268
282
|
|
283
|
+
def drain_to_incoming(self):
|
284
|
+
""" Send heartbeat to the incoming task queue
|
285
|
+
"""
|
286
|
+
msg = {'type': 'drain'}
|
287
|
+
b_msg = json.dumps(msg).encode('utf-8')
|
288
|
+
self.task_incoming.send(b_msg)
|
289
|
+
logger.debug("Sent drain")
|
290
|
+
|
269
291
|
@wrap_with_logs
|
270
292
|
def pull_tasks(self, kill_event):
|
271
293
|
""" Pull tasks from the incoming tasks zmq pipe onto the internal
|
@@ -298,6 +320,7 @@ class Manager:
|
|
298
320
|
# time here are correctly copy-pasted from the relevant if
|
299
321
|
# statements.
|
300
322
|
next_interesting_event_time = min(last_beat + self.heartbeat_period,
|
323
|
+
self.drain_time,
|
301
324
|
last_interchange_contact + self.heartbeat_threshold)
|
302
325
|
try:
|
303
326
|
pending_task_count = self.pending_task_queue.qsize()
|
@@ -312,6 +335,14 @@ class Manager:
|
|
312
335
|
self.heartbeat_to_incoming()
|
313
336
|
last_beat = time.time()
|
314
337
|
|
338
|
+
if self.drain_time and time.time() > self.drain_time:
|
339
|
+
logger.info("Requesting drain")
|
340
|
+
self.drain_to_incoming()
|
341
|
+
self.drain_time = None
|
342
|
+
# This will start the pool draining...
|
343
|
+
# Drained exit behaviour does not happen here. It will be
|
344
|
+
# driven by the interchange sending a DRAINED_CODE message.
|
345
|
+
|
315
346
|
poll_duration_s = max(0, next_interesting_event_time - time.time())
|
316
347
|
socks = dict(poller.poll(timeout=poll_duration_s * 1000))
|
317
348
|
|
@@ -322,7 +353,9 @@ class Manager:
|
|
322
353
|
|
323
354
|
if tasks == HEARTBEAT_CODE:
|
324
355
|
logger.debug("Got heartbeat from interchange")
|
325
|
-
|
356
|
+
elif tasks == DRAINED_CODE:
|
357
|
+
logger.info("Got fulled drained message from interchange - setting kill flag")
|
358
|
+
kill_event.set()
|
326
359
|
else:
|
327
360
|
task_recv_counter += len(tasks)
|
328
361
|
logger.debug("Got executor tasks: {}, cumulative count of tasks: {}".format([t['task_id'] for t in tasks], task_recv_counter))
|
@@ -413,7 +446,9 @@ class Manager:
|
|
413
446
|
raise WorkerLost(worker_id, platform.node())
|
414
447
|
except Exception:
|
415
448
|
logger.info("Putting exception for executor task {} in the pending result queue".format(task['task_id']))
|
416
|
-
result_package = {'type': 'result',
|
449
|
+
result_package = {'type': 'result',
|
450
|
+
'task_id': task['task_id'],
|
451
|
+
'exception': serialize(RemoteExceptionWrapper(*sys.exc_info()))}
|
417
452
|
pkl_package = pickle.dumps(result_package)
|
418
453
|
self.pending_result_queue.put(pkl_package)
|
419
454
|
except KeyError:
|
@@ -488,9 +523,8 @@ class Manager:
|
|
488
523
|
self._worker_watchdog_thread.start()
|
489
524
|
self._monitoring_handler_thread.start()
|
490
525
|
|
491
|
-
logger.info("
|
526
|
+
logger.info("Manager threads started")
|
492
527
|
|
493
|
-
# TODO : Add mechanism in this loop to stop the worker pool
|
494
528
|
# This might need a multiprocessing event to signal back.
|
495
529
|
self._kill_event.wait()
|
496
530
|
logger.critical("Received kill event, terminating worker processes")
|
@@ -802,6 +836,8 @@ if __name__ == "__main__":
|
|
802
836
|
help="Heartbeat period in seconds. Uses manager default unless set")
|
803
837
|
parser.add_argument("--hb_threshold", default=120,
|
804
838
|
help="Heartbeat threshold in seconds. Uses manager default unless set")
|
839
|
+
parser.add_argument("--drain_period", default=None,
|
840
|
+
help="Drain this pool after specified number of seconds. By default, does not drain.")
|
805
841
|
parser.add_argument("--address_probe_timeout", default=30,
|
806
842
|
help="Timeout to probe for viable address to interchange. Default: 30s")
|
807
843
|
parser.add_argument("--poll", default=10,
|
@@ -822,7 +858,7 @@ if __name__ == "__main__":
|
|
822
858
|
required=True,
|
823
859
|
help="Whether/how workers should control CPU affinity.")
|
824
860
|
parser.add_argument("--available-accelerators", type=str, nargs="*",
|
825
|
-
help="Names of available accelerators")
|
861
|
+
help="Names of available accelerators, if not given assumed to be zero accelerators available", default=[])
|
826
862
|
parser.add_argument("--enable_mpi_mode", action='store_true',
|
827
863
|
help="Enable MPI mode")
|
828
864
|
parser.add_argument("--mpi-launcher", type=str, choices=VALID_LAUNCHERS,
|
@@ -854,6 +890,7 @@ if __name__ == "__main__":
|
|
854
890
|
logger.info("Prefetch capacity: {}".format(args.prefetch_capacity))
|
855
891
|
logger.info("Heartbeat threshold: {}".format(args.hb_threshold))
|
856
892
|
logger.info("Heartbeat period: {}".format(args.hb_period))
|
893
|
+
logger.info("Drain period: {}".format(args.drain_period))
|
857
894
|
logger.info("CPU affinity: {}".format(args.cpu_affinity))
|
858
895
|
logger.info("Accelerators: {}".format(" ".join(args.available_accelerators)))
|
859
896
|
logger.info("enable_mpi_mode: {}".format(args.enable_mpi_mode))
|
@@ -867,10 +904,14 @@ if __name__ == "__main__":
|
|
867
904
|
block_id=args.block_id,
|
868
905
|
cores_per_worker=float(args.cores_per_worker),
|
869
906
|
mem_per_worker=None if args.mem_per_worker == 'None' else float(args.mem_per_worker),
|
870
|
-
max_workers_per_node=
|
907
|
+
max_workers_per_node=(
|
908
|
+
args.max_workers_per_node if args.max_workers_per_node == float('inf')
|
909
|
+
else int(args.max_workers_per_node)
|
910
|
+
),
|
871
911
|
prefetch_capacity=int(args.prefetch_capacity),
|
872
912
|
heartbeat_threshold=int(args.hb_threshold),
|
873
913
|
heartbeat_period=int(args.hb_period),
|
914
|
+
drain_period=None if args.drain_period == "None" else int(args.drain_period),
|
874
915
|
poll_period=int(args.poll),
|
875
916
|
cpu_affinity=args.cpu_affinity,
|
876
917
|
enable_mpi_mode=args.enable_mpi_mode,
|
@@ -196,8 +196,9 @@ class TaskVineExecutor(BlockProviderExecutor, putils.RepresentationMixin):
|
|
196
196
|
if self.manager_config.port == 0 and self.manager_config.project_name is None:
|
197
197
|
self.manager_config.project_name = "parsl-vine-" + str(uuid.uuid4())
|
198
198
|
|
199
|
-
# guess the host name if the project name is not given
|
200
|
-
|
199
|
+
# guess the host name if the project name is not given and none has been supplied
|
200
|
+
# explicitly in the manager config.
|
201
|
+
if not self.manager_config.project_name and self.manager_config.address is None:
|
201
202
|
self.manager_config.address = get_any_address()
|
202
203
|
|
203
204
|
# Factory communication settings are overridden by manager communication settings.
|
@@ -228,7 +229,9 @@ class TaskVineExecutor(BlockProviderExecutor, putils.RepresentationMixin):
|
|
228
229
|
# factory logs go with manager logs regardless
|
229
230
|
self.factory_config.scratch_dir = self.manager_config.vine_log_dir
|
230
231
|
logger.debug(f"Function data directory: {self._function_data_dir}, log directory: {log_dir}")
|
231
|
-
logger.debug(
|
232
|
+
logger.debug(
|
233
|
+
f"TaskVine manager log directory: {self.manager_config.vine_log_dir}, "
|
234
|
+
f"factory log directory: {self.factory_config.scratch_dir}")
|
232
235
|
|
233
236
|
def start(self):
|
234
237
|
"""Create submit process and collector thread to create, send, and
|
@@ -376,6 +376,7 @@ def _taskvine_submit_wait(ready_task_queue=None,
|
|
376
376
|
task_out_file = parsl_file_name_to_vine_file[spec.parsl_name]
|
377
377
|
else:
|
378
378
|
task_out_file = m.declare_file(spec.parsl_name, cache=spec.cache, peer_transfer=True)
|
379
|
+
parsl_file_name_to_vine_file[spec.parsl_name] = task_out_file
|
379
380
|
t.add_output(task_out_file, spec.parsl_name)
|
380
381
|
|
381
382
|
# Submit the task to the TaskVine object
|
@@ -1,4 +1,3 @@
|
|
1
|
-
import socket
|
2
1
|
from dataclasses import dataclass
|
3
2
|
from typing import Optional
|
4
3
|
|
@@ -23,9 +22,9 @@ class TaskVineManagerConfig:
|
|
23
22
|
A value of 0 means TaskVine chooses any available port.
|
24
23
|
Default is VINE_DEFAULT_PORT.
|
25
24
|
|
26
|
-
address: str
|
25
|
+
address: Optional[str]
|
27
26
|
Address of the local machine.
|
28
|
-
|
27
|
+
If None, socket.gethostname() will be used to determine the address.
|
29
28
|
|
30
29
|
project_name: Optional[str]
|
31
30
|
If given, TaskVine will periodically report its status and performance
|
@@ -161,7 +160,7 @@ class TaskVineManagerConfig:
|
|
161
160
|
|
162
161
|
# Connection and communication settings
|
163
162
|
port: int = VINE_DEFAULT_PORT
|
164
|
-
address: str =
|
163
|
+
address: Optional[str] = None
|
165
164
|
project_name: Optional[str] = None
|
166
165
|
project_password_file: Optional[str] = None
|
167
166
|
|
@@ -2,7 +2,7 @@ import logging
|
|
2
2
|
import parsl
|
3
3
|
import time
|
4
4
|
import zmq
|
5
|
-
from typing import Dict, List, Sequence, Optional
|
5
|
+
from typing import Dict, List, Sequence, Optional, Union
|
6
6
|
|
7
7
|
from parsl.jobs.states import JobStatus, JobState
|
8
8
|
from parsl.jobs.strategy import Strategy
|
@@ -106,13 +106,14 @@ class PollItem:
|
|
106
106
|
|
107
107
|
|
108
108
|
class JobStatusPoller(Timer):
|
109
|
-
def __init__(self, strategy: Optional[str]
|
109
|
+
def __init__(self, *, strategy: Optional[str], max_idletime: float,
|
110
|
+
strategy_period: Union[float, int],
|
110
111
|
dfk: Optional["parsl.dataflow.dflow.DataFlowKernel"] = None) -> None:
|
111
112
|
self._poll_items = [] # type: List[PollItem]
|
112
113
|
self.dfk = dfk
|
113
114
|
self._strategy = Strategy(strategy=strategy,
|
114
115
|
max_idletime=max_idletime)
|
115
|
-
super().__init__(self.poll, interval=
|
116
|
+
super().__init__(self.poll, interval=strategy_period, name="JobStatusPoller")
|
116
117
|
|
117
118
|
def poll(self) -> None:
|
118
119
|
self._update_state()
|