Added a per-process cache for reserved memory

regions that aren't actually allocated in the
process.  This cache is used by the expression
parser if the underlying process doesn't support
memory allocation, to avoid needless repeated
searches for unused address ranges.

Also fixed a silly bug in IRMemoryMap where it
would continue searching even after it found a
valid region.

<rdar://problem/13866629>

llvm-svn: 182028
This commit is contained in:
Sean Callanan 2013-05-16 17:30:37 +00:00
parent 9daaf5775c
commit bb77704cd1
3 changed files with 153 additions and 16 deletions

View File

@ -3533,6 +3533,72 @@ public:
return m_public_run_lock;
}
//------------------------------------------------------------------
// This is a cache of reserved and available memory address ranges
// for a single modification ID (see m_mod_id). It's meant for use
// by IRMemoryMap, but to stick with the process. These memory
// ranges happen to be unallocated in the underlying process, but we
// make no guarantee that at a future modification ID they won't be
// gone. This is only useful if the underlying process can't
// allocate memory.
//
// When a memory space is determined to be available it is
// registered as reserved at the current modification. If it is
// freed later, it is added to the free list if the modification ID
// hasn't changed. Then clients can simply query the free list for
// the size they want.
//------------------------------------------------------------------
class ReservationCache
{
public:
ReservationCache (Process &process);
//------------------------------------------------------------------
// Mark that a particular range of addresses is in use. Adds it
// to the reserved map, implicitly tying it to the current
// modification ID.
//------------------------------------------------------------------
void
Reserve (lldb::addr_t addr, size_t size);
//------------------------------------------------------------------
// Mark that a range is no longer in use. If it's found in the
// reservation list, that means that the modification ID hasn't
// changed since it was reserved, so it can be safely added to the
// free list.
//------------------------------------------------------------------
void
Unreserve (lldb::addr_t addr);
//------------------------------------------------------------------
// Try to find an unused range of the given size in the free list.
//------------------------------------------------------------------
lldb::addr_t
Find (size_t size);
private:
//------------------------------------------------------------------
// Clear all lists if the modification ID has changed.
//------------------------------------------------------------------
void CheckModID();
typedef std::map <lldb::addr_t, size_t> ReservedMap;
typedef std::vector <lldb::addr_t> FreeList;
typedef std::map <size_t, FreeList> FreeMap;
ReservedMap m_reserved_cache;
FreeMap m_free_cache;
Process &m_process;
ProcessModID m_mod_id;
};
ReservationCache &
GetReservationCache ()
{
return m_reservation_cache;
}
private:
ReservationCache m_reservation_cache;
protected:
//------------------------------------------------------------------
// NextEventAction provides a way to register an action on the next

View File

@ -31,19 +31,14 @@ IRMemoryMap::~IRMemoryMap ()
if (process_sp)
{
for (AllocationMap::value_type &allocation : m_allocations)
{
if (allocation.second.m_policy == eAllocationPolicyMirror ||
allocation.second.m_policy == eAllocationPolicyProcessOnly ||
(allocation.second.m_policy == eAllocationPolicyHostOnly && process_sp->CanJIT()))
process_sp->DeallocateMemory(allocation.second.m_process_alloc);
AllocationMap::iterator iter;
if (lldb_private::Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS))
Error err;
while ((iter = m_allocations.begin()) != m_allocations.end())
{
log->Printf("IRMemoryMap::~IRMemoryMap deallocated [0x%llx..0x%llx)",
(uint64_t)allocation.second.m_process_start,
(uint64_t)allocation.second.m_process_start + (uint64_t)allocation.second.m_size);
}
err.Clear();
Free(iter->first, err);
}
}
}
@ -68,6 +63,14 @@ IRMemoryMap::FindSpace (size_t size)
return ret;
}
if (process_sp)
{
ret = process_sp->GetReservationCache().Find(size);
if (ret != LLDB_INVALID_ADDRESS)
return ret;
}
for (int iterations = 0; iterations < 16; ++iterations)
{
lldb::addr_t candidate = LLDB_INVALID_ADDRESS;
@ -106,6 +109,11 @@ IRMemoryMap::FindSpace (size_t size)
continue;
ret = candidate;
if (process_sp)
process_sp->GetReservationCache().Reserve(candidate, size);
return ret;
}
return ret;
@ -382,8 +390,13 @@ IRMemoryMap::Free (lldb::addr_t process_address, Error &error)
case eAllocationPolicyHostOnly:
{
lldb::ProcessSP process_sp = m_process_wp.lock();
if (process_sp && process_sp->CanJIT())
if (process_sp)
{
if (process_sp->CanJIT())
process_sp->DeallocateMemory(allocation.m_process_alloc); // FindSpace allocated this for real
else
process_sp->GetReservationCache().Unreserve(allocation.m_process_alloc); // FindSpace registered this memory
}
break;
}

View File

@ -996,6 +996,7 @@ Process::Process(Target &target, Listener &listener) :
ProcessProperties (false),
UserID (LLDB_INVALID_PROCESS_ID),
Broadcaster (&(target.GetDebugger()), "lldb.process"),
m_reservation_cache (*this),
m_target (target),
m_public_state (eStateUnloaded),
m_private_state (eStateUnloaded),
@ -5589,3 +5590,60 @@ Process::DidExec ()
DoDidExec();
CompleteAttach ();
}
Process::ReservationCache::ReservationCache (Process &process) : m_process(process)
{
m_mod_id = process.GetModID();
}
void
Process::ReservationCache::Reserve (lldb::addr_t addr, size_t size)
{
CheckModID();
m_reserved_cache[addr] = size;
}
void
Process::ReservationCache::Unreserve (lldb::addr_t addr)
{
CheckModID();
ReservedMap::iterator iter = m_reserved_cache.find(addr);
if (iter != m_reserved_cache.end())
{
size_t size = iter->second;
m_reserved_cache.erase(iter);
m_free_cache[size].push_back(addr);
}
}
lldb::addr_t
Process::ReservationCache::Find (size_t size)
{
CheckModID();
lldb::addr_t ret = LLDB_INVALID_ADDRESS;
FreeMap::iterator map_iter = m_free_cache.find(size);
if (map_iter != m_free_cache.end())
{
if (!map_iter->second.empty())
{
ret = map_iter->second.back();
map_iter->second.pop_back();
m_reserved_cache[ret] = size;
}
}
return ret;
}
void
Process::ReservationCache::CheckModID()
{
if (m_mod_id != m_process.GetModID())
{
// wipe all our caches, they're invalid
m_reserved_cache.clear();
m_free_cache.clear();
m_mod_id = m_process.GetModID();
}
}