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   kFullLSEAllocationRemoved,
112   kFullLSEPossible,
113   kNonPartialLoadRemoved,
114   kPartialLSEPossible,
115   kPartialStoreRemoved,
116   kPartialAllocationMoved,
117   kPredicatedLoadAdded,
118   kPredicatedStoreAdded,
119   kDevirtualized,
120   kLastStat
121 };
122 std::ostream& operator<<(std::ostream& os, MethodCompilationStat rhs);
123 
124 class OptimizingCompilerStats {
125  public:
OptimizingCompilerStats()126   OptimizingCompilerStats() {
127     // The std::atomic<> default constructor leaves values uninitialized, so initialize them now.
128     Reset();
129   }
130 
131   void RecordStat(MethodCompilationStat stat, uint32_t count = 1) {
132     size_t stat_index = static_cast<size_t>(stat);
133     DCHECK_LT(stat_index, arraysize(compile_stats_));
134     compile_stats_[stat_index] += count;
135   }
136 
GetStat(MethodCompilationStat stat)137   uint32_t GetStat(MethodCompilationStat stat) const {
138     size_t stat_index = static_cast<size_t>(stat);
139     DCHECK_LT(stat_index, arraysize(compile_stats_));
140     return compile_stats_[stat_index];
141   }
142 
Log()143   void Log() const {
144     uint32_t compiled_intrinsics = GetStat(MethodCompilationStat::kCompiledIntrinsic);
145     uint32_t compiled_native_stubs = GetStat(MethodCompilationStat::kCompiledNativeStub);
146     uint32_t bytecode_attempts =
147         GetStat(MethodCompilationStat::kAttemptBytecodeCompilation);
148     if (compiled_intrinsics == 0u && compiled_native_stubs == 0u && bytecode_attempts == 0u) {
149       LOG(INFO) << "Did not compile any method.";
150     } else {
151       uint32_t compiled_bytecode_methods =
152           GetStat(MethodCompilationStat::kCompiledBytecode);
153       // Successful intrinsic compilation preempts other compilation attempts but failed intrinsic
154       // compilation shall still count towards bytecode or native stub compilation attempts.
155       uint32_t num_compilation_attempts =
156           compiled_intrinsics + compiled_native_stubs + bytecode_attempts;
157       uint32_t num_successful_compilations =
158           compiled_intrinsics + compiled_native_stubs + compiled_bytecode_methods;
159       float compiled_percent = num_successful_compilations * 100.0f / num_compilation_attempts;
160       LOG(INFO) << "Attempted compilation of "
161           << num_compilation_attempts << " methods: " << std::fixed << std::setprecision(2)
162           << compiled_percent << "% (" << num_successful_compilations << ") compiled.";
163 
164       for (size_t i = 0; i < arraysize(compile_stats_); ++i) {
165         if (compile_stats_[i] != 0) {
166           LOG(INFO) << "OptStat#" << static_cast<MethodCompilationStat>(i) << ": "
167               << compile_stats_[i];
168         }
169       }
170     }
171   }
172 
AddTo(OptimizingCompilerStats * other_stats)173   void AddTo(OptimizingCompilerStats* other_stats) {
174     for (size_t i = 0; i != arraysize(compile_stats_); ++i) {
175       uint32_t count = compile_stats_[i];
176       if (count != 0) {
177         other_stats->RecordStat(static_cast<MethodCompilationStat>(i), count);
178       }
179     }
180   }
181 
Reset()182   void Reset() {
183     for (std::atomic<uint32_t>& stat : compile_stats_) {
184       stat = 0u;
185     }
186   }
187 
188  private:
189   std::atomic<uint32_t> compile_stats_[static_cast<size_t>(MethodCompilationStat::kLastStat)];
190 
191   DISALLOW_COPY_AND_ASSIGN(OptimizingCompilerStats);
192 };
193 
194 inline void MaybeRecordStat(OptimizingCompilerStats* compiler_stats,
195                             MethodCompilationStat stat,
196                             uint32_t count = 1) {
197   if (compiler_stats != nullptr) {
198     compiler_stats->RecordStat(stat, count);
199   }
200 }
201 
202 }  // namespace art
203 
204 #endif  // ART_COMPILER_OPTIMIZING_OPTIMIZING_COMPILER_STATS_H_
205