#include <algorithm>
#include <deque>
#include <iostream>
+#include <map>
#include <memory>
#include <queue>
#include <string>
}
}
-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;
}