buffer_cache: Use boost::container::small_vector for maps in range

Most overlaps in the buffer cache only contain one mapped address.
We can avoid close to all heap allocations once the buffer cache is
warmed up by using a small_vector with a stack size of one.
This commit is contained in:
ReinUsesLisp 2020-05-20 23:55:40 -03:00
parent 891236124c
commit 19d4f28001
1 changed files with 15 additions and 13 deletions

View File

@ -12,6 +12,7 @@
#include <utility> #include <utility>
#include <vector> #include <vector>
#include <boost/container/small_vector.hpp>
#include <boost/icl/interval_map.hpp> #include <boost/icl/interval_map.hpp>
#include <boost/icl/interval_set.hpp> #include <boost/icl/interval_set.hpp>
#include <boost/intrusive/set.hpp> #include <boost/intrusive/set.hpp>
@ -33,6 +34,10 @@ namespace VideoCommon {
template <typename OwnerBuffer, typename BufferType, typename StreamBuffer> template <typename OwnerBuffer, typename BufferType, typename StreamBuffer>
class BufferCache { class BufferCache {
using IntervalSet = boost::icl::interval_set<VAddr>;
using IntervalType = typename IntervalSet::interval_type;
using VectorMapInterval = boost::container::small_vector<MapInterval*, 1>;
public: public:
using BufferInfo = std::pair<BufferType, u64>; using BufferInfo = std::pair<BufferType, u64>;
@ -133,7 +138,7 @@ public:
void FlushRegion(VAddr addr, std::size_t size) { void FlushRegion(VAddr addr, std::size_t size) {
std::lock_guard lock{mutex}; std::lock_guard lock{mutex};
std::vector<MapInterval*> objects = GetMapsInRange(addr, size); VectorMapInterval objects = GetMapsInRange(addr, size);
std::sort(objects.begin(), objects.end(), std::sort(objects.begin(), objects.end(),
[](MapInterval* lhs, MapInterval* rhs) { return lhs->ticks < rhs->ticks; }); [](MapInterval* lhs, MapInterval* rhs) { return lhs->ticks < rhs->ticks; });
for (MapInterval* object : objects) { for (MapInterval* object : objects) {
@ -148,7 +153,7 @@ public:
bool MustFlushRegion(VAddr addr, std::size_t size) { bool MustFlushRegion(VAddr addr, std::size_t size) {
std::lock_guard lock{mutex}; std::lock_guard lock{mutex};
const std::vector<MapInterval*> objects = GetMapsInRange(addr, size); const VectorMapInterval objects = GetMapsInRange(addr, size);
return std::any_of(objects.cbegin(), objects.cend(), [](const MapInterval* map) { return std::any_of(objects.cbegin(), objects.cend(), [](const MapInterval* map) {
return map->is_modified && map->is_registered; return map->is_modified && map->is_registered;
}); });
@ -158,8 +163,7 @@ public:
void InvalidateRegion(VAddr addr, u64 size) { void InvalidateRegion(VAddr addr, u64 size) {
std::lock_guard lock{mutex}; std::lock_guard lock{mutex};
std::vector<MapInterval*> objects = GetMapsInRange(addr, size); for (auto& object : GetMapsInRange(addr, size)) {
for (auto& object : objects) {
if (object->is_registered) { if (object->is_registered) {
Unregister(object); Unregister(object);
} }
@ -314,7 +318,7 @@ protected:
private: private:
MapInterval* MapAddress(const OwnerBuffer& block, GPUVAddr gpu_addr, VAddr cpu_addr, MapInterval* MapAddress(const OwnerBuffer& block, GPUVAddr gpu_addr, VAddr cpu_addr,
std::size_t size) { std::size_t size) {
std::vector<MapInterval*> overlaps = GetMapsInRange(cpu_addr, size); const VectorMapInterval overlaps = GetMapsInRange(cpu_addr, size);
if (overlaps.empty()) { if (overlaps.empty()) {
auto& memory_manager = system.GPU().MemoryManager(); auto& memory_manager = system.GPU().MemoryManager();
const VAddr cpu_addr_end = cpu_addr + size; const VAddr cpu_addr_end = cpu_addr + size;
@ -368,7 +372,7 @@ private:
} }
void UpdateBlock(const OwnerBuffer& block, VAddr start, VAddr end, void UpdateBlock(const OwnerBuffer& block, VAddr start, VAddr end,
std::vector<MapInterval*>& overlaps) { const VectorMapInterval& overlaps) {
const IntervalType base_interval{start, end}; const IntervalType base_interval{start, end};
IntervalSet interval_set{}; IntervalSet interval_set{};
interval_set.add(base_interval); interval_set.add(base_interval);
@ -387,14 +391,13 @@ private:
} }
} }
std::vector<MapInterval*> GetMapsInRange(VAddr addr, std::size_t size) { VectorMapInterval GetMapsInRange(VAddr addr, std::size_t size) {
VectorMapInterval result;
if (size == 0) { if (size == 0) {
return {}; return result;
} }
std::vector<MapInterval*> result;
const VAddr addr_end = addr + size; const VAddr addr_end = addr + size;
auto it = mapped_addresses.lower_bound(addr); auto it = mapped_addresses.lower_bound(addr);
if (it != mapped_addresses.begin()) { if (it != mapped_addresses.begin()) {
--it; --it;
@ -574,10 +577,9 @@ private:
u64 buffer_offset = 0; u64 buffer_offset = 0;
u64 buffer_offset_base = 0; u64 buffer_offset_base = 0;
using IntervalSet = boost::icl::interval_set<VAddr>;
using IntervalType = typename IntervalSet::interval_type;
std::list<MapInterval> mapped_addresses_storage; // Temporary hack std::list<MapInterval> mapped_addresses_storage; // Temporary hack
boost::intrusive::set<MapInterval, boost::intrusive::compare<MapIntervalCompare>> mapped_addresses; boost::intrusive::set<MapInterval, boost::intrusive::compare<MapIntervalCompare>>
mapped_addresses;
static constexpr u64 write_page_bit = 11; static constexpr u64 write_page_bit = 11;
std::unordered_map<u64, u32> written_pages; std::unordered_map<u64, u32> written_pages;