[llvm] [HWASAN] Implement selective instrumentation based on profiling information (PR #83503)

Kirill Stoimenov via llvm-commits llvm-commits at lists.llvm.org
Thu Feb 29 15:38:04 PST 2024


https://github.com/kstoimenov updated https://github.com/llvm/llvm-project/pull/83503

>From 6fff46376325201823391dc9702d8aab1fd8b1c7 Mon Sep 17 00:00:00 2001
From: Kirill Stoimenov <kstoimenov at google.com>
Date: Fri, 23 Feb 2024 17:33:02 +0000
Subject: [PATCH 1/4] [HWASAN] Implement selective instumentation based on
 profiling information.

---
 .../Instrumentation/HWAddressSanitizer.cpp    | 65 ++++++++++++++++++-
 1 file changed, 63 insertions(+), 2 deletions(-)

diff --git a/llvm/lib/Transforms/Instrumentation/HWAddressSanitizer.cpp b/llvm/lib/Transforms/Instrumentation/HWAddressSanitizer.cpp
index 33add6d4cd767b..ba79c221ea5490 100644
--- a/llvm/lib/Transforms/Instrumentation/HWAddressSanitizer.cpp
+++ b/llvm/lib/Transforms/Instrumentation/HWAddressSanitizer.cpp
@@ -15,11 +15,14 @@
 #include "llvm/ADT/MapVector.h"
 #include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/Statistic.h"
 #include "llvm/ADT/StringExtras.h"
 #include "llvm/ADT/StringRef.h"
 #include "llvm/Analysis/DomTreeUpdater.h"
 #include "llvm/Analysis/GlobalsModRef.h"
 #include "llvm/Analysis/PostDominators.h"
+#include "llvm/Analysis/BlockFrequencyInfo.h"
+#include "llvm/Analysis/ProfileSummaryInfo.h"
 #include "llvm/Analysis/StackSafetyAnalysis.h"
 #include "llvm/Analysis/TargetLibraryInfo.h"
 #include "llvm/Analysis/ValueTracking.h"
@@ -177,6 +180,25 @@ static cl::opt<bool> ClWithTls(
              "platforms that support this"),
     cl::Hidden, cl::init(true));
 
