blob: eb335785d5813845d2840ba207186caab10d1644 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 <benchmark/benchmark.h>
#include "celix/FrameworkFactory.h"
//note using c++ service for both the C and C++ benchmark, because this should not impact the performance.
class IService {
public:
static constexpr const char * const NAME = "IService";
virtual ~IService() noexcept = default;
};
class ServiceImpl : public IService {
public:
~ServiceImpl() noexcept override = default;
};
/**
* Benchmark to measure to lookup/track services in Celix framework already containing more
* or less registered services.
*/
class LookupServicesBenchmark {
public:
explicit LookupServicesBenchmark(int64_t _nrOfServiceRegistrations) : nrOfServiceRegistrations{_nrOfServiceRegistrations}, fw{createFw()} {
auto ctx = fw->getFrameworkBundleContext();
for (int i = 0; i < nrOfServiceRegistrations; ++i) {
auto reg = ctx->registerService<IService>(std::make_shared<ServiceImpl>(), IService::NAME)
.addProperty("key", std::string{"value"} + std::to_string(i))
.build();
registrations.emplace_back(std::move(reg));
}
ctx->waitForEvents();
}
static std::shared_ptr<celix::Framework> createFw() {
celix::Properties config{};
config.set(celix::FRAMEWORK_STATIC_EVENT_QUEUE_SIZE, 1024*10);
config.set("CELIX_LOGGING_DEFAULT_ACTIVE_LOG_LEVEL", "error");
return celix::createFramework(config);
}
const int64_t nrOfServiceRegistrations;
const std::shared_ptr<celix::Framework> fw;
std::vector<std::shared_ptr<celix::ServiceRegistration>> registrations{};
};
static void findSingleService(benchmark::State& state, bool cTest, bool useFilter) {
LookupServicesBenchmark benchmark{state.range(0)};
auto ctx = benchmark.fw->getFrameworkBundleContext();
auto* cCtx = ctx->getCBundleContext();
auto index = benchmark.nrOfServiceRegistrations / 2;
auto filter = std::string{"(key=value"} + std::to_string(index) + ")";
if (cTest) {
if (useFilter) {
celix_service_filter_options_t opts{};
opts.serviceName = IService::NAME;
opts.filter = filter.c_str();
for (auto _ : state) {
// This code gets timed
long svcId = celix_bundleContext_findServiceWithOptions(cCtx, &opts);
if (svcId < 0) {
state.SkipWithError("invalid svc id");
}
}
} else {
for (auto _ : state) {
// This code gets timed
long svcId = celix_bundleContext_findService(cCtx, IService::NAME);
if (svcId < 0) {
state.SkipWithError("invalid svc id");
}
}
}
} else {
if (useFilter) {
for (auto _ : state) {
// This code gets timed
long svcId = ctx->findServiceWithName(IService::NAME, filter);
if (svcId < 0) {
state.SkipWithError("invalid svc id");
}
}
} else {
for (auto _ : state) {
// This code gets timed
long svcId = ctx->findServiceWithName(IService::NAME);
if (svcId < 0) {
state.SkipWithError("invalid svc id");
}
}
}
}
state.SetItemsProcessed(state.iterations());
}
static void createDestroyServiceTracker(benchmark::State& state, bool cTest) {
LookupServicesBenchmark benchmark{state.range(0)};
auto ctx = benchmark.fw->getFrameworkBundleContext();
auto* cCtx = ctx->getCBundleContext();
if (cTest) {
celix_service_tracking_options_t opts{};
opts.filter.serviceName = IService::NAME;
for (auto _ : state) {
// This code gets timed
long trkId = celix_bundleContext_trackServicesWithOptions(cCtx, &opts);
celix_bundleContext_stopTracker(cCtx, trkId);
}
} else {
for (auto _ : state) {
// This code gets timed
auto trk = ctx->trackServices<IService>(IService::NAME).build();
trk->wait();
trk->close();
trk->wait();
}
}
state.SetItemsProcessed(state.iterations());
}
static void LookupServicesBenchmark_cFindSingleService(benchmark::State& state) {
findSingleService(state, true, false);
}
static void LookupServicesBenchmark_cxxFindSingleService(benchmark::State& state) {
findSingleService(state, false, false);
}
static void LookupServicesBenchmark_cFindServiceWithFilter(benchmark::State& state) {
findSingleService(state, true, true);
}
static void LookupServicesBenchmark_cxxFindServiceWithFilter(benchmark::State& state) {
findSingleService(state, false, true);
}
static void LookupServicesBenchmark_cCreateDestroyTracker(benchmark::State& state) {
createDestroyServiceTracker(state, true);
}
static void LookupServicesBenchmark_cxxCreateDestroyTracker(benchmark::State& state) {
createDestroyServiceTracker(state, false);
}
#define CELIX_BENCHMARK(name) \
BENCHMARK(name)->MeasureProcessCPUTime()->UseRealTime()->Unit(benchmark::kMillisecond)
CELIX_BENCHMARK(LookupServicesBenchmark_cFindSingleService)->RangeMultiplier(10)->Range(1, 10000);
CELIX_BENCHMARK(LookupServicesBenchmark_cxxFindSingleService)->RangeMultiplier(10)->Range(1, 10000);
CELIX_BENCHMARK(LookupServicesBenchmark_cFindServiceWithFilter)->RangeMultiplier(10)->Range(1, 10000);
CELIX_BENCHMARK(LookupServicesBenchmark_cxxFindServiceWithFilter)->RangeMultiplier(10)->Range(1, 10000);
CELIX_BENCHMARK(LookupServicesBenchmark_cCreateDestroyTracker)->RangeMultiplier(10)->Range(1, 1000);
CELIX_BENCHMARK(LookupServicesBenchmark_cxxCreateDestroyTracker)->RangeMultiplier(10)->Range(1, 1000);