Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -60,3 +60,5 @@ frameworks/pinpoint-java/pinpoint/pinpoint-web-starter-*.jar
frameworks/pinpoint-java/pinpoint/pinpoint-agent-*
frameworks/pinpoint-java/pinpoint/pinpoint.tar.gz
frameworks/pinpoint-java/scripts/*.json
zipkin.jar
zipkin.jar
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't duplicate

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is still present

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have removed the duplicate.

10 changes: 10 additions & 0 deletions frameworks/OpenTelemetry-python/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
venv/
__pycache__/
kieker-lang-pack-python/
results/
config.ini
*.log
*.bak
*.zip
results-OpenTelemetry-python/
.DS_Store
37 changes: 37 additions & 0 deletions frameworks/OpenTelemetry-python/benchmark.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
DIR=$(cd "$(dirname "$0")" && pwd)
source "$DIR/config.rc"

source "$DIR/functions.sh"
source "$DIR/../../common-functions.sh"

echo " # Preparing Environment..."
if [ -d "$VENV_DIR" ]; then rm -rf "$VENV_DIR"; fi

# For windows compatibility
if command -v python3 &>/dev/null; then
PYTHON_EXE=python3
else
PYTHON_EXE=python
fi

$PYTHON_EXE -m venv "$VENV_DIR"
source "$VENV_DIR/bin/activate"

pip install -q --upgrade pip
pip install -q -r "$REQUIREMENTS_FILE"
opentelemetry-bootstrap -a install

cp "$CONFIG_TEMPLATE" "$CONFIG_FILE"

export NUM_OF_LOOPS=${NUM_OF_LOOPS:-10}
export TOTAL_NUM_OF_CALLS=${TOTAL_NUM_OF_CALLS:-2000000}
export RECURSION_DEPTH=${RECURSION_DEPTH:-10}
export METHOD_TIME=${METHOD_TIME:-0}
export SLEEP_TIME=${SLEEP_TIME:-15}

echo " # Starting Benchmark with $NUM_OF_LOOPS loops"
executeAllLoops

deactivate
rm "$CONFIG_FILE" 2>/dev/null
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Put this in .gitignore, do not delete the config file (except there is a specific reason)

echo " # Completed."
10 changes: 10 additions & 0 deletions frameworks/OpenTelemetry-python/config.ini.template
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
[Benchmark]
total_calls = 2000000
recursion_depth = 10
method_time = 0
config_path = /tmp/monitoring.ini
inactive = False
# so it doesn't use kieker instrumentation
instrumentation_on = False
approach = 1
output_filename = results.csv
37 changes: 37 additions & 0 deletions frameworks/OpenTelemetry-python/config.rc
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# OpenTelemetry-python configuration

#resolve paths for windows
RAW_BASE_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)

# Check if we are running in Git Bash on Windows
if command -v cygpath &>/dev/null; then
BASE_DIR=$(cygpath -w "$RAW_BASE_DIR")
RAW_MAIN_DIR="$RAW_BASE_DIR/../../"
MAIN_DIR=$(cygpath -w "$RAW_MAIN_DIR")
PYTHON_BIN="python"
else
# Linux/Mac
BASE_DIR="$RAW_BASE_DIR"
MAIN_DIR="$RAW_BASE_DIR/../../"
PYTHON_BIN="python3"
fi

if [ -f "${MAIN_DIR}/config.rc" ]; then
source "${MAIN_DIR}/config.rc"
fi

export VENV_DIR="$BASE_DIR/venv"
export REQUIREMENTS_FILE="$BASE_DIR/requirements.txt"
export CONFIG_TEMPLATE="$BASE_DIR/config.ini.template"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please try whether this can be removed as well.

export CONFIG_FILE="$BASE_DIR/config.ini"

export RESULTS_DIR="$BASE_DIR/results-OpenTelemetry-python"
export RAWFN="$RESULTS_DIR/raw"

KIEKER_REPO_URL="https://github.com/kieker-monitoring/kieker-lang-pack-python.git"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This shouldn't be necessary for Otel Python

KIEKER_DIR="$BASE_DIR/kieker-lang-pack-python"

export PYTHON_SCRIPT="$MAIN_DIR/tools/pybenchmark/benchmark.py"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you name this MOOBENCH_BIN_PY (like in config.rc of Kieker-python)?

export ZIPKIN_BIN="$BASE_DIR/zipkin.jar"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This line can probably just be removed if you use startZipkin and stopBackgroundProcess.


mkdir -p "$RAW_BASE_DIR/results-OpenTelemetry-python"
90 changes: 90 additions & 0 deletions frameworks/OpenTelemetry-python/functions.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
MOOBENCH_CONFIGURATIONS="0 1 2"
TITLE[0]="No Instrumentation"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you move these into label.sh?

TITLE[1]="OpenTelemetry No Export"
TITLE[2]="OpenTelemetry Zipkin"

export RECURSION_DEPTH="${RECURSION_DEPTH:-10}"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't duplicate this - it should be defined from benchmark.sh already

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have removed the duplicate.


# helper to inject filename
function updateConfigFilename {
local filename=$1
grep -v "output_filename" "$CONFIG_TEMPLATE" > "$CONFIG_FILE"
echo "output_filename = $filename" >> "$CONFIG_FILE"
}

function get_os_path {
local raw_path=$1
if command -v cygpath &>/dev/null; then cygpath -w "$raw_path"; else echo "$raw_path"; fi
}

function runNoInstrumentation {
local k=$1
local i=$2

# use the global RESULTS_DIR directly (Fixes the /output read-only error)
local RAW_CSV="${RAWFN}-${i}-${RECURSION_DEPTH}-${k}.csv"
local CSV_FILE=$(get_os_path "$RAW_CSV")
local LOG_FILE="${RESULTS_DIR}/output-raw-${i}-${RECURSION_DEPTH}-${k}.txt"

echo " # Running Config $k: ${TITLE[$k]} (Iter $i)"

updateConfigFilename "$CSV_FILE"
export ENABLE_OTEL="false"

python3 "$PYTHON_SCRIPT" "$CONFIG_FILE" > "$LOG_FILE" 2>&1
}

function runOpenTelemetryNoExport {
local k=$1
local i=$2

local RAW_CSV="${RAWFN}-${i}-${RECURSION_DEPTH}-${k}.csv"
local CSV_FILE=$(get_os_path "$RAW_CSV")
local LOG_FILE="${RESULTS_DIR}/output-raw-${i}-${RECURSION_DEPTH}-${k}.txt"

echo " # Running Config $k: ${TITLE[$k]} (Iter $i)"
updateConfigFilename "$CSV_FILE"

export ENABLE_OTEL="true"
export OTEL_TRACES_EXPORTER="none"
export OTEL_METRICS_EXPORTER="none"
export OTEL_LOGS_EXPORTER="none"

python3 "$PYTHON_SCRIPT" "$CONFIG_FILE" > "$LOG_FILE" 2>&1
}

function runOpenTelemetryZipkin {
local k=$1
local i=$2

local RAW_CSV="${RAWFN}-${i}-${RECURSION_DEPTH}-${k}.csv"
local CSV_FILE=$(get_os_path "$RAW_CSV")
local LOG_FILE="${RESULTS_DIR}/output-raw-${i}-${RECURSION_DEPTH}-${k}.txt"

startZipkin
echo " # Running Config $k: ${TITLE[$k]} (Iter $i)"
updateConfigFilename "$CSV_FILE"

export ENABLE_OTEL="true"
export OTEL_SERVICE_NAME="moobench-python"
export OTEL_TRACES_EXPORTER="zipkin"
export OTEL_EXPORTER_ZIPKIN_ENDPOINT="http://localhost:9411/api/v2/spans"
export OTEL_METRICS_EXPORTER="none"
export OTEL_LOGS_EXPORTER="none"

python3 "$PYTHON_SCRIPT" "$CONFIG_FILE" > "$LOG_FILE" 2>&1

stopBackgroundProcess
}

function executeBenchmark {
for index in $MOOBENCH_CONFIGURATIONS
do
case $index in
0) runNoInstrumentation 0 $i ;;
1) runOpenTelemetryNoExport 1 $i ;;
2) runOpenTelemetryZipkin 2 $i ;;
esac
sleep 1
done
}
4 changes: 4 additions & 0 deletions frameworks/OpenTelemetry-python/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
opentelemetry-distro
opentelemetry-exporter-zipkin
opentelemetry-sdk
opentelemetry-api
140 changes: 85 additions & 55 deletions tools/pybenchmark/benchmark.py
Original file line number Diff line number Diff line change
@@ -1,83 +1,113 @@
# -*- coding: utf-8 -*-
# standard import
import sys
import time
import configparser
import re
# instrumentation
import os

try:
from opentelemetry import trace
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import BatchSpanProcessor
from opentelemetry.exporter.zipkin.json import ZipkinExporter
from opentelemetry.sdk.resources import Resource
from opentelemetry.semconv.resource import ResourceAttributes
OTEL_AVAILABLE = True
except ImportError:
OTEL_AVAILABLE = False

try:
from monitoring.controller import SingleMonitoringController
from tools.importhookast import InstrumentOnImportFinder
from tools.importhook import PostImportFinder
KIEKER_AVAILABLE = True
except ImportError:
KIEKER_AVAILABLE = False

# read argumetns
if len(sys.argv) < 2:
print('Path to the benchmark configuration file was not provided.')
sys.exit(1)

parser = configparser.ConfigParser()
parser.read(sys.argv[1])

total_calls =int(parser.get('Benchmark','total_calls'))
recursion_depth = int(parser.get('Benchmark','recursion_depth'))
method_time = int(parser.get('Benchmark','method_time'))
ini_path = parser.get('Benchmark','config_path')
inactive = parser.getboolean('Benchmark', 'inactive')
instrumentation_on = parser.getboolean('Benchmark', 'instrumentation_on')
approach = parser.getint('Benchmark', 'approach')
output_filename = parser.get('Benchmark', 'output_filename')

# debug
#print(f"total_calls = {total_calls}")
#print(f"recurison_depth = {recursion_depth}")
#print(f"method_time = {method_time}")

# instrument
from monitoring.controller import SingleMonitoringController
from tools.importhookast import InstrumentOnImportFinder
from tools.importhook import PostImportFinder
ex =[]
some_var = SingleMonitoringController(ini_path)
if instrumentation_on:
# print ('Instrumentation is on.')
try:
total_calls = int(parser.get('Benchmark','total_calls'))
recursion_depth = int(parser.get('Benchmark','recursion_depth'))
method_time = int(parser.get('Benchmark','method_time'))
output_filename = parser.get('Benchmark', 'output_filename')
ini_path = parser.get('Benchmark','config_path')
inactive = parser.getboolean('Benchmark', 'inactive')
instrumentation_on = parser.getboolean('Benchmark', 'instrumentation_on')
approach = parser.getint('Benchmark', 'approach')
except Exception as e:
print(f"Error parsing config: {e}")
sys.exit(1)

# Setup Kieker only if requested
if KIEKER_AVAILABLE and instrumentation_on:
# This segment runs only for the original Kieker framework logic
some_var = SingleMonitoringController(ini_path)
if approach == 2:
# print("2nd instrumentation approach is chosen")
#if not inactive:
#print("Instrumentation is activated")
#else:
# print("Instrumentation is not activated")

sys.meta_path.insert(0, InstrumentOnImportFinder(ignore_list=ex, empty=inactive, debug_on=False))
sys.meta_path.insert(0, InstrumentOnImportFinder(ignore_list=[], empty=inactive, debug_on=False))
else:
#print("1st instrumentation approach is chosen")
#if not inactive:
# print("Instrumentation is activated")
#else:
# print("Instrumentation is not activated")

pattern_object = re.compile('monitored_application')
exclude_modules = list()
sys.meta_path.insert(0, PostImportFinder(pattern_object, exclude_modules, empty = inactive))
#else:
# print('Instrumentation is off')
sys.meta_path.insert(0, PostImportFinder(pattern_object, exclude_modules, empty=inactive))

# opentelemetry manual instrumentation
tracer = None
# Only enable if installed and requested via environment variable
enable_otel = os.environ.get("ENABLE_OTEL", "false").lower() == "true"

if OTEL_AVAILABLE and enable_otel:
resource = Resource(attributes={
ResourceAttributes.SERVICE_NAME: "moobench-python"
})

provider = TracerProvider(resource=resource)

exporter_type = os.environ.get('OTEL_TRACES_EXPORTER', 'none')

if exporter_type == 'zipkin':
print("Initializing Zipkin Exporter...")
zipkin_endpoint = os.environ.get('OTEL_EXPORTER_ZIPKIN_ENDPOINT', "http://localhost:9411/api/v2/spans")
zipkin_exporter = ZipkinExporter(endpoint=zipkin_endpoint)
provider.add_span_processor(BatchSpanProcessor(zipkin_exporter))

trace.set_tracer_provider(provider)
tracer = trace.get_tracer("moobench.benchmark")

import monitored_application

# setup
output_file = open(output_filename, "w")
print(f"Writing results to: {output_filename}")
print(f"Starting execution: {total_calls} calls.")

output_file = open(output_filename, "w")
thread_id = 0

start_ns = 0
stop_ns = 0
timings = []

# run experiment
for i in range(total_calls):

start_ns = time.time_ns()
monitored_application.monitored_method(method_time, recursion_depth)

if OTEL_AVAILABLE and tracer:
with tracer.start_as_current_span("monitored_method"):
monitored_application.monitored_method(method_time, recursion_depth)
else:
monitored_application.monitored_method(method_time, recursion_depth)

stop_ns = time.time_ns()
timings.append(stop_ns-start_ns)
if i%100000 == 0:
print(timings[-1])

duration = stop_ns - start_ns

if i % 100000 == 0 and i > 0:
print(f"Call {i}: {duration} ns")

output_file.write(f"{thread_id};{timings[-1]}\n")
output_file.write(f"{thread_id};{duration}\n")

output_file.close()

# end
if OTEL_AVAILABLE and os.environ.get('OTEL_TRACES_EXPORTER') == 'zipkin':
print("Flushing traces to Zipkin (waiting 5s)...")
time.sleep(5)

print("Benchmark finished.")