+static cl::opt<bool>
+    CSkipHotCode("hwasan-skip-hot-code",
+                 cl::desc("Do not instument hot functions based on FDO."),
+                 cl::Hidden, cl::init(false));
+
+static cl::opt<int> HotPercentileCutoff("opt-hwasan-percentile-cutoff-hot",
+                                        cl::init(0));
+static cl::opt<int> ColdPercentileCutoff("opt-hwasan-percentile-cutoff-cold",
+                                         cl::init(0));
+
+STATISTIC(NumTotalFuncs, "Number of funcs seen by HWASAN");
+STATISTIC(NumHwasanCtors, "Number of HWASAN ctors");
+STATISTIC(NumNoSanitizeFuncs, "Number of no-sanitize HWASAN funcs");
+STATISTIC(NumConsideredFuncs, "Number of funcs considered for HWASAN");
+STATISTIC(NumInstrumentedFuncs, "Number of HWASAN instrumented funcs");
+STATISTIC(NumNoProfileSummaryFuncs, "Number of HWASAN funcs without PS");
+STATISTIC(NumSkippedHotFuncs, "Number of skipped hot HWASAN funcs");
+STATISTIC(NumSkippedNotColdFuncs, "Number of skipped not cold HWASAN funcs");
+
 // Mode for selecting how to insert frame record info into the stack ring
 // buffer.
 enum RecordStackHistoryMode {
@@ -1501,11 +1523,50 @@ bool HWAddressSanitizer::instrumentStack(memtag::StackInfo &SInfo,
 
 void HWAddressSanitizer::sanitizeFunction(Function &F,
                                           FunctionAnalysisManager &FAM) {
-  if (&F == HwasanCtorFunction)
+  NumTotalFuncs++;
+  if (&F == HwasanCtorFunction) {
+    NumHwasanCtors++;
     return;
+  }
 
-  if (!F.hasFnAttribute(Attribute::SanitizeHWAddress))
+  if (!F.hasFnAttribute(Attribute::SanitizeHWAddress)) {
+    NumNoSanitizeFuncs++;
     return;
+  }
+
+  NumConsideredFuncs++;
+  if (CSkipHotCode) {
+    auto &MAMProxy = FAM.getResult<ModuleAnalysisManagerFunctionProxy>(F);
+    ProfileSummaryInfo *PSI =
+        MAMProxy.getCachedResult<ProfileSummaryAnalysis>(*F.getParent());
+    if (PSI != nullptr && PSI->hasProfileSummary()) {
+      auto &BFI = FAM.getResult<BlockFrequencyAnalysis>(F);
+
+      const bool is_hot =
+          (HotPercentileCutoff.getNumOccurrences() && HotPercentileCutoff >= 0)
+              ? PSI->isFunctionHotInCallGraphNthPercentile(HotPercentileCutoff,
+                                                           &F, BFI)
+              : PSI->isFunctionEntryHot(&F);
+
+      const auto is_cold = (ColdPercentileCutoff.getNumOccurrences() &&
+                            ColdPercentileCutoff >= 0)
+                               ? PSI->isFunctionColdInCallGraphNthPercentile(
+                                     ColdPercentileCutoff, &F, BFI)
+                               : PSI->isFunctionEntryCold(&F);
+
+      if (is_hot) {
+        ++NumSkippedHotFuncs;
+        return;
+      }
+      if (!is_cold) {
+        ++NumSkippedNotColdFuncs;
+        return;
+      }
+    } else {
+      ++NumNoProfileSummaryFuncs;
+    }
+  }
+  NumInstrumentedFuncs++;
 
   LLVM_DEBUG(dbgs() << "Function: " << F.getName() << "\n");
 

>From fc36ab787a98c38f3c19d8b8bd3318d48bb777bb Mon Sep 17 00:00:00 2001
From: Kirill Stoimenov <kstoimenov at google.com>
Date: Thu, 29 Feb 2024 21:33:40 +0000
Subject: [PATCH 2/4] Removed cold code.

---
 .../Instrumentation/HWAddressSanitizer.cpp         | 14 --------------
 1 file changed, 14 deletions(-)

diff --git a/llvm/lib/Transforms/Instrumentation/HWAddressSanitizer.cpp b/llvm/lib/Transforms/Instrumentation/HWAddressSanitizer.cpp
index ba79c221ea5490..99b92731a3b9ac 100644
--- a/llvm/lib/Transforms/Instrumentation/HWAddressSanitizer.cpp
+++ b/llvm/lib/Transforms/Instrumentation/HWAddressSanitizer.cpp
@@ -187,8 +187,6 @@ static cl::opt<bool>
 
 static cl::opt<int> HotPercentileCutoff("opt-hwasan-percentile-cutoff-hot",
                                         cl::init(0));
-static cl::opt<int> ColdPercentileCutoff("opt-hwasan-percentile-cutoff-cold",
-                                         cl::init(0));
 
 STATISTIC(NumTotalFuncs, "Number of funcs seen by HWASAN");
 STATISTIC(NumHwasanCtors, "Number of HWASAN ctors");
@@ -197,7 +195,6 @@ STATISTIC(NumConsideredFuncs, "Number of funcs considered for HWASAN");
 STATISTIC(NumInstrumentedFuncs, "Number of HWASAN instrumented funcs");
 STATISTIC(NumNoProfileSummaryFuncs, "Number of HWASAN funcs without PS");
 STATISTIC(NumSkippedHotFuncs, "Number of skipped hot HWASAN funcs");
-STATISTIC(NumSkippedNotColdFuncs, "Number of skipped not cold HWASAN funcs");
 
 // Mode for selecting how to insert frame record info into the stack ring
 // buffer.
@@ -1541,27 +1538,16 @@ void HWAddressSanitizer::sanitizeFunction(Function &F,
         MAMProxy.getCachedResult<ProfileSummaryAnalysis>(*F.getParent());
     if (PSI != nullptr && PSI->hasProfileSummary()) {
       auto &BFI = FAM.getResult<BlockFrequencyAnalysis>(F);
-
       const bool is_hot =
           (HotPercentileCutoff.getNumOccurrences() && HotPercentileCutoff >= 0)
               ? PSI->isFunctionHotInCallGraphNthPercentile(HotPercentileCutoff,
                                                            &F, BFI)
               : PSI->isFunctionEntryHot(&F);
 
-      const auto is_cold = (ColdPercentileCutoff.getNumOccurrences() &&
-                            ColdPercentileCutoff >= 0)
-                               ? PSI->isFunctionColdInCallGraphNthPercentile(
-                                     ColdPercentileCutoff, &F, BFI)
-                               : PSI->isFunctionEntryCold(&F);
-
       if (is_hot) {
         ++NumSkippedHotFuncs;
         return;
       }
-      if (!is_cold) {
-        ++NumSkippedNotColdFuncs;
-        return;
-      }
     } else {
       ++NumNoProfileSummaryFuncs;
     }

>From 269c6c879fba684e5f0ced9b7b2f4b6cab21e3ba Mon Sep 17 00:00:00 2001
From: Kirill Stoimenov <kstoimenov at google.com>
Date: Thu, 29 Feb 2024 23:34:56 +0000
Subject: [PATCH 3/4] Added tests.

---
 llvm/lib/Transforms/Instrumentation/HWAddressSanitizer.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/llvm/lib/Transforms/Instrumentation/HWAddressSanitizer.cpp b/llvm/lib/Transforms/Instrumentation/HWAddressSanitizer.cpp
index 99b92731a3b9ac..bf59f10723c2db 100644
--- a/llvm/lib/Transforms/Instrumentation/HWAddressSanitizer.cpp
+++ b/llvm/lib/Transforms/Instrumentation/HWAddressSanitizer.cpp
@@ -185,7 +185,7 @@ static cl::opt<bool>
                  cl::desc("Do not instument hot functions based on FDO."),
                  cl::Hidden, cl::init(false));
 
-static cl::opt<int> HotPercentileCutoff("opt-hwasan-percentile-cutoff-hot",
+static cl::opt<int> HotPercentileCutoff("hwasan-percentile-cutoff-hot",
                                         cl::init(0));
 
 STATISTIC(NumTotalFuncs, "Number of funcs seen by HWASAN");

>From 587cb5d7680fd49e9f29da19cffbfff9f11b306c Mon Sep 17 00:00:00 2001
From: Kirill Stoimenov <kstoimenov at google.com>
Date: Thu, 29 Feb 2024 23:37:41 +0000
Subject: [PATCH 4/4] For realz added tests.

---
 .../HWAddressSanitizer/selsan-no-ps.ll        | 16 ++++++++++
 .../HWAddressSanitizer/selsan.ll              | 32 +++++++++++++++++++
 2 files changed, 48 insertions(+)
 create mode 100644 llvm/test/Instrumentation/HWAddressSanitizer/selsan-no-ps.ll
 create mode 100644 llvm/test/Instrumentation/HWAddressSanitizer/selsan.ll

diff --git a/llvm/test/Instrumentation/HWAddressSanitizer/selsan-no-ps.ll b/llvm/test/Instrumentation/HWAddressSanitizer/selsan-no-ps.ll
new file mode 100644
index 00000000000000..d7c7365edf200a
--- /dev/null
+++ b/llvm/test/Instrumentation/HWAddressSanitizer/selsan-no-ps.ll
@@ -0,0 +1,16 @@
+; RUN: opt < %s -passes='require<profile-summary>,hwasan' -S -stats 2>&1 \
+; RUN:   -hwasan-skip-hot-code=0 | FileCheck %s --check-prefix=FULL
+; RUN: opt < %s -passes='require<profile-summary>,hwasan' -S -stats 2>&1 \
+; RUN:   -hwasan-skip-hot-code=1 | FileCheck %s --check-prefix=SELSAN
+
+; FULL: 1 hwasan - Number of funcs considered for HWASAN
+; FULL: 1 hwasan - Number of HWASAN ctors
+; FULL: 1 hwasan - Number of HWASAN instrumented funcs
+
+; SELSAN: 1 hwasan - Number of funcs considered for HWASAN
+; SELSAN: 1 hwasan - Number of HWASAN ctors
+; SELSAN: 1 hwasan - Number of HWASAN instrumented funcs
+; SELSAN: 1 hwasan - Number of HWASAN funcs without PS
+
+define void @not_sanitized() { ret void }
+define void @sanitized_no_ps() sanitize_hwaddress { ret void }
diff --git a/llvm/test/Instrumentation/HWAddressSanitizer/selsan.ll b/llvm/test/Instrumentation/HWAddressSanitizer/selsan.ll
new file mode 100644
index 00000000000000..77fc9d4ab5ac49
--- /dev/null
+++ b/llvm/test/Instrumentation/HWAddressSanitizer/selsan.ll
@@ -0,0 +1,32 @@
+; RUN: opt < %s -passes='require<profile-summary>,hwasan' -S -stats 2>&1 \
+; RUN:   -hwasan-skip-hot-code=1 | FileCheck %s --check-prefix=DEFAULT
+; RUN: opt < %s -passes='require<profile-summary>,hwasan' -S -stats 2>&1 \
+; RUN:   -hwasan-skip-hot-code=1 -hwasan-percentile-cutoff-hot=700000 | FileCheck %s --check-prefix=PERCENT
+
+; DEFAULT: 1 hwasan - Number of funcs considered for HWASAN
+; DEFAULT: 1 hwasan - Number of skipped hot HWASAN funcs
+
+; PERCENT: 1 hwasan - Number of funcs considered for HWASAN
+; PERCENT: 1 hwasan - Number of HWASAN instrumented funcs
+
+define void @sanitized() sanitize_hwaddress !prof !36 { ret void }
+
+!llvm.module.flags = !{!6}
+!6 = !{i32 1, !"ProfileSummary", !7}
+!7 = !{!8, !9, !10, !11, !12, !13, !14, !17}
+!8 = !{!"ProfileFormat", !"InstrProf"}
+!9 = !{!"TotalCount", i64 30000}
+!10 = !{!"MaxCount", i64 10000}
+!11 = !{!"MaxInternalCount", i64 10000}
+!12 = !{!"MaxFunctionCount", i64 10000}
+!13 = !{!"NumCounts", i64 3}
+!14 = !{!"NumFunctions", i64 5}
+!17 = !{!"DetailedSummary", !18}
+!18 = !{!19, !29, !30, !32, !34}
+!19 = !{i32 10000, i64 10000, i32 3}
+!29 = !{i32 950000, i64 5000, i32 3}
+!30 = !{i32 990000, i64 500, i32 4}
+!32 = !{i32 999900, i64 250, i32 4}
+!34 = !{i32 999999, i64 1, i32 6}
+
+!36 = !{!"function_entry_count", i64 1000}



More information about the llvm-commits mailing list