Skip to content
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .bazelrc
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ build --flag_alias=release_dpc=@config//:release_dpc
build --flag_alias=device=@config//:device
build --flag_alias=cpu=@config//:cpu
build --flag_alias=enable_assert=@config//:enable_assert
build --flag_alias=code_coverage=@config//:code_coverage

# Always pass this env variable to test rules, because SYCL
# OpenCL backend uses it to determine available devices
Expand Down
17 changes: 17 additions & 0 deletions .ci/pipeline/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -388,6 +388,9 @@ jobs:
- script: |
.ci/env/apt.sh opencl
displayName: 'install opencl'
- script: |
.ci/env/apt.sh dpcpp
displayName: 'dpcpp installation'

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would this actually get used if the public CI jobs are not running anything with GPUs?

- script: |
# sourcing done to set bazel version value from script
source .ci/env/bazelisk.sh
Expand Down Expand Up @@ -440,8 +443,22 @@ jobs:

echo "Checking Bazel config: dev"
bazel build --nobuild //cpp/oneapi/dal:tests --config=dev

echo "Checking code-coverage rejection with the GCC-only Bazel toolchain"
if coverage_error=$(bazel build --nobuild :release --code_coverage=true 2>&1); then
echo "ERROR: code coverage unexpectedly accepted the GCC host compiler"
exit 1
fi
printf '%s\n' "${coverage_error}"
grep -F -- "--code_coverage=true requires host compiler ID 'icx'" <<< "${coverage_error}"
grep -F -- "detected compiler ID: 'gcc'" <<< "${coverage_error}"
displayName: 'Bazel config smoke checks'

- script: |
source /opt/intel/oneapi/setvars.sh
BAZEL=bazel dev/bazel/tests/code_coverage_test.sh
displayName: 'Bazel code-coverage icx smoke build'

- script: |
bazel build :release --release_dpc=false
displayName: 'release'
Expand Down
13 changes: 13 additions & 0 deletions INSTALL.md
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,19 @@ It is possible to integrate various sanitizers by specifying the REQSAN flag, av

make -f makefile daal oneapi_c PLAT=lnx32e CODE_COVERAGE=yes

The equivalent Bazel build is default-off and uses a typed Boolean flag:

bazel build //:release --code_coverage=true

Bazel coverage instrumentation is supported only on Linux when the detected
host compiler ID is `icx`. It applies the Make compiler options to
oneDAL-owned actions only: host compilations and dynamic-library links are
instrumented, DPC++ dynamic-library links use `-Xscoverage`, and
`GCOV_BUILD` is limited to DAAL core sources. Static archives receive no
linker option; executable and test links receive the matching host or
DPC++ coverage driver option so instrumented objects resolve the coverage
runtime.

- To build oneDAL with kernel profiling information (`REQPROFILE=yes`):

