Skip to content

[hwasan] Don't instrument when PGO profile is collected #86739

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

vitalybuka
Copy link
Collaborator

@vitalybuka vitalybuka commented Mar 26, 2024

We can't do that for msan, dfsan, and probably tsan as they may
be linked with pre-instrumented binary.

Probably we can disable SanitizerCoveragePass and SanitizerBinaryMetadataPass,
but they are not expensive enough to justify diverging pipeline.

Created using spr 1.3.4
@llvmbot llvmbot added clang Clang issues not falling into any other category clang:codegen IR generation bugs: mangling, exceptions, etc. labels Mar 26, 2024
@llvmbot
Copy link
Member

llvmbot commented Mar 26, 2024

@llvm/pr-subscribers-clang

@llvm/pr-subscribers-clang-codegen

Author: Vitaly Buka (vitalybuka)

Changes

Full diff: https://github.com/llvm/llvm-project/pull/86739.diff

3 Files Affected:

  • (modified) clang/lib/CodeGen/BackendUtil.cpp (+10-4)
  • (modified) clang/test/CodeGen/asan-new-pm.ll (+8-1)
  • (modified) clang/test/CodeGen/hwasan-new-pm.c (+20-2)
diff --git a/clang/lib/CodeGen/BackendUtil.cpp b/clang/lib/CodeGen/BackendUtil.cpp
index 82b30b8d815629..75ba3f2c3785de 100644
--- a/clang/lib/CodeGen/BackendUtil.cpp
+++ b/clang/lib/CodeGen/BackendUtil.cpp
@@ -717,8 +717,11 @@ static void addSanitizers(const Triple &TargetTriple,
                                          DestructorKind));
       }
     };
-    ASanPass(SanitizerKind::Address, false);
-    ASanPass(SanitizerKind::KernelAddress, true);
+    // Don't slow down already slow `ProfileIRInstr` binary.
+    if (!CodeGenOpts.hasProfileIRInstr()) {
+      ASanPass(SanitizerKind::Address, false);
+      ASanPass(SanitizerKind::KernelAddress, true);
+    }
 
     auto HWASanPass = [&](SanitizerMask Mask, bool CompileKernel) {
       if (LangOpts.Sanitize.has(Mask)) {
@@ -728,8 +731,11 @@ static void addSanitizers(const Triple &TargetTriple,
              /*DisableOptimization=*/CodeGenOpts.OptimizationLevel == 0}));
       }
     };
