cars 1.0.0rc2__cp312-cp312-win_amd64.whl
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.
Potentially problematic release.
This version of cars might be problematic. Click here for more details.
- cars/__init__.py +86 -0
- cars/applications/__init__.py +40 -0
- cars/applications/application.py +117 -0
- cars/applications/application_constants.py +29 -0
- cars/applications/application_template.py +146 -0
- cars/applications/auxiliary_filling/__init__.py +29 -0
- cars/applications/auxiliary_filling/abstract_auxiliary_filling_app.py +105 -0
- cars/applications/auxiliary_filling/auxiliary_filling_algo.py +475 -0
- cars/applications/auxiliary_filling/auxiliary_filling_from_sensors_app.py +632 -0
- cars/applications/auxiliary_filling/auxiliary_filling_wrappers.py +90 -0
- cars/applications/dem_generation/__init__.py +30 -0
- cars/applications/dem_generation/abstract_dem_generation_app.py +116 -0
- cars/applications/dem_generation/bulldozer_config/base_config.yaml +42 -0
- cars/applications/dem_generation/bulldozer_dem_app.py +641 -0
- cars/applications/dem_generation/bulldozer_memory.py +55 -0
- cars/applications/dem_generation/dem_generation_algo.py +107 -0
- cars/applications/dem_generation/dem_generation_constants.py +32 -0
- cars/applications/dem_generation/dem_generation_wrappers.py +323 -0
- cars/applications/dense_match_filling/__init__.py +30 -0
- cars/applications/dense_match_filling/abstract_dense_match_filling_app.py +242 -0
- cars/applications/dense_match_filling/fill_disp_algo.py +113 -0
- cars/applications/dense_match_filling/fill_disp_constants.py +39 -0
- cars/applications/dense_match_filling/fill_disp_wrappers.py +83 -0
- cars/applications/dense_match_filling/zero_padding_app.py +302 -0
- cars/applications/dense_matching/__init__.py +30 -0
- cars/applications/dense_matching/abstract_dense_matching_app.py +261 -0
- cars/applications/dense_matching/census_mccnn_sgm_app.py +1461 -0
- cars/applications/dense_matching/cpp/__init__.py +0 -0
- cars/applications/dense_matching/cpp/dense_matching_cpp.cp312-win_amd64.dll.a +0 -0
- cars/applications/dense_matching/cpp/dense_matching_cpp.cp312-win_amd64.pyd +0 -0
- cars/applications/dense_matching/cpp/dense_matching_cpp.py +94 -0
- cars/applications/dense_matching/cpp/includes/dense_matching.hpp +58 -0
- cars/applications/dense_matching/cpp/meson.build +9 -0
- cars/applications/dense_matching/cpp/src/bindings.cpp +13 -0
- cars/applications/dense_matching/cpp/src/dense_matching.cpp +207 -0
- cars/applications/dense_matching/dense_matching_algo.py +401 -0
- cars/applications/dense_matching/dense_matching_constants.py +89 -0
- cars/applications/dense_matching/dense_matching_wrappers.py +951 -0
- cars/applications/dense_matching/disparity_grid_algo.py +597 -0
- cars/applications/dense_matching/loaders/__init__.py +23 -0
- cars/applications/dense_matching/loaders/config_census_sgm_default.json +31 -0
- cars/applications/dense_matching/loaders/config_census_sgm_homogeneous.json +30 -0
- cars/applications/dense_matching/loaders/config_census_sgm_mountain_and_vegetation.json +30 -0
- cars/applications/dense_matching/loaders/config_census_sgm_shadow.json +30 -0
- cars/applications/dense_matching/loaders/config_census_sgm_sparse.json +36 -0
- cars/applications/dense_matching/loaders/config_census_sgm_urban.json +30 -0
- cars/applications/dense_matching/loaders/config_mapping.json +13 -0
- cars/applications/dense_matching/loaders/config_mccnn.json +28 -0
- cars/applications/dense_matching/loaders/global_land_cover_map.tif +0 -0
- cars/applications/dense_matching/loaders/pandora_loader.py +593 -0
- cars/applications/dsm_filling/__init__.py +32 -0
- cars/applications/dsm_filling/abstract_dsm_filling_app.py +101 -0
- cars/applications/dsm_filling/border_interpolation_app.py +278 -0
- cars/applications/dsm_filling/bulldozer_config/base_config.yaml +44 -0
- cars/applications/dsm_filling/bulldozer_filling_app.py +288 -0
- cars/applications/dsm_filling/exogenous_filling_app.py +341 -0
- cars/applications/dsm_merging/__init__.py +28 -0
- cars/applications/dsm_merging/abstract_dsm_merging_app.py +101 -0
- cars/applications/dsm_merging/weighted_fusion_app.py +639 -0
- cars/applications/grid_correction/__init__.py +30 -0
- cars/applications/grid_correction/abstract_grid_correction_app.py +103 -0
- cars/applications/grid_correction/grid_correction_app.py +557 -0
- cars/applications/grid_generation/__init__.py +30 -0
- cars/applications/grid_generation/abstract_grid_generation_app.py +142 -0
- cars/applications/grid_generation/epipolar_grid_generation_app.py +327 -0
- cars/applications/grid_generation/grid_generation_algo.py +388 -0
- cars/applications/grid_generation/grid_generation_constants.py +46 -0
- cars/applications/grid_generation/transform_grid.py +88 -0
- cars/applications/ground_truth_reprojection/__init__.py +30 -0
- cars/applications/ground_truth_reprojection/abstract_ground_truth_reprojection_app.py +137 -0
- cars/applications/ground_truth_reprojection/direct_localization_app.py +629 -0
- cars/applications/ground_truth_reprojection/ground_truth_reprojection_algo.py +275 -0
- cars/applications/point_cloud_outlier_removal/__init__.py +30 -0
- cars/applications/point_cloud_outlier_removal/abstract_outlier_removal_app.py +385 -0
- cars/applications/point_cloud_outlier_removal/outlier_removal_algo.py +392 -0
- cars/applications/point_cloud_outlier_removal/outlier_removal_constants.py +43 -0
- cars/applications/point_cloud_outlier_removal/small_components_app.py +522 -0
- cars/applications/point_cloud_outlier_removal/statistical_app.py +528 -0
- cars/applications/rasterization/__init__.py +30 -0
- cars/applications/rasterization/abstract_pc_rasterization_app.py +183 -0
- cars/applications/rasterization/rasterization_algo.py +534 -0
- cars/applications/rasterization/rasterization_constants.py +38 -0
- cars/applications/rasterization/rasterization_wrappers.py +639 -0
- cars/applications/rasterization/simple_gaussian_app.py +1152 -0
- cars/applications/resampling/__init__.py +28 -0
- cars/applications/resampling/abstract_resampling_app.py +187 -0
- cars/applications/resampling/bicubic_resampling_app.py +760 -0
- cars/applications/resampling/resampling_algo.py +590 -0
- cars/applications/resampling/resampling_constants.py +36 -0
- cars/applications/resampling/resampling_wrappers.py +309 -0
- cars/applications/sensors_subsampling/__init__.py +32 -0
- cars/applications/sensors_subsampling/abstract_subsampling_app.py +109 -0
- cars/applications/sensors_subsampling/rasterio_subsampling_app.py +420 -0
- cars/applications/sensors_subsampling/subsampling_algo.py +108 -0
- cars/applications/sparse_matching/__init__.py +30 -0
- cars/applications/sparse_matching/abstract_sparse_matching_app.py +599 -0
- cars/applications/sparse_matching/sift_app.py +724 -0
- cars/applications/sparse_matching/sparse_matching_algo.py +360 -0
- cars/applications/sparse_matching/sparse_matching_constants.py +66 -0
- cars/applications/sparse_matching/sparse_matching_wrappers.py +282 -0
- cars/applications/triangulation/__init__.py +32 -0
- cars/applications/triangulation/abstract_triangulation_app.py +227 -0
- cars/applications/triangulation/line_of_sight_intersection_app.py +1243 -0
- cars/applications/triangulation/pc_transform.py +552 -0
- cars/applications/triangulation/triangulation_algo.py +371 -0
- cars/applications/triangulation/triangulation_constants.py +38 -0
- cars/applications/triangulation/triangulation_wrappers.py +259 -0
- cars/bundleadjustment.py +750 -0
- cars/cars.py +179 -0
- cars/conf/__init__.py +23 -0
- cars/conf/geoid/egm96.grd +0 -0
- cars/conf/geoid/egm96.grd.hdr +15 -0
- cars/conf/input_parameters.py +156 -0
- cars/conf/mask_cst.py +35 -0
- cars/core/__init__.py +23 -0
- cars/core/cars_logging.py +402 -0
- cars/core/constants.py +191 -0
- cars/core/constants_disparity.py +50 -0
- cars/core/datasets.py +140 -0
- cars/core/geometry/__init__.py +27 -0
- cars/core/geometry/abstract_geometry.py +1119 -0
- cars/core/geometry/shareloc_geometry.py +598 -0
- cars/core/inputs.py +568 -0
- cars/core/outputs.py +176 -0
- cars/core/preprocessing.py +722 -0
- cars/core/projection.py +843 -0
- cars/core/roi_tools.py +215 -0
- cars/core/tiling.py +774 -0
- cars/core/utils.py +164 -0
- cars/data_structures/__init__.py +23 -0
- cars/data_structures/cars_dataset.py +1544 -0
- cars/data_structures/cars_dict.py +74 -0
- cars/data_structures/corresponding_tiles_tools.py +186 -0
- cars/data_structures/dataframe_converter.py +185 -0
- cars/data_structures/format_transformation.py +297 -0
- cars/devibrate.py +689 -0
- cars/extractroi.py +264 -0
- cars/orchestrator/__init__.py +23 -0
- cars/orchestrator/achievement_tracker.py +125 -0
- cars/orchestrator/cluster/__init__.py +37 -0
- cars/orchestrator/cluster/abstract_cluster.py +250 -0
- cars/orchestrator/cluster/abstract_dask_cluster.py +381 -0
- cars/orchestrator/cluster/dask_cluster_tools.py +103 -0
- cars/orchestrator/cluster/dask_config/README.md +94 -0
- cars/orchestrator/cluster/dask_config/dask.yaml +21 -0
- cars/orchestrator/cluster/dask_config/distributed.yaml +70 -0
- cars/orchestrator/cluster/dask_config/jobqueue.yaml +26 -0
- cars/orchestrator/cluster/dask_config/reference_confs/dask-schema.yaml +137 -0
- cars/orchestrator/cluster/dask_config/reference_confs/dask.yaml +26 -0
- cars/orchestrator/cluster/dask_config/reference_confs/distributed-schema.yaml +1009 -0
- cars/orchestrator/cluster/dask_config/reference_confs/distributed.yaml +273 -0
- cars/orchestrator/cluster/dask_config/reference_confs/jobqueue.yaml +212 -0
- cars/orchestrator/cluster/dask_jobqueue_utils.py +204 -0
- cars/orchestrator/cluster/local_dask_cluster.py +116 -0
- cars/orchestrator/cluster/log_wrapper.py +728 -0
- cars/orchestrator/cluster/mp_cluster/__init__.py +27 -0
- cars/orchestrator/cluster/mp_cluster/mp_factorizer.py +212 -0
- cars/orchestrator/cluster/mp_cluster/mp_objects.py +535 -0
- cars/orchestrator/cluster/mp_cluster/mp_tools.py +93 -0
- cars/orchestrator/cluster/mp_cluster/mp_wrapper.py +505 -0
- cars/orchestrator/cluster/mp_cluster/multiprocessing_cluster.py +986 -0
- cars/orchestrator/cluster/mp_cluster/multiprocessing_profiler.py +399 -0
- cars/orchestrator/cluster/pbs_dask_cluster.py +207 -0
- cars/orchestrator/cluster/sequential_cluster.py +139 -0
- cars/orchestrator/cluster/slurm_dask_cluster.py +234 -0
- cars/orchestrator/memory_tools.py +47 -0
- cars/orchestrator/orchestrator.py +755 -0
- cars/orchestrator/orchestrator_constants.py +29 -0
- cars/orchestrator/registry/__init__.py +23 -0
- cars/orchestrator/registry/abstract_registry.py +143 -0
- cars/orchestrator/registry/compute_registry.py +106 -0
- cars/orchestrator/registry/id_generator.py +116 -0
- cars/orchestrator/registry/replacer_registry.py +213 -0
- cars/orchestrator/registry/saver_registry.py +363 -0
- cars/orchestrator/registry/unseen_registry.py +118 -0
- cars/orchestrator/tiles_profiler.py +279 -0
- cars/pipelines/__init__.py +26 -0
- cars/pipelines/conf_resolution/conf_final_resolution.yaml +5 -0
- cars/pipelines/conf_resolution/conf_first_resolution.yaml +4 -0
- cars/pipelines/conf_resolution/conf_intermediate_resolution.yaml +2 -0
- cars/pipelines/default/__init__.py +26 -0
- cars/pipelines/default/default_pipeline.py +1088 -0
- cars/pipelines/filling/__init__.py +26 -0
- cars/pipelines/filling/filling.py +981 -0
- cars/pipelines/formatting/__init__.py +26 -0
- cars/pipelines/formatting/formatting.py +186 -0
- cars/pipelines/merging/__init__.py +26 -0
- cars/pipelines/merging/merging.py +439 -0
- cars/pipelines/parameters/__init__.py +0 -0
- cars/pipelines/parameters/advanced_parameters.py +256 -0
- cars/pipelines/parameters/advanced_parameters_constants.py +68 -0
- cars/pipelines/parameters/application_parameters.py +72 -0
- cars/pipelines/parameters/depth_map_inputs.py +0 -0
- cars/pipelines/parameters/dsm_inputs.py +349 -0
- cars/pipelines/parameters/dsm_inputs_constants.py +25 -0
- cars/pipelines/parameters/output_constants.py +52 -0
- cars/pipelines/parameters/output_parameters.py +438 -0
- cars/pipelines/parameters/sensor_inputs.py +859 -0
- cars/pipelines/parameters/sensor_inputs_constants.py +51 -0
- cars/pipelines/parameters/sensor_loaders/__init__.py +29 -0
- cars/pipelines/parameters/sensor_loaders/basic_classif_loader.py +86 -0
- cars/pipelines/parameters/sensor_loaders/basic_image_loader.py +98 -0
- cars/pipelines/parameters/sensor_loaders/pivot_classif_loader.py +90 -0
- cars/pipelines/parameters/sensor_loaders/pivot_image_loader.py +105 -0
- cars/pipelines/parameters/sensor_loaders/sensor_loader.py +93 -0
- cars/pipelines/parameters/sensor_loaders/sensor_loader_template.py +71 -0
- cars/pipelines/parameters/sensor_loaders/slurp_classif_loader.py +86 -0
- cars/pipelines/pipeline.py +119 -0
- cars/pipelines/pipeline_constants.py +38 -0
- cars/pipelines/pipeline_template.py +135 -0
- cars/pipelines/subsampling/__init__.py +26 -0
- cars/pipelines/subsampling/subsampling.py +358 -0
- cars/pipelines/surface_modeling/__init__.py +26 -0
- cars/pipelines/surface_modeling/surface_modeling.py +2098 -0
- cars/pipelines/tie_points/__init__.py +26 -0
- cars/pipelines/tie_points/tie_points.py +536 -0
- cars/starter.py +167 -0
- cars-1.0.0rc2.dist-info/DELVEWHEEL +2 -0
- cars-1.0.0rc2.dist-info/METADATA +289 -0
- cars-1.0.0rc2.dist-info/RECORD +225 -0
- cars-1.0.0rc2.dist-info/WHEEL +4 -0
- cars-1.0.0rc2.dist-info/entry_points.txt +8 -0
- cars.libs/libgcc_s_seh-1-b2494fcbd4d80cf2c98fdd5261f6d850.dll +0 -0
- cars.libs/libstdc++-6-e9b0d12ae0e9555bbae55e8dfd08c3f7.dll +0 -0
- cars.libs/libwinpthread-1-7882d1b093714ccdfaf4e0789a817792.dll +0 -0
|
@@ -0,0 +1,399 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
# coding: utf8
|
|
3
|
+
#
|
|
4
|
+
# Copyright (c) 2020 Centre National d'Etudes Spatiales (CNES).
|
|
5
|
+
#
|
|
6
|
+
# This file is part of CARS
|
|
7
|
+
# (see https://github.com/CNES/cars).
|
|
8
|
+
#
|
|
9
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
10
|
+
# you may not use this file except in compliance with the License.
|
|
11
|
+
# You may obtain a copy of the License at
|
|
12
|
+
#
|
|
13
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
14
|
+
#
|
|
15
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
16
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
17
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
18
|
+
# See the License for the specific language governing permissions and
|
|
19
|
+
# limitations under the License.
|
|
20
|
+
#
|
|
21
|
+
"""
|
|
22
|
+
Contains multiprocessing_profiler class
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
import logging
|
|
26
|
+
import os
|
|
27
|
+
import threading
|
|
28
|
+
import time
|
|
29
|
+
|
|
30
|
+
import matplotlib
|
|
31
|
+
import matplotlib.pyplot as plt
|
|
32
|
+
import pandas as pd
|
|
33
|
+
import psutil
|
|
34
|
+
|
|
35
|
+
# Agg backend for non interactive
|
|
36
|
+
matplotlib.use("Agg")
|
|
37
|
+
|
|
38
|
+
TERMINATE = 1
|
|
39
|
+
RUN = 0
|
|
40
|
+
RAM_PER_WORKER_CHECK_SLEEP_TIME = 2
|
|
41
|
+
INTERVAL_CPU = 0.2
|
|
42
|
+
SAVE_TIME = 120
|
|
43
|
+
|
|
44
|
+
TIME = "time"
|
|
45
|
+
MAIN_MEMORY = "main_memory"
|
|
46
|
+
MAX_PROCESS_MEMORY = "max_process_memory"
|
|
47
|
+
MAIN_AND_PROCESS = "main_and_processes"
|
|
48
|
+
TOTAL_PROCESS_MEMORY = "total_process_memory"
|
|
49
|
+
AVAILABLE_RAM = "available_ram"
|
|
50
|
+
TOTAL_RAM = "total_ram"
|
|
51
|
+
|
|
52
|
+
MAIN_CPU_USAGE = "main_cpu_usage"
|
|
53
|
+
TOTAL_PROCESS_CPU_USAGE = "total Proces_cpu_usage"
|
|
54
|
+
MAIN_AND_PROCESS_CPU = "main_and_process_cpu"
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
class Timer: # pylint: disable=too-few-public-methods
|
|
58
|
+
"""
|
|
59
|
+
Start time
|
|
60
|
+
"""
|
|
61
|
+
|
|
62
|
+
def __init__(self):
|
|
63
|
+
"""
|
|
64
|
+
Init
|
|
65
|
+
"""
|
|
66
|
+
self.timer = time.time()
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
class MultiprocessingProfiler: # pylint: disable=too-few-public-methods
|
|
70
|
+
"""
|
|
71
|
+
MultiprocessingProfiler
|
|
72
|
+
|
|
73
|
+
Used to profile memory in processes
|
|
74
|
+
"""
|
|
75
|
+
|
|
76
|
+
def __init__( # pylint: disable=too-many-positional-arguments
|
|
77
|
+
self, pool, out_dir, max_ram_per_worker, mp_dataframe=None, timer=None
|
|
78
|
+
):
|
|
79
|
+
"""
|
|
80
|
+
Init function of MultiprocessingProfiler
|
|
81
|
+
|
|
82
|
+
:param pool: pool process to monitor
|
|
83
|
+
:param out_dir: out_dir to save graph
|
|
84
|
+
:param max_ram_per_worker: max ram per worker to use
|
|
85
|
+
"""
|
|
86
|
+
|
|
87
|
+
self.main_pid = os.getpid()
|
|
88
|
+
self.pool = pool
|
|
89
|
+
self.out_dir = out_dir
|
|
90
|
+
self.file_plot = os.path.join(
|
|
91
|
+
self.out_dir, "profiling", "memory_profiling.png"
|
|
92
|
+
)
|
|
93
|
+
os.makedirs(os.path.dirname(self.file_plot), exist_ok=True)
|
|
94
|
+
self.max_ram_per_worker = max_ram_per_worker
|
|
95
|
+
|
|
96
|
+
if mp_dataframe is not None and timer is not None:
|
|
97
|
+
self.memory_data = mp_dataframe
|
|
98
|
+
self.timer = timer
|
|
99
|
+
else:
|
|
100
|
+
self.timer = Timer()
|
|
101
|
+
self.memory_data = pd.DataFrame(
|
|
102
|
+
columns=[
|
|
103
|
+
TIME,
|
|
104
|
+
MAIN_MEMORY,
|
|
105
|
+
MAX_PROCESS_MEMORY,
|
|
106
|
+
MAIN_AND_PROCESS,
|
|
107
|
+
TOTAL_PROCESS_MEMORY,
|
|
108
|
+
AVAILABLE_RAM,
|
|
109
|
+
TOTAL_RAM,
|
|
110
|
+
MAIN_CPU_USAGE,
|
|
111
|
+
TOTAL_PROCESS_CPU_USAGE,
|
|
112
|
+
MAIN_AND_PROCESS_CPU,
|
|
113
|
+
]
|
|
114
|
+
)
|
|
115
|
+
|
|
116
|
+
# Memory usage of Pool
|
|
117
|
+
self.monitor_thread = threading.Thread(
|
|
118
|
+
target=check_pool_memory_usage,
|
|
119
|
+
args=(
|
|
120
|
+
self.main_pid,
|
|
121
|
+
self.pool,
|
|
122
|
+
self.max_ram_per_worker,
|
|
123
|
+
self.memory_data,
|
|
124
|
+
self.timer,
|
|
125
|
+
),
|
|
126
|
+
)
|
|
127
|
+
self.monitor_thread.daemon = True
|
|
128
|
+
self.monitor_thread._state = RUN
|
|
129
|
+
self.monitor_thread.start()
|
|
130
|
+
|
|
131
|
+
self.saver_thread = threading.Thread(
|
|
132
|
+
target=save_figure_in_thread,
|
|
133
|
+
args=(self.memory_data, self.file_plot),
|
|
134
|
+
)
|
|
135
|
+
self.saver_thread.daemon = True
|
|
136
|
+
self.saver_thread._state = RUN
|
|
137
|
+
self.saver_thread.start()
|
|
138
|
+
|
|
139
|
+
def cleanup(self):
|
|
140
|
+
"""
|
|
141
|
+
Cleanup
|
|
142
|
+
"""
|
|
143
|
+
|
|
144
|
+
clean_thread(self.monitor_thread)
|
|
145
|
+
clean_thread(self.saver_thread)
|
|
146
|
+
|
|
147
|
+
def save_plot(self):
|
|
148
|
+
"""
|
|
149
|
+
Save plots
|
|
150
|
+
"""
|
|
151
|
+
logging.info("Save profiling plots ...")
|
|
152
|
+
try:
|
|
153
|
+
save_data(self.memory_data, self.file_plot)
|
|
154
|
+
except Exception as exc:
|
|
155
|
+
logging.warning("unable to save monitoring graph : {}".format(exc))
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
def clean_thread(thread):
|
|
159
|
+
"""
|
|
160
|
+
Clean thread
|
|
161
|
+
|
|
162
|
+
:param thread: thread to clean
|
|
163
|
+
"""
|
|
164
|
+
# Terminate worker
|
|
165
|
+
thread._state = TERMINATE # pylint: disable=W0212
|
|
166
|
+
while thread.is_alive():
|
|
167
|
+
time.sleep(0)
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
def get_process_memory(process):
|
|
171
|
+
"""
|
|
172
|
+
Get process current memory
|
|
173
|
+
|
|
174
|
+
:param process
|
|
175
|
+
|
|
176
|
+
:return: memory Mb
|
|
177
|
+
"""
|
|
178
|
+
return process.memory_info().rss / (1024 * 1024)
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
def get_cpu_usage(process):
|
|
182
|
+
"""
|
|
183
|
+
Get cpu usage
|
|
184
|
+
|
|
185
|
+
:param process: Process to monitor
|
|
186
|
+
"""
|
|
187
|
+
|
|
188
|
+
try:
|
|
189
|
+
cpu_usage = process.cpu_percent(interval=0.1)
|
|
190
|
+
except Exception:
|
|
191
|
+
cpu_usage = 0
|
|
192
|
+
|
|
193
|
+
return cpu_usage
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
def save_figure_in_thread(to_fill_dataframe, file_path):
|
|
197
|
+
"""
|
|
198
|
+
Save data during compute
|
|
199
|
+
|
|
200
|
+
:param to_fill_dataframe: dataframe to fill
|
|
201
|
+
:param file_path: path to save path
|
|
202
|
+
"""
|
|
203
|
+
|
|
204
|
+
thread = threading.current_thread()
|
|
205
|
+
|
|
206
|
+
start_time = time.time()
|
|
207
|
+
while thread._state == RUN: # pylint: disable=protected-access
|
|
208
|
+
time.sleep(RAM_PER_WORKER_CHECK_SLEEP_TIME)
|
|
209
|
+
if time.time() - start_time > SAVE_TIME:
|
|
210
|
+
start_time = time.time()
|
|
211
|
+
# Save file
|
|
212
|
+
try:
|
|
213
|
+
save_data(to_fill_dataframe, file_path)
|
|
214
|
+
except Exception as exc:
|
|
215
|
+
logging.warning(
|
|
216
|
+
"unable to save monitoring graph : {}".format(exc)
|
|
217
|
+
)
|
|
218
|
+
|
|
219
|
+
|
|
220
|
+
def check_pool_memory_usage(
|
|
221
|
+
main_process_id, pool, max_ram_per_worker, to_fill_dataframe, timer
|
|
222
|
+
):
|
|
223
|
+
"""
|
|
224
|
+
Check memory usage of each worker in pool
|
|
225
|
+
|
|
226
|
+
:param main_process_id: main process id
|
|
227
|
+
:param pool: pool of worker
|
|
228
|
+
:param max_ram_per_worker: max ram to use per worker
|
|
229
|
+
:param to_fill_dataframe: dataframe to fill
|
|
230
|
+
:param timer: timer
|
|
231
|
+
"""
|
|
232
|
+
|
|
233
|
+
thread = threading.current_thread()
|
|
234
|
+
|
|
235
|
+
main_process = psutil.Process(main_process_id)
|
|
236
|
+
start_time = timer.timer
|
|
237
|
+
|
|
238
|
+
while thread._state == RUN: # pylint: disable=protected-access
|
|
239
|
+
# Get time
|
|
240
|
+
current_time = time.time() - start_time
|
|
241
|
+
minutes = current_time / 60
|
|
242
|
+
|
|
243
|
+
# Get available memory
|
|
244
|
+
ram = psutil.virtual_memory()
|
|
245
|
+
total_ram = ram.total / (1024 * 1024)
|
|
246
|
+
available = ram.available / (1024 * 1024)
|
|
247
|
+
|
|
248
|
+
# Check main process
|
|
249
|
+
main_current_memory = get_process_memory(main_process)
|
|
250
|
+
main_process_cpu = get_cpu_usage(main_process)
|
|
251
|
+
|
|
252
|
+
# Check workers
|
|
253
|
+
main_and_processes_total = main_current_memory
|
|
254
|
+
total_memory = 0
|
|
255
|
+
max_process_ram = 0
|
|
256
|
+
processes_cpu = 0
|
|
257
|
+
total_cpu = main_process_cpu
|
|
258
|
+
|
|
259
|
+
size_pool = len(pool._pool) # pylint: disable=protected-access
|
|
260
|
+
sleep_time = max(
|
|
261
|
+
0, RAM_PER_WORKER_CHECK_SLEEP_TIME - INTERVAL_CPU * size_pool
|
|
262
|
+
)
|
|
263
|
+
for worker in pool._pool: # pylint: disable=protected-access
|
|
264
|
+
pid = worker.pid
|
|
265
|
+
try:
|
|
266
|
+
process = psutil.Process(pid)
|
|
267
|
+
memory_usage_mb = get_process_memory(process)
|
|
268
|
+
|
|
269
|
+
# Add to metrics
|
|
270
|
+
max_process_ram = max(max_process_ram, memory_usage_mb)
|
|
271
|
+
total_memory += memory_usage_mb
|
|
272
|
+
processes_cpu += get_cpu_usage(process)
|
|
273
|
+
|
|
274
|
+
# Check memory to inform user
|
|
275
|
+
if memory_usage_mb > max_ram_per_worker:
|
|
276
|
+
logging.info(
|
|
277
|
+
"Process {} is using {} Mb > "
|
|
278
|
+
"max_ram_per_worker = {} Mb".format(
|
|
279
|
+
pid, memory_usage_mb, max_ram_per_worker
|
|
280
|
+
)
|
|
281
|
+
)
|
|
282
|
+
except psutil.NoSuchProcess:
|
|
283
|
+
# Process no longer exists
|
|
284
|
+
pass
|
|
285
|
+
|
|
286
|
+
main_and_processes_total += total_memory
|
|
287
|
+
available_ram_mb = main_and_processes_total + available
|
|
288
|
+
|
|
289
|
+
total_cpu += processes_cpu
|
|
290
|
+
|
|
291
|
+
# Add to dataframe
|
|
292
|
+
to_fill_dataframe.loc[len(to_fill_dataframe)] = [
|
|
293
|
+
minutes,
|
|
294
|
+
main_current_memory,
|
|
295
|
+
max_process_ram,
|
|
296
|
+
main_and_processes_total,
|
|
297
|
+
total_memory,
|
|
298
|
+
available_ram_mb,
|
|
299
|
+
total_ram,
|
|
300
|
+
main_process_cpu,
|
|
301
|
+
processes_cpu,
|
|
302
|
+
total_cpu,
|
|
303
|
+
]
|
|
304
|
+
|
|
305
|
+
time.sleep(sleep_time)
|
|
306
|
+
|
|
307
|
+
|
|
308
|
+
def save_data(dataframe, file_path):
|
|
309
|
+
"""
|
|
310
|
+
Save dataframe to disk
|
|
311
|
+
|
|
312
|
+
:param dataframe: file
|
|
313
|
+
:param file_path:
|
|
314
|
+
"""
|
|
315
|
+
|
|
316
|
+
fig, axs = plt.subplots(5, 1, figsize=(10, 25))
|
|
317
|
+
|
|
318
|
+
axs[0].set_title("Total memory used by CARS Mb")
|
|
319
|
+
axs[0].set_xlabel("Time (min)")
|
|
320
|
+
axs[0].set_ylabel("Memory (MB)")
|
|
321
|
+
dataframe.plot(
|
|
322
|
+
x=TIME,
|
|
323
|
+
y=MAIN_AND_PROCESS,
|
|
324
|
+
ax=axs[0],
|
|
325
|
+
label="Main + Processes memory",
|
|
326
|
+
color="blue",
|
|
327
|
+
)
|
|
328
|
+
dataframe.plot(
|
|
329
|
+
x=TIME, y=TOTAL_RAM, ax=axs[0], label="Machine max memory", color="red"
|
|
330
|
+
)
|
|
331
|
+
dataframe.plot(
|
|
332
|
+
x=TIME,
|
|
333
|
+
y=AVAILABLE_RAM,
|
|
334
|
+
ax=axs[0],
|
|
335
|
+
label=" total CARS + still Available memory",
|
|
336
|
+
color="green",
|
|
337
|
+
)
|
|
338
|
+
|
|
339
|
+
axs[1].set_title("Main CARS Process Memory Mb")
|
|
340
|
+
axs[1].set_xlabel("Time (min)")
|
|
341
|
+
axs[1].set_ylabel("Memory (MB)")
|
|
342
|
+
dataframe.plot(
|
|
343
|
+
x=TIME,
|
|
344
|
+
y=MAIN_MEMORY,
|
|
345
|
+
ax=axs[1],
|
|
346
|
+
label="CARS main process",
|
|
347
|
+
color="blue",
|
|
348
|
+
)
|
|
349
|
+
dataframe.plot(
|
|
350
|
+
x=TIME,
|
|
351
|
+
y=MAX_PROCESS_MEMORY,
|
|
352
|
+
ax=axs[1],
|
|
353
|
+
label="CARS max of workers ",
|
|
354
|
+
color="red",
|
|
355
|
+
)
|
|
356
|
+
|
|
357
|
+
axs[2].set_title("CARS workers Process Memory Mb")
|
|
358
|
+
axs[2].set_xlabel("Time (min)")
|
|
359
|
+
axs[2].set_ylabel("Memory (MB)")
|
|
360
|
+
dataframe.plot(
|
|
361
|
+
x=TIME,
|
|
362
|
+
y=TOTAL_PROCESS_MEMORY,
|
|
363
|
+
ax=axs[2],
|
|
364
|
+
label="Total Process Memory",
|
|
365
|
+
color="blue",
|
|
366
|
+
)
|
|
367
|
+
|
|
368
|
+
axs[3].set_title("CARS CPU Usage")
|
|
369
|
+
axs[3].set_xlabel("Time (min)")
|
|
370
|
+
axs[3].set_ylabel("CPU (%")
|
|
371
|
+
dataframe.plot(
|
|
372
|
+
x=TIME,
|
|
373
|
+
y=TOTAL_PROCESS_CPU_USAGE,
|
|
374
|
+
ax=axs[3],
|
|
375
|
+
label="Total Process CPU ",
|
|
376
|
+
color="blue",
|
|
377
|
+
)
|
|
378
|
+
dataframe.plot(
|
|
379
|
+
x=TIME,
|
|
380
|
+
y=MAIN_AND_PROCESS_CPU,
|
|
381
|
+
ax=axs[3],
|
|
382
|
+
label="MAIN + Total Process CPU",
|
|
383
|
+
color="red",
|
|
384
|
+
)
|
|
385
|
+
|
|
386
|
+
axs[4].set_title("CARS CPU Usage of main process")
|
|
387
|
+
axs[4].set_xlabel("Time (min)")
|
|
388
|
+
axs[4].set_ylabel("CPU (%")
|
|
389
|
+
dataframe.plot(
|
|
390
|
+
x=TIME,
|
|
391
|
+
y=MAIN_CPU_USAGE,
|
|
392
|
+
ax=axs[4],
|
|
393
|
+
label="Main Process CPU ",
|
|
394
|
+
color="blue",
|
|
395
|
+
)
|
|
396
|
+
|
|
397
|
+
plt.savefig(file_path, format="png")
|
|
398
|
+
|
|
399
|
+
plt.close(fig)
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
# coding: utf8
|
|
3
|
+
#
|
|
4
|
+
# Copyright (c) 2020 Centre National d'Etudes Spatiales (CNES).
|
|
5
|
+
#
|
|
6
|
+
# This file is part of CARS
|
|
7
|
+
# (see https://github.com/CNES/cars).
|
|
8
|
+
#
|
|
9
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
10
|
+
# you may not use this file except in compliance with the License.
|
|
11
|
+
# You may obtain a copy of the License at
|
|
12
|
+
#
|
|
13
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
14
|
+
#
|
|
15
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
16
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
17
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
18
|
+
# See the License for the specific language governing permissions and
|
|
19
|
+
# limitations under the License.
|
|
20
|
+
#
|
|
21
|
+
"""
|
|
22
|
+
Contains abstract function for PBS dask Cluster
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
# Standard imports
|
|
26
|
+
import logging
|
|
27
|
+
import os
|
|
28
|
+
import warnings
|
|
29
|
+
|
|
30
|
+
# Third party imports
|
|
31
|
+
from dask.distributed import Client
|
|
32
|
+
|
|
33
|
+
from cars.orchestrator.cluster.dask_cluster_tools import (
|
|
34
|
+
check_configuration,
|
|
35
|
+
create_checker_schema,
|
|
36
|
+
)
|
|
37
|
+
from cars.orchestrator.cluster.dask_jobqueue_utils import (
|
|
38
|
+
get_dashboard_link,
|
|
39
|
+
init_cluster_variables,
|
|
40
|
+
stop_cluster,
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
with warnings.catch_warnings():
|
|
44
|
+
# Ignore some internal dask_jobqueue warnings
|
|
45
|
+
warnings.filterwarnings(
|
|
46
|
+
"ignore",
|
|
47
|
+
category=FutureWarning,
|
|
48
|
+
message=".*format_bytes is deprecated.*",
|
|
49
|
+
)
|
|
50
|
+
warnings.filterwarnings(
|
|
51
|
+
"ignore",
|
|
52
|
+
category=FutureWarning,
|
|
53
|
+
message=".*parse_bytes is deprecated.*",
|
|
54
|
+
)
|
|
55
|
+
warnings.filterwarnings(
|
|
56
|
+
"ignore",
|
|
57
|
+
category=FutureWarning,
|
|
58
|
+
message=".*tmpfile is deprecated.*",
|
|
59
|
+
)
|
|
60
|
+
from dask_jobqueue import PBSCluster
|
|
61
|
+
|
|
62
|
+
# CARS imports
|
|
63
|
+
from cars.orchestrator.cluster import ( # pylint: disable=C0412
|
|
64
|
+
abstract_cluster,
|
|
65
|
+
abstract_dask_cluster,
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
@abstract_cluster.AbstractCluster.register_subclass("pbs_dask")
|
|
70
|
+
class PbsDaskCluster(abstract_dask_cluster.AbstractDaskCluster):
|
|
71
|
+
"""
|
|
72
|
+
PbsDaskCluster
|
|
73
|
+
"""
|
|
74
|
+
|
|
75
|
+
def check_conf(self, conf):
|
|
76
|
+
"""
|
|
77
|
+
Check configuration
|
|
78
|
+
|
|
79
|
+
:param conf: configuration to check
|
|
80
|
+
:type conf: dict
|
|
81
|
+
|
|
82
|
+
:return: overloaded configuration
|
|
83
|
+
:rtype: dict
|
|
84
|
+
|
|
85
|
+
"""
|
|
86
|
+
|
|
87
|
+
return check_configuration(*create_checker_schema(conf))
|
|
88
|
+
|
|
89
|
+
def start_dask_cluster(self):
|
|
90
|
+
"""
|
|
91
|
+
Start dask cluster
|
|
92
|
+
"""
|
|
93
|
+
|
|
94
|
+
return start_cluster(
|
|
95
|
+
self.nb_workers,
|
|
96
|
+
self.walltime,
|
|
97
|
+
self.out_dir,
|
|
98
|
+
activate_dashboard=self.activate_dashboard,
|
|
99
|
+
python=self.python,
|
|
100
|
+
)
|
|
101
|
+
|
|
102
|
+
def cleanup(self):
|
|
103
|
+
"""
|
|
104
|
+
Cleanup cluster
|
|
105
|
+
|
|
106
|
+
"""
|
|
107
|
+
stop_cluster(self.cluster, self.client)
|
|
108
|
+
logging.info("Dask cluster closed")
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
def start_cluster( # pylint: disable=too-many-positional-arguments
|
|
112
|
+
nb_workers,
|
|
113
|
+
walltime,
|
|
114
|
+
out_dir,
|
|
115
|
+
timeout=600,
|
|
116
|
+
activate_dashboard=False,
|
|
117
|
+
python=None,
|
|
118
|
+
):
|
|
119
|
+
"""Create a Dask cluster.
|
|
120
|
+
|
|
121
|
+
Each worker will be spawned in an independent job with a single CPU
|
|
122
|
+
allocated to it, and will use a single process. This is done to maximize
|
|
123
|
+
CPU utilization and minimize scheduling delay.
|
|
124
|
+
|
|
125
|
+
The CARS_PBS_QUEUE environment variable, if defined, is used to specify the
|
|
126
|
+
queue in which worker jobs are scheduled.
|
|
127
|
+
|
|
128
|
+
:param nb_workers: Number of dask workers
|
|
129
|
+
:type nb_workers: int
|
|
130
|
+
:param walltime: Walltime for each dask worker
|
|
131
|
+
:type walltime: string
|
|
132
|
+
:param out_dir: Output directory
|
|
133
|
+
:type out_dir: string
|
|
134
|
+
:return: Dask cluster and dask client
|
|
135
|
+
:rtype: (dask_jobqueue.PBSCluster, dask.distributed.Client) tuple
|
|
136
|
+
"""
|
|
137
|
+
|
|
138
|
+
(
|
|
139
|
+
python,
|
|
140
|
+
nb_workers_per_job,
|
|
141
|
+
memory,
|
|
142
|
+
nb_cpus,
|
|
143
|
+
stagger,
|
|
144
|
+
lifetime_with_margin,
|
|
145
|
+
scheduler_options,
|
|
146
|
+
envs,
|
|
147
|
+
log_directory,
|
|
148
|
+
local_directory,
|
|
149
|
+
) = init_cluster_variables(
|
|
150
|
+
nb_workers,
|
|
151
|
+
walltime,
|
|
152
|
+
out_dir,
|
|
153
|
+
activate_dashboard,
|
|
154
|
+
python,
|
|
155
|
+
core_memory=5000,
|
|
156
|
+
cluster_name="PBS",
|
|
157
|
+
)
|
|
158
|
+
|
|
159
|
+
# Retrieve PBS queue
|
|
160
|
+
pbs_queue = os.environ.get("CARS_PBS_QUEUE")
|
|
161
|
+
|
|
162
|
+
with warnings.catch_warnings():
|
|
163
|
+
# Ignore some internal dask_jobqueue warnings
|
|
164
|
+
# TODO remove when Future warning do not exist anymore
|
|
165
|
+
warnings.filterwarnings(
|
|
166
|
+
"ignore",
|
|
167
|
+
category=FutureWarning,
|
|
168
|
+
message=".*extra has been renamed to worker_extra_args*",
|
|
169
|
+
)
|
|
170
|
+
warnings.filterwarnings(
|
|
171
|
+
"ignore",
|
|
172
|
+
category=FutureWarning,
|
|
173
|
+
message=".*job_extra has been renamed to job_extra_directives*",
|
|
174
|
+
)
|
|
175
|
+
warnings.filterwarnings(
|
|
176
|
+
"ignore",
|
|
177
|
+
category=FutureWarning,
|
|
178
|
+
message=".*env_extra has been renamed to job_script_prologue*",
|
|
179
|
+
)
|
|
180
|
+
cluster = PBSCluster(
|
|
181
|
+
processes=nb_workers_per_job,
|
|
182
|
+
cores=nb_workers_per_job,
|
|
183
|
+
memory="{}MiB".format(memory),
|
|
184
|
+
local_directory=local_directory,
|
|
185
|
+
account="dask-test",
|
|
186
|
+
walltime=walltime,
|
|
187
|
+
interface="ib0",
|
|
188
|
+
queue=pbs_queue,
|
|
189
|
+
job_script_prologue=envs,
|
|
190
|
+
log_directory=log_directory,
|
|
191
|
+
python=python,
|
|
192
|
+
worker_extra_args=[
|
|
193
|
+
"--lifetime",
|
|
194
|
+
f"{int(lifetime_with_margin.total_seconds())}s",
|
|
195
|
+
"--lifetime-stagger",
|
|
196
|
+
f"{int(stagger.total_seconds())}s",
|
|
197
|
+
],
|
|
198
|
+
scheduler_options=scheduler_options,
|
|
199
|
+
resource_spec="select=1:ncpus={}:mem={}MB".format(nb_cpus, memory),
|
|
200
|
+
)
|
|
201
|
+
logging.info("Dask cluster started")
|
|
202
|
+
cluster.adapt(minimum=nb_workers, maximum=nb_workers)
|
|
203
|
+
client = Client(cluster, timeout=timeout)
|
|
204
|
+
logging.info(
|
|
205
|
+
"Dashboard started at {}".format(get_dashboard_link(cluster))
|
|
206
|
+
)
|
|
207
|
+
return cluster, client
|