Skip to content

Commit

Permalink
Build retrieval improvements (#4412)
Browse files Browse the repository at this point in the history
### Motivation

Small changes for the build retrieval metric, as requested per Chrome
folks after initially using the feature:

* Adding the time for listing fuzz targets as a step
* Added the total retrieval duration
* Tracking metric as minutes, for readability

Part of #4271
  • Loading branch information
vitorguidi authored Nov 19, 2024
1 parent 5cfd235 commit c46d537
Show file tree
Hide file tree
Showing 2 changed files with 30 additions and 35 deletions.
63 changes: 29 additions & 34 deletions src/clusterfuzz/_internal/build_management/build_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,17 @@ def set_env_var(name, value):
logs.error(f'Could not find app {app_name!r} in search directories.')


def _emit_job_build_retrieval_metric(start_time, step, build_type):
elapsed_minutes = (time.time() - start_time) / 60
monitoring_metrics.JOB_BUILD_RETRIEVAL_TIME.add(
elapsed_minutes, {
'job': os.getenv('JOB_NAME'),
'platform': environment.platform(),
'step': step,
'build_type': build_type,
})


class BaseBuild:
"""Represents a build."""

Expand Down Expand Up @@ -440,14 +451,7 @@ def _download_and_open_build_archive(self, base_build_dir: str,
try:
start_time = time.time()
storage.copy_file_from(build_url, build_local_archive)
build_download_duration = time.time() - start_time
monitoring_metrics.JOB_BUILD_RETRIEVAL_TIME.add(
build_download_duration, {
'job': os.getenv('JOB_NAME'),
'platform': environment.platform(),
'step': 'download',
'build_type': self._build_type,
})
_emit_job_build_retrieval_metric(start_time, 'download', self._build_type)
except Exception as e:
logs.error(f'Unable to download build from {build_url}: {e}')
raise
Expand Down Expand Up @@ -522,7 +526,11 @@ def _unpack_build(self,
if not self._unpack_everything:
# We will never unpack the full build so we need to get the targets
# from the build archive.
list_fuzz_target_start_time = time.time()
self._fuzz_targets = list(build.list_fuzz_targets())
_emit_job_build_retrieval_metric(list_fuzz_target_start_time,
'list_fuzz_targets',
self._build_type)
# We only want to unpack a single fuzz target if unpack_everything is
# False.
fuzz_target_to_unpack = self.fuzz_target
Expand All @@ -547,15 +555,8 @@ def _unpack_build(self,
fuzz_target=fuzz_target_to_unpack,
trusted=trusted)

unpack_elapsed_time = time.time() - unpack_start_time

monitoring_metrics.JOB_BUILD_RETRIEVAL_TIME.add(
unpack_elapsed_time, {
'job': os.getenv('JOB_NAME'),
'platform': environment.platform(),
'step': 'unpack',
'build_type': self._build_type,
})
_emit_job_build_retrieval_metric(unpack_start_time, 'unpack',
self._build_type)

except Exception as e:
logs.error(f'Unable to unpack build archive {build_url}: {e}')
Expand All @@ -567,6 +568,7 @@ def _unpack_build(self,
partial_build_file_path = os.path.join(build_dir, PARTIAL_BUILD_FILE)
utils.write_data_to_file('', partial_build_file_path)

_emit_job_build_retrieval_metric(start_time, 'total', self._build_type)
elapsed_time = time.time() - start_time

elapsed_mins = elapsed_time / 60.
Expand Down Expand Up @@ -598,7 +600,10 @@ def fuzz_targets(self):
if not self._fuzz_targets and self._unpack_everything:
# we can lazily compute that when unpacking the whole archive, since we
# know all the fuzzers will be in the build directory.
start_time = time.time()
self._fuzz_targets = list(self._get_fuzz_targets_from_dir(self.build_dir))
_emit_job_build_retrieval_metric(start_time, 'list_fuzz_targets',
self._build_type)
return self._fuzz_targets

def exists(self):
Expand Down Expand Up @@ -905,15 +910,8 @@ def _unpack_custom_build(self):
build_local_archive):
return False

build_download_time = time.time() - download_start_time
monitoring_metrics.JOB_BUILD_RETRIEVAL_TIME.add(
build_download_time, {
'job': os.getenv('JOB_NAME'),
'platform': environment.platform(),
'step': 'download',
'build_type': self._build_type,
})

_emit_job_build_retrieval_metric(download_start_time, 'download',
self._build_type)
# If custom binary is an archive, then unpack it.
if archive.is_archive(self.custom_binary_filename):
try:
Expand All @@ -933,14 +931,8 @@ def _unpack_custom_build(self):
# Unpack belongs to the BuildArchive class
unpack_start_time = time.time()
build.unpack(self.build_dir, trusted=True)
build_unpack_time = time.time() - unpack_start_time
monitoring_metrics.JOB_BUILD_RETRIEVAL_TIME.add(
build_unpack_time, {
'job': os.getenv('JOB_NAME'),
'platform': environment.platform(),
'step': 'unpack',
'build_type': self._build_type,
})
_emit_job_build_retrieval_metric(unpack_start_time, 'unpack',
self._build_type)
except:
build.close()
logs.error('Unable to unpack build archive %s.' % build_local_archive)
Expand All @@ -949,6 +941,9 @@ def _unpack_custom_build(self):
build.close()
# Remove the archive.
shell.remove_file(build_local_archive)

_emit_job_build_retrieval_metric(download_start_time, 'download',
self._build_type)
return True

def setup(self):
Expand Down
2 changes: 1 addition & 1 deletion src/clusterfuzz/_internal/metrics/monitoring_metrics.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@
'task/build_retrieval_time',
bucketer=monitor.FixedWidthBucketer(width=0.05, num_finite_buckets=20),
description=('Distribution of fuzz task\'s build retrieval times. '
'(grouped by fuzzer/job)'),
'(grouped by fuzzer/job, in minutes).'),
field_spec=[
monitor.StringField('job'),
monitor.StringField('step'),
Expand Down

0 comments on commit c46d537

Please sign in to comment.