cpp/systemcounters/SystemCounterThread.cpp (102 lines of code) (raw):

/** * Copyright 2004-present, Facebook, Inc. * * 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 "SystemCounterThread.h" #include <profilo/logger/buffer/RingBuffer.h> #include <profilo/util/common.h> #include <unordered_set> using facebook::jni::alias_ref; using facebook::jni::local_ref; namespace facebook { namespace profilo { namespace counters { namespace { struct Whitelist { // When in high freq counter tracing mode, we can optionally whitelist // additional threads to profile as well. This list maintains current // list of threads that are candidates to be profiled in high freq mode. std::unordered_set<int32_t> whitelistedThreads; // Since this list is subject to updates by multiple threads, thread // safety is important, this following guards whitelistedThreads. std::mutex whitelistMtx; }; // Function wrapper around the static profile state to avoid // using a DSO constructor. Whitelist& getWhitelistState() { static Whitelist state; return state; } void addToWhitelist(alias_ref<jclass>, int targetThread) { auto& whitelistState = getWhitelistState(); std::unique_lock<std::mutex> lock(whitelistState.whitelistMtx); whitelistState.whitelistedThreads.insert(static_cast<int32_t>(targetThread)); } void removeFromWhitelist(alias_ref<jclass>, int targetThread) { // Don't remove the thread from whitelist if it is the main thread static auto pid = getpid(); if (targetThread == pid) { return; } auto& whitelistState = getWhitelistState(); std::unique_lock<std::mutex> lock(whitelistState.whitelistMtx); whitelistState.whitelistedThreads.erase(targetThread); } } // namespace SystemCounterThread::SystemCounterThread(MultiBufferLogger& logger) : logger_(logger), threadCounters_(logger), processCounters_(logger), systemCounters_(logger) {} local_ref<SystemCounterThread::jhybriddata> SystemCounterThread::initHybrid( alias_ref<jobject>, JMultiBufferLogger* logger) { return makeCxxInstance(logger->nativeInstance()); } void SystemCounterThread::registerNatives() { registerHybrid({ makeNativeMethod("initHybrid", SystemCounterThread::initHybrid), makeNativeMethod("logCounters", SystemCounterThread::logCounters), makeNativeMethod( "logExpensiveCounters", SystemCounterThread::logExpensiveCounters), makeNativeMethod( "logHighFrequencyThreadCounters", SystemCounterThread::logHighFrequencyThreadCounters), makeNativeMethod( "logTraceAnnotations", SystemCounterThread::logTraceAnnotations), makeNativeMethod("nativeAddToWhitelist", addToWhitelist), makeNativeMethod("nativeRemoveFromWhitelist", removeFromWhitelist), makeNativeMethod( "nativeSetHighFrequencyMode", SystemCounterThread::setHighFrequencyMode), }); } void SystemCounterThread::logCounters() { // When collecting counters for all threads and in high frequency mode then // thread ids from the high frequency whitelist should be ignored. // Making a copy of whitelist here to avoid holding the whitelist lock while // collecting counter data. std::unordered_set<int32_t> ignoredTids; if (highFrequencyMode_) { auto& whitelistState = getWhitelistState(); std::unique_lock<std::mutex> lockT(whitelistState.whitelistMtx); ignoredTids = whitelistState.whitelistedThreads; } threadCounters_.logCounters(highFrequencyMode_, ignoredTids); processCounters_.logCounters(); systemCounters_.logCounters(); } void SystemCounterThread::logExpensiveCounters() { processCounters_.logExpensiveCounters(); } void SystemCounterThread::logHighFrequencyThreadCounters() { std::unordered_set<int32_t> whitelist; auto& whitelistState = getWhitelistState(); { std::unique_lock<std::mutex> lockT(whitelistState.whitelistMtx); whitelist = whitelistState.whitelistedThreads; } threadCounters_.logHighFreqCounters(whitelist); systemCounters_.logHighFreqCounters(); } void SystemCounterThread::logTraceAnnotations() { int64_t value = processCounters_.getAvailableCounters() | systemCounters_.getAvailableCounters() | threadCounters_.getAvailableCounters(); logger_.write(StandardEntry{ .id = 0, .type = EntryType::TRACE_ANNOTATION, .timestamp = monotonicTime(), .tid = threadID(), .callid = QuickLogConstants::AVAILABLE_COUNTERS, .matchid = 0, .extra = value, }); } } // namespace counters } // namespace profilo } // namespace facebook