diff --git a/.github/workflows/benchmarks.yml b/.github/workflows/benchmarks.yml index 0c06f8b741f..965b701f312 100644 --- a/.github/workflows/benchmarks.yml +++ b/.github/workflows/benchmarks.yml @@ -7,42 +7,25 @@ on: jobs: sdk-benchmarks: env: - py312: "3.12" - RUN_MATRIX_COMBINATION: ${{ matrix.python-version }}-sdk-${{ matrix.os }} runs-on: self-hosted - strategy: - # Ensures the entire test matrix is run, even if one permutation fails - fail-fast: false - matrix: - python-version: [py312] - os: [ubuntu-20.04, windows-2019] steps: - name: Checkout Core Repo @ SHA - ${{ github.sha }} uses: actions/checkout@v4 - - name: Set up Python ${{ env[matrix.python-version] }} + - name: Set up Python uses: actions/setup-python@v5 with: - python-version: ${{ env[matrix.python-version] }} + python-version: "3.12" architecture: 'x64' - name: Install tox run: pip install tox - - name: Cache tox environment - # Preserves .tox directory between runs for faster installs - uses: actions/cache@v4 - with: - path: | - .tox - ~/.cache/pip - key: v3-tox-cache-${{ env.RUN_MATRIX_COMBINATION }}-${{ hashFiles('tox.ini', - 'dev-requirements.txt') }}-core - name: Run tox - run: tox -f ${{ matrix.python-version }}-sdk -- -k opentelemetry-sdk/tests/performance/benchmarks --benchmark-json=opentelemetry-sdk/tests/output.json + run: tox -e benchmark-opentelemetry-sdk -- -k opentelemetry-sdk/benchmarks --benchmark-json=opentelemetry-sdk/output.json - name: Report on SDK benchmark results uses: benchmark-action/github-action-benchmark@v1 with: - name: OpenTelemetry Python SDK Benchmarks - Python ${{ env[matrix.python-version ]}} - SDK + name: OpenTelemetry Python SDK Benchmarks tool: pytest - output-file-path: opentelemetry-sdk/tests/output.json + output-file-path: opentelemetry-sdk/output.json gh-pages-branch: gh-pages github-token: ${{ secrets.GITHUB_TOKEN }} # Make a commit on `gh-pages` with benchmarks from previous step diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index cc19428329f..f70b22765a4 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -92,11 +92,7 @@ jobs: - name: Windows does not let git check out files with long names if: ${{ matrix.os == 'windows-2019'}} run: git config --system core.longpaths true - - name: run pytest with --benchmark-skip - if: ${{ matrix.package == 'sdk' || matrix.package == 'exporter-otlp-proto-grpc' }} - run: tox -f ${{ matrix.python-version }}-${{ matrix.package }} -- -ra --benchmark-skip - - name: run pytest without --benchmark-skip - if: ${{ !(matrix.package == 'sdk' || matrix.package == 'exporter-otlp-proto-grpc') }} + - name: run tox run: tox -f ${{ matrix.python-version }}-${{ matrix.package }} -- -ra misc: strategy: @@ -217,4 +213,4 @@ jobs: key: v3-tox-cache-${{ matrix.python-version }}-${{ matrix.package }}-${{ matrix.os }}-${{ hashFiles('tox.ini', 'dev-requirements.txt') }}-contrib - name: run tox - run: tox -f ${{ matrix.python-version }}-${{ matrix.package }} -- -ra --benchmark-skip + run: tox -f ${{ matrix.python-version }}-${{ matrix.package }} -- -ra diff --git a/.gitignore b/.gitignore index f2324c7bfca..07c7b9aa6e4 100644 --- a/.gitignore +++ b/.gitignore @@ -66,3 +66,6 @@ docs/examples/django/db.sqlite3 # Semantic conventions scripts/semconv/semantic-conventions + +# Benchmark result files +*-benchmark.json diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index e4b13bf3dd7..31eedfef8c6 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -126,7 +126,7 @@ The continuation integration overrides that environment variable with as per the ### Benchmarks -Running the `tox` tests also runs the performance tests if any are available. Benchmarking tests are done with `pytest-benchmark` and they output a table with results to the console. +Some packages have benchmark tests. To run them, run `tox -f benchmark`. Benchmark tests use `pytest-benchmark` and they output a table with results to the console. To write benchmarks, simply use the [pytest benchmark fixture](https://pytest-benchmark.readthedocs.io/en/latest/usage.html#usage) like the following: @@ -142,10 +142,10 @@ def test_simple_start_span(benchmark): benchmark(benchmark_start_as_current_span, "benchmarkedSpan", 42) ``` -Make sure the test file is under the `tests/performance/benchmarks/` folder of +Make sure the test file is under the `benchmarks/` folder of the package it is benchmarking and further has a path that corresponds to the file in the package it is testing. Make sure that the file name begins with -`test_benchmark_`. (e.g. `opentelemetry-sdk/tests/performance/benchmarks/trace/propagation/test_benchmark_b3_format.py`) +`test_benchmark_`. (e.g. `opentelemetry-sdk/benchmarks/trace/propagation/test_benchmark_b3_format.py`) ## Pull Requests diff --git a/opentelemetry-sdk/benchmark-requirements.txt b/opentelemetry-sdk/benchmark-requirements.txt new file mode 100644 index 00000000000..44564857ef4 --- /dev/null +++ b/opentelemetry-sdk/benchmark-requirements.txt @@ -0,0 +1 @@ +pytest-benchmark==4.0.0 diff --git a/opentelemetry-sdk/tests/performance/benchmarks/metrics/test_benchmark_metrics.py b/opentelemetry-sdk/benchmarks/metrics/test_benchmark_metrics.py similarity index 100% rename from opentelemetry-sdk/tests/performance/benchmarks/metrics/test_benchmark_metrics.py rename to opentelemetry-sdk/benchmarks/metrics/test_benchmark_metrics.py diff --git a/opentelemetry-sdk/tests/performance/benchmarks/metrics/test_benchmark_metrics_histogram,.py b/opentelemetry-sdk/benchmarks/metrics/test_benchmark_metrics_histogram,.py similarity index 100% rename from opentelemetry-sdk/tests/performance/benchmarks/metrics/test_benchmark_metrics_histogram,.py rename to opentelemetry-sdk/benchmarks/metrics/test_benchmark_metrics_histogram,.py diff --git a/opentelemetry-sdk/tests/performance/benchmarks/trace/test_benchmark_trace.py b/opentelemetry-sdk/benchmarks/trace/test_benchmark_trace.py similarity index 100% rename from opentelemetry-sdk/tests/performance/benchmarks/trace/test_benchmark_trace.py rename to opentelemetry-sdk/benchmarks/trace/test_benchmark_trace.py diff --git a/opentelemetry-sdk/tests/performance/resource-usage/trace/profile_resource_usage_batch_export.py b/opentelemetry-sdk/tests/performance/resource-usage/trace/profile_resource_usage_batch_export.py deleted file mode 100644 index 3e9a201c967..00000000000 --- a/opentelemetry-sdk/tests/performance/resource-usage/trace/profile_resource_usage_batch_export.py +++ /dev/null @@ -1,49 +0,0 @@ -# Copyright The OpenTelemetry Authors -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -import time - -from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import ( - OTLPSpanExporter, -) -from opentelemetry.sdk.trace import TracerProvider, sampling -from opentelemetry.sdk.trace.export import BatchSpanProcessor - -TEST_DURATION_SECONDS = 15 -SPANS_PER_SECOND = 10_000 - - -class MockTraceServiceStub: - def __init__(self, channel): - self.Export = lambda *args, **kwargs: None - - -old_stub = OTLPSpanExporter._stub -OTLPSpanExporter._stub = MockTraceServiceStub - -simple_span_processor = BatchSpanProcessor(OTLPSpanExporter()) -tracer = TracerProvider( - active_span_processor=simple_span_processor, - sampler=sampling.DEFAULT_ON, -).get_tracer("resource_usage_tracer") - -starttime = time.time() -for _ in range(TEST_DURATION_SECONDS): - for _ in range(SPANS_PER_SECOND): - span = tracer.start_span("benchmarkedSpan") - span.end() - time_to_finish_spans = time.time() - starttime - time.sleep(1.0 - time_to_finish_spans if time_to_finish_spans < 1.0 else 0) - -OTLPSpanExporter._stub = old_stub diff --git a/opentelemetry-sdk/tests/performance/resource-usage/trace/profile_resource_usage_simple_export.py b/opentelemetry-sdk/tests/performance/resource-usage/trace/profile_resource_usage_simple_export.py deleted file mode 100644 index bc27fb519da..00000000000 --- a/opentelemetry-sdk/tests/performance/resource-usage/trace/profile_resource_usage_simple_export.py +++ /dev/null @@ -1,49 +0,0 @@ -# Copyright The OpenTelemetry Authors -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -import time - -from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import ( - OTLPSpanExporter, -) -from opentelemetry.sdk.trace import TracerProvider, sampling -from opentelemetry.sdk.trace.export import SimpleSpanProcessor - -TEST_DURATION_SECONDS = 15 -SPANS_PER_SECOND = 10_000 - - -class MockTraceServiceStub: - def __init__(self, channel): - self.Export = lambda *args, **kwargs: None - - -old_stub = OTLPSpanExporter._stub -OTLPSpanExporter._stub = MockTraceServiceStub - -simple_span_processor = SimpleSpanProcessor(OTLPSpanExporter()) -tracer = TracerProvider( - active_span_processor=simple_span_processor, - sampler=sampling.DEFAULT_ON, -).get_tracer("resource_usage_tracer") - -starttime = time.time() -for _ in range(TEST_DURATION_SECONDS): - for _ in range(SPANS_PER_SECOND): - span = tracer.start_span("benchmarkedSpan") - span.end() - time_to_finish_spans = time.time() - starttime - time.sleep(1.0 - time_to_finish_spans if time_to_finish_spans < 1.0 else 0) - -OTLPSpanExporter._stub = old_stub diff --git a/tox.ini b/tox.ini index c766a20ff54..48ca1f10df8 100644 --- a/tox.ini +++ b/tox.ini @@ -17,6 +17,7 @@ envlist = py3{8,9,10,11,12}-opentelemetry-sdk pypy3-opentelemetry-sdk + benchmark-opentelemetry-sdk py3{8,9,10,11,12}-opentelemetry-semantic-conventions pypy3-opentelemetry-semantic-conventions @@ -113,6 +114,7 @@ commands_pre = api: pip install -r {toxinidir}/opentelemetry-api/test-requirements.txt sdk: pip install -r {toxinidir}/opentelemetry-sdk/test-requirements.txt + benchmark-opentelemetry-sdk: pip install -r {toxinidir}/opentelemetry-sdk/benchmark-requirements.txt semantic-conventions: pip install -r {toxinidir}/opentelemetry-semantic-conventions/test-requirements.txt @@ -168,6 +170,7 @@ commands_pre = commands = api: pytest {toxinidir}/opentelemetry-api/tests {posargs} sdk: pytest {toxinidir}/opentelemetry-sdk/tests {posargs} + benchmark-opentelemetry-sdk: pytest {toxinidir}/opentelemetry-sdk/benchmarks {posargs} --benchmark-json=sdk-benchmark.json protobuf: pytest {toxinidir}/opentelemetry-proto/tests {posargs} semantic-conventions: pytest {toxinidir}/opentelemetry-semantic-conventions/tests {posargs} getting-started: pytest {toxinidir}/docs/getting_started/tests {posargs}