-    HWASanPass(SanitizerKind::HWAddress, false);
-    HWASanPass(SanitizerKind::KernelHWAddress, true);
+    // Don't slow down already slow `ProfileIRInstr` binary.
+    if (!CodeGenOpts.hasProfileIRInstr()) {
+      HWASanPass(SanitizerKind::HWAddress, false);
+      HWASanPass(SanitizerKind::KernelHWAddress, true);
+    }
 
     if (LangOpts.Sanitize.has(SanitizerKind::DataFlow)) {
       MPM.addPass(DataFlowSanitizerPass(LangOpts.NoSanitizeFiles));
diff --git a/clang/test/CodeGen/asan-new-pm.ll b/clang/test/CodeGen/asan-new-pm.ll
index 78d195b0ea2471..528dc1f7a7c400 100644
--- a/clang/test/CodeGen/asan-new-pm.ll
+++ b/clang/test/CodeGen/asan-new-pm.ll
@@ -1,6 +1,12 @@
 ; Test that ASan runs with the new pass manager
 ; RUN: %clang_cc1 -triple x86_64-unknown-unknown -S -emit-llvm -o - -fsanitize=address %s | FileCheck %s
-; RUN: %clang_cc1 -triple x86_64-unknown-unknown -S -emit-llvm -o - -O1 -fsanitize=address %s | FileCheck %s
+; RUN: %clang_cc1 -triple x86_64-unknown-unknown -S -emit-llvm -o - -fsanitize=address -O1 %s | FileCheck %s
+
+; RUN: %clang_cc1 -triple x86_64-unknown-unknown -S -emit-llvm -o - -fsanitize=address -fprofile-instrument=llvm %s | FileCheck %s -check-prefixes=NOASAN
+; RUN: %clang_cc1 -triple x86_64-unknown-unknown -S -emit-llvm -o - -fsanitize=address -fprofile-instrument=llvm -O1 %s | FileCheck %s -check-prefixes=NOASAN
+
+; RUN: %clang_cc1 -triple x86_64-unknown-unknown -S -emit-llvm -o - -fsanitize=address -fprofile-instrument=clang %s | FileCheck %s
+; RUN: %clang_cc1 -triple x86_64-unknown-unknown -S -emit-llvm -o - -fsanitize=address -fprofile-instrument=clang -O1 %s | FileCheck %s
 
 ; CHECK-DAG: @llvm.global_ctors = {{.*}}@asan.module_ctor
 
@@ -20,3 +26,4 @@ entry:
 
 ; CHECK-DAG: __asan_version_mismatch_check_v8
 
+; NOASAN-NOT: __asan
\ No newline at end of file
diff --git a/clang/test/CodeGen/hwasan-new-pm.c b/clang/test/CodeGen/hwasan-new-pm.c
index 47014698f6df72..8f5a25c82df222 100644
--- a/clang/test/CodeGen/hwasan-new-pm.c
+++ b/clang/test/CodeGen/hwasan-new-pm.c
@@ -3,12 +3,30 @@
 // being instrumented properly.
 
 // RUN: %clang_cc1 -triple x86_64-linux-gnu -S -emit-llvm -o - -fsanitize=hwaddress %s | FileCheck %s
-// RUN: %clang_cc1 -triple x86_64-linux-gnu -S -emit-llvm -o - -O1 -fsanitize=hwaddress %s | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -S -emit-llvm -o - -fsanitize=hwaddress -O1 %s | FileCheck %s
+
+// Don't instrument when collecting profiles, to avoid additional slowdown of slow `profile-instrument` binary.
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -S -emit-llvm -o - -fsanitize=hwaddress -fprofile-instrument=llvm %s | FileCheck %s -check-prefixes=NOHWASAN
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -S -emit-llvm -o - -fsanitize=hwaddress -fprofile-instrument=llvm -O1 %s | FileCheck %s -check-prefixes=NOHWASAN
+
+// Nothing special is done for clang PGO.
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -S -emit-llvm -o - -fsanitize=hwaddress -fprofile-instrument=clang %s | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -S -emit-llvm -o - -fsanitize=hwaddress -fprofile-instrument=clang -O1 %s | FileCheck %s
 
 // RUN: %clang_cc1 -triple x86_64-linux-gnu -S -emit-llvm -o - -fsanitize=kernel-hwaddress %s | FileCheck %s
-// RUN: %clang_cc1 -triple x86_64-linux-gnu -S -emit-llvm -o - -O1 -fsanitize=kernel-hwaddress %s | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -S -emit-llvm -o - -fsanitize=kernel-hwaddress -O1 %s | FileCheck %s
+
+// Don't instrument when collecting profiles, to avoid additional slowdown of slow `profile-instrument` binary.
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -S -emit-llvm -o - -fsanitize=kernel-hwaddress -fprofile-instrument=llvm %s | FileCheck %s -check-prefixes=NOHWASAN
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -S -emit-llvm -o - -fsanitize=kernel-hwaddress -fprofile-instrument=llvm -O1 %s | FileCheck %s -check-prefixes=NOHWASAN
+
+// Nothing special is done for clang PGO.
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -S -emit-llvm -o - -fsanitize=kernel-hwaddress -fprofile-instrument=clang %s | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -S -emit-llvm -o - -fsanitize=kernel-hwaddress -fprofile-instrument=clang -O1 %s | FileCheck %s
 
 int foo(int *a) { return *a; }
 
 // All the cases above mark the function with sanitize_hwaddress.
 // CHECK: sanitize_hwaddress
+// CHECK: declare void @__hwasan_
+// NOHWASAN-NOT: __hwasan

@aeubanks
Copy link
Contributor

why can't hwasan and PGO instrumentation coexist?

and this seems like it should be an error at the clang driver level, instead of silently turning off one of the requested features

@vitalybuka
Copy link
Collaborator Author

vitalybuka commented Mar 26, 2024

why can't hwasan and PGO instrumentation coexist?

They can, but binary is like 5x times slower, on top of 10x slowdown of PGO instrumentation. (don't quote me on these numbers, they are from large but single benchmark, still it's very slow)

and this seems like it should be an error at the clang driver level, instead of silently turning off one of the requested features

  1. We need -fsanitizer=hwaddress, for attributes and profile matching, and some special handling done in earlier passes.
  2. We don't wan't users care about profile instrumentation/use difference.

@aeubanks
Copy link
Contributor

why can't hwasan and PGO instrumentation coexist?

They can, but binary is like 5x times slower, on top of 10x slowdown of PGO instrumentation. (don't quote me on these numbers, they are from large but single benchmark, still it's very slow)

If it's usable as a configuration, I don't see why we should prevent this. It still may be useful to some people. Seems like this checking should be done at a build system level if you don't want some codebase to compile with this configuration.

and this seems like it should be an error at the clang driver level, instead of silently turning off one of the requested features

  1. We need -fsanitizer=hwaddress, for attributes and profile matching, and some special handling done in earlier passes.

Do you mean that if you want a hwasan/PGO optimized build, you want the corresponding PGO instrumented build to also use hwasan?

Doesn't PGO instrumentation/use happen before the sanitizer passes run?

  1. We don't wan't users care about profile instrumentation/use difference.

@vitalybuka
Copy link
Collaborator Author

vitalybuka commented Mar 26, 2024

why can't hwasan and PGO instrumentation coexist?

They can, but binary is like 5x times slower, on top of 10x slowdown of PGO instrumentation. (don't quote me on these numbers, they are from large but single benchmark, still it's very slow)

If it's usable as a configuration, I don't see why we should prevent this. It still may be useful to some people. Seems like this checking should be done at a build system level if you don't want some codebase to compile with this configuration.

At the moment builds system can only disable HWASAN, there is no option to enabled HWASAN but drop the pass.
Note: -fno-sanitize=hwasan is not what we want. It will produce mismatching profile.

and this seems like it should be an error at the clang driver level, instead of silently turning off one of the requested features

  1. We need -fsanitizer=hwaddress, for attributes and profile matching, and some special handling done in earlier passes.

Do you mean that if you want a hwasan/PGO optimized build, you want the corresponding PGO instrumented build to also use hwasan?

I want PGO optimized binary with HWASAN.
But I don't rely want collect PGO profile with HWASAN, because the process is very slow.

Doesn't PGO instrumentation/use happen before the sanitizer passes run?

Instrumentation/use happens before sanitizer pass.
This is why drooping the pass will still produce the same optimized binary.

  1. We don't wan't users care about profile instrumentation/use difference.

@vitalybuka
Copy link
Collaborator Author

We already have similar stuff:

if (PGOOpt && Phase != ThinOrFullLTOPhase::ThinLTOPostLink &&
      !PGOOpt->MemoryProfile.empty())
    MPM.addPass(MemProfUsePass(PGOOpt->MemoryProfile, PGOOpt->FS));

@vitalybuka
Copy link
Collaborator Author

Alternative is we need a new clang fronted flag to control this behavior.
Assuming that this is rather strange use case, I'd prefer to land the patch and introduce new flag only when we have request for that case.

@aeubanks
Copy link
Contributor

We already have similar stuff:

if (PGOOpt && Phase != ThinOrFullLTOPhase::ThinLTOPostLink &&
      !PGOOpt->MemoryProfile.empty())
    MPM.addPass(MemProfUsePass(PGOOpt->MemoryProfile, PGOOpt->FS));

checking for ThinLTO pre/post link is a correctness thing though

I think I'm still confused on exactly what the use case is and why we can't just ask the user to not specify hwasan in the PGO instrumented build. Just for user convenience? Or does clang change the emitted IR when hwasan is enabled? And that's what will lead to mismatched profiles?

@vitalybuka
Copy link
Collaborator Author

vitalybuka commented Mar 26, 2024

I think I'm still confused on exactly what the use case is and why we can't just ask the user to not specify hwasan in the PGO instrumented build. Just for user convenience? Or does clang change the emitted IR when hwasan is enabled? And that's what will lead to mismatched profiles?

-fno-sanitize= IR changes:

  1. #ifdef branches on sanitizer
  2. function attributes
  3. some pre-profile optimization suppressed with sanitizer

maybe other reasons, but as is profile does not match if collected with -fno-sanitize=hwsan

Maybe we can find work around for 2 and 3, but no. 1 seems require magic flag to pretend to be HWASAN

@vitalybuka
Copy link
Collaborator Author

Looked into IR and HWASAN instrument stuff which it should not
https://godbolt.org/z/MnYs75Meq

Should be easy to fix.

@vitalybuka vitalybuka marked this pull request as draft March 27, 2024 01:07
@aeubanks
Copy link
Contributor

ah I see. I feel like this should be a more principled approach that other sanitizers also share, as you've mentioned as an alternative. do people not care about other sanitizers in production?

(I'm going to be OOO for a week, so someone else will need to review)

@vitalybuka
Copy link
Collaborator Author

vitalybuka commented Mar 27, 2024

ah I see. I feel like this should be a more principled approach that other sanitizers also share, as you've mentioned as an alternative. do people not care about other sanitizers in production?

Actually Asan should not exhibit this behavior, by some lack it does not instrument PGO counters. We likely need that optimization in HWASAN.

generic approach could be marking PGO stuff as MD_nosanitize

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
clang:codegen IR generation bugs: mangling, exceptions, etc. clang Clang issues not falling into any other category
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants