/* * Copyright (C) 2020 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. */ #include #include "android-base/file.h" #include "android-base/logging.h" #include "base/macros.h" #include "base/scoped_flock.h" #include "metrics.h" #pragma clang diagnostic push #pragma clang diagnostic error "-Wconversion" namespace art { namespace metrics { std::string DatumName(DatumId datum) { switch (datum) { #define ART_METRIC(name, Kind, ...) \ case DatumId::k##name: \ return #name; ART_METRICS(ART_METRIC) #undef ART_METRIC default: LOG(FATAL) << "Unknown datum id: " << static_cast(datum); UNREACHABLE(); } } SessionData SessionData::CreateDefault() { #ifdef _WIN32 int32_t uid = kInvalidUserId; // Windows does not support getuid(); #else int32_t uid = static_cast(getuid()); #endif return SessionData{ .compilation_reason = CompilationReason::kUnknown, .compiler_filter = CompilerFilterReporting::kUnknown, .session_id = kInvalidSessionId, .uid = uid, }; } ArtMetrics::ArtMetrics() : beginning_timestamp_ {MilliTime()} #define ART_METRIC(name, Kind, ...) \ , name##_ {} ART_METRICS(ART_METRIC) #undef ART_METRIC { } void ArtMetrics::ReportAllMetrics(MetricsBackend* backend) const { backend->BeginReport(MilliTime() - beginning_timestamp_); #define ART_METRIC(name, Kind, ...) name()->Report(backend); ART_METRICS(ART_METRIC) #undef ART_METRIC backend->EndReport(); } void ArtMetrics::DumpForSigQuit(std::ostream& os) const { StringBackend backend; ReportAllMetrics(&backend); os << backend.GetAndResetBuffer(); } void ArtMetrics::Reset() { beginning_timestamp_ = MilliTime(); #define ART_METRIC(name, kind, ...) name##_.Reset(); ART_METRICS(ART_METRIC); #undef ART_METRIC } StringBackend::StringBackend() {} std::string StringBackend::GetAndResetBuffer() { std::string result = os_.str(); os_.clear(); os_.str(""); return result; } void StringBackend::BeginOrUpdateSession(const SessionData& session_data) { session_data_ = session_data; } void StringBackend::BeginReport(uint64_t timestamp_since_start_ms) { os_ << "\n*** ART internal metrics ***\n"; os_ << " Metadata:\n"; os_ << " timestamp_since_start_ms: " << timestamp_since_start_ms << "\n"; if (session_data_.has_value()) { os_ << " session_id: " << session_data_->session_id << "\n"; os_ << " uid: " << session_data_->uid << "\n"; os_ << " compilation_reason: " << CompilationReasonName(session_data_->compilation_reason) << "\n"; os_ << " compiler_filter: " << CompilerFilterReportingName(session_data_->compiler_filter) << "\n"; } os_ << " Metrics:\n"; } void StringBackend::EndReport() { os_ << "*** Done dumping ART internal metrics ***\n"; } void StringBackend::ReportCounter(DatumId counter_type, uint64_t value) { os_ << " " << DatumName(counter_type) << ": count = " << value << "\n"; } void StringBackend::ReportHistogram(DatumId histogram_type, int64_t minimum_value_, int64_t maximum_value_, const std::vector& buckets) { os_ << " " << DatumName(histogram_type) << ": range = " << minimum_value_ << "..." << maximum_value_; if (buckets.size() > 0) { os_ << ", buckets: "; bool first = true; for (const auto& count : buckets) { if (!first) { os_ << ","; } first = false; os_ << count; } os_ << "\n"; } else { os_ << ", no buckets\n"; } } LogBackend::LogBackend(android::base::LogSeverity level) : level_{level} {} void LogBackend::BeginReport(uint64_t timestamp_since_start_ms) { GetAndResetBuffer(); StringBackend::BeginReport(timestamp_since_start_ms); } void LogBackend::EndReport() { StringBackend::EndReport(); LOG_STREAM(level_) << GetAndResetBuffer(); } FileBackend::FileBackend(const std::string& filename) : filename_{filename} {} void FileBackend::BeginReport(uint64_t timestamp_since_start_ms) { GetAndResetBuffer(); StringBackend::BeginReport(timestamp_since_start_ms); } void FileBackend::EndReport() { StringBackend::EndReport(); std::string error_message; auto file{ LockedFile::Open(filename_.c_str(), O_CREAT | O_WRONLY | O_APPEND, true, &error_message)}; if (file.get() == nullptr) { LOG(WARNING) << "Could open metrics file '" << filename_ << "': " << error_message; } else { if (!android::base::WriteStringToFd(GetAndResetBuffer(), file.get()->Fd())) { PLOG(WARNING) << "Error writing metrics to file"; } } } // Make sure CompilationReasonName and CompilationReasonForName are inverses. static_assert(CompilationReasonFromName(CompilationReasonName(CompilationReason::kError)) == CompilationReason::kError); static_assert(CompilationReasonFromName(CompilationReasonName(CompilationReason::kUnknown)) == CompilationReason::kUnknown); static_assert(CompilationReasonFromName(CompilationReasonName(CompilationReason::kFirstBoot)) == CompilationReason::kFirstBoot); static_assert(CompilationReasonFromName(CompilationReasonName(CompilationReason::kBootAfterOTA)) == CompilationReason::kBootAfterOTA); static_assert(CompilationReasonFromName(CompilationReasonName(CompilationReason::kPostBoot)) == CompilationReason::kPostBoot); static_assert(CompilationReasonFromName(CompilationReasonName(CompilationReason::kInstall)) == CompilationReason::kInstall); static_assert(CompilationReasonFromName(CompilationReasonName(CompilationReason::kInstallFast)) == CompilationReason::kInstallFast); static_assert(CompilationReasonFromName(CompilationReasonName(CompilationReason::kInstallBulk)) == CompilationReason::kInstallBulk); static_assert( CompilationReasonFromName(CompilationReasonName(CompilationReason::kInstallBulkSecondary)) == CompilationReason::kInstallBulkSecondary); static_assert( CompilationReasonFromName(CompilationReasonName(CompilationReason::kInstallBulkDowngraded)) == CompilationReason::kInstallBulkDowngraded); static_assert(CompilationReasonFromName( CompilationReasonName(CompilationReason::kInstallBulkSecondaryDowngraded)) == CompilationReason::kInstallBulkSecondaryDowngraded); static_assert(CompilationReasonFromName(CompilationReasonName(CompilationReason::kBgDexopt)) == CompilationReason::kBgDexopt); static_assert(CompilationReasonFromName(CompilationReasonName(CompilationReason::kABOTA)) == CompilationReason::kABOTA); static_assert(CompilationReasonFromName(CompilationReasonName(CompilationReason::kInactive)) == CompilationReason::kInactive); static_assert(CompilationReasonFromName(CompilationReasonName(CompilationReason::kShared)) == CompilationReason::kShared); static_assert( CompilationReasonFromName(CompilationReasonName(CompilationReason::kInstallWithDexMetadata)) == CompilationReason::kInstallWithDexMetadata); static_assert(CompilationReasonFromName(CompilationReasonName(CompilationReason::kPrebuilt)) == CompilationReason::kPrebuilt); static_assert(CompilationReasonFromName(CompilationReasonName(CompilationReason::kCmdLine)) == CompilationReason::kCmdLine); } // namespace metrics } // namespace art #pragma clang diagnostic pop // -Wconversion