| /* |
| * Copyright (C) 2014 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| #ifndef ART_COMPILER_OPTIMIZING_OPTIMIZING_COMPILER_STATS_H_ |
| #define ART_COMPILER_OPTIMIZING_OPTIMIZING_COMPILER_STATS_H_ |
| |
| #include <atomic> |
| #include <iomanip> |
| #include <string> |
| #include <type_traits> |
| |
| #include "atomic.h" |
| #include "base/logging.h" // For VLOG_IS_ON. |
| #include "globals.h" |
| |
| namespace art { |
| |
| enum class MethodCompilationStat { |
| kAttemptBytecodeCompilation = 0, |
| kAttemptIntrinsicCompilation, |
| kCompiledNativeStub, |
| kCompiledIntrinsic, |
| kCompiledBytecode, |
| kCHAInline, |
| kInlinedInvoke, |
| kReplacedInvokeWithSimplePattern, |
| kInstructionSimplifications, |
| kInstructionSimplificationsArch, |
| kUnresolvedMethod, |
| kUnresolvedField, |
| kUnresolvedFieldNotAFastAccess, |
| kRemovedCheckedCast, |
| kRemovedDeadInstruction, |
| kRemovedNullCheck, |
| kNotCompiledSkipped, |
| kNotCompiledInvalidBytecode, |
| kNotCompiledThrowCatchLoop, |
| kNotCompiledAmbiguousArrayOp, |
| kNotCompiledHugeMethod, |
| kNotCompiledLargeMethodNoBranches, |
| kNotCompiledMalformedOpcode, |
| kNotCompiledNoCodegen, |
| kNotCompiledPathological, |
| kNotCompiledSpaceFilter, |
| kNotCompiledUnhandledInstruction, |
| kNotCompiledUnsupportedIsa, |
| kNotCompiledVerificationError, |
| kNotCompiledVerifyAtRuntime, |
| kInlinedMonomorphicCall, |
| kInlinedPolymorphicCall, |
| kMonomorphicCall, |
| kPolymorphicCall, |
| kMegamorphicCall, |
| kBooleanSimplified, |
| kIntrinsicRecognized, |
| kLoopInvariantMoved, |
| kLoopVectorized, |
| kLoopVectorizedIdiom, |
| kSelectGenerated, |
| kRemovedInstanceOf, |
| kInlinedInvokeVirtualOrInterface, |
| kImplicitNullCheckGenerated, |
| kExplicitNullCheckGenerated, |
| kSimplifyIf, |
| kInstructionSunk, |
| kNotInlinedUnresolvedEntrypoint, |
| kNotInlinedDexCache, |
| kNotInlinedStackMaps, |
| kNotInlinedEnvironmentBudget, |
| kNotInlinedInstructionBudget, |
| kNotInlinedLoopWithoutExit, |
| kNotInlinedIrreducibleLoop, |
| kNotInlinedAlwaysThrows, |
| kNotInlinedInfiniteLoop, |
| kNotInlinedTryCatch, |
| kNotInlinedRegisterAllocator, |
| kNotInlinedCannotBuild, |
| kNotInlinedNotVerified, |
| kNotInlinedCodeItem, |
| kNotInlinedWont, |
| kNotInlinedRecursiveBudget, |
| kNotInlinedProxy, |
| kConstructorFenceGeneratedNew, |
| kConstructorFenceGeneratedFinal, |
| kConstructorFenceRemovedLSE, |
| kConstructorFenceRemovedPFRA, |
| kConstructorFenceRemovedCFRE, |
| kJitOutOfMemoryForCommit, |
| kLastStat |
| }; |
| std::ostream& operator<<(std::ostream& os, const MethodCompilationStat& rhs); |
| |
| class OptimizingCompilerStats { |
| public: |
| OptimizingCompilerStats() { |
| // The std::atomic<> default constructor leaves values uninitialized, so initialize them now. |
| Reset(); |
| } |
| |
| void RecordStat(MethodCompilationStat stat, uint32_t count = 1) { |
| size_t stat_index = static_cast<size_t>(stat); |
| DCHECK_LT(stat_index, arraysize(compile_stats_)); |
| compile_stats_[stat_index] += count; |
| } |
| |
| uint32_t GetStat(MethodCompilationStat stat) const { |
| size_t stat_index = static_cast<size_t>(stat); |
| DCHECK_LT(stat_index, arraysize(compile_stats_)); |
| return compile_stats_[stat_index]; |
| } |
| |
| void Log() const { |
| if (!kIsDebugBuild && !VLOG_IS_ON(compiler)) { |
| // Log only in debug builds or if the compiler is verbose. |
| return; |
| } |
| |
| uint32_t compiled_intrinsics = GetStat(MethodCompilationStat::kCompiledIntrinsic); |
| uint32_t compiled_native_stubs = GetStat(MethodCompilationStat::kCompiledNativeStub); |
| uint32_t bytecode_attempts = |
| GetStat(MethodCompilationStat::kAttemptBytecodeCompilation); |
| if (compiled_intrinsics == 0u && compiled_native_stubs == 0u && bytecode_attempts == 0u) { |
| LOG(INFO) << "Did not compile any method."; |
| } else { |
| uint32_t compiled_bytecode_methods = |
| GetStat(MethodCompilationStat::kCompiledBytecode); |
| // Successful intrinsic compilation preempts other compilation attempts but failed intrinsic |
| // compilation shall still count towards bytecode or native stub compilation attempts. |
| uint32_t num_compilation_attempts = |
| compiled_intrinsics + compiled_native_stubs + bytecode_attempts; |
| uint32_t num_successful_compilations = |
| compiled_intrinsics + compiled_native_stubs + compiled_bytecode_methods; |
| float compiled_percent = num_successful_compilations * 100.0f / num_compilation_attempts; |
| LOG(INFO) << "Attempted compilation of " |
| << num_compilation_attempts << " methods: " << std::fixed << std::setprecision(2) |
| << compiled_percent << "% (" << num_successful_compilations << ") compiled."; |
| |
| for (size_t i = 0; i < arraysize(compile_stats_); ++i) { |
| if (compile_stats_[i] != 0) { |
| LOG(INFO) << "OptStat#" << static_cast<MethodCompilationStat>(i) << ": " |
| << compile_stats_[i]; |
| } |
| } |
| } |
| } |
| |
| void AddTo(OptimizingCompilerStats* other_stats) { |
| for (size_t i = 0; i != arraysize(compile_stats_); ++i) { |
| uint32_t count = compile_stats_[i]; |
| if (count != 0) { |
| other_stats->RecordStat(static_cast<MethodCompilationStat>(i), count); |
| } |
| } |
| } |
| |
| void Reset() { |
| for (std::atomic<uint32_t>& stat : compile_stats_) { |
| stat = 0u; |
| } |
| } |
| |
| private: |
| std::atomic<uint32_t> compile_stats_[static_cast<size_t>(MethodCompilationStat::kLastStat)]; |
| |
| DISALLOW_COPY_AND_ASSIGN(OptimizingCompilerStats); |
| }; |
| |
| inline void MaybeRecordStat(OptimizingCompilerStats* compiler_stats, |
| MethodCompilationStat stat, |
| uint32_t count = 1) { |
| if (compiler_stats != nullptr) { |
| compiler_stats->RecordStat(stat, count); |
| } |
| } |
| |
| } // namespace art |
| |
| #endif // ART_COMPILER_OPTIMIZING_OPTIMIZING_COMPILER_STATS_H_ |