diff options
Diffstat (limited to 'src/md/hotdata/hotheapwriter.cpp')
-rw-r--r-- | src/md/hotdata/hotheapwriter.cpp | 305 |
1 files changed, 305 insertions, 0 deletions
diff --git a/src/md/hotdata/hotheapwriter.cpp b/src/md/hotdata/hotheapwriter.cpp new file mode 100644 index 0000000000..7f4edf4cff --- /dev/null +++ b/src/md/hotdata/hotheapwriter.cpp @@ -0,0 +1,305 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. +// +// File: HotHeapWriter.cpp +// + +// +// Class code:HotHeapWriter represents a writer of hot heap into MetaData hot stream (collected by IBC). +// +// ====================================================================================== + +#include "external.h" + +#include "hotheapwriter.h" +#include "../heaps/export.h" + +#include <stgpool.h> +#include <metamodelpub.h> +#include <utilcode.h> +#include "../inc/streamutil.h" + +#include "hotdataformat.h" + +#ifdef FEATURE_PREJIT +// Cannot be included without FEATURE_PREJIT: +#include <corcompile.h> +#endif //FEATURE_PREJIT + +namespace MetaData +{ + +// -------------------------------------------------------------------------------------- +// +// Creates writer for #String heap. +// +HotHeapWriter::HotHeapWriter( + const StringHeapRW *pStringHeap) +{ + m_HeapIndex = HeapIndex::StringHeapIndex; + m_pStringHeap = pStringHeap; +} // HotHeapWriter::HotHeapWriter + +// -------------------------------------------------------------------------------------- +// +// Creates writer for #Blob or #US heap (if fUserStringHeap is TRUE). +// +HotHeapWriter::HotHeapWriter( + const BlobHeapRW *pBlobHeap, + BOOL fUserStringHeap) +{ + m_HeapIndex = fUserStringHeap ? HeapIndex::UserStringHeapIndex : HeapIndex::BlobHeapIndex; + m_pBlobHeap = pBlobHeap; +} // HotHeapWriter::HotHeapWriter + +// -------------------------------------------------------------------------------------- +// +// Creates writer for #GUID heap. +// +HotHeapWriter::HotHeapWriter( + const GuidHeapRW *pGuidHeap) +{ + m_HeapIndex = HeapIndex::GuidHeapIndex; + m_pGuidHeap = pGuidHeap; +} // HotHeapWriter::HotHeapWriter + +// -------------------------------------------------------------------------------------- +// +// Destroys the writer of hot heap. +// +void +HotHeapWriter::Delete() +{ +} // HotHeapWriter::Delete + +typedef struct _RidOffsetPair +{ + ULONG rid; + ULONG offset; + // compare function for qsort + static int __cdecl Compare(void const *_x, void const *_y); +} RidOffsetPair; + +// static +int __cdecl +RidOffsetPair::Compare(void const *_x, void const *_y) +{ + RidOffsetPair const *x = reinterpret_cast<RidOffsetPair const *>(_x); + RidOffsetPair const *y = reinterpret_cast<RidOffsetPair const *>(_y); + + return x->rid - y->rid; +} + +// -------------------------------------------------------------------------------------- +// +// Stores hot data reported by IBC in profile data (code:CorProfileData) to a stream. +// Aligns output stream to 4-bytes. +// +__checkReturn +HRESULT +HotHeapWriter::SaveToStream( + IStream *pStream, + CorProfileData *pProfileData, + UINT32 *pnSavedSize) const +{ + _ASSERTE(pStream != NULL); + _ASSERTE(pProfileData != NULL); + _ASSERTE(pnSavedSize != NULL); + +#ifdef FEATURE_PREJIT + HRESULT hr = S_OK; + UINT32 nOffset = 0; + UINT32 nValueHeapStart_PositiveOffset; + UINT32 nValueOffsetTableStart_PositiveOffset; + UINT32 nIndexTableStart_PositiveOffset; + + // data + // + + // number of hot tokens + UINT32 nHotItemsCount = pProfileData->GetHotTokens( + GetTableIndex(), + 1 << ProfilingFlags_MetaData, + 1 << ProfilingFlags_MetaData, + NULL, + 0); + CONSISTENCY_CHECK(nHotItemsCount != 0); + + NewArrayHolder<UINT32> hotItemArr = new (nothrow) UINT32[nHotItemsCount]; + IfNullRet(hotItemArr); + + // get hot tokens + static_assert_no_msg(sizeof(UINT32) == sizeof(mdToken)); + pProfileData->GetHotTokens( + GetTableIndex(), + 1 << ProfilingFlags_MetaData, + 1 << ProfilingFlags_MetaData, + reinterpret_cast<mdToken *>(&hotItemArr[0]), + nHotItemsCount); + + // convert tokens to rids + for (UINT32 i = 0; i < nHotItemsCount; i++) + { + hotItemArr[i] = RidFromToken(hotItemArr[i]); + } + + NewArrayHolder<RidOffsetPair> offsetMapping = new (nothrow) RidOffsetPair[nHotItemsCount]; + IfNullRet(offsetMapping); + + // write data + nValueHeapStart_PositiveOffset = nOffset; + + // note that we write hot items in the order they appear in pProfileData->GetHotTokens + // this is so that we preserve the ordering optimizations done by IbcMerge + for (UINT32 i = 0; i < nHotItemsCount; i++) + { + DataBlob data; + IfFailRet(GetData( + hotItemArr[i], + &data)); + + // keep track of the offset at which each hot item is written + offsetMapping[i].rid = hotItemArr[i]; + offsetMapping[i].offset = nOffset; + + IfFailRet(StreamUtil::WriteToStream( + pStream, + data.GetDataPointer(), + data.GetSize(), + &nOffset)); + } + + IfFailRet(StreamUtil::AlignDWORD(pStream, &nOffset)); + + // sort by rid so that a hot rid can be looked up by binary search + qsort(offsetMapping, nHotItemsCount, sizeof(RidOffsetPair), RidOffsetPair::Compare); + + // initialize table of offsets to data + NewArrayHolder<UINT32> dataIndices = new (nothrow) UINT32[nHotItemsCount]; + IfNullRet(dataIndices); + + // fill in the hotItemArr (now sorted by rid) and dataIndices array with each offset + for (UINT32 i = 0; i < nHotItemsCount; i++) + { + hotItemArr[i] = offsetMapping[i].rid; + dataIndices[i] = offsetMapping[i].offset; + } + + // table of offsets to data + // + + nValueOffsetTableStart_PositiveOffset = nOffset; + IfFailRet(StreamUtil::WriteToStream(pStream, &dataIndices[0], sizeof(UINT32) * nHotItemsCount, &nOffset)); + + // rid table (sorted) + // + + nIndexTableStart_PositiveOffset = nOffset; + + IfFailRet(StreamUtil::WriteToStream(pStream, &hotItemArr[0], nHotItemsCount * sizeof(UINT32), &nOffset)); + IfFailRet(StreamUtil::AlignDWORD(pStream, &nOffset)); + + { + // hot pool header + struct HotHeapHeader header; + + // fix offsets + header.m_nIndexTableStart_NegativeOffset = nOffset - nIndexTableStart_PositiveOffset; + header.m_nValueOffsetTableStart_NegativeOffset = nOffset - nValueOffsetTableStart_PositiveOffset; + header.m_nValueHeapStart_NegativeOffset = nOffset - nValueHeapStart_PositiveOffset; + + // write header + IfFailRet(StreamUtil::WriteToStream(pStream, &header, sizeof(header), &nOffset)); + } + + *pnSavedSize = nOffset; + +#endif //FEATURE_PREJIT + + return S_OK; +} // HotHeapWriter::PersistHotToStream + +// -------------------------------------------------------------------------------------- +// +// Returns index of the heap as table index used by IBC (code:CorProfileData). +// +UINT32 +HotHeapWriter::GetTableIndex() const +{ + return TBL_COUNT + m_HeapIndex.Get(); +} // HotHeapWriter::GetTableIndex + +// -------------------------------------------------------------------------------------- +// +// Returns heap data at index (nIndex). +// +__checkReturn +HRESULT +HotHeapWriter::GetData( + UINT32 nIndex, + DataBlob *pData) const +{ + HRESULT hr; + + switch (m_HeapIndex.Get()) + { + case HeapIndex::StringHeapIndex: + { + LPCSTR szString; + IfFailGo(m_pStringHeap->GetString( + nIndex, + &szString)); + _ASSERTE(hr == S_OK); + + // This should not overflow, because we checked it before, but it doesn't hurt + S_UINT32 cbStringSize = S_UINT32(strlen(szString)) + S_UINT32(1); + if (cbStringSize.IsOverflow()) + { + Debug_ReportInternalError("There's a bug in the string heap consistency - string is too long."); + IfFailGo(METADATA_E_INTERNAL_ERROR); + } + + pData->Init((BYTE *)szString, cbStringSize.Value()); + return S_OK; + } + case HeapIndex::GuidHeapIndex: + { + // The nIndex is in fact 0-based offset into GUID heap (0, 16, 32, ...), convert it to 1-based element index (1, 2, 3, ...) for GetGuid method + if ((nIndex % sizeof(GUID)) != 0) + { + Debug_ReportInternalError("There's a bug in the caller/IBC - this should be GUID offset aligned to 16-B."); + IfFailGo(METADATA_E_INTERNAL_ERROR); + } + nIndex = (nIndex / sizeof(GUID)) + 1; + + GUID UNALIGNED *pGuid; + IfFailGo(const_cast<GuidHeapRW *>(m_pGuidHeap)->GetGuid( + nIndex, + &pGuid)); + _ASSERTE(hr == S_OK); + pData->Init((BYTE *)pGuid, sizeof(GUID)); + return S_OK; + } + case HeapIndex::BlobHeapIndex: + case HeapIndex::UserStringHeapIndex: + { + IfFailGo(const_cast<BlobHeapRW *>(m_pBlobHeap)->GetBlobWithSizePrefix( + nIndex, + pData)); + _ASSERTE(hr == S_OK); + + return S_OK; + } + default: + Debug_ReportInternalError("There's a bug in the caller - this is wrong heap index."); + IfFailGo(METADATA_E_INTERNAL_ERROR); + } + return S_OK; + +ErrExit: + pData->Clear(); + return hr; +} // HotHeapWriter::GetData + +}; // namespace MetaData |