diff options
author | Derek Bruening <bruening@google.com> | 2016-07-09 04:13:25 +0000 |
---|---|---|
committer | Derek Bruening <bruening@google.com> | 2016-07-09 04:13:25 +0000 |
commit | bcdfb408444c657422499a2274eb377879588e89 (patch) | |
tree | aedcaccf6e02afc9348c1680cddf2df18aecc29e /lib/esan | |
parent | 87110b4eb106dc2ccaaa74647293fe6e05cabb96 (diff) |
[esan] Add __esan_report for mid-run data
Summary:
Adds a new public interface routine __esan_report() which can be used to
request profiling results prior to abnormal termination (e.g., for a server
process killed by its parent where the normal exit does not allow for
normal result reporting).
Implements this for the working-set tool. The cache frag tool is left
unimplemented as it requires missing iteration capabilities.
Adds a new test.
Reviewers: aizatsky
Subscribers: vitalybuka, zhaoqin, kcc, eugenis, llvm-commits, kubabrecka
Differential Revision: http://reviews.llvm.org/D22098
git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@274964 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/esan')
-rw-r--r-- | lib/esan/cache_frag.cpp | 6 | ||||
-rw-r--r-- | lib/esan/cache_frag.h | 1 | ||||
-rw-r--r-- | lib/esan/esan.cpp | 9 | ||||
-rw-r--r-- | lib/esan/esan.h | 1 | ||||
-rw-r--r-- | lib/esan/esan_interface.cpp | 7 | ||||
-rw-r--r-- | lib/esan/working_set.cpp | 26 | ||||
-rw-r--r-- | lib/esan/working_set.h | 1 |
7 files changed, 46 insertions, 5 deletions
diff --git a/lib/esan/cache_frag.cpp b/lib/esan/cache_frag.cpp index 343abfcd5..a3e612dac 100644 --- a/lib/esan/cache_frag.cpp +++ b/lib/esan/cache_frag.cpp @@ -199,4 +199,10 @@ int finalizeCacheFrag() { return 0; } +void reportCacheFrag() { + VPrintf(2, "in esan::%s\n", __FUNCTION__); + // FIXME: Not yet implemented. We need to iterate over all of the + // compilation unit data. +} + } // namespace __esan diff --git a/lib/esan/cache_frag.h b/lib/esan/cache_frag.h index 9f8793220..646d3f85e 100644 --- a/lib/esan/cache_frag.h +++ b/lib/esan/cache_frag.h @@ -22,6 +22,7 @@ void processCacheFragCompilationUnitExit(void *Ptr); void initializeCacheFrag(); int finalizeCacheFrag(); +void reportCacheFrag(); } // namespace __esan diff --git a/lib/esan/esan.cpp b/lib/esan/esan.cpp index 970f91a83..3c69b4e91 100644 --- a/lib/esan/esan.cpp +++ b/lib/esan/esan.cpp @@ -228,6 +228,15 @@ int finalizeLibrary() { return 0; } +void reportResults() { + VPrintf(1, "in esan::%s\n", __FUNCTION__); + if (__esan_which_tool == ESAN_CacheFrag) { + return reportCacheFrag(); + } else if (__esan_which_tool == ESAN_WorkingSet) { + return reportWorkingSet(); + } +} + void processCompilationUnitInit(void *Ptr) { VPrintf(2, "in esan::%s\n", __FUNCTION__); if (__esan_which_tool == ESAN_CacheFrag) { diff --git a/lib/esan/esan.h b/lib/esan/esan.h index 4171522db..371810d5e 100644 --- a/lib/esan/esan.h +++ b/lib/esan/esan.h @@ -37,6 +37,7 @@ extern bool EsanDuringInit; void initializeLibrary(ToolType Tool); int finalizeLibrary(); +void reportResults(); // Esan creates the variable per tool per compilation unit at compile time // and passes its pointer Ptr to the runtime library. void processCompilationUnitInit(void *Ptr); diff --git a/lib/esan/esan_interface.cpp b/lib/esan/esan_interface.cpp index f6ad3caa8..8a64d1526 100644 --- a/lib/esan/esan_interface.cpp +++ b/lib/esan/esan_interface.cpp @@ -109,3 +109,10 @@ void __esan_unaligned_loadN(void *Addr, uptr Size) { void __esan_unaligned_storeN(void *Addr, uptr Size) { processRangeAccess(GET_CALLER_PC(), (uptr)Addr, Size, true); } + +// Public interface: +extern "C" { +SANITIZER_INTERFACE_ATTRIBUTE void __esan_report() { + reportResults(); +} +} // extern "C" diff --git a/lib/esan/working_set.cpp b/lib/esan/working_set.cpp index 622fd29e8..3fde5a8b5 100644 --- a/lib/esan/working_set.cpp +++ b/lib/esan/working_set.cpp @@ -118,6 +118,8 @@ void processRangeAccessWorkingSet(uptr PC, uptr Addr, SIZE_T Size, } // This routine will word-align ShadowStart and ShadowEnd prior to scanning. +// It does *not* clear for BitIdx==TotalWorkingSetBitIdx, as that top bit +// measures the access during the entire execution and should never be cleared. static u32 countAndClearShadowValues(u32 BitIdx, uptr ShadowStart, uptr ShadowEnd) { u32 WorkingSetSize = 0; @@ -127,6 +129,8 @@ static u32 countAndClearShadowValues(u32 BitIdx, uptr ShadowStart, // Get word aligned start. ShadowStart = RoundDownTo(ShadowStart, sizeof(u32)); bool Accum = getFlags()->record_snapshots && BitIdx < MaxAccumBitIdx; + // Do not clear the bit that measures access during the entire execution. + bool Clear = BitIdx < TotalWorkingSetBitIdx; for (u32 *Ptr = (u32 *)ShadowStart; Ptr < (u32 *)ShadowEnd; ++Ptr) { if ((*Ptr & WordValue) != 0) { byte *BytePtr = (byte *)Ptr; @@ -139,8 +143,10 @@ static u32 countAndClearShadowValues(u32 BitIdx, uptr ShadowStart, } } } - // Clear this bit from every shadow byte. - *Ptr &= ~WordValue; + if (Clear) { + // Clear this bit from every shadow byte. + *Ptr &= ~WordValue; + } } } return WorkingSetSize; @@ -149,6 +155,8 @@ static u32 countAndClearShadowValues(u32 BitIdx, uptr ShadowStart, // Scan shadow memory to calculate the number of cache lines being accessed, // i.e., the number of non-zero bits indexed by BitIdx in each shadow byte. // We also clear the lowest bits (most recent working set snapshot). +// We do *not* clear for BitIdx==TotalWorkingSetBitIdx, as that top bit +// measures the access during the entire execution and should never be cleared. static u32 computeWorkingSizeAndReset(u32 BitIdx) { u32 WorkingSetSize = 0; MemoryMappingLayout MemIter(true/*cache*/); @@ -226,10 +234,9 @@ static u32 getSizeForPrinting(u32 NumOfCachelines, const char *&Unit) { } } -int finalizeWorkingSet() { +void reportWorkingSet() { const char *Unit; if (getFlags()->record_snapshots) { - Thread.joinThread(); u32 Freq = 1; Report(" Total number of samples: %u\n", SnapshotNum); for (u32 i = 0; i < NumFreq; ++i) { @@ -243,7 +250,6 @@ int finalizeWorkingSet() { SizePerFreq[i][j]); } Freq = Freq << getFlags()->snapshot_step; - SizePerFreq[i].free(); } } @@ -252,6 +258,16 @@ int finalizeWorkingSet() { u32 Size = getSizeForPrinting(NumOfCachelines, Unit); Report(" %s: the total working set size: %u %s (%u cache lines)\n", SanitizerToolName, Size, Unit, NumOfCachelines); +} + +int finalizeWorkingSet() { + if (getFlags()->record_snapshots) + Thread.joinThread(); + reportWorkingSet(); + if (getFlags()->record_snapshots) { + for (u32 i = 0; i < NumFreq; ++i) + SizePerFreq[i].free(); + } return 0; } diff --git a/lib/esan/working_set.h b/lib/esan/working_set.h index 660b5d066..38ff0635d 100644 --- a/lib/esan/working_set.h +++ b/lib/esan/working_set.h @@ -23,6 +23,7 @@ namespace __esan { void initializeWorkingSet(); void initializeShadowWorkingSet(); int finalizeWorkingSet(); +void reportWorkingSet(); void processRangeAccessWorkingSet(uptr PC, uptr Addr, SIZE_T Size, bool IsWrite); |