Skip to content

Commit

Permalink
add benchmarks
Browse files Browse the repository at this point in the history
* add a benchmark for files with lots of symbols
* add a plotnine visualization
  • Loading branch information
fzakaria committed Oct 2, 2023
1 parent 2947a0d commit 358dc4b
Show file tree
Hide file tree
Showing 2 changed files with 115 additions and 0 deletions.
49 changes: 49 additions & 0 deletions benchmarks/graph_symbol_size_benchmark.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
#! /usr/bin/env python3

from plotnine import *
import pandas as pd
import numpy as np

# Raw data
data = {
"Number of Functions": [10**exponent for exponent in range(1, 6)],
"readelf": [
0.005350531006115489,
0.005340991003322415,
0.005842811006004922,
0.01410250501066912,
0.09029568900587037,
],
"sqlelf": [
0.02874817499832716,
0.07305189099861309,
0.53968190800515,
5.312782863009488,
51.02671549099614,
],
}

# Create the pandas DataFrame
df = pd.DataFrame(data=data)

# Melt the data
df_melted = pd.melt(
df,
id_vars=["Number of Functions"],
value_vars=["readelf", "sqlelf"],
var_name="Category",
value_name="Value",
)

plot = (
ggplot(
df_melted, aes(x="Number of Functions", y="Value", color="Category")
) # Define data and aesthetics
+ geom_line() # Add line geometry
+ theme_classic() # Minimal theme
+ labs(title="", x="Number of Functions", y="Time (s)", color="")
+ scale_x_continuous(trans="log10")
+ scale_y_log10(expand=(0, 0, 0, 1))
)

save_as_pdf_pages([plot])
66 changes: 66 additions & 0 deletions benchmarks/symbol_size_benchmark.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
#! /usr/bin/env python3
"""A benchmark to measure the time it takes to load a binary with a given number of functions."""
import timeit
import tempfile
import subprocess
from pathlib import Path
from sqlelf import sql, elf
import time


def create_executable_file(file_name: str, num_functions: int) -> str:
"""Create an ELF executable file with a given number of functions"""
functions = ""
for i in range(num_functions):
functions += f"""void function_{i}() {{ printf("Hello World {i}"); }}\n"""
content = f"""
#include <stdio.h>
{functions}
int main() {{ printf("Hello World!"); return 0; }}
"""
file.write(content)
file.flush()

binary_name = tempfile.NamedTemporaryFile().name
subprocess.run(["gcc", "-x", "c++", "-o", binary_name, file.name])
return binary_name


def readelf_benchmark(binary_name: str, num_functions: int) -> None:
result = subprocess.run(
f"readelf -s {binary_name} | wc -l",
capture_output=True,
text=True,
shell=True,
)
assert int(result.stdout) >= num_functions


def sqlelf_benchmark(binary_name: str, num_functions: int) -> None:
sql_engine = sql.make_sql_engine([binary_name], cache_flags=elf.CacheFlag.SYMBOLS)
result = list(sql_engine.execute("SELECT COUNT(*) as 'count' FROM ELF_SYMBOLS"))
count = result[0]["count"]
assert count >= num_functions


for exponent in range(1, 6):
num_functions = 10**exponent
print(f"Number of functions: {num_functions}")
# create the executable
with tempfile.NamedTemporaryFile(mode="w") as file:
file_name = file.name
binary_file = create_executable_file(file_name, num_functions)
print(
"readelf benchmark: {}".format(
timeit.timeit(
lambda: readelf_benchmark(binary_file, num_functions), number=1
)
)
)
print(
"sqlelf benchmark: {}".format(
timeit.timeit(
lambda: sqlelf_benchmark(binary_file, num_functions), number=1
)
)
)

0 comments on commit 358dc4b

Please sign in to comment.