cpp/TraceProviders.cpp (80 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 "TraceProviders.h"
#include <fbjni/fbjni.h>
#include <algorithm>
#include <cstring>
namespace facebook {
namespace profilo {
namespace {
struct StrCompare {
bool operator()(const ProviderEntry& entry, const char* key) {
return strcmp(entry.first.c_str(), key) < 0;
}
bool operator()(const char* key, const ProviderEntry& entry) {
return strcmp(key, entry.first.c_str()) < 0;
}
};
} // namespace
TraceProviders& TraceProviders::get() {
static TraceProviders providers{};
return providers;
}
bool TraceProviders::isEnabled(const char* provider) {
// The native side doesn't have the full name -> int mapping.
// This function retrieves the mapping for a single provider from
// pre-initialized cache.
// Reader side of the lock only, this is the fast path.
std::shared_lock<std::shared_timed_mutex> lock(name_lookup_mutex_);
if (name_lookup_cache_.empty()) {
return false;
}
auto iter = std::lower_bound(
name_lookup_cache_.begin(),
name_lookup_cache_.end(),
provider,
StrCompare());
if (iter == name_lookup_cache_.end() ||
strcmp(iter->first.c_str(), provider) != 0) {
return false;
}
return isEnabled(iter->second);
}
bool TraceProviders::isEnabled(const std::string& provider) {
return isEnabled(provider.c_str());
}
uint32_t TraceProviders::enableProviders(uint32_t providers) {
std::lock_guard<std::mutex> lock(mutex_);
auto p = providers;
int lsb_index;
while ((lsb_index = __builtin_ffs(p) - 1) != -1) {
provider_counts_[lsb_index]++;
p ^= static_cast<unsigned int>(1) << lsb_index;
}
providers_ |= providers;
return providers_;
}
uint32_t TraceProviders::disableProviders(uint32_t providers) {
std::lock_guard<std::mutex> lock(mutex_);
uint32_t disable_providers = 0;
auto p = providers;
int lsb_index;
while ((lsb_index = __builtin_ffs(p) - 1) != -1) {
if (provider_counts_[lsb_index] > 0) {
provider_counts_[lsb_index]--;
if (provider_counts_[lsb_index] == 0) {
disable_providers |= static_cast<unsigned int>(1) << lsb_index;
}
}
p ^= static_cast<unsigned int>(1) << lsb_index;
}
providers_ ^= disable_providers;
return providers_;
}
void TraceProviders::clearAllProviders() {
std::lock_guard<std::mutex> lock(mutex_);
provider_counts_.fill(0);
providers_ = 0;
}
void TraceProviders::initProviderNames(
std::vector<ProviderEntry>&& provider_names) {
std::unique_lock<std::shared_timed_mutex> lock(name_lookup_mutex_);
std::sort(provider_names.begin(), provider_names.end());
name_lookup_cache_ = std::move(provider_names);
}
} // namespace profilo
} // namespace facebook