Skip to content

Commit

Permalink
Add a benchmark which uses Google benchmark library (#1392)
Browse files Browse the repository at this point in the history
* Add attestation steps for packaging

* tab to spaces

* update permissions

* Update README for verify procedure

* fix

* version to commit hash

* Use google benchmark

* add stats

* update comment

* change default opt

* add workflow

* test package install

* forgot to build :)

* fix path

* fix path

* fix path again

* pre-commit fixes

* Fix cmake format + disable pull requests

* disable verbose

* add dev for testing

* add ignore files

* upload as artifact for test

* upload results as artifact to generate charts manually

* change action version format

* update

* remove ubuntu 18.04

* move permissions

* should be package dir

* remove wildcard

* bump version str

* fix format issues

* move benchmark

* compile success

* minor fixes

* remove unnecessary changes

* not related

* test benchmark workflow is buildable

* Add PRs temporarily

* fix errors

* fix

* no need matrix

* use bencher

* remove bencher

* minor update

* Add write and crafting benchmarks

* update function names

* add info to benchmarks

* update path

* update python

* format fix

* fix typos

* simplify

* use pps

* use FetchContent to get benchmark

* Rename benchmark in example because same name with lib

* format cmake

* simplify parsedPacket process

* move benchmarks to examples

* set cross-compiling

* Revert "set cross-compiling"

This reverts commit 66b3e14.

* change readme and enable benchmark for only linux

* revert unnecessary change

* improve readme

* fix for comments

* table header

* pre-commit fix

* remove PCAPPP_USE_GOOGLEBENCHMARK

* test cross-compile macos

* use additional flag for macos13

* add same flag to tutorial build

* disable google bench lib install

* add comment to cmake

* test macos from CI

* auto detect C++14

* remove additional flags

* fetchcontent_makeavailable requires 3.14

* fix macos arch difference

* add warning message for C++14

* fix logic

---------

Co-authored-by: seladb <[email protected]>
  • Loading branch information
egecetin and seladb authored Nov 14, 2024
1 parent 573effc commit 3929558
Show file tree
Hide file tree
Showing 5 changed files with 294 additions and 8 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
*.pcapng.zst
*.pcapng.zstd
*.cap
*.snoop

#Bin and Obj directories
**/Bin
Expand Down
2 changes: 1 addition & 1 deletion Examples/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
cmake_minimum_required(VERSION 3.12)
cmake_minimum_required(VERSION 3.14)

project(PcapPlusPlusExamples)

Expand Down
46 changes: 42 additions & 4 deletions Examples/PcapPlusPlus-benchmark/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,12 +1,50 @@
add_executable(benchmark benchmark.cpp)
add_executable(BenchmarkExample benchmark.cpp)

target_link_libraries(benchmark PUBLIC PcapPlusPlus::Pcap++)
target_link_libraries(BenchmarkExample PUBLIC PcapPlusPlus::Pcap++)

