diff options
Diffstat (limited to 'runtime/class_linker.cc')
-rw-r--r-- | runtime/class_linker.cc | 137 |
1 files changed, 81 insertions, 56 deletions
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc index e65672a71b..abd35f1712 100644 --- a/runtime/class_linker.cc +++ b/runtime/class_linker.cc @@ -19,6 +19,7 @@ #include <algorithm> #include <deque> #include <iostream> +#include <map> #include <memory> #include <queue> #include <string> @@ -8479,70 +8480,94 @@ void ClassLinker::CleanupClassLoaders() { } } -std::set<DexCacheResolvedClasses> ClassLinker::GetResolvedClasses(bool ignore_boot_classes) { - ScopedTrace trace(__PRETTY_FUNCTION__); - ScopedObjectAccess soa(Thread::Current()); - ScopedAssertNoThreadSuspension ants(__FUNCTION__); - std::set<DexCacheResolvedClasses> ret; - VLOG(class_linker) << "Collecting resolved classes"; - const uint64_t start_time = NanoTime(); - ReaderMutexLock mu(soa.Self(), *Locks::dex_lock_); - // Loop through all the dex caches and inspect resolved classes. - for (const ClassLinker::DexCacheData& data : GetDexCachesData()) { - if (soa.Self()->IsJWeakCleared(data.weak_root)) { - continue; - } - ObjPtr<mirror::DexCache> dex_cache = soa.Decode<mirror::DexCache>(data.weak_root); - if (dex_cache == nullptr) { - continue; - } - const DexFile* dex_file = dex_cache->GetDexFile(); - const std::string& location = dex_file->GetLocation(); - const size_t num_class_defs = dex_file->NumClassDefs(); - // Use the resolved types, this will miss array classes. - const size_t num_types = dex_file->NumTypeIds(); - VLOG(class_linker) << "Collecting class profile for dex file " << location - << " types=" << num_types << " class_defs=" << num_class_defs; - DexCacheResolvedClasses resolved_classes(dex_file->GetLocation(), - dex_file->GetBaseLocation(), - dex_file->GetLocationChecksum()); - size_t num_resolved = 0; - std::unordered_set<dex::TypeIndex> class_set; - CHECK_EQ(num_types, dex_cache->NumResolvedTypes()); - for (size_t i = 0; i < num_types; ++i) { - ObjPtr<mirror::Class> klass = dex_cache->GetResolvedType(dex::TypeIndex(i)); - // Filter out null class loader since that is the boot class loader. - if (klass == nullptr || (ignore_boot_classes && klass->GetClassLoader() == nullptr)) { - continue; - } - ++num_resolved; - DCHECK(!klass->IsProxyClass()); - DCHECK(klass->IsResolved()); - if (klass->IsErroneousResolved()) { - continue; +class GetResolvedClassesVisitor : public ClassVisitor { + public: + GetResolvedClassesVisitor(std::set<DexCacheResolvedClasses>* result, bool ignore_boot_classes) + : result_(result), + ignore_boot_classes_(ignore_boot_classes), + last_resolved_classes_(result->end()), + last_dex_file_(nullptr), + vlog_is_on_(VLOG_IS_ON(class_linker)), + extra_stats_(), + last_extra_stats_(extra_stats_.end()) { } + + bool operator()(ObjPtr<mirror::Class> klass) OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_) { + if (!klass->IsProxyClass() && + !klass->IsArrayClass() && + klass->IsResolved() && + !klass->IsErroneousResolved() && + (!ignore_boot_classes_ || klass->GetClassLoader() != nullptr)) { + const DexFile& dex_file = klass->GetDexFile(); + if (&dex_file != last_dex_file_) { + last_dex_file_ = &dex_file; + DexCacheResolvedClasses resolved_classes(dex_file.GetLocation(), + dex_file.GetBaseLocation(), + dex_file.GetLocationChecksum()); + last_resolved_classes_ = result_->find(resolved_classes); + if (last_resolved_classes_ == result_->end()) { + last_resolved_classes_ = result_->insert(resolved_classes).first; + } } - ObjPtr<mirror::DexCache> klass_dex_cache = klass->GetDexCache(); - if (klass_dex_cache == dex_cache) { - CHECK_LT(klass->GetDexClassDefIndex(), num_class_defs); - class_set.insert(klass->GetDexTypeIndex()); + bool added = last_resolved_classes_->AddClass(klass->GetDexTypeIndex()); + if (UNLIKELY(vlog_is_on_) && added) { + const DexCacheResolvedClasses* resolved_classes = std::addressof(*last_resolved_classes_); + if (last_extra_stats_ == extra_stats_.end() || + last_extra_stats_->first != resolved_classes) { + last_extra_stats_ = extra_stats_.find(resolved_classes); + if (last_extra_stats_ == extra_stats_.end()) { + last_extra_stats_ = + extra_stats_.emplace(resolved_classes, ExtraStats(dex_file.NumClassDefs())).first; + } + } } } + return true; + } - if (!class_set.empty()) { - auto it = ret.find(resolved_classes); - if (it != ret.end()) { - // Already have the key, union the class type indexes. - it->AddClasses(class_set.begin(), class_set.end()); - } else { - resolved_classes.AddClasses(class_set.begin(), class_set.end()); - ret.insert(resolved_classes); + void PrintStatistics() const { + if (vlog_is_on_) { + for (const DexCacheResolvedClasses& resolved_classes : *result_) { + auto it = extra_stats_.find(std::addressof(resolved_classes)); + DCHECK(it != extra_stats_.end()); + const ExtraStats& extra_stats = it->second; + LOG(INFO) << "Dex location " << resolved_classes.GetDexLocation() + << " has " << resolved_classes.GetClasses().size() << " / " + << extra_stats.number_of_class_defs_ << " resolved classes"; } } + } + + private: + struct ExtraStats { + explicit ExtraStats(uint32_t number_of_class_defs) + : number_of_class_defs_(number_of_class_defs) {} + uint32_t number_of_class_defs_; + }; + + std::set<DexCacheResolvedClasses>* result_; + bool ignore_boot_classes_; + std::set<DexCacheResolvedClasses>::iterator last_resolved_classes_; + const DexFile* last_dex_file_; + + // Statistics. + bool vlog_is_on_; + std::map<const DexCacheResolvedClasses*, ExtraStats> extra_stats_; + std::map<const DexCacheResolvedClasses*, ExtraStats>::iterator last_extra_stats_; +}; - VLOG(class_linker) << "Dex location " << location << " has " << num_resolved << " / " - << num_class_defs << " resolved classes"; +std::set<DexCacheResolvedClasses> ClassLinker::GetResolvedClasses(bool ignore_boot_classes) { + ScopedTrace trace(__PRETTY_FUNCTION__); + ScopedObjectAccess soa(Thread::Current()); + ScopedAssertNoThreadSuspension ants(__FUNCTION__); + std::set<DexCacheResolvedClasses> ret; + VLOG(class_linker) << "Collecting resolved classes"; + const uint64_t start_time = NanoTime(); + GetResolvedClassesVisitor visitor(&ret, ignore_boot_classes); + VisitClasses(&visitor); + if (VLOG_IS_ON(class_linker)) { + visitor.PrintStatistics(); + LOG(INFO) << "Collecting class profile took " << PrettyDuration(NanoTime() - start_time); } - VLOG(class_linker) << "Collecting class profile took " << PrettyDuration(NanoTime() - start_time); return ret; } |