-
-
Notifications
You must be signed in to change notification settings - Fork 8
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* add a benchmark for files with lots of symbols * add a plotnine visualization
- Loading branch information
Showing
2 changed files
with
115 additions
and
0 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,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]) |
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,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 | ||
) | ||
) | ||
) |