The open source OpenXR runtime
at main 141 lines 3.6 kB view raw
1#include <atomic> 2#include <assert.h> 3#include <errno.h> 4#include <linux/perf_event.h> 5#include <stdint.h> 6#include <string.h> 7#include <sys/ioctl.h> 8#include <sys/mman.h> 9#include <unistd.h> 10 11#include "TracyDebug.hpp" 12 13namespace tracy 14{ 15 16class RingBuffer 17{ 18public: 19 RingBuffer( unsigned int size, int fd, int id, int cpu = -1 ) 20 : m_size( size ) 21 , m_id( id ) 22 , m_cpu( cpu ) 23 , m_fd( fd ) 24 { 25 const auto pageSize = uint32_t( getpagesize() ); 26 assert( size >= pageSize ); 27 assert( __builtin_popcount( size ) == 1 ); 28 m_mapSize = size + pageSize; 29 auto mapAddr = mmap( nullptr, m_mapSize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0 ); 30 if( mapAddr == MAP_FAILED ) 31 { 32 TracyDebug( "mmap failed: errno %i (%s)\n", errno, strerror( errno ) ); 33 m_fd = 0; 34 m_metadata = nullptr; 35 close( fd ); 36 return; 37 } 38 m_metadata = (perf_event_mmap_page*)mapAddr; 39 assert( m_metadata->data_offset == pageSize ); 40 m_buffer = ((char*)mapAddr) + pageSize; 41 m_tail = m_metadata->data_tail; 42 } 43 44 ~RingBuffer() 45 { 46 if( m_metadata ) munmap( m_metadata, m_mapSize ); 47 if( m_fd ) close( m_fd ); 48 } 49 50 RingBuffer( const RingBuffer& ) = delete; 51 RingBuffer& operator=( const RingBuffer& ) = delete; 52 53 RingBuffer( RingBuffer&& other ) 54 { 55 memcpy( (char*)&other, (char*)this, sizeof( RingBuffer ) ); 56 m_metadata = nullptr; 57 m_fd = 0; 58 } 59 60 RingBuffer& operator=( RingBuffer&& other ) 61 { 62 memcpy( (char*)&other, (char*)this, sizeof( RingBuffer ) ); 63 m_metadata = nullptr; 64 m_fd = 0; 65 return *this; 66 } 67 68 bool IsValid() const { return m_metadata != nullptr; } 69 int GetId() const { return m_id; } 70 int GetCpu() const { return m_cpu; } 71 72 void Enable() 73 { 74 ioctl( m_fd, PERF_EVENT_IOC_ENABLE, 0 ); 75 } 76 77 void Read( void* dst, uint64_t offset, uint64_t cnt ) 78 { 79 const auto size = m_size; 80 auto src = ( m_tail + offset ) % size; 81 if( src + cnt <= size ) 82 { 83 memcpy( dst, m_buffer + src, cnt ); 84 } 85 else 86 { 87 const auto s0 = size - src; 88 const auto buf = m_buffer; 89 memcpy( dst, buf + src, s0 ); 90 memcpy( (char*)dst + s0, buf, cnt - s0 ); 91 } 92 } 93 94 void Advance( uint64_t cnt ) 95 { 96 m_tail += cnt; 97 StoreTail(); 98 } 99 100 bool CheckTscCaps() const 101 { 102 return m_metadata->cap_user_time_zero; 103 } 104 105 int64_t ConvertTimeToTsc( int64_t timestamp ) const 106 { 107 if( !m_metadata->cap_user_time_zero ) return 0; 108 const auto time = timestamp - m_metadata->time_zero; 109 const auto quot = time / m_metadata->time_mult; 110 const auto rem = time % m_metadata->time_mult; 111 return ( quot << m_metadata->time_shift ) + ( rem << m_metadata->time_shift ) / m_metadata->time_mult; 112 } 113 114 uint64_t LoadHead() const 115 { 116 return std::atomic_load_explicit( (const volatile std::atomic<uint64_t>*)&m_metadata->data_head, std::memory_order_acquire ); 117 } 118 119 uint64_t GetTail() const 120 { 121 return m_tail; 122 } 123 124private: 125 void StoreTail() 126 { 127 std::atomic_store_explicit( (volatile std::atomic<uint64_t>*)&m_metadata->data_tail, m_tail, std::memory_order_release ); 128 } 129 130 unsigned int m_size; 131 uint64_t m_tail; 132 char* m_buffer; 133 int m_id; 134 int m_cpu; 135 perf_event_mmap_page* m_metadata; 136 137 size_t m_mapSize; 138 int m_fd; 139}; 140 141}