/* * Copyright (C) 2024 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_RUNTIME_TRACE_COMMON_H_ #define ART_RUNTIME_TRACE_COMMON_H_ #include "android-base/stringprintf.h" #include "art_method-inl.h" #include "dex/descriptors_names.h" #include "oat/oat_quick_method_header.h" using android::base::StringPrintf; namespace art HIDDEN { static std::string GetMethodInfoLine(ArtMethod* method) REQUIRES_SHARED(Locks::mutator_lock_) { method = method->GetInterfaceMethodIfProxy(kRuntimePointerSize); return StringPrintf("%s\t%s\t%s\t%s\n", PrettyDescriptor(method->GetDeclaringClassDescriptor()).c_str(), method->GetName(), method->GetSignature().ToString().c_str(), method->GetDeclaringClassSourceFile()); } class TimestampCounter { public: static uint64_t GetTimestamp() { uint64_t t = 0; #if defined(__arm__) // On ARM 32 bit, we don't always have access to the timestamp counters from user space. There // is no easy way to check if it is safe to read the timestamp counters. There is HWCAP_EVTSTRM // which is set when generic timer is available but not necessarily from the user space. Kernel // disables access to generic timer when there are known problems on the target CPUs. Sometimes // access is disabled only for 32-bit processes even when 64-bit processes can accesses the // timer from user space. These are not reflected in the HWCAP_EVTSTRM capability.So just // fallback to clock_gettime on these processes. See b/289178149 for more discussion. t = NanoTime(); #elif defined(__aarch64__) // See Arm Architecture Registers Armv8 section System Registers asm volatile("mrs %0, cntvct_el0" : "=r"(t)); #elif defined(__i386__) || defined(__x86_64__) // rdtsc returns two 32-bit values in rax and rdx even on 64-bit architectures. unsigned int lo, hi; asm volatile("rdtsc" : "=a"(lo), "=d"(hi)); t = (static_cast(hi) << 32) | lo; #elif defined(__riscv) asm volatile("rdtime %0" : "=r"(t)); #else t = NanoTime(); #endif return t; } static void InitializeTimestampCounters() { // It is sufficient to initialize this once for the entire execution. Just return if it is // already initialized. if (tsc_to_nanosec_scaling_factor > 0.0) { return; } #if defined(__arm__) // On ARM 32 bit, we don't always have access to the timestamp counters from // user space. Seem comment in GetTimestamp for more details. tsc_to_nanosec_scaling_factor = 1.0; #elif defined(__aarch64__) double seconds_to_nanoseconds = 1000 * 1000; uint64_t freq = 0; // See Arm Architecture Registers Armv8 section System Registers asm volatile("mrs %0, cntfrq_el0" : "=r"(freq)); if (freq == 0) { // It is expected that cntfrq_el0 is correctly setup during system initialization but some // devices don't do this. In such cases fall back to computing the frequency. See b/315139000. tsc_to_nanosec_scaling_factor = computeScalingFactor(); } else { tsc_to_nanosec_scaling_factor = seconds_to_nanoseconds / static_cast(freq); } #elif defined(__i386__) || defined(__x86_64__) tsc_to_nanosec_scaling_factor = GetScalingFactorForX86(); #else tsc_to_nanosec_scaling_factor = 1.0; #endif } static ALWAYS_INLINE uint64_t GetNanoTime(uint64_t counter) { DCHECK(tsc_to_nanosec_scaling_factor > 0.0) << tsc_to_nanosec_scaling_factor; return tsc_to_nanosec_scaling_factor * counter; } private: #if defined(__i386__) || defined(__x86_64__) || defined(__aarch64__) // Here we compute the scaling factor by sleeping for a millisecond. Alternatively, we could // generate raw timestamp counter and also time using clock_gettime at the start and the end of // the trace. We can compute the frequency of timestamp counter upadtes in the post processing // step using these two samples. However, that would require a change in Android Studio which is // the main consumer of these profiles. For now, just compute the frequency of tsc updates here. static double computeScalingFactor() { uint64_t start = NanoTime(); uint64_t start_tsc = GetTimestamp(); // Sleep for one millisecond. usleep(1000); uint64_t diff_tsc = GetTimestamp() - start_tsc; uint64_t diff_time = NanoTime() - start; double scaling_factor = static_cast(diff_time) / diff_tsc; DCHECK(scaling_factor > 0.0) << scaling_factor; return scaling_factor; } #endif #if defined(__i386__) || defined(__x86_64__) static double GetScalingFactorForX86() { uint32_t eax, ebx, ecx; asm volatile("cpuid" : "=a"(eax), "=b"(ebx), "=c"(ecx) : "a"(0x0), "c"(0)); if (eax < 0x15) { // There is no 15H - Timestamp counter and core crystal clock information // leaf. Just compute the frequency. return computeScalingFactor(); } // From Intel architecture-instruction-set-extensions-programming-reference: // EBX[31:0]/EAX[31:0] indicates the ratio of the TSC frequency and the // core crystal clock frequency. // If EBX[31:0] is 0, the TSC and "core crystal clock" ratio is not enumerated. // If ECX is 0, the nominal core crystal clock frequency is not enumerated. // "TSC frequency" = "core crystal clock frequency" * EBX/EAX. // The core crystal clock may differ from the reference clock, bus clock, or core clock // frequencies. // EAX Bits 31 - 00: An unsigned integer which is the denominator of the // TSC/"core crystal clock" ratio. // EBX Bits 31 - 00: An unsigned integer which is the numerator of the // TSC/"core crystal clock" ratio. // ECX Bits 31 - 00: An unsigned integer which is the nominal frequency of the core // crystal clock in Hz. // EDX Bits 31 - 00: Reserved = 0. asm volatile("cpuid" : "=a"(eax), "=b"(ebx), "=c"(ecx) : "a"(0x15), "c"(0)); if (ebx == 0 || ecx == 0) { return computeScalingFactor(); } double coreCrystalFreq = ecx; // frequency = coreCrystalFreq * (ebx / eax) // scaling_factor = seconds_to_nanoseconds / frequency // = seconds_to_nanoseconds * eax / (coreCrystalFreq * ebx) double seconds_to_nanoseconds = 1000 * 1000; double scaling_factor = (seconds_to_nanoseconds * eax) / (coreCrystalFreq * ebx); return scaling_factor; } #endif // Scaling factor to convert timestamp counter into wall clock time reported in nano seconds. // This is initialized at the start of tracing using the timestamp counter update frequency. // See InitializeTimestampCounters for more details. static double tsc_to_nanosec_scaling_factor; }; } // namespace art #endif // ART_RUNTIME_TRACE_COMMON_H_