ProfilingInfo* ProfilingInfo::Create(Thread* self,
ArtMethod* method, const std::vector<uint32_t>& inline_cache_entries) { // Walk over the dex instructions of the method and keep track of // instructions we are interested in profiling.
DCHECK(!method->IsNative());
std::vector<uint32_t> branch_cache_entries; for (const DexInstructionPcPair& inst : method->DexInstructions()) { switch (inst->Opcode()) { case Instruction::IF_EQ: case Instruction::IF_EQZ: case Instruction::IF_NE: case Instruction::IF_NEZ: case Instruction::IF_LT: case Instruction::IF_LTZ: case Instruction::IF_LE: case Instruction::IF_LEZ: case Instruction::IF_GT: case Instruction::IF_GTZ: case Instruction::IF_GE: case Instruction::IF_GEZ:
branch_cache_entries.push_back(inst.DexPc()); break;
default: break;
}
}
// We always create a `ProfilingInfo` object, even if there is no instruction we are // interested in. The JIT code cache internally uses it for hotness counter.
// Allocate the `ProfilingInfo` object int the JIT's data space.
jit::JitCodeCache* code_cache = Runtime::Current()->GetJit()->GetCodeCache(); return code_cache->AddProfilingInfo(self, method, inline_cache_entries, branch_cache_entries);
}
InlineCache* ProfilingInfo::GetInlineCache(uint32_t dex_pc) { // TODO: binary search if array is too long.
InlineCache* caches = GetInlineCaches(); for (size_t i = 0; i < number_of_inline_caches_; ++i) { if (caches[i].dex_pc_ == dex_pc) { return &caches[i];
}
} return nullptr;
}
BranchCache* ProfilingInfo::GetBranchCache(uint32_t dex_pc) { // TODO: binary search if array is too long.
BranchCache* caches = GetBranchCaches(); for (size_t i = 0; i < number_of_branch_caches_; ++i) { if (caches[i].dex_pc_ == dex_pc) { return &caches[i];
}
} // Currently, only if instructions are profiled. The compiler will see other // branches, like switches. return nullptr;
}
void ProfilingInfo::AddInvokeInfo(uint32_t dex_pc, mirror::Class* cls) {
InlineCache* cache = GetInlineCache(dex_pc); if (cache == nullptr) { return;
} for (size_t i = 0; i < InlineCache::kIndividualCacheSize; ++i) {
mirror::Class* existing = cache->classes_[i].Read<kWithoutReadBarrier>();
mirror::Class* marked = ReadBarrier::IsMarked(existing); if (marked == cls) { // Receiver type is already in the cache, nothing else to do. return;
} elseif (marked == nullptr) { // Cache entry is empty, try to put `cls` in it. // Note: it's ok to spin on 'existing' here: if 'existing' is not null, that means // it is a stalled heap address, which will only be cleared during SweepSystemWeaks, // *after* this thread hits a suspend point.
GcRoot<mirror::Class> expected_root(existing);
GcRoot<mirror::Class> desired_root(cls); auto atomic_root = reinterpret_cast<Atomic<GcRoot<mirror::Class>>*>(&cache->classes_[i]); if (!atomic_root->CompareAndSetStrongSequentiallyConsistent(expected_root, desired_root)) { // Some other thread put a class in the cache, continue iteration starting at this // entry in case the entry contains `cls`.
--i;
} else { // We successfully set `cls`, just return. return;
}
}
} // Unsuccessfull - cache is full, making it megamorphic. We do not DCHECK it though, // as the garbage collector might clear the entries concurrently.
}
ScopedProfilingInfoUse::ScopedProfilingInfoUse(jit::Jit* jit, ArtMethod* method, Thread* self)
: jit_(jit),
method_(method),
self_(self), // Fetch the profiling info ahead of using it. If it's null when fetching, // we should not call JitCodeCache::DoneCompilerUse.
profiling_info_(jit == nullptr
? nullptr
: jit->GetCodeCache()->NotifyCompilerUse(method, self))
{}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.