| /* |
| * 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 "globals.h" |
| |
| namespace art { |
| |
| enum MethodCompilationStat { |
| kAttemptCompilation = 0, |
| kCHAInline, |
| kCompiled, |
| 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, |
| kLastStat |
| }; |
| |
| 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) { |
| compile_stats_[stat] += count; |
| } |
| |
| void Log() const { |
| if (!kIsDebugBuild && !VLOG_IS_ON(compiler)) { |
| // Log only in debug builds or if the compiler is verbose. |
| return; |
| } |
| |
| if (compile_stats_[kAttemptCompilation] == 0) { |
| LOG(INFO) << "Did not compile any method."; |
| } else { |
| float compiled_percent = |
| compile_stats_[kCompiled] * 100.0f / compile_stats_[kAttemptCompilation]; |
| LOG(INFO) << "Attempted compilation of " << compile_stats_[kAttemptCompilation] |
| << " methods: " << std::fixed << std::setprecision(2) |
| << compiled_percent << "% (" << compile_stats_[kCompiled] << ") compiled."; |
| |
| for (size_t i = 0; i < kLastStat; i++) { |
| if (compile_stats_[i] != 0) { |
| LOG(INFO) << PrintMethodCompilationStat(static_cast<MethodCompilationStat>(i)) << ": " |
| << compile_stats_[i]; |
| } |
| } |
| } |
| } |
| |
| void AddTo(OptimizingCompilerStats* other_stats) { |
| for (size_t i = 0; i != kLastStat; ++i) { |
| uint32_t count = compile_stats_[i]; |
| if (count != 0) { |
| other_stats->RecordStat(static_cast<MethodCompilationStat>(i), count); |
| } |
| } |
| } |
| |
| void Reset() { |
| for (size_t i = 0; i != kLastStat; ++i) { |
| compile_stats_[i] = 0u; |
| } |
| } |
| |
| private: |
| std::string PrintMethodCompilationStat(MethodCompilationStat stat) const { |
| std::string name; |
| switch (stat) { |
| case kAttemptCompilation : name = "AttemptCompilation"; break; |
| case kCHAInline : name = "CHAInline"; break; |
| case kCompiled : name = "Compiled"; break; |
| case kInlinedInvoke : name = "InlinedInvoke"; break; |
| case kReplacedInvokeWithSimplePattern: name = "ReplacedInvokeWithSimplePattern"; break; |
| case kInstructionSimplifications: name = "InstructionSimplifications"; break; |
| case kInstructionSimplificationsArch: name = "InstructionSimplificationsArch"; break; |
| case kUnresolvedMethod : name = "UnresolvedMethod"; break; |
| case kUnresolvedField : name = "UnresolvedField"; break; |
| case kUnresolvedFieldNotAFastAccess : name = "UnresolvedFieldNotAFastAccess"; break; |
| case kRemovedCheckedCast: name = "RemovedCheckedCast"; break; |
| case kRemovedDeadInstruction: name = "RemovedDeadInstruction"; break; |
| case kRemovedNullCheck: name = "RemovedNullCheck"; break; |
| case kNotCompiledSkipped: name = "NotCompiledSkipped"; break; |
| case kNotCompiledInvalidBytecode: name = "NotCompiledInvalidBytecode"; break; |
| case kNotCompiledThrowCatchLoop : name = "NotCompiledThrowCatchLoop"; break; |
| case kNotCompiledAmbiguousArrayOp : name = "NotCompiledAmbiguousArrayOp"; break; |
| case kNotCompiledHugeMethod : name = "NotCompiledHugeMethod"; break; |
| case kNotCompiledLargeMethodNoBranches : name = "NotCompiledLargeMethodNoBranches"; break; |
| case kNotCompiledMalformedOpcode : name = "NotCompiledMalformedOpcode"; break; |
| case kNotCompiledNoCodegen : name = "NotCompiledNoCodegen"; break; |
| case kNotCompiledPathological : name = "NotCompiledPathological"; break; |
| case kNotCompiledSpaceFilter : name = "NotCompiledSpaceFilter"; break; |
| case kNotCompiledUnhandledInstruction : name = "NotCompiledUnhandledInstruction"; break; |
| case kNotCompiledUnsupportedIsa : name = "NotCompiledUnsupportedIsa"; break; |
| case kNotCompiledVerificationError : name = "NotCompiledVerificationError"; break; |
| case kNotCompiledVerifyAtRuntime : name = "NotCompiledVerifyAtRuntime"; break; |
| case kInlinedMonomorphicCall: name = "InlinedMonomorphicCall"; break; |
| case kInlinedPolymorphicCall: name = "InlinedPolymorphicCall"; break; |
| case kMonomorphicCall: name = "MonomorphicCall"; break; |
| case kPolymorphicCall: name = "PolymorphicCall"; break; |
| case kMegamorphicCall: name = "MegamorphicCall"; break; |
| case kBooleanSimplified : name = "BooleanSimplified"; break; |
| case kIntrinsicRecognized : name = "IntrinsicRecognized"; break; |
| case kLoopInvariantMoved : name = "LoopInvariantMoved"; break; |
| case kLoopVectorized : name = "LoopVectorized"; break; |
| case kLoopVectorizedIdiom : name = "LoopVectorizedIdiom"; break; |
| case kSelectGenerated : name = "SelectGenerated"; break; |
| case kRemovedInstanceOf: name = "RemovedInstanceOf"; break; |
| case kInlinedInvokeVirtualOrInterface: name = "InlinedInvokeVirtualOrInterface"; break; |
| case kImplicitNullCheckGenerated: name = "ImplicitNullCheckGenerated"; break; |
| case kExplicitNullCheckGenerated: name = "ExplicitNullCheckGenerated"; break; |
| case kSimplifyIf: name = "SimplifyIf"; break; |
| case kInstructionSunk: name = "InstructionSunk"; break; |
| case kNotInlinedUnresolvedEntrypoint: name = "NotInlinedUnresolvedEntrypoint"; break; |
| case kNotInlinedDexCache: name = "NotInlinedDexCache"; break; |
| case kNotInlinedStackMaps: name = "NotInlinedStackMaps"; break; |
| case kNotInlinedEnvironmentBudget: name = "NotInlinedEnvironmentBudget"; break; |
| case kNotInlinedInstructionBudget: name = "NotInlinedInstructionBudget"; break; |
| case kNotInlinedLoopWithoutExit: name = "NotInlinedLoopWithoutExit"; break; |
| case kNotInlinedIrreducibleLoop: name = "NotInlinedIrreducibleLoop"; break; |
| case kNotInlinedAlwaysThrows: name = "NotInlinedAlwaysThrows"; break; |
| case kNotInlinedInfiniteLoop: name = "NotInlinedInfiniteLoop"; break; |
| case kNotInlinedTryCatch: name = "NotInlinedTryCatch"; break; |
| case kNotInlinedRegisterAllocator: name = "NotInlinedRegisterAllocator"; break; |
| case kNotInlinedCannotBuild: name = "NotInlinedCannotBuild"; break; |
| case kNotInlinedNotVerified: name = "NotInlinedNotVerified"; break; |
| case kNotInlinedCodeItem: name = "NotInlinedCodeItem"; break; |
| case kNotInlinedWont: name = "NotInlinedWont"; break; |
| case kNotInlinedRecursiveBudget: name = "NotInlinedRecursiveBudget"; break; |
| case kNotInlinedProxy: name = "NotInlinedProxy"; break; |
| case kConstructorFenceGeneratedNew: name = "ConstructorFenceGeneratedNew"; break; |
| case kConstructorFenceGeneratedFinal: name = "ConstructorFenceGeneratedFinal"; break; |
| case kConstructorFenceRemovedLSE: name = "ConstructorFenceRemovedLSE"; break; |
| case kConstructorFenceRemovedPFRA: name = "ConstructorFenceRemovedPFRA"; break; |
| case kConstructorFenceRemovedCFRE: name = "ConstructorFenceRemovedCFRE"; break; |
| |
| case kLastStat: |
| LOG(FATAL) << "invalid stat " |
| << static_cast<std::underlying_type<MethodCompilationStat>::type>(stat); |
| UNREACHABLE(); |
| } |
| return "OptStat#" + name; |
| } |
| |
| std::atomic<uint32_t> compile_stats_[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_ |