mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-25 13:51:41 +00:00
Bug 892774 - Breakpad Stack scan: speed up MyCodeModules::GetModuleForAddress. r=bgirard.
This commit is contained in:
parent
bbd8a0f445
commit
3a424b6297
@ -1572,6 +1572,8 @@ public:
|
|||||||
// copied CodeModule as far as the CodeModule interface is concerned.
|
// copied CodeModule as far as the CodeModule interface is concerned.
|
||||||
const CodeModule* Copy() const { MOZ_CRASH(); return NULL; }
|
const CodeModule* Copy() const { MOZ_CRASH(); return NULL; }
|
||||||
|
|
||||||
|
friend void read_procmaps(std::vector<MyCodeModule*>& mods_);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// record info for a file backed executable mapping
|
// record info for a file backed executable mapping
|
||||||
u_int64_t x_start_;
|
u_int64_t x_start_;
|
||||||
@ -1580,10 +1582,20 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// Simple predicates on MyCodeModule, used by read_procmaps
|
||||||
|
static bool mcm_has_zero_length(MyCodeModule* cm) {
|
||||||
|
return cm->size() == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool mcm_is_lessthan_by_start(MyCodeModule* cm1, MyCodeModule* cm2) {
|
||||||
|
return cm1->base_address() < cm2->base_address();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Find out, in a platform-dependent way, where the code modules got
|
/* Find out, in a platform-dependent way, where the code modules got
|
||||||
mapped in the process' virtual address space, and add them to
|
mapped in the process' virtual address space, and add them to
|
||||||
|mods_|. */
|
|mods_|. */
|
||||||
static void read_procmaps(std::vector<MyCodeModule*>& mods_)
|
void read_procmaps(std::vector<MyCodeModule*>& mods_)
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(mods_.size() == 0);
|
MOZ_ASSERT(mods_.size() == 0);
|
||||||
#if defined(SPS_OS_linux) || defined(SPS_OS_android) || defined(SPS_OS_darwin)
|
#if defined(SPS_OS_linux) || defined(SPS_OS_android) || defined(SPS_OS_darwin)
|
||||||
@ -1601,6 +1613,44 @@ static void read_procmaps(std::vector<MyCodeModule*>& mods_)
|
|||||||
# error "Unknown platform"
|
# error "Unknown platform"
|
||||||
#endif
|
#endif
|
||||||
if (0) LOGF("got %d mappings\n", (int)mods_.size());
|
if (0) LOGF("got %d mappings\n", (int)mods_.size());
|
||||||
|
|
||||||
|
// Now tidy up |_mods| to ensure that it is possible to do
|
||||||
|
// binary search for addresses in it, without risk of infinite loops:
|
||||||
|
// * segments must be ordered by x_start_ values
|
||||||
|
// * segments must not have zero size (x_len_)
|
||||||
|
// * segments must be non-overlapping
|
||||||
|
std::sort(mods_.begin(), mods_.end(), mcm_is_lessthan_by_start);
|
||||||
|
if (mods_.size() >= 2) {
|
||||||
|
// trim range ends, to guarantee no overlaps
|
||||||
|
for (std::vector<MyCodeModule*>::size_type i = 1; i < mods_.size(); i++) {
|
||||||
|
uint64_t prev_start = mods_[i-1]->x_start_;
|
||||||
|
uint64_t prev_len = mods_[i-1]->x_len_;
|
||||||
|
uint64_t here_start = mods_[i]->x_start_;
|
||||||
|
MOZ_ASSERT(prev_start <= here_start);
|
||||||
|
if (prev_start + prev_len > here_start) {
|
||||||
|
// overlap; trim the end of the previous one
|
||||||
|
mods_[i-1]->x_len_ = here_start - prev_start;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove any zero-sized ranges
|
||||||
|
std::remove_if(mods_.begin(), mods_.end(), mcm_has_zero_length);
|
||||||
|
// Final sanity check: ascending, non-overlapping
|
||||||
|
if (mods_.size() >= 2) {
|
||||||
|
for (std::vector<MyCodeModule*>::size_type i = 1; i < mods_.size(); i++) {
|
||||||
|
uint64_t prev_start = mods_[i-1]->x_start_;
|
||||||
|
uint64_t prev_len = mods_[i-1]->x_len_;
|
||||||
|
uint64_t here_start = mods_[i]->x_start_;
|
||||||
|
uint64_t here_len = mods_[i]->x_len_;
|
||||||
|
MOZ_ASSERT(prev_len > 0 && here_len > 0);
|
||||||
|
MOZ_ASSERT(prev_start + prev_len <= here_start);
|
||||||
|
(void)prev_start;
|
||||||
|
(void)prev_len;
|
||||||
|
(void)here_start;
|
||||||
|
(void)here_len;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1608,7 +1658,14 @@ class MyCodeModules : public google_breakpad::CodeModules
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
MyCodeModules() {
|
MyCodeModules() {
|
||||||
|
max_addr_ = 0;
|
||||||
|
min_addr_ = ~0;
|
||||||
read_procmaps(mods_);
|
read_procmaps(mods_);
|
||||||
|
if (mods_.size() > 0) {
|
||||||
|
MyCodeModule *first = mods_[0], *last = mods_[mods_.size()-1];
|
||||||
|
min_addr_ = first->base_address();
|
||||||
|
max_addr_ = last->base_address() + last->size() - 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
~MyCodeModules() {
|
~MyCodeModules() {
|
||||||
@ -1620,7 +1677,21 @@ class MyCodeModules : public google_breakpad::CodeModules
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::vector<MyCodeModule*> mods_;
|
// A vector of loaded modules, in ascending order of base_address(),
|
||||||
|
// non-zero size()d, and non-overlapping, suitable for binary
|
||||||
|
// search. These guarantees are ensured by read_procmaps() as
|
||||||
|
// called from the constructor, hence they will need to be
|
||||||
|
// re-ensured if there is ever a use case in which modules are added
|
||||||
|
// to |mods_| after the initial construction. Likewise, |min_addr_|
|
||||||
|
// and |max_addr_| would need to be updates. At the moment that
|
||||||
|
// never happens, so the code is safe as it stands.
|
||||||
|
mutable std::vector<MyCodeModule*> mods_;
|
||||||
|
|
||||||
|
// Additional optimisation: cache the minimum and maximum code address
|
||||||
|
// for any of the entries in |mods_|, so that GetModuleForAddress can
|
||||||
|
// reject obviously out-of-range values without having to do any binary
|
||||||
|
// search.
|
||||||
|
uint64_t min_addr_, max_addr_;
|
||||||
|
|
||||||
unsigned int module_count() const { MOZ_CRASH(); return 1; }
|
unsigned int module_count() const { MOZ_CRASH(); return 1; }
|
||||||
|
|
||||||
@ -1628,17 +1699,34 @@ class MyCodeModules : public google_breakpad::CodeModules
|
|||||||
GetModuleForAddress(u_int64_t address) const
|
GetModuleForAddress(u_int64_t address) const
|
||||||
{
|
{
|
||||||
if (0) printf("GMFA %llx\n", (unsigned long long int)address);
|
if (0) printf("GMFA %llx\n", (unsigned long long int)address);
|
||||||
std::vector<MyCodeModule*>::const_iterator it;
|
std::vector<MyCodeModule*>::size_type nMods = mods_.size();
|
||||||
for (it = mods_.begin(); it < mods_.end(); it++) {
|
|
||||||
MyCodeModule* cm = *it;
|
// Reject obviously-nonsensical requests. Note that the
|
||||||
if (0) printf("considering %p %llx +%llx\n",
|
// comparisons against {min_,max_}addr_ are only valid in the case
|
||||||
(void*)cm, (unsigned long long int)cm->base_address(),
|
// where nMods > 0, hence the ordering of tests.
|
||||||
(unsigned long long int)cm->size());
|
if (nMods == 0 || address < min_addr_ || address > max_addr_) {
|
||||||
if (cm->base_address() <= address
|
return NULL;
|
||||||
&& address < cm->base_address() + cm->size())
|
}
|
||||||
return cm;
|
|
||||||
|
// Binary search in |mods_|. lo and hi need to be signed, else
|
||||||
|
// the loop termination tests don't work properly.
|
||||||
|
long int lo = 0;
|
||||||
|
long int hi = nMods-1;
|
||||||
|
while (true) {
|
||||||
|
// current unsearched space is from lo to hi, inclusive.
|
||||||
|
if (lo > hi) {
|
||||||
|
// not found
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
long int mid = (lo + hi) / 2;
|
||||||
|
MyCodeModule* mid_mod = mods_[mid];
|
||||||
|
uint64_t mid_minAddr = mid_mod->base_address();
|
||||||
|
uint64_t mid_maxAddr = mid_minAddr + mid_mod->size() - 1;
|
||||||
|
if (address < mid_minAddr) { hi = mid-1; continue; }
|
||||||
|
if (address > mid_maxAddr) { lo = mid+1; continue; }
|
||||||
|
MOZ_ASSERT(mid_minAddr <= address && address <= mid_maxAddr);
|
||||||
|
return mid_mod;
|
||||||
}
|
}
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const google_breakpad::CodeModule* GetMainModule() const {
|
const google_breakpad::CodeModule* GetMainModule() const {
|
||||||
|
Loading…
Reference in New Issue
Block a user