summaryrefslogtreecommitdiff
path: root/src/jit/compiler.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/jit/compiler.cpp')
-rw-r--r--src/jit/compiler.cpp169
1 files changed, 169 insertions, 0 deletions
diff --git a/src/jit/compiler.cpp b/src/jit/compiler.cpp
index 14b2abafb6..1c24b93abe 100644
--- a/src/jit/compiler.cpp
+++ b/src/jit/compiler.cpp
@@ -1134,6 +1134,170 @@ var_types Compiler::getReturnTypeForStruct(CORINFO_CLASS_HANDLE clsHnd,
return useType;
}
+///////////////////////////////////////////////////////////////////////////////
+//
+// MEASURE_NOWAY: code to measure and rank dynamic occurences of noway_assert.
+// (Just the appearances of noway_assert, whether the assert is true or false.)
+// This might help characterize the cost of noway_assert in non-DEBUG builds,
+// or determine which noway_assert should be simple DEBUG-only asserts.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#if MEASURE_NOWAY
+
+struct FileLine
+{
+ char* m_file;
+ unsigned m_line;
+ char* m_condStr;
+
+ FileLine() : m_file(nullptr), m_line(0), m_condStr(nullptr)
+ {
+ }
+
+ FileLine(const char* file, unsigned line, const char* condStr) : m_line(line)
+ {
+ size_t newSize = (strlen(file) + 1) * sizeof(char);
+ m_file = (char*)HostAllocator::getHostAllocator()->Alloc(newSize);
+ strcpy_s(m_file, newSize, file);
+
+ newSize = (strlen(condStr) + 1) * sizeof(char);
+ m_condStr = (char*)HostAllocator::getHostAllocator()->Alloc(newSize);
+ strcpy_s(m_condStr, newSize, condStr);
+ }
+
+ FileLine(const FileLine& other)
+ {
+ m_file = other.m_file;
+ m_line = other.m_line;
+ m_condStr = other.m_condStr;
+ }
+
+ // GetHashCode() and Equals() are needed by SimplerHashTable
+
+ static unsigned GetHashCode(FileLine fl)
+ {
+ assert(fl.m_file != nullptr);
+ unsigned code = fl.m_line;
+ for (const char* p = fl.m_file; *p != '\0'; p++)
+ {
+ code += *p;
+ }
+ // Could also add condStr.
+ return code;
+ }
+
+ static bool Equals(FileLine fl1, FileLine fl2)
+ {
+ return (fl1.m_line == fl2.m_line) && (0 == strcmp(fl1.m_file, fl2.m_file));
+ }
+};
+
+typedef SimplerHashTable<FileLine, FileLine, size_t, JitSimplerHashBehavior> FileLineToCountMap;
+FileLineToCountMap* NowayAssertMap;
+
+void Compiler::RecordNowayAssert(const char* filename, unsigned line, const char* condStr)
+{
+ if (NowayAssertMap == nullptr)
+ {
+ NowayAssertMap = new (HostAllocator::getHostAllocator()) FileLineToCountMap(HostAllocator::getHostAllocator());
+ }
+ FileLine fl(filename, line, condStr);
+ size_t* pCount = NowayAssertMap->LookupPointer(fl);
+ if (pCount == nullptr)
+ {
+ NowayAssertMap->Set(fl, 1);
+ }
+ else
+ {
+ ++(*pCount);
+ }
+}
+
+void RecordNowayAssertGlobal(const char* filename, unsigned line, const char* condStr)
+{
+ if ((JitConfig.JitMeasureNowayAssert() == 1) && (JitTls::GetCompiler() != nullptr))
+ {
+ JitTls::GetCompiler()->RecordNowayAssert(filename, line, condStr);
+ }
+}
+
+struct NowayAssertCountMap
+{
+ size_t count;
+ FileLine fl;
+
+ NowayAssertCountMap() : count(0)
+ {
+ }
+
+ static int __cdecl compare(const void* elem1, const void* elem2)
+ {
+ NowayAssertCountMap* e1 = (NowayAssertCountMap*)elem1;
+ NowayAssertCountMap* e2 = (NowayAssertCountMap*)elem2;
+ return (int)((ssize_t)e2->count - (ssize_t)e1->count); // sort in descending order
+ }
+};
+
+void DisplayNowayAssertMap()
+{
+ if (NowayAssertMap != nullptr)
+ {
+ FILE* fout;
+
+ LPCWSTR strJitMeasureNowayAssertFile = JitConfig.JitMeasureNowayAssertFile();
+ if (strJitMeasureNowayAssertFile != nullptr)
+ {
+ fout = _wfopen(strJitMeasureNowayAssertFile, W("a"));
+ if (fout == nullptr)
+ {
+ fprintf(jitstdout, "Failed to open JitMeasureNowayAssertFile \"%ws\"\n", strJitMeasureNowayAssertFile);
+ return;
+ }
+ }
+ else
+ {
+ fout = jitstdout;
+ }
+
+ // Iterate noway assert map, create sorted table by occurrence, dump it.
+ unsigned count = NowayAssertMap->GetCount();
+ NowayAssertCountMap* nacp = new NowayAssertCountMap[count];
+ unsigned i = 0;
+
+ for (FileLineToCountMap::KeyIterator iter = NowayAssertMap->Begin(), end = NowayAssertMap->End();
+ !iter.Equal(end); ++iter)
+ {
+ nacp[i].count = iter.GetValue();
+ nacp[i].fl = iter.Get();
+ ++i;
+ }
+
+ qsort(nacp, count, sizeof(nacp[0]), NowayAssertCountMap::compare);
+
+ if (fout == jitstdout)
+ {
+ // Don't output the header if writing to a file, since we'll be appending to existing dumps in that case.
+ fprintf(fout, "\nnoway_assert counts:\n");
+ fprintf(fout, "count, file, line, text\n");
+ }
+
+ for (i = 0; i < count; i++)
+ {
+ fprintf(fout, "%u, %s, %u, \"%s\"\n", nacp[i].count, nacp[i].fl.m_file, nacp[i].fl.m_line,
+ nacp[i].fl.m_condStr);
+ }
+
+ if (fout != jitstdout)
+ {
+ fclose(fout);
+ fout = nullptr;
+ }
+ }
+}
+
+#endif // MEASURE_NOWAY
+
/*****************************************************************************
* variables to keep track of how many iterations we go in a dataflow pass
*/
@@ -1222,6 +1386,10 @@ void Compiler::compShutdown()
}
#endif // ALT_JIT
+#if MEASURE_NOWAY
+ DisplayNowayAssertMap();
+#endif // MEASURE_NOWAY
+
ArenaAllocator::shutdown();
/* Shut down the emitter */
@@ -2414,6 +2582,7 @@ bool Compiler::compShouldThrowOnNoway(
#ifdef FEATURE_TRACELOGGING
compJitTelemetry.NotifyNowayAssert(filename, line);
#endif
+
// In min opts, we don't want the noway assert to go through the exception
// path. Instead we want it to just silently go through codegen for
// compat reasons.