_Note: if you used the general oneAPI setvars script from a Base Toolkit installation, those steps will not be necessary as Intel(R) VTune(TM) Profiler will already have been set up._
Expand Down
2 changes: 2 additions & 0 deletions cpp/daal/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,8 @@ daal_module(
daal_module(
name = "threading_tbb",
srcs = glob(["src/threading/**/*.cpp"]),
# Make builds these as THR_TBB.objs, outside GCOV_BUILD-scoped CORE.objs_a/y.
define_gcov_build = False,
visibility_hidden = False,
local_defines = [
"__TBB_NO_IMPLICIT_LINKAGE",
Expand Down
37 changes: 37 additions & 0 deletions dev/bazel/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -631,8 +631,45 @@ build --linkopt=-your-link-flag
| `REQSAN=undefined` | `--config=ubsan` | UBSan |
| `REQSAN=memory` | `--config=msan` | MemorySanitizer (Clang/LLVM + lld; instrumented dependencies recommended) |
| `REQSAN=type` | `--config=type` | TypeSanitizer; Clang-only; GCC/ICPX unsupported |
| `CODE_COVERAGE=yes` | `--code_coverage=true` | Linux with host compiler ID `icx`; Make-equivalent action-local flags |
| `COMPILER=gnu` | `CC=gcc bazel build ...` | Override compiler via `CC` env |
| `OPTFLAG=O2` | `--copt=-O2` | Override optimization level |
| `COPT=-flag` | `--copt=-flag` (C+C++) / `--cxxopt=-flag` (C++ only) | Arbitrary compiler flag |
| `PLAT=<isa>` | `--cpu=<isa>` | ISA selection |
| Full CPU ISA release coverage | `bazel build //:release --cpu=all` | Build all supported CPU ISA variants |

With `--code_coverage=true`, Bazel keeps instrumentation on oneDAL-owned
actions instead of forwarding global `--copt`/`--linkopt` values into external
dependencies. The action-level parity with `makefile` and the compiler
definitions under `dev/make/compiler_definitions/` is:

| oneDAL action | Added options |
|---------------|---------------|
| ICX compile | `-coverage` |
| DAAL core compile (the Bazel counterpart of Make `CORE.objs_a/y`) | `-DGCOV_BUILD` in addition to `-coverage` |
| DPC++ compile | None |
| ICX dynamic-library/module link | `-coverage` |
| DPC++ dynamic-library/module link | `-Xscoverage` |
| Static-library archive | None |
| ICX executable/test link | `-coverage` |
| DPC++ executable/test link | `-Xscoverage` |

`GCOV_BUILD` is deliberately independent of compiler instrumentation: it is
opted in by `daal_module`, and explicitly excluded from separately built DAAL
threading modules. oneAPI DAL, DPC++, tests, examples, and tools use the default
off setting. This mirrors the Make target-specific assignment on
`CORE.objs_a/y`; Make's compiler-level coverage option still applies to other
host compilations.

Make's compiler drivers add the coverage runtime on dynamic links. Bazel
applies the corresponding driver option to dynamic-library, module, executable,
and test link actions; executable/test links need it to resolve the coverage
runtime from instrumented objects. Static archives remain flag-free. The flag
is rejected on non-Linux platforms and unless the detected host compiler ID is
exactly `icx`.

CI uses `dev/bazel/tests/code_coverage_test.sh` on the icx toolchain to build
`//cpp/daal:core_static` and `//cpp/daal:thread_static` with
`--code_coverage=true`, then inspects `bazel aquery` output to confirm DAAL
core compile actions carry `-coverage`/`-DGCOV_BUILD` and the separately built
threading module does not.
99 changes: 95 additions & 4 deletions dev/bazel/cc.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ load("@onedal//dev/bazel:utils.bzl",

load("@rules_cc//cc:defs.bzl", "cc_library")
load("@onedal//dev/bazel/config:config.bzl",
"ConfigFlagInfo",
"CpuInfo",
"VersionInfo",
)
Expand Down Expand Up @@ -83,8 +84,58 @@ def _init_cc_rule(ctx, features=[], disable_features=[]):
)
return cc_toolchain, feature_config


def _coverage_options(ctx, cc_toolchain, feature_config):
"""Return Make-compatible coverage driver options for oneDAL actions."""
if not ctx.attr._code_coverage[ConfigFlagInfo].flag:
return struct(compile_flags = [], link_flags = [])

is_linux = ctx.target_platform_has_constraint(
ctx.attr._linux_constraint[platform_common.ConstraintValueInfo],
)
compiler_id = cc_toolchain.compiler.split("-")[0]
if not is_linux:
fail("--code_coverage=true requires Linux (detected target OS is not Linux)")
if compiler_id != "icx":
fail("--code_coverage=true requires host compiler ID 'icx' " +
"(detected compiler ID: '{}')".format(compiler_id))

is_dpc = cc_common.is_enabled(
feature_configuration = feature_config,
feature_name = "dpc++",
)
# Make adds -coverage to every ICX compilation and to dynamic links.
# DPC++ compilations are unchanged; DPC++ dynamic links use -Xscoverage.
return struct(
compile_flags = [] if is_dpc else ["-coverage"],
link_flags = ["-Xscoverage"] if is_dpc else ["-coverage"],
)

def _without_coverage_link_flags(linking_context, coverage_link_flags):
"""Remove action-local coverage flags while preserving linker metadata."""
linker_inputs = []
for linker_input in linking_context.linker_inputs.to_list():
linker_inputs.append(cc_common.create_linker_input(
owner = linker_input.owner,
libraries = depset(linker_input.libraries),
user_link_flags = [
flag
for flag in linker_input.user_link_flags
if flag not in coverage_link_flags
],
additional_inputs = depset(linker_input.additional_inputs),
linkstamps = depset(linker_input.linkstamps),
))
Comment on lines +118 to +128
return cc_common.create_linking_context(
linker_inputs = depset(linker_inputs),
)

def _cc_module_impl(ctx):
toolchain, feature_config = _init_cc_rule(ctx)
coverage = _coverage_options(ctx, toolchain, feature_config)
coverage_defines = ["GCOV_BUILD"] if (
ctx.attr.define_gcov_build and ctx.attr._code_coverage[ConfigFlagInfo].flag
) else []
dep_compilation_contexts = onedal_cc_common.collect_compilation_contexts(ctx.attr.deps)
is_windows = ctx.target_platform_has_constraint(
ctx.attr._windows_constraint[platform_common.ConstraintValueInfo],
Expand All @@ -103,8 +154,8 @@ def _cc_module_impl(ctx):
public_hdrs = ctx.files.hdrs,
private_hdrs = ctx.files.private_hdrs,
defines = ctx.attr.defines,
local_defines = ctx.attr.local_defines,
user_compile_flags = ctx.attr.copts,
local_defines = ctx.attr.local_defines + coverage_defines,
user_compile_flags = ctx.attr.copts + coverage.compile_flags,
includes = ctx.attr.includes,
system_includes = ctx.attr.system_includes,
quote_includes = ctx.attr.quote_includes,
Expand All @@ -124,7 +175,13 @@ def _cc_module_impl(ctx):
cc_toolchain = toolchain,
feature_configuration = feature_config,
compilation_outputs = compilation_outputs,
user_link_flags = coverage.link_flags,
)
# create_linking_context_from_compilation_outputs uses the flags for the
# module dynamic-link action and also puts them in its linking context.
# Keep module-action coverage flags from leaking transitively;
# executable and test actions add their own coverage driver option.
linking_context = _without_coverage_link_flags(linking_context, coverage.link_flags)
tagged_linking_contexts.append(onedal_cc_common.create_tagged_linking_context(
tag = ctx.attr.lib_tag,
linking_context = linking_context,
Expand All @@ -150,6 +207,10 @@ _cc_module = rule(
"copts": attr.string_list(),
"defines": attr.string_list(),
"local_defines": attr.string_list(),
"define_gcov_build": attr.bool(
default = False,
doc = "Define GCOV_BUILD for Make CORE.objs_a/y-equivalent sources.",
),
"cpu_defines": attr.string_list_dict(),
"fpt_defines": attr.string_list_dict(),
"includes": attr.string_list(),
Expand All @@ -162,6 +223,13 @@ _cc_module = rule(
"_windows_constraint": attr.label(
default = "@platforms//os:windows",
),
"_linux_constraint": attr.label(
default = "@platforms//os:linux",
),
"_code_coverage": attr.label(
default = "@config//:code_coverage",
providers = [ConfigFlagInfo],
),
},
toolchains = ["@bazel_tools//tools/cpp:toolchain_type"],
fragments = ["cpp"],
Expand Down Expand Up @@ -263,6 +331,7 @@ def _cc_dynamic_lib_impl(ctx):
# resolved through the executable RUNPATH.
"do_not_link_dynamic_dependencies",
])
coverage = _coverage_options(ctx, toolchain, feature_config)
compilation_context = onedal_cc_common.collect_and_merge_compilation_contexts(ctx.attr.deps)
linking_contexts = onedal_cc_common.collect_and_filter_linking_contexts(
ctx.attr.deps, ctx.attr.lib_tags)
Expand All @@ -287,7 +356,7 @@ def _cc_dynamic_lib_impl(ctx):
feature_configuration = feature_config,
linking_contexts = linking_contexts,
def_file = ctx.file.def_file,
user_link_flags = linux_soname_flags + linux_linker_script_flags + (["-Wl,--exclude-libs=ALL"] if not is_windows else []) + ctx.attr.linkopts,
user_link_flags = linux_soname_flags + linux_linker_script_flags + (["-Wl,--exclude-libs=ALL"] if not is_windows else []) + ctx.attr.linkopts + coverage.link_flags,
is_windows = is_windows,
additional_inputs = ctx.files.linker_scripts,
is_dpc = ctx.attr.lib_name.endswith("_dpc") or ctx.label.name.endswith("_dpc"),
Expand Down Expand Up @@ -342,6 +411,13 @@ cc_dynamic_lib = rule(
default = "@config//:version",
providers = [VersionInfo],
),
"_linux_constraint": attr.label(
default = "@platforms//os:linux",
),
"_code_coverage": attr.label(
default = "@config//:code_coverage",
providers = [ConfigFlagInfo],
),
},
toolchains = ["@bazel_tools//tools/cpp:toolchain_type"],
fragments = ["cpp"],
Expand All @@ -352,6 +428,7 @@ def _cc_exec_impl(ctx):
if not ctx.attr.deps:
return
toolchain, feature_config = _init_cc_rule(ctx)
coverage = _coverage_options(ctx, toolchain, feature_config)
is_windows = ctx.target_platform_has_constraint(
ctx.attr._windows_constraint[platform_common.ConstraintValueInfo],
)
Expand All @@ -365,7 +442,7 @@ def _cc_exec_impl(ctx):
cc_toolchain = toolchain,
feature_configuration = feature_config,
linking_contexts = linking_contexts,
user_link_flags = ctx.attr.user_link_flags,
user_link_flags = ctx.attr.user_link_flags + coverage.link_flags,
)
runtime_files = _copy_windows_runtime_files(ctx, ctx.files.data, is_windows)
default_info = DefaultInfo(
Expand All @@ -385,6 +462,13 @@ cc_test = rule(
"data": attr.label_list(allow_files=True),
"user_link_flags": attr.string_list(),
"_is_test": attr.bool(default=True),
"_linux_constraint": attr.label(
default = "@platforms//os:linux",
),
"_code_coverage": attr.label(
default = "@config//:code_coverage",
providers = [ConfigFlagInfo],
),
"_windows_constraint": attr.label(
default = "@platforms//os:windows",
),
Expand All @@ -402,6 +486,13 @@ cc_executable = rule(
"data": attr.label_list(allow_files=True),
"user_link_flags": attr.string_list(),
"_is_test": attr.bool(default=False),
"_linux_constraint": attr.label(
default = "@platforms//os:linux",
),
"_code_coverage": attr.label(
default = "@config//:code_coverage",
providers = [ConfigFlagInfo],
),
"_windows_constraint": attr.label(
default = "@platforms//os:windows",
),
Expand Down
8 changes: 8 additions & 0 deletions dev/bazel/config/config.tpl.BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,13 @@ config_bool_flag(
build_setting_default = False,
)

# Instrument oneDAL sources with the Intel coverage options used by Make.
# The implementation intentionally rejects unsupported OS/compiler pairs.
config_bool_flag(
name = "code_coverage",
build_setting_default = False,
)

config_setting(
name = "assert_enabled",
flag_values = {
Expand All @@ -159,5 +166,6 @@ dump_config_info(
flags = [
":test_link_mode",
":test_thread_mode",
":code_coverage",
],
)
4 changes: 3 additions & 1 deletion dev/bazel/daal.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@ load("@onedal//dev/bazel/config:config.bzl",

def daal_module(name, features=[], lib_tag="daal",
hdrs=[], srcs=[], auto=False,
local_defines=[], copts=[], visibility_hidden=True, **kwargs):
local_defines=[], copts=[], visibility_hidden=True,
define_gcov_build=True, **kwargs):
if auto:
auto_hdrs = native.glob(["**/*.h", "**/*.i"], allow_empty=True,)
auto_srcs = native.glob(["**/*.cpp"], allow_empty=True,)
Expand Down Expand Up @@ -59,6 +60,7 @@ def daal_module(name, features=[], lib_tag="daal",
"@platforms//os:windows": ["/utf-8"],
"//conditions:default": [],
})),
define_gcov_build = define_gcov_build,
local_defines = select({
"@config//:assert_enabled": local_defines + ["__DAAL_IMPLEMENTATION", "DEBUG_ASSERT=1"],
"//conditions:default": local_defines + ["__DAAL_IMPLEMENTATION"],
Expand Down
1 change: 1 addition & 0 deletions dev/bazel/tests/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,5 @@ exports_files([
"release_structure_test.sh",
"isa_coverage_test.sh",
"mkl_linkage_test.sh",
"code_coverage_test.sh",
])
Loading
Loading