-
Notifications
You must be signed in to change notification settings - Fork 243
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Summary: This is doing the benchmark test for the fib module of openr. That is, it is to evaluate route-processing-time metric that consists of following 1. Time it takes to send the routes to Fib module; 2. Processing time within module; 3. Time it takes to send routes for programming. This measurement is using the standard benchmark framework. Reviewed By: saifhhasan Differential Revision: D15761635 fbshipit-source-id: b442abf0e687a6fee6482d5954b32a418632f1e3
- Loading branch information
1 parent
0155837
commit 0018ee8
Showing
6 changed files
with
389 additions
and
62 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,227 @@ | ||
/** | ||
* Copyright (c) 2014-present, Facebook, Inc. | ||
* | ||
* This source code is licensed under the MIT license found in the | ||
* LICENSE file in the root directory of this source tree. | ||
*/ | ||
#include <benchmark/benchmark.h> | ||
#include <fbzmq/async/StopEventLoopSignalHandler.h> | ||
#include <openr/fib/Fib.h> | ||
#include <openr/fib/tests/MockNetlinkFibHandler.h> | ||
#include <openr/fib/tests/PrefixGenerator.h> | ||
#include <thrift/lib/cpp2/server/ThriftServer.h> | ||
#include <thrift/lib/cpp2/util/ScopedServerThread.h> | ||
#include <thread> | ||
|
||
namespace { | ||
// Virtual interface | ||
const std::string kVethNameY("vethTestY"); | ||
// Prefix length of a subnet | ||
static const long kBitMaskLen = 128; | ||
// Updating kDeltaSize routing entries | ||
static const uint32_t kDeltaSize = 10; | ||
// Number of nexthops | ||
const uint8_t kNumOfNexthops = 128; | ||
|
||
} // anonymous namespace | ||
|
||
namespace openr { | ||
|
||
using apache::thrift::CompactSerializer; | ||
using apache::thrift::FRAGILE; | ||
using apache::thrift::ThriftServer; | ||
using apache::thrift::util::ScopedServerThread; | ||
|
||
class FibWrapper { | ||
public: | ||
FibWrapper() { | ||
// Register Singleton | ||
folly::SingletonVault::singleton()->registrationComplete(); | ||
// Create MockNetlinkFibHandler | ||
mockFibHandler = std::make_shared<MockNetlinkFibHandler>(); | ||
|
||
// Start ThriftServer | ||
server = std::make_shared<ThriftServer>(); | ||
server->setNumIOWorkerThreads(1); | ||
server->setNumAcceptThreads(1); | ||
server->setPort(0); | ||
server->setInterface(mockFibHandler); | ||
fibThriftThread.start(server); | ||
|
||
// Create sockets | ||
decisionPub.bind(fbzmq::SocketUrl{"inproc://decision-pub"}); | ||
decisionRep.bind(fbzmq::SocketUrl{"inproc://decision-cmd"}).value(); | ||
lmPub.bind(fbzmq::SocketUrl{"inproc://lm-pub"}).value(); | ||
fibReq.connect(fbzmq::SocketUrl{"inproc://fib-cmd"}).value(); | ||
|
||
// Creat Fib module and start fib thread | ||
port = fibThriftThread.getAddress()->getPort(); | ||
fib = std::make_shared<Fib>( | ||
"node-1", | ||
port, // thrift port | ||
false, // dryrun | ||
true, // periodic syncFib | ||
false, // segment route | ||
false, // orderedFib | ||
std::chrono::seconds(2), | ||
DecisionPubUrl{"inproc://decision-pub"}, | ||
std::string{"inproc://fib-cmd"}, | ||
LinkMonitorGlobalPubUrl{"inproc://lm-pub"}, | ||
MonitorSubmitUrl{"inproc://monitor-sub"}, | ||
KvStoreLocalCmdUrl{"inproc://kvstore-cmd"}, | ||
KvStoreLocalPubUrl{"inproc://kvstore-sub"}, | ||
context); | ||
|
||
fibThread = std::make_unique<std::thread>([this]() { | ||
LOG(INFO) << "Fib thread starting"; | ||
fib->run(); | ||
LOG(INFO) << "Fib thread finishing"; | ||
}); | ||
fib->waitUntilRunning(); | ||
} | ||
|
||
~FibWrapper() { | ||
// This will be invoked before Fib's d-tor | ||
fib->stop(); | ||
fibThread->join(); | ||
|
||
// Close socket | ||
decisionPub.close(); | ||
decisionRep.close(); | ||
lmPub.close(); | ||
|
||
// Stop mocked nl platform | ||
mockFibHandler->stop(); | ||
fibThriftThread.stop(); | ||
} | ||
|
||
thrift::PerfDatabase | ||
getPerfDb() { | ||
// Send a fib request to get perfDB | ||
fibReq.sendThriftObj( | ||
thrift::FibRequest(FRAGILE, thrift::FibCommand::PERF_DB_GET), | ||
serializer); | ||
|
||
// Receive reply | ||
auto maybeReply = fibReq.recvThriftObj<thrift::PerfDatabase>(serializer); | ||
if (maybeReply.hasError()) { | ||
LOG(ERROR) << "Error::maybeReply.hasError()"; | ||
} | ||
const auto& perfDb = maybeReply.value(); | ||
return perfDb; | ||
} | ||
|
||
void | ||
accumulatePerfTimes(std::vector<uint64_t>& processTimes) { | ||
// Get perfDB | ||
auto perfDB = getPerfDb(); | ||
// If get empty perfDB, just log it | ||
if (perfDB.eventInfo.size() == 0 or | ||
perfDB.eventInfo[0].events.size() == 0) { | ||
LOG(INFO) << "perfDB is emtpy."; | ||
} else { | ||
// Accumulate time into processTimes | ||
// Each time get the latest perf event. | ||
auto perfDBInfoSize = perfDB.eventInfo.size(); | ||
auto eventInfo = perfDB.eventInfo[perfDBInfoSize - 1]; | ||
for (auto index = 1; index < eventInfo.events.size(); index++) { | ||
processTimes[index - 1] += | ||
(eventInfo.events[index].unixTs - | ||
eventInfo.events[index - 1].unixTs); | ||
} | ||
} | ||
} | ||
|
||
int port{0}; | ||
std::shared_ptr<ThriftServer> server; | ||
ScopedServerThread fibThriftThread; | ||
|
||
fbzmq::Context context{}; | ||
fbzmq::Socket<ZMQ_PUB, fbzmq::ZMQ_SERVER> decisionPub{context}; | ||
fbzmq::Socket<ZMQ_REP, fbzmq::ZMQ_SERVER> decisionRep{context}; | ||
fbzmq::Socket<ZMQ_PUB, fbzmq::ZMQ_SERVER> lmPub{context}; | ||
fbzmq::Socket<ZMQ_REQ, fbzmq::ZMQ_CLIENT> fibReq{context}; | ||
|
||
// Create the serializer for write/read | ||
apache::thrift::CompactSerializer serializer; | ||
|
||
std::shared_ptr<Fib> fib; | ||
std::unique_ptr<std::thread> fibThread; | ||
|
||
std::shared_ptr<MockNetlinkFibHandler> mockFibHandler; | ||
PrefixGenerator prefixGenerator; | ||
}; | ||
|
||
static void | ||
getProcessTimeBM(benchmark::State& state) { | ||
// Fib starts with clean route database | ||
auto fibWrapper = std::make_unique<FibWrapper>(); | ||
|
||
// Initial syncFib debounce | ||
fibWrapper->mockFibHandler->waitForSyncFib(); | ||
|
||
// Mimic decision pub sock publishing RouteDatabase | ||
const uint32_t numOfPrefixes = state.range(0); | ||
// Generate random prefixes | ||
auto prefixes = fibWrapper->prefixGenerator.ipv6PrefixGenerator( | ||
numOfPrefixes, kBitMaskLen); | ||
thrift::RouteDatabase routeDb; | ||
routeDb.thisNodeName = "node-1"; | ||
for (auto& prefix : prefixes) { | ||
routeDb.unicastRoutes.emplace_back(createUnicastRoute( | ||
prefix, | ||
fibWrapper->prefixGenerator.getRandomNextHopsUnicast( | ||
kNumOfNexthops, kVethNameY))); | ||
} | ||
// Send routeDB to Fib and wait for updating completing | ||
fibWrapper->decisionPub.sendThriftObj(routeDb, fibWrapper->serializer); | ||
fibWrapper->mockFibHandler->waitForUpdateUnicastRoutes(); | ||
|
||
// Customized time counter | ||
// processTimes[0] is the time of sending routDB to Fib | ||
// processTimes[1] is the time of processing within Fib | ||
// processTimes[2] is the time of synchonizing routs with Fib agent server | ||
std::vector<uint64_t> processTimes{0, 0, 0}; | ||
// Maek sure deltaSize <= numOfPrefixes | ||
auto deltaSize = kDeltaSize <= numOfPrefixes ? kDeltaSize : numOfPrefixes; | ||
|
||
for (auto _ : state) { | ||
// Update routes by randomly regenerating nextHops for deltaSize prefixes. | ||
for (auto index = 0; index < deltaSize; index++) { | ||
routeDb.unicastRoutes.emplace_back(createUnicastRoute( | ||
prefixes[index], | ||
fibWrapper->prefixGenerator.getRandomNextHopsUnicast( | ||
kNumOfNexthops, kVethNameY))); | ||
} | ||
// Add perfevents | ||
thrift::PerfEvents perfEvents; | ||
addPerfEvent(perfEvents, routeDb.thisNodeName, "FIB_INIT_UPDATE"); | ||
routeDb.perfEvents = perfEvents; | ||
|
||
// Send routeDB to Fib for updates | ||
fibWrapper->decisionPub.sendThriftObj(routeDb, fibWrapper->serializer); | ||
fibWrapper->mockFibHandler->waitForUpdateUnicastRoutes(); | ||
|
||
// Get time information from perf event | ||
fibWrapper->accumulatePerfTimes(processTimes); | ||
} | ||
|
||
// Get average time for each itaration | ||
// To avoid 'division by 0', add 1 to state.iterations() | ||
for (auto& processTime : processTimes) { | ||
processTime /= (state.iterations() + 1); | ||
} | ||
|
||
// Get items/s | ||
state.SetItemsProcessed(state.iterations()); | ||
|
||
// Add customized counters to state. | ||
state.counters.insert({{"SendTime", processTimes[0]}, | ||
{"ProcessTime", processTimes[1]}, | ||
{"ProgramTime (ms)", processTimes[2]}}); | ||
} | ||
|
||
BENCHMARK(getProcessTimeBM)->RangeMultiplier(10)->Range(10, 10000); | ||
} // namespace openr | ||
|
||
BENCHMARK_MAIN(); |
Oops, something went wrong.