#ifndef __TRACYSOURCEVIEW_HPP__ #define __TRACYSOURCEVIEW_HPP__ #include #include #include #include "tracy_robin_hood.h" #include "TracyCharUtil.hpp" #include "TracyDecayValue.hpp" #include "TracySourceContents.hpp" #include "TracySourceTokenizer.hpp" #include "../public/common/TracyForceInline.hpp" #include "../public/common/TracyProtocol.hpp" struct ImFont; struct ImVec2; namespace tracy { class View; class Worker; struct CallstackFrameData; class SourceView { public: enum class RegsX86 : uint8_t { invalid, flags, rax, rbx, rcx, rdx, rsi, rdi, rbp, rsp, r8, r9, r10, r11, r12, r13, r14, r15, mm0, mm1, mm2, mm3, mm4, mm5, mm6, mm7, xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7, xmm8, xmm9, xmm10, xmm11, xmm12, xmm13, xmm14, xmm15, xmm16, xmm17, xmm18, xmm19, xmm20, xmm21, xmm22, xmm23, xmm24, xmm25, xmm26, xmm27, xmm28, xmm29, xmm30, xmm31, k0, k1, k2, k3, k4, k5, k6, k7, NUMBER_OF_ENTRIES }; enum class CostType { SampleCount, Cycles, SlowBranches, SlowCache, Retirements, BranchesTaken, BranchMiss, CacheAccess, CacheMiss }; private: struct AsmOpParams { uint8_t type; uint16_t width; }; enum class LeaData : uint8_t { none, b, bd, bi, bid, d, i, id, r, rd }; enum { ReadBit = 0x100 }; enum { WriteBit = 0x200 }; enum { ReuseBit = 0x400 }; enum { RegMask = 0x0FF }; enum { FlagMask = 0xF00 }; enum class OpType : uint8_t { None, Jump, Branch, Call, Ret, Privileged }; struct AsmLine { uint64_t addr; uint64_t jumpAddr; std::string mnemonic; std::string operands; uint8_t len; LeaData leaData; OpType opType; bool jumpConditional; std::vector params; std::vector opTokens; union { RegsX86 readX86[12]; }; union { RegsX86 writeX86[20]; }; uint16_t regData[20]; }; enum { AsmLineSize = sizeof( AsmLine ) }; struct JumpData { uint64_t min; uint64_t max; size_t level; std::vector source; }; enum { DisplaySource, DisplayAsm, DisplayMixed }; struct AddrStat { uint64_t local; uint64_t ext; AddrStat& operator+=( const AddrStat& other ) { local += other.local; ext += other.ext; return *this; } }; struct AddrStatData { AddrStat ipTotalSrc = {}; AddrStat ipTotalAsm = {}; AddrStat ipMaxSrc = {}; AddrStat ipMaxAsm = {}; AddrStat hwMaxSrc = {}; AddrStat hwMaxAsm = {}; unordered_flat_map ipCountSrc, ipCountAsm; unordered_flat_map hwCountSrc, hwCountAsm; }; struct History { const char* fileName; int64_t line; uint64_t baseAddr; uint64_t symAddr; }; public: SourceView(); void UpdateFont( ImFont* fixed, ImFont* small, ImFont* big ) { m_font = fixed; m_smallFont = small; m_bigFont = big; } void SetCpuId( uint32_t cpuid ); void OpenSource( const char* fileName, int line, const View& view, const Worker& worker ); void OpenSymbol( const char* fileName, int line, uint64_t baseAddr, uint64_t symAddr, Worker& worker, const View& view, bool updateHistory = true ); void Render( Worker& worker, View& view ); void CalcInlineStats( bool val ) { m_calcInlineStats = val; } bool IsSymbolView() const { return !m_asm.empty(); } private: void ParseSource( const char* fileName, const Worker& worker, const View& view ); bool Disassemble( uint64_t symAddr, const Worker& worker ); void SelectViewMode(); void RenderSimpleSourceView(); void RenderSymbolView( Worker& worker, View& view ); void RenderSymbolSourceView( const AddrStatData& as, Worker& worker, const View& view ); uint64_t RenderSymbolAsmView( const AddrStatData& as, Worker& worker, View& view ); void RenderLine( const Tokenizer::Line& line, int lineNum, const AddrStat& ipcnt, const AddrStatData& as, Worker* worker, const View* view ); void RenderAsmLine( AsmLine& line, const AddrStat& ipcnt, const AddrStatData& as, Worker& worker, uint64_t& jumpOut, int maxAddrLen, int maxAddrLenRel, View& view ); void RenderHwLinePart( size_t cycles, size_t retired, size_t branchRetired, size_t branchMiss, size_t cacheRef, size_t cacheMiss, size_t branchRel, size_t branchRelMax, size_t cacheRel, size_t cacheRelMax, const ImVec2& ts ); void SelectLine( uint32_t line, const Worker* worker, bool updateAsmLine = true, uint64_t targetAddr = 0, bool changeAsmLine = true ); void SelectAsmLines( uint32_t file, uint32_t line, const Worker& worker, bool updateAsmLine = true, uint64_t targetAddr = 0, bool changeAsmLine = true ); void SelectAsmLinesHover( uint32_t file, uint32_t line, const Worker& worker ); void GatherIpHwStats( AddrStatData& as, Worker& worker, const View& view, CostType cost ); void GatherIpStats( uint64_t baseAddr, AddrStatData& as, const Worker& worker, bool limitView, const View& view ); void GatherAdditionalIpStats( uint64_t baseAddr, AddrStatData& as, const Worker& worker, bool limitView, const View& view ); void GatherChildStats( uint64_t baseAddr, unordered_flat_map& vec, Worker& worker, bool limitView, const View& view ); uint32_t CountAsmIpStats( uint64_t baseAddr, const Worker& worker, bool limitView, const View& view ); void CountHwStats( AddrStatData& as, Worker& worker, const View& view ); void SelectMicroArchitecture( const char* moniker ); void ResetAsm(); void FollowRead( size_t line, RegsX86 reg, size_t limit ); void FollowWrite( size_t line, RegsX86 reg, size_t limit ); void CheckRead( size_t line, RegsX86 reg, size_t limit ); void CheckWrite( size_t line, RegsX86 reg, size_t limit ); bool IsInContext( const Worker& worker, uint64_t addr ) const; const std::vector* GetAddressesForLocation( uint32_t fileStringIdx, uint32_t line, const Worker& worker ); tracy_force_inline float CalcJumpSeparation( float scale ); #ifndef TRACY_NO_FILESELECTOR void Save( const Worker& worker, size_t start = 0, size_t stop = std::numeric_limits::max() ); #endif tracy_force_inline void SetFont(); tracy_force_inline void UnsetFont(); ImFont* m_font; ImFont* m_smallFont; ImFont* m_bigFont; uint64_t m_symAddr; uint64_t m_baseAddr; uint64_t m_targetAddr; int m_targetLine; int m_selectedLine; int m_asmSelected; DecayValue m_hoveredLine; DecayValue m_hoveredSource; int m_displayMode; uint32_t m_codeLen; int32_t m_disasmFail; DecayValue m_highlightAddr; int m_asmCountBase; bool m_asmRelative; bool m_asmBytes; bool m_asmShowSourceLocation; bool m_calcInlineStats; uint8_t m_maxAsmBytes; uint64_t m_jumpPopupAddr; const CallstackFrameData* m_localCallstackPopup; bool m_hwSamples, m_hwSamplesRelative; bool m_childCalls; bool m_childCallList; bool m_propagateInlines; CostType m_cost; SourceContents m_source; SourceContents m_sourceTooltip; std::vector m_asm; unordered_flat_map m_locMap; unordered_flat_map m_jumpTable; unordered_flat_set m_jumpOut; size_t m_maxJumpLevel; bool m_showJumps; unordered_flat_map> m_locationAddress; bool m_locAddrIsProp; unordered_flat_map m_sourceFiles; unordered_flat_set m_selectedAddresses; unordered_flat_set m_selectedAddressesHover; uint32_t m_maxLine; int m_maxMnemonicLen; int m_maxOperandLen; unordered_flat_map m_microArchOpMap; CpuArchitecture m_cpuArch; int m_selMicroArch; int m_idxMicroArch, m_profileMicroArch; unordered_flat_set m_asmSampleSelect; unordered_flat_set m_srcSampleSelect; int32_t m_asmGroupSelect = -1; int32_t m_srcGroupSelect = -1; float m_srcWidth; float m_asmWidth; float m_jumpOffset; Tokenizer m_tokenizer; struct { uint32_t file = 0; uint32_t line = 0; size_t sel; std::vector target; } m_asmTarget; std::vector m_history; size_t m_historyCursor = 0; }; } #endif