set_target_properties(BenchmarkExample PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${PCAPPP_BINARY_EXAMPLES_DIR}")

if("cxx_std_14" IN_LIST CMAKE_CXX_COMPILE_FEATURES)
if(
(CMAKE_HOST_SYSTEM_PROCESSOR STREQUAL CMAKE_SYSTEM_PROCESSOR)
AND (NOT CMAKE_OSX_ARCHITECTURES OR (CMAKE_HOST_SYSTEM_PROCESSOR STREQUAL CMAKE_OSX_ARCHITECTURES))
)
include(FetchContent)

# Fetch Google Benchmark
fetchcontent_declare(
benchmark
GIT_REPOSITORY https://github.com/google/benchmark.git
GIT_TAG v1.9.0)

# Disable testing and installation for Google Benchmark
set(BENCHMARK_ENABLE_TESTING OFF)
set(BENCHMARK_ENABLE_INSTALL OFF)
fetchcontent_makeavailable(benchmark)

add_executable(BenchmarkExampleGoogle benchmark-google.cpp)

target_link_libraries(BenchmarkExampleGoogle PUBLIC PcapPlusPlus::Pcap++ benchmark::benchmark)

set_target_properties(BenchmarkExampleGoogle PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${PCAPPP_BINARY_EXAMPLES_DIR}")
else()
message(WARNING "Google Benchmark backend is not supported for cross-compilation")
endif()
else()
message(WARNING "Google Benchmark backend requires C++14 support")
endif()

set_target_properties(benchmark PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${PCAPPP_BINARY_EXAMPLES_DIR}")

if(PCAPPP_INSTALL)
install(
TARGETS benchmark
TARGETS BenchmarkExample
EXPORT PcapPlusPlusTargets
RUNTIME DESTINATION ${PCAPPP_INSTALL_BINDIR})

if(TARGET BenchmarkExampleGoogle)
install(
TARGETS BenchmarkExampleGoogle
EXPORT PcapPlusPlusTargets
RUNTIME DESTINATION ${PCAPPP_INSTALL_BINDIR})
endif()
endif()
17 changes: 14 additions & 3 deletions Examples/PcapPlusPlus-benchmark/README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,19 @@
PcapPlusPlus Benchmark
======================

This is a benchmark application used for measuring PcapPlusPlus performance. It is based on Matias Fontanini's packet-capture-benchmarks project (https://github.com/mfontanini/packet-capture-benchmarks).
This folder contains benchmark applications for measuring the performance of PcapPlusPlus. Currently, there are two benchmark applications.

See this page for more details: https://pcapplusplus.github.io/docs/benchmark
## Compare with other libraries

This application currently compiles on Linux only (where benchmark was running on)
A benchmark application used for measuring PcapPlusPlus performance can be found in `benchmark.cpp`. It is based on Matias Fontanini's packet-capture-benchmarks project (https://github.com/mfontanini/packet-capture-benchmarks) and allows us to compare PcapPlusPlus with other packet libraries. See this page for more details and result comparisons: https://pcapplusplus.github.io/docs/benchmark

## Directly benchmark PcapPlusPlus

Another application integrates with the Google Benchmark library and can be found in `benchmark-google.cpp`. This application currently consists of four different benchmarks, and each benchmark can be influenced by various factors. These benchmarks aim to utilize different influence factors to provide accurate results for different scenarios. You can check the table below for more information. For performance-critical applications using PcapPlusPlus, it is recommended to run benchmarks in your specific environment for more accurate results. Using larger pcap files and those with diverse protocols and sessions can provide better insights into PcapPlusPlus performance in your setup.

| Benchmark | Operation | Influencing factors |
|:-----------------:|:-------------:|:--------------------:|
| BM_PcapFileRead | Read | CPU + Disk (Read) |
| BM_PcapFileWrite | Write | CPU + Disk (Write) |
| BM_PacketParsing | Read + Parse | CPU + Disk (Read) |
| BM_PacketCrafting | Craft | CPU |
236 changes: 236 additions & 0 deletions Examples/PcapPlusPlus-benchmark/benchmark-google.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,236 @@
#include <Packet.h>
#include <PcapFileDevice.h>
#include <PcapPlusPlusVersion.h>

#include <EthLayer.h>
#include <IPv4Layer.h>
#include <IPv6Layer.h>
#include <TcpLayer.h>
#include <UdpLayer.h>

#include <benchmark/benchmark.h>

#include <iostream>

static std::string pcapFileName = "";

static void BM_PcapFileRead(benchmark::State& state)
{
// Open the pcap file for reading
pcpp::PcapFileReaderDevice reader(pcapFileName);
if (!reader.open())
{
state.SkipWithError("Cannot open pcap file for reading");
return;
}

size_t totalBytes = 0;
size_t totalPackets = 0;
pcpp::RawPacket rawPacket;
for (auto _ : state)
{
if (!reader.getNextPacket(rawPacket))
{
// If the rawPacket is empty there should be an error
if (totalBytes == 0)
{
state.SkipWithError("Cannot read packet");
return;
}

// Rewind the file if it reached the end
state.PauseTiming();
reader.close();
reader.open();
state.ResumeTiming();
continue;
}

++totalPackets;
totalBytes += rawPacket.getRawDataLen();
}

state.SetBytesProcessed(totalBytes);
state.SetItemsProcessed(totalPackets);
}
BENCHMARK(BM_PcapFileRead);

static void BM_PcapFileWrite(benchmark::State& state)
{
// Open the pcap file for writing
pcpp::PcapFileWriterDevice writer("benchmark-output.pcap");
if (!writer.open())
{
state.SkipWithError("Cannot open pcap file for writing");
return;
}

pcpp::Packet packet;
pcpp::EthLayer ethLayer(pcpp::MacAddress("00:00:00:00:00:00"), pcpp::MacAddress("00:00:00:00:00:00"));
pcpp::IPv4Layer ip4Layer(pcpp::IPv4Address("192.168.0.1"), pcpp::IPv4Address("192.168.0.2"));
pcpp::TcpLayer tcpLayer(12345, 80);

packet.addLayer(&ethLayer);
packet.addLayer(&ip4Layer);
packet.addLayer(&tcpLayer);
packet.computeCalculateFields();

size_t totalBytes = 0;
size_t totalPackets = 0;
for (auto _ : state)
{
// Write packet to file
writer.writePacket(*(packet.getRawPacket()));

// Count total bytes and packets
++totalPackets;
totalBytes += packet.getRawPacket()->getRawDataLen();
}

// Set statistics to the benchmark state
state.SetBytesProcessed(totalBytes);
state.SetItemsProcessed(totalPackets);
}
BENCHMARK(BM_PcapFileWrite);

static void BM_PacketParsing(benchmark::State& state)
{
// Open the pcap file for reading
size_t totalBytes = 0;
size_t totalPackets = 0;
pcpp::PcapFileReaderDevice reader(pcapFileName);
if (!reader.open())
{
state.SkipWithError("Cannot open pcap file for reading");
return;
}

pcpp::RawPacket rawPacket;
for (auto _ : state)
{
if (!reader.getNextPacket(rawPacket))
{
// If the rawPacket is empty there should be an error
if (totalBytes == 0)
{
state.SkipWithError("Cannot read packet");
return;
}

// Rewind the file if it reached the end
state.PauseTiming();
reader.close();
reader.open();
state.ResumeTiming();
continue;
}

// Parse packet
pcpp::Packet parsedPacket(&rawPacket);

// Use parsedPacket to prevent compiler optimizations
assert(parsedPacket.getFirstLayer());

// Count total bytes and packets
++totalPackets;
totalBytes += rawPacket.getRawDataLen();
}

// Set statistics to the benchmark state
state.SetBytesProcessed(totalBytes);
state.SetItemsProcessed(totalPackets);
}
BENCHMARK(BM_PacketParsing);

static void BM_PacketCrafting(benchmark::State& state)
{
size_t totalBytes = 0;
size_t totalPackets = 0;

for (auto _ : state)
{
uint8_t randNum = static_cast<uint8_t>(rand() % 256);

pcpp::Packet packet;

// Generate random MAC addresses
pcpp::MacAddress srcMac(randNum, randNum, randNum, randNum, randNum, randNum);
pcpp::MacAddress dstMac(randNum, randNum, randNum, randNum, randNum, randNum);
packet.addLayer(new pcpp::EthLayer(srcMac, dstMac), true);

// Randomly choose between IPv4 and IPv6
if (randNum % 2)
{
packet.addLayer(new pcpp::IPv4Layer(randNum, randNum), true);
}
else
{
std::array<uint8_t, 16> srcIP = { randNum, randNum, randNum, randNum, randNum, randNum, randNum, randNum,
randNum, randNum, randNum, randNum, randNum, randNum, randNum, randNum };
std::array<uint8_t, 16> dstIP = { randNum, randNum, randNum, randNum, randNum, randNum, randNum, randNum,
randNum, randNum, randNum, randNum, randNum, randNum, randNum, randNum };

packet.addLayer(new pcpp::IPv6Layer(srcIP, dstIP), true);
}

// Randomly choose between TCP and UDP
if (randNum % 2)
{
packet.addLayer(new pcpp::TcpLayer(randNum % 65536, randNum % 65536), true);
}
else
{
packet.addLayer(new pcpp::UdpLayer(randNum % 65536, randNum % 65536), true);
}

// Calculate all fields to update the packet
packet.computeCalculateFields();

// Count total bytes and packets
++totalPackets;
totalBytes += packet.getRawPacket()->getRawDataLen();
}

// Set statistics to the benchmark state
state.SetBytesProcessed(totalBytes);
state.SetItemsProcessed(totalPackets);
}
BENCHMARK(BM_PacketCrafting);

int main(int argc, char** argv)
{
// Initialize the benchmark
benchmark::Initialize(&argc, argv);

// Parse command line arguments to find the pcap file name
for (int idx = 1; idx < argc; ++idx)
{
if (strcmp(argv[idx], "--pcap-file") == 0)
{
if (idx == argc - 1)
{
std::cerr << "Please provide a pcap file name after --pcap-file" << std::endl;
return 1;
}

pcapFileName = argv[idx + 1];
break;
}
}

if (pcapFileName.empty())
{
std::cerr << "Please provide a pcap file name using --pcap-file" << std::endl;
return 1;
}

benchmark::AddCustomContext("PcapPlusPlus version", pcpp::getPcapPlusPlusVersionFull());
benchmark::AddCustomContext("Build info", pcpp::getBuildDateTime());
benchmark::AddCustomContext("Git info", pcpp::getGitInfo());
benchmark::AddCustomContext("Pcap file", pcapFileName);

// Run the benchmarks
benchmark::RunSpecifiedBenchmarks();

return 0;
}

0 comments on commit 3929558

Please sign in to comment.