1 /*
2  * Copyright (C) 2014 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #ifndef ART_COMPILER_OPTIMIZING_OPTIMIZING_COMPILER_STATS_H_
18 #define ART_COMPILER_OPTIMIZING_OPTIMIZING_COMPILER_STATS_H_
19 
20 #include <atomic>
21 #include <iomanip>
22 #include <string>
23 #include <type_traits>
24 
25 #include <android-base/logging.h>
26 
27 #include "base/atomic.h"
28 #include "base/globals.h"
29 
30 namespace art {
31 
32 enum class MethodCompilationStat {
33   kAttemptBytecodeCompilation = 0,
34   kAttemptIntrinsicCompilation,
35   kCompiledNativeStub,
36   kCompiledIntrinsic,
37   kCompiledBytecode,
38   kCHAInline,
39   kInlinedInvoke,
40   kReplacedInvokeWithSimplePattern,
41   kInstructionSimplifications,
42   kInstructionSimplificationsArch,
43   kUnresolvedMethod,
44   kUnresolvedField,
45   kUnresolvedFieldNotAFastAccess,
46   kRemovedCheckedCast,
47   kRemovedDeadInstruction,
48   kRemovedNullCheck,
49   kNotCompiledSkipped,
50   kNotCompiledInvalidBytecode,
51   kNotCompiledThrowCatchLoop,
52   kNotCompiledAmbiguousArrayOp,
53   kNotCompiledHugeMethod,
54   kNotCompiledLargeMethodNoBranches,
55   kNotCompiledMalformedOpcode,
56   kNotCompiledNoCodegen,
57   kNotCompiledPathological,
58   kNotCompiledSpaceFilter,
59   kNotCompiledUnhandledInstruction,
60   kNotCompiledUnsupportedIsa,
61   kNotCompiledVerificationError,
62   kNotCompiledVerifyAtRuntime,
63   kNotCompiledIrreducibleLoopAndStringInit,
64   kNotCompiledPhiEquivalentInOsr,
65   kInlinedMonomorphicCall,
66   kInlinedPolymorphicCall,
67   kMonomorphicCall,
68   kPolymorphicCall,
69   kMegamorphicCall,
70   kBooleanSimplified,
71   kIntrinsicRecognized,
72   kLoopInvariantMoved,
73   kLoopVectorized,
74   kLoopVectorizedIdiom,
75   kSelectGenerated,
76   kRemovedInstanceOf,
77   kInlinedInvokeVirtualOrInterface,
78   kImplicitNullCheckGenerated,
79   kExplicitNullCheckGenerated,
80   kSimplifyIf,
81   kSimplifyThrowingInvoke,
82   kInstructionSunk,
83   kNotInlinedUnresolvedEntrypoint,
84   kNotInlinedDexCache,
85   kNotInlinedStackMaps,
86   kNotInlinedEnvironmentBudget,
87   kNotInlinedInstructionBudget,
88   kNotInlinedLoopWithoutExit,
89   kNotInlinedIrreducibleLoop,
90   kNotInlinedAlwaysThrows,
91   kNotInlinedInfiniteLoop,
92   kNotInlinedTryCatch,
93   kNotInlinedRegisterAllocator,
94   kNotInlinedCannotBuild,
95   kNotInlinedNotVerified,
96   kNotInlinedCodeItem,
97   kNotInlinedWont,
98   kNotInlinedRecursiveBudget,
99   kNotInlinedProxy,
100   kNotInlinedUnresolved,
101   kNotInlinedPolymorphic,
102   kNotInlinedCustom,
103   kTryInline,
104   kConstructorFenceGeneratedNew,
105   kConstructorFenceGeneratedFinal,
106   kConstructorFenceRemovedLSE,
107   kConstructorFenceRemovedPFRA,
108   kConstructorFenceRemovedCFRE,
109   kBitstringTypeCheck,
110   kJitOutOfMemoryForCommit,
111   kLastStat
112 };
113 std::ostream& operator<<(std::ostream& os, MethodCompilationStat rhs);
114 
115 class OptimizingCompilerStats {
116  public:
OptimizingCompilerStats()117   OptimizingCompilerStats() {
118     // The std::atomic<> default constructor leaves values uninitialized, so initialize them now.
119     Reset();
120   }
121 
122   void RecordStat(MethodCompilationStat stat, uint32_t count = 1) {
123     size_t stat_index = static_cast<size_t>(stat);
124     DCHECK_LT(stat_index, arraysize(compile_stats_));
125     compile_stats_[stat_index] += count;
126   }
127 
GetStat(MethodCompilationStat stat)128   uint32_t GetStat(MethodCompilationStat stat) const {
129     size_t stat_index = static_cast<size_t>(stat);
130     DCHECK_LT(stat_index, arraysize(compile_stats_));
131     return compile_stats_[stat_index];
132   }
133 
Log()134   void Log() const {
135     uint32_t compiled_intrinsics = GetStat(MethodCompilationStat::kCompiledIntrinsic);
136     uint32_t compiled_native_stubs = GetStat(MethodCompilationStat::kCompiledNativeStub);
137     uint32_t bytecode_attempts =
138         GetStat(MethodCompilationStat::kAttemptBytecodeCompilation);
139     if (compiled_intrinsics == 0u && compiled_native_stubs == 0u && bytecode_attempts == 0u) {
140       LOG(INFO) << "Did not compile any method.";
141     } else {
142       uint32_t compiled_bytecode_methods =
143           GetStat(MethodCompilationStat::kCompiledBytecode);
144       // Successful intrinsic compilation preempts other compilation attempts but failed intrinsic
145       // compilation shall still count towards bytecode or native stub compilation attempts.
146       uint32_t num_compilation_attempts =
147           compiled_intrinsics + compiled_native_stubs + bytecode_attempts;
148       uint32_t num_successful_compilations =
149           compiled_intrinsics + compiled_native_stubs + compiled_bytecode_methods;
150       float compiled_percent = num_successful_compilations * 100.0f / num_compilation_attempts;
151       LOG(INFO) << "Attempted compilation of "
152           << num_compilation_attempts << " methods: " << std::fixed << std::setprecision(2)
153           << compiled_percent << "% (" << num_successful_compilations << ") compiled.";
154 
155       for (size_t i = 0; i < arraysize(compile_stats_); ++i) {
156         if (compile_stats_[i] != 0) {
157           LOG(INFO) << "OptStat#" << static_cast<MethodCompilationStat>(i) << ": "
158               << compile_stats_[i];
159         }
160       }
161     }
162   }
163 
AddTo(OptimizingCompilerStats * other_stats)164   void AddTo(OptimizingCompilerStats* other_stats) {
165     for (size_t i = 0; i != arraysize(compile_stats_); ++i) {
166       uint32_t count = compile_stats_[i];
167       if (count != 0) {
168         other_stats->RecordStat(static_cast<MethodCompilationStat>(i), count);
169       }
170     }
171   }
172 
Reset()173   void Reset() {
174     for (std::atomic<uint32_t>& stat : compile_stats_) {
175       stat = 0u;
176     }
177   }
178 
179  private:
180   std::atomic<uint32_t> compile_stats_[static_cast<size_t>(MethodCompilationStat::kLastStat)];
181 
182   DISALLOW_COPY_AND_ASSIGN(OptimizingCompilerStats);
183 };
184 
185 inline void MaybeRecordStat(OptimizingCompilerStats* compiler_stats,
186                             MethodCompilationStat stat,
187                             uint32_t count = 1) {
188   if (compiler_stats != nullptr) {
189     compiler_stats->RecordStat(stat, count);
190   }
191 }
192 
193 }  // namespace art
194 
195 #endif  // ART_COMPILER_OPTIMIZING_OPTIMIZING_COMPILER_STATS_H_
196