Skip to content
This repository was archived by the owner on Aug 28, 2023. It is now read-only.

Commit cbf5064

Browse files
author
Artyom Tugaryov
authored
[80000] Instant profiling assets sharing in DevCloud (#11)
1 parent e18e08b commit cbf5064

File tree

66 files changed

+651
-489
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

66 files changed

+651
-489
lines changed

automation/bom/image_BOM.txt

+4-1
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ migrations/versions/1e1c4fc30e7c_add_accuracy_import.py
3838
migrations/versions/2133a18b601e_load_text_dataset_support.py
3939
migrations/versions/241ced8ef5aa_create_project_report_pipeline.py
4040
migrations/versions/260ffba4b041_create_inference_report_pipeline.py
41+
migrations/versions/275bd4d6cd35_instant_assets_sharing.py
4142
migrations/versions/2a070ca81f20_tensor_distance_report_query_api.py
4243
migrations/versions/39bd11960375_edge_node_script_in_deployment.py
4344
migrations/versions/424ed0531227_add_annotate_dataset_job.py
@@ -536,13 +537,14 @@ wb/main/models/analyze_model_input_shape_job_model.py
536537
wb/main/models/apply_model_layout_model.py
537538
wb/main/models/artifacts_model.py
538539
wb/main/models/base_model.py
540+
wb/main/models/cloud_bundle_model.py
539541
wb/main/models/convert_dataset_jobs_model.py
540542
wb/main/models/convert_keras_job_model.py
541543
wb/main/models/cpu_info_model.py
542544
wb/main/models/create_accuracy_bundle_job_model.py
543545
wb/main/models/create_accuracy_scripts_job_model.py
546+
wb/main/models/create_int8_calibration_bundle_job_model.py
544547
wb/main/models/create_int8_calibration_scripts_job_model.py
545-
wb/main/models/create_int8calibration_bundle_job_model.py
546548
wb/main/models/create_profiling_bundle_job_model.py
547549
wb/main/models/create_profiling_scripts_job_model.py
548550
wb/main/models/create_reshape_model_scripts_model.py
@@ -599,6 +601,7 @@ wb/main/models/remote_target_model.py
599601
wb/main/models/reshape_model_job_model.py
600602
wb/main/models/setup_environment_job_model.py
601603
wb/main/models/setup_target_jobs_model.py
604+
wb/main/models/shared_artifact_model.py
602605
wb/main/models/single_inference_info_model.py
603606
wb/main/models/system_resources_model.py
604607
wb/main/models/target_model.py

config/constants.py

+5
Original file line numberDiff line numberDiff line change
@@ -160,12 +160,16 @@
160160
CLOUD_SERVICE_URL = get_env_var(name='CLOUD_SERVICE_URL')
161161
CLOUD_SERVICE_HOST = None
162162
CLOUD_SERVICE_PORT = None
163+
CLOUD_SHARED_FOLDER = None
163164
# dev cloud session duration in minutes
164165
CLOUD_SERVICE_SESSION_TTL_MINUTES = None
165166

166167
if CLOUD_SERVICE_URL:
167168
CLOUD_SERVICE_HOST, CLOUD_SERVICE_PORT = parse_host_port_from_url(CLOUD_SERVICE_URL)
168169
CLOUD_SERVICE_SESSION_TTL_MINUTES = get_env_var(name='CLOUD_SERVICE_SESSION_TTL_MINUTES', cast_function=int)
170+
CLOUD_SHARED_FOLDER = os.path.join(ESSENTIAL_DATA_FOLDER, 'bundles')
171+
172+
SETUP_BUNDLE_SUBFOLDER = 'setup_bundle'
169173

170174
WORKBENCH_NETWORK_ALIAS = get_env_var(name='NETWORK_ALIAS', default='localhost')
171175

@@ -251,6 +255,7 @@
251255
ENABLED_FEATURE_PREVIEW_FILE = Path(ROOT_FOLDER) / '.features.json'
252256

253257
FOLDER_PERMISSION = 0o775 # rwxrwxr-x
258+
FULL_ACCESS_FOLDER_PERMISSION = 0o777 # rwxrwxrwx
254259
FILE_PERMISSION = 0o664 # rw-rw-r--
255260

256261
DATASET_LABELS_PATH = os.path.join(ROOT_FOLDER, 'wb', 'main', 'accuracy_utils', 'yml_templates', 'datasets_labels')
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
"""Instant assets sharing
2+
3+
Revision ID: c2f12b313b48
4+
Revises: f7fcb58b99cd
5+
Create Date: 2022-03-01 13:48:42.551162
6+
7+
"""
8+
9+
"""
10+
OpenVINO DL Workbench
11+
Migration: Instant assets sharing
12+
13+
Copyright (c) 2022 Intel Corporation
14+
15+
LEGAL NOTICE: Your use of this software and any required dependent software (the “Software Package”) is subject to
16+
the terms and conditions of the software license agreements for Software Package, which may also include
17+
notices, disclaimers, or license terms for third party or open source software
18+
included in or with the Software Package, and your use indicates your acceptance of all such terms.
19+
Please refer to the “third-party-programs.txt” or other similarly-named text file included with the Software Package
20+
for additional details.
21+
You may obtain a copy of the License at
22+
https://software.intel.com/content/dam/develop/external/us/en/documents/intel-openvino-license-agreements.pdf
23+
"""
24+
from alembic import op
25+
import sqlalchemy as sa
26+
27+
# revision identifiers, used by Alembic.
28+
revision = 'c2f12b313b48'
29+
down_revision = 'f7fcb58b99cd'
30+
branch_labels = None
31+
depends_on = None
32+
33+
34+
def upgrade():
35+
op.rename_table('downloadable_artifacts', 'shared_artifacts')
36+
op.drop_column('create_profiling_bundle_jobs', 'tab_id')
37+
38+
op.execute("UPDATE artifacts SET type='downloadable_artifact' WHERE type='downloadable_artifacts';")
39+
40+
op.execute("UPDATE shared_artifacts SET job_id=create_profiling_bundle_jobs.job_id FROM create_profiling_bundle_jobs WHERE shared_artifacts.id=create_profiling_bundle_jobs.bundle_id;")
41+
# Connect bundles from downloadable_artifacts with jobs throw job_id instead of bundle_id
42+
op.execute("UPDATE shared_artifacts SET job_id=create_profiling_bundle_jobs.job_id FROM create_profiling_bundle_jobs WHERE shared_artifacts.id=create_profiling_bundle_jobs.bundle_id;")
43+
op.drop_constraint('create_profiling_bundle_jobs_bundle_id_fkey', 'create_profiling_bundle_jobs', type_='foreignkey')
44+
op.drop_column('create_profiling_bundle_jobs', 'bundle_id')
45+
46+
op.execute("UPDATE shared_artifacts SET job_id=create_int8_calibration_bundle_jobs.job_id FROM create_int8_calibration_bundle_jobs WHERE shared_artifacts.id=create_int8_calibration_bundle_jobs.bundle_id;")
47+
op.drop_constraint('create_int8_calibration_bundle_jobs_bundle_id_fkey', 'create_int8_calibration_bundle_jobs',
48+
type_='foreignkey')
49+
op.drop_column('create_int8_calibration_bundle_jobs', 'bundle_id')
50+
51+
op.execute("UPDATE shared_artifacts SET job_id=create_accuracy_bundle_jobs.job_id FROM create_accuracy_bundle_jobs WHERE shared_artifacts.id=create_accuracy_bundle_jobs.bundle_id;")
52+
op.drop_constraint('create_accuracy_bundle_jobs_bundle_id_fkey', 'create_accuracy_bundle_jobs', type_='foreignkey')
53+
op.drop_column('create_accuracy_bundle_jobs', 'bundle_id')
54+
55+
op.execute("UPDATE shared_artifacts SET job_id=create_annotate_dataset_bundle_jobs.job_id FROM create_annotate_dataset_bundle_jobs WHERE shared_artifacts.id=create_annotate_dataset_bundle_jobs.bundle_id;")
56+
op.drop_constraint('create_annotate_dataset_bundle_jobs_bundle_id_fkey', 'create_annotate_dataset_bundle_jobs',
57+
type_='foreignkey')
58+
op.drop_column('create_annotate_dataset_bundle_jobs', 'bundle_id')
59+
60+
op.execute("UPDATE shared_artifacts SET job_id=create_per_tensor_bundle_jobs.job_id FROM create_per_tensor_bundle_jobs WHERE shared_artifacts.id=create_per_tensor_bundle_jobs.bundle_id;")
61+
op.drop_constraint('create_per_tensor_bundle_jobs_bundle_id_fkey', 'create_per_tensor_bundle_jobs',
62+
type_='foreignkey')
63+
op.drop_column('create_per_tensor_bundle_jobs', 'bundle_id')
64+
65+
op.add_column('parse_dev_cloud_result_jobs', sa.Column('are_results_obtained', sa.Boolean(), nullable=True))
66+
op.alter_column('parse_dev_cloud_result_jobs', 'result_artifact_id', existing_type=sa.INTEGER(), nullable=True)
67+
68+
op.drop_constraint('parse_dev_cloud_result_jobs_result_artifact_id_fkey', 'parse_dev_cloud_result_jobs',
69+
type_='foreignkey')
70+
op.create_foreign_key(None, 'parse_dev_cloud_result_jobs', 'shared_artifacts', ['result_artifact_id'], ['id'])
71+
72+
op.drop_constraint('trigger_dev_cloud_jobs_job_bundle_id_fkey', 'trigger_dev_cloud_jobs', type_='foreignkey')
73+
op.drop_constraint('trigger_dev_cloud_profiling_jobs_setup_bundle_id_fkey', 'trigger_dev_cloud_jobs',
74+
type_='foreignkey')
75+
op.create_foreign_key(None, 'trigger_dev_cloud_jobs', 'shared_artifacts', ['job_bundle_id'], ['id'])
76+
op.create_foreign_key(None, 'trigger_dev_cloud_jobs', 'shared_artifacts', ['setup_bundle_id'], ['id'])
77+
op.drop_constraint('upload_artifact_to_target_jobs_artifact_id_fkey', 'upload_artifact_to_target_jobs',
78+
type_='foreignkey')
79+
op.create_foreign_key(None, 'upload_artifact_to_target_jobs', 'shared_artifacts', ['artifact_id'], ['id'])
80+
81+
# ### end Alembic commands ###
82+
83+
84+
def downgrade():
85+
raise NotImplementedError(f'Downgrade is not implemented for the {revision} migration')

wb/main/api_endpoints/utils.py

-44
Original file line numberDiff line numberDiff line change
@@ -160,53 +160,9 @@ def delete_model_from_db(model_id: int):
160160

161161

162162
def delete_dataset_from_db(dataset_id: int):
163-
for records in dataset_related_information(dataset_id):
164-
DatasetsModel.delete_records(records, get_db_session_for_app())
165-
166163
dataset = DatasetsModel.query.get(dataset_id)
167-
168164
if dataset:
169-
dataset_path = dataset.path
170165
dataset.delete_record(get_db_session_for_app())
171-
remove_dir(dataset_path)
172-
173-
174-
def dataset_related_information(dataset_id: int):
175-
projects = ProjectsModel.query.filter_by(dataset_id=dataset_id).all()
176-
all_project_ids = [p.id for p in projects]
177-
178-
run_results, compound_configs = projects_related_information(all_project_ids)
179-
180-
all_accuracy_results = (
181-
AccuracyJobsModel.query
182-
.filter(AccuracyJobsModel.project_id.in_(all_project_ids))
183-
.all()
184-
)
185-
all_int8_results = (
186-
Int8CalibrationJobModel.query
187-
.filter(Int8CalibrationJobModel.project_id.in_(all_project_ids))
188-
.all()
189-
)
190-
191-
return run_results, compound_configs, all_int8_results, all_accuracy_results, projects
192-
193-
194-
def projects_related_information(project_ids: List[int]) -> tuple:
195-
compound_configs = (
196-
ProfilingJobModel.query
197-
.filter(ProfilingJobModel.project_id.in_(project_ids))
198-
.all()
199-
)
200-
201-
all_infer_config_ids = [i.job_id for i in compound_configs]
202-
203-
inference_results = (
204-
SingleInferenceInfoModel.query
205-
.filter(SingleInferenceInfoModel.profiling_job_id.in_(all_infer_config_ids))
206-
.all()
207-
)
208-
209-
return inference_results, compound_configs
210166

211167

212168
def find_projects(model_id: int, all_levels: bool) -> tuple:

wb/main/api_endpoints/v1/export.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@
3737
def archive_model(model_id: int):
3838
download_job: ModelDownloadConfigsModel = ModelDownloadConfigsModel.query.filter_by(model_id=model_id).first()
3939
if download_job:
40-
downloadable_artifact = download_job.downloadable_artifact
40+
downloadable_artifact = download_job.shared_artifact
4141
exist, _ = downloadable_artifact.archive_exists()
4242
if exist:
4343
return jsonify({

wb/main/api_endpoints/v1/profiling.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ def check_sum_profiling_bundle():
100100
md5sum = None
101101
job = CreateProfilingBundleJobModel.query.filter_by(project_id=project_id).first()
102102
if job:
103-
bundle = job.bundle.path
103+
bundle = job.shared_artifact
104104
exists, _ = bundle.archive_exists()
105105
if exists:
106106
md5sum = md5(bundle.path)

wb/main/api_endpoints/v1/registry.py

+4-2
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,8 @@
2626
SHORT_TRANSFORMATIONS_CONFIGS, UPLOAD_FOLDER_DATASETS,
2727
UPLOAD_FOLDER_MODELS,
2828
DISABLE_JUPYTER, ENABLE_AUTH, JUPYTER_NOTEBOOKS_FOLDER, PYTHON_WRAPPER,
29-
PRC_URL_TO_CHECK_CONNECTION, GENERAL_URL_TO_CHECK_CONNECTION)
29+
PRC_URL_TO_CHECK_CONNECTION, GENERAL_URL_TO_CHECK_CONNECTION, CLOUD_SHARED_FOLDER,
30+
ENVIRONMENTS_FOLDER)
3031
from wb.config.application import get_config
3132
from wb.error.code_registry import CodeRegistry
3233
from wb.extensions_factories.database import get_db_for_app
@@ -169,9 +170,10 @@ def clear_assets_paths():
169170
assets_paths = (
170171
ARTIFACTS_PATH, MODEL_DOWNLOADS_FOLDER, PROFILING_ARTIFACTS_REPORT_DIR,
171172
UPLOAD_FOLDER_DATASETS, UPLOAD_FOLDER_MODELS, JUPYTER_NOTEBOOKS_FOLDER,
173+
ENVIRONMENTS_FOLDER, CLOUD_SHARED_FOLDER
172174
)
173175
for path in assets_paths:
174-
if not os.path.exists(path):
176+
if not path or not os.path.exists(path):
175177
continue
176178
shutil.rmtree(path)
177179

wb/main/api_endpoints/v1/remote_job.py

+36-8
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
from flask import jsonify, request
1919

20+
from wb.error.request_error import NotFoundRequestError
2021
from wb.extensions_factories.database import get_db_session_for_app
2122
from wb.main.api_endpoints.utils import save_artifact_chunk_upload
2223
from wb.main.api_endpoints.v1 import V1_REMOTE_JOB_API
@@ -29,6 +30,32 @@
2930
from wb.main.utils.utils import create_empty_dir, FileSizeConverter
3031

3132

33+
@V1_REMOTE_JOB_API.route('/remote-job/finish', methods=['POST'])
34+
@safe_run
35+
def set_remote_job_ready():
36+
data = request.get_json()
37+
wb_pipeline_id = data['wbPipelineId']
38+
job_models: List[ParseDevCloudResultJobModel] = (
39+
ParseDevCloudResultJobModel.query.filter_by(pipeline_id=wb_pipeline_id).all()
40+
)
41+
if not job_models:
42+
raise NotFoundRequestError(f'No job found for provided pipeline id: {wb_pipeline_id}')
43+
44+
for job_model in job_models:
45+
parent_job: JobsModel = JobsModel.query.get(job_model.parent_job)
46+
if not parent_job:
47+
raise NotFoundRequestError(f'No job found for provided pipeline id: {wb_pipeline_id}')
48+
if parent_job.status == StatusEnum.running:
49+
break
50+
else:
51+
raise NotFoundRequestError(f'No job found for provided pipeline id: {wb_pipeline_id}')
52+
53+
job_model.are_results_obtained = True
54+
job_model.write_record(session=get_db_session_for_app())
55+
56+
return jsonify({})
57+
58+
3259
@V1_REMOTE_JOB_API.route('/remote-job-result/upload', methods=['POST'])
3360
@safe_run
3461
def upload_remote_job_result():
@@ -41,16 +68,16 @@ def upload_remote_job_result():
4168

4269
# find a particular job from a big pipeline (int8+profiling) for this artifact
4370
if not job_models:
44-
return no_job_found_response()
71+
raise NotFoundRequestError(f'No job found for provided pipeline id: {wb_pipeline_id}')
4572

4673
for job_model in job_models:
4774
parent_job: JobsModel = JobsModel.query.get(job_model.parent_job)
4875
if not parent_job:
49-
return no_job_found_response()
76+
raise NotFoundRequestError(f'No job found for provided pipeline id: {wb_pipeline_id}')
5077
if parent_job.status == StatusEnum.running:
5178
break
5279
else:
53-
return no_job_found_response()
80+
raise NotFoundRequestError(f'No job found for provided pipeline id: {wb_pipeline_id}')
5481

5582
remote_job_result_artifact: DownloadableArtifactsModel = job_model.result_artifact
5683
if not remote_job_result_artifact:
@@ -65,15 +92,16 @@ def upload_remote_job_result():
6592
return jsonify({'artifactItem': remote_job_result_artifact.json(), 'files': files_ids})
6693

6794

68-
def no_job_found_response():
69-
return 'No job found for provided pipeline id', 404
70-
71-
7295
@V1_REMOTE_JOB_API.route('/remote-job-result/upload/<int:file_id>', methods=['POST'])
7396
@safe_run
7497
def upload_remote_job_result_chunk(file_id: int):
7598
file_record = FilesModel.query.get(file_id)
7699
if not file_record:
77-
return 'File record with id {} was not found on the database'.format(file_id), 404
100+
raise NotFoundRequestError(f'File record with id {file_id} was not found on the database')
78101
save_artifact_chunk_upload(request, file_id)
102+
artifact = file_record.artifact
103+
if artifact.is_all_files_uploaded:
104+
job_model = ParseDevCloudResultJobModel.query.filter_by(result_artifact_id=artifact.id).first()
105+
job_model.are_results_obtained = True
106+
job_model.write_record(session=get_db_session_for_app())
79107
return jsonify({})

wb/main/console_tool_wrapper/reshape/console_output_parser.py

-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
"""
1616
import re
1717

18-
from wb.error.job_error import Int8CalibrationError
1918
from wb.main.enumerates import StatusEnum
2019
from wb.main.jobs.interfaces.job_state import JobStateSubject
2120
from wb.main.jobs.tools_runner.console_output_parser import ConsoleToolOutputParser, skip_empty_line_decorator

wb/main/enumerates.py

+5
Original file line numberDiff line numberDiff line change
@@ -518,6 +518,11 @@ class DevCloudRemoteJobTypeEnum(enum.Enum):
518518
accuracy = 'accuracy'
519519

520520

521+
class DevCloudAPIVersionEnum(enum.Enum):
522+
v1 = 'v1'
523+
v2 = 'v2'
524+
525+
521526
class BenchmarkAppReportTypesEnum(enum.Enum):
522527
no_counters = 'no_counters'
523528
average_counters = 'average_counters'

wb/main/jobs/accuracy_analysis/accuracy/create_accuracy_bundle_job.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ def run(self):
4747
project = job_model.project
4848
model_path = project.topology.path
4949
dataset_path = accuracy_job_model.target_dataset.path
50-
bundle_id = job_model.bundle_id
50+
bundle_id = job_model.shared_artifact.id
5151
accuracy_artifacts_path = Path(ACCURACY_ARTIFACTS_FOLDER) / str(job_model.pipeline_id)
5252

5353
configuration_path = accuracy_artifacts_path / JOBS_SCRIPTS_FOLDER_NAME / ACCURACY_CONFIGURATION_FILE_NAME
@@ -72,8 +72,8 @@ def on_success(self):
7272
with closing(get_db_session_for_celery()) as session:
7373
job: CreateAccuracyBundleJobModel = self.get_job_model(session)
7474
# TODO: [61937] Move to separate DBObserver
75-
bundle: DownloadableArtifactsModel = job.bundle
76-
bundle_path = DownloadableArtifactsModel.get_archive_path(bundle.id)
75+
bundle: DownloadableArtifactsModel = job.shared_artifact
76+
bundle_path = bundle.build_full_artifact_path()
7777
bundle.update(bundle_path)
7878
bundle.write_record(session)
7979
set_status_in_db(DownloadableArtifactsModel, bundle.id, StatusEnum.ready, session, force=True)

wb/main/jobs/accuracy_analysis/annotate_datset/create_annotate_dataset_bundle_job.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ def run(self):
5555
project = job_model.project
5656
model_path = project.topology.original_model.path
5757
dataset_path = annotate_dataset_job_model.project.dataset.dataset_data_dir
58-
bundle_id = job_model.bundle_id
58+
bundle_id = job_model.shared_artifact.id
5959
annotate_dataset_artifacts_path = Path(DATASET_ANNOTATION_ARTIFACTS_FOLDER) / str(job_model.pipeline_id)
6060

6161
configuration_path = annotate_dataset_artifacts_path / JOBS_SCRIPTS_FOLDER_NAME / DATASET_ANNOTATION_ACCURACY_CONFIGURATION_FILE_NAME
@@ -80,8 +80,8 @@ def on_success(self):
8080
with closing(get_db_session_for_celery()) as session:
8181
job: CreateAccuracyBundleJobModel = self.get_job_model(session)
8282
# TODO: [61937] Move to separate DBObserver
83-
bundle: DownloadableArtifactsModel = job.bundle
84-
bundle_path = DownloadableArtifactsModel.get_archive_path(bundle.id)
83+
bundle: DownloadableArtifactsModel = job.shared_artifact
84+
bundle_path = bundle.build_full_artifact_path()
8585
bundle.update(bundle_path)
8686
bundle.write_record(session)
8787
set_status_in_db(DownloadableArtifactsModel, bundle.id, StatusEnum.ready, session, force=True)

wb/main/jobs/accuracy_analysis/per_tensor/create_per_tensor_bundle_job.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ def run(self):
5151
optimized_model_path = project.topology.path
5252
parent_model_path = project.topology.optimized_from_record.path
5353
dataset_path = per_tensor_report_job_model.project.dataset.dataset_data_dir
54-
bundle_id = job_model.bundle_id
54+
bundle_id = job_model.shared_artifact.id
5555
accuracy_artifacts_path = Path(ACCURACY_ARTIFACTS_FOLDER) / str(job_model.pipeline_id)
5656

5757
job_script_path = accuracy_artifacts_path / JOBS_SCRIPTS_FOLDER_NAME / JOB_SCRIPT_NAME
@@ -75,8 +75,8 @@ def on_success(self):
7575
with closing(get_db_session_for_celery()) as session:
7676
job: CreateAccuracyBundleJobModel = self.get_job_model(session)
7777
# TODO: [61937] Move to separate DBObserver
78-
bundle: DownloadableArtifactsModel = job.bundle
79-
bundle_path = DownloadableArtifactsModel.get_archive_path(bundle.id)
78+
bundle: DownloadableArtifactsModel = job.shared_artifact
79+
bundle_path = bundle.build_full_artifact_path()
8080
bundle.update(bundle_path)
8181
bundle.write_record(session)
8282
set_status_in_db(DownloadableArtifactsModel, bundle.id, StatusEnum.ready, session, force=True)

0 commit comments

Comments
 (0)