• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2024 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_RUNTIME_TRACE_COMMON_H_
18 #define ART_RUNTIME_TRACE_COMMON_H_
19 
20 #include "android-base/stringprintf.h"
21 #include "art_method-inl.h"
22 #include "dex/descriptors_names.h"
23 #include "oat/oat_quick_method_header.h"
24 
25 using android::base::StringPrintf;
26 
27 namespace art HIDDEN {
28 
GetMethodInfoLine(ArtMethod * method)29 static std::string GetMethodInfoLine(ArtMethod* method) REQUIRES_SHARED(Locks::mutator_lock_) {
30   method = method->GetInterfaceMethodIfProxy(kRuntimePointerSize);
31   return StringPrintf("%s\t%s\t%s\t%s\n",
32                       PrettyDescriptor(method->GetDeclaringClassDescriptor()).c_str(),
33                       method->GetName(),
34                       method->GetSignature().ToString().c_str(),
35                       method->GetDeclaringClassSourceFile());
36 }
37 
38 class TimestampCounter {
39  public:
GetTimestamp()40   static uint64_t GetTimestamp() {
41     uint64_t t = 0;
42 #if defined(__arm__)
43     // On ARM 32 bit, we don't always have access to the timestamp counters from user space. There
44     // is no easy way to check if it is safe to read the timestamp counters. There is HWCAP_EVTSTRM
45     // which is set when generic timer is available but not necessarily from the user space. Kernel
46     // disables access to generic timer when there are known problems on the target CPUs. Sometimes
47     // access is disabled only for 32-bit processes even when 64-bit processes can accesses the
48     // timer from user space. These are not reflected in the HWCAP_EVTSTRM capability.So just
49     // fallback to clock_gettime on these processes. See b/289178149 for more discussion.
50     t = NanoTime();
51 #elif defined(__aarch64__)
52     // See Arm Architecture Registers  Armv8 section System Registers
53     asm volatile("mrs %0, cntvct_el0" : "=r"(t));
54 #elif defined(__i386__) || defined(__x86_64__)
55     // rdtsc returns two 32-bit values in rax and rdx even on 64-bit architectures.
56     unsigned int lo, hi;
57     asm volatile("rdtsc" : "=a"(lo), "=d"(hi));
58     t = (static_cast<uint64_t>(hi) << 32) | lo;
59 #elif defined(__riscv)
60     asm volatile("rdtime %0" : "=r"(t));
61 #else
62     t = NanoTime();
63 #endif
64     return t;
65   }
66 
InitializeTimestampCounters()67   static void InitializeTimestampCounters() {
68     // It is sufficient to initialize this once for the entire execution. Just return if it is
69     // already initialized.
70     if (tsc_to_nanosec_scaling_factor > 0.0) {
71       return;
72     }
73 
74 #if defined(__arm__)
75     // On ARM 32 bit, we don't always have access to the timestamp counters from
76     // user space. Seem comment in GetTimestamp for more details.
77     tsc_to_nanosec_scaling_factor = 1.0;
78 #elif defined(__aarch64__)
79     double seconds_to_nanoseconds = 1000 * 1000;
80     uint64_t freq = 0;
81     // See Arm Architecture Registers  Armv8 section System Registers
82     asm volatile("mrs %0,  cntfrq_el0" : "=r"(freq));
83     if (freq == 0) {
84       // It is expected that cntfrq_el0 is correctly setup during system initialization but some
85       // devices don't do this. In such cases fall back to computing the frequency. See b/315139000.
86       tsc_to_nanosec_scaling_factor = computeScalingFactor();
87     } else {
88       tsc_to_nanosec_scaling_factor = seconds_to_nanoseconds / static_cast<double>(freq);
89     }
90 #elif defined(__i386__) || defined(__x86_64__)
91     tsc_to_nanosec_scaling_factor = GetScalingFactorForX86();
92 #else
93     tsc_to_nanosec_scaling_factor = 1.0;
94 #endif
95   }
96 
GetNanoTime(uint64_t counter)97   static ALWAYS_INLINE uint64_t GetNanoTime(uint64_t counter) {
98     DCHECK(tsc_to_nanosec_scaling_factor > 0.0) << tsc_to_nanosec_scaling_factor;
99     return tsc_to_nanosec_scaling_factor * counter;
100   }
101 
102  private:
103 #if defined(__i386__) || defined(__x86_64__) || defined(__aarch64__)
104   // Here we compute the scaling factor by sleeping for a millisecond. Alternatively, we could
105   // generate raw timestamp counter and also time using clock_gettime at the start and the end of
106   // the trace. We can compute the frequency of timestamp counter upadtes in the post processing
107   // step using these two samples. However, that would require a change in Android Studio which is
108   // the main consumer of these profiles. For now, just compute the frequency of tsc updates here.
computeScalingFactor()109   static double computeScalingFactor() {
110     uint64_t start = NanoTime();
111     uint64_t start_tsc = GetTimestamp();
112     // Sleep for one millisecond.
113     usleep(1000);
114     uint64_t diff_tsc = GetTimestamp() - start_tsc;
115     uint64_t diff_time = NanoTime() - start;
116     double scaling_factor = static_cast<double>(diff_time) / diff_tsc;
117     DCHECK(scaling_factor > 0.0) << scaling_factor;
118     return scaling_factor;
119   }
120 #endif
121 
122 #if defined(__i386__) || defined(__x86_64__)
GetScalingFactorForX86()123   static double GetScalingFactorForX86() {
124     uint32_t eax, ebx, ecx;
125     asm volatile("cpuid" : "=a"(eax), "=b"(ebx), "=c"(ecx) : "a"(0x0), "c"(0));
126     if (eax < 0x15) {
127       // There is no 15H - Timestamp counter and core crystal clock information
128       // leaf. Just compute the frequency.
129       return computeScalingFactor();
130     }
131 
132     // From Intel architecture-instruction-set-extensions-programming-reference:
133     // EBX[31:0]/EAX[31:0] indicates the ratio of the TSC frequency and the
134     // core crystal clock frequency.
135     // If EBX[31:0] is 0, the TSC and "core crystal clock" ratio is not enumerated.
136     // If ECX is 0, the nominal core crystal clock frequency is not enumerated.
137     // "TSC frequency" = "core crystal clock frequency" * EBX/EAX.
138     // The core crystal clock may differ from the reference clock, bus clock, or core clock
139     // frequencies.
140     // EAX Bits 31 - 00: An unsigned integer which is the denominator of the
141     //                   TSC/"core crystal clock" ratio.
142     // EBX Bits 31 - 00: An unsigned integer which is the numerator of the
143     //                   TSC/"core crystal clock" ratio.
144     // ECX Bits 31 - 00: An unsigned integer which is the nominal frequency of the core
145     //                   crystal clock in Hz.
146     // EDX Bits 31 - 00: Reserved = 0.
147     asm volatile("cpuid" : "=a"(eax), "=b"(ebx), "=c"(ecx) : "a"(0x15), "c"(0));
148     if (ebx == 0 || ecx == 0) {
149       return computeScalingFactor();
150     }
151     double coreCrystalFreq = ecx;
152     // frequency = coreCrystalFreq * (ebx / eax)
153     // scaling_factor = seconds_to_nanoseconds / frequency
154     //                = seconds_to_nanoseconds * eax / (coreCrystalFreq * ebx)
155     double seconds_to_nanoseconds = 1000 * 1000;
156     double scaling_factor = (seconds_to_nanoseconds * eax) / (coreCrystalFreq * ebx);
157     return scaling_factor;
158   }
159 #endif
160 
161   // Scaling factor to convert timestamp counter into wall clock time reported in nano seconds.
162   // This is initialized at the start of tracing using the timestamp counter update frequency.
163   // See InitializeTimestampCounters for more details.
164   static double tsc_to_nanosec_scaling_factor;
165 };
166 
167 }  // namespace art
168 
169 #endif  // ART_RUNTIME_TRACE_COMMON_H_
170