Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

⚡️ Speed up percentage() by 40% in posthog/templatetags/posthog_filters.py #40

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

codeflash-ai[bot]
Copy link

@codeflash-ai codeflash-ai bot commented Jun 28, 2024

📄 percentage() in posthog/templatetags/posthog_filters.py

📈 Performance improved by 40% (0.40x faster)

⏱️ Runtime went down from 35.0 microseconds to 25.0 microseconds

Explanation and details

Why these changes?

We initially refactored the code to opt for a more modern and efficient way of string formatting using f-strings.
Then, we combined this with lazy evaluation to remove unnecessary computations.
In the final stages, we micro-optimized by introducing constant pre-calculation and single-line conditionals.

Correctness

The better micro-optimized code maintains the same functionality as the original code.

  • Checks if the value is None and returns "-" if it is.
  • Multiplies the value by 100 and formats it as a percentage with the specified number of decimal places if the value is not None.
    Thus, it produces the same outputs for the same inputs and has the same side effects.

How is this faster?

The use of f-strings improves string formatting speed.
Lazy evaluation immediately returns for None values, avoiding unnecessary calculations.
Removing repeated computations (e.g., pre-calculating constant multipliers) reduces the computational overhead.
Single-line conditionals make the execution path shorter and more efficient.

Correctness verification

The new optimized code was tested for correctness. The results are listed below.

🔘 (none found) − ⚙️ Existing Unit Tests

✅ 21 Passed − 🌀 Generated Regression Tests

(click to show generated tests)
# imports
# function to test
from typing import Optional, Union

import pytest  # used for our unit tests

Number = Union[int, float]
from posthog.templatetags.posthog_filters import percentage

# unit tests

# Basic Valid Inputs
def test_percentage_basic():
    assert percentage(0.5) == "50.0%"
    assert percentage(0.1234) == "12.3%"
    assert percentage(1) == "100.0%"
    assert percentage(0) == "0.0%"

# Custom Decimal Places
def test_percentage_custom_decimals():
    assert percentage(0.1234, 2) == "12.34%"
    assert percentage(0.1234, 3) == "12.340%"
    assert percentage(1, 2) == "100.00%"
    assert percentage(0, 2) == "0.00%"

# Edge Cases
def test_percentage_edge_cases():
    assert percentage(None) == "-"
    assert percentage(0) == "0.0%"
    assert percentage(-0.5) == "-50.0%"
    assert percentage(-0.1234, 2) == "-12.34%"

# Invalid `decimals` Parameter
def test_percentage_invalid_decimals():
    with pytest.raises(ValueError):
        percentage(0.1234, -1)
    with pytest.raises(TypeError):
        percentage(0.1234, 1.5)
    with pytest.raises(TypeError):
        percentage(0.1234, "two")

# Large Decimal Values
def test_percentage_large_decimal_values():
    assert percentage(0.000001234, 6) == "0.000123%"
    assert percentage(12345.6789) == "1234567.9%"

# Performance and Scalability
def test_percentage_performance():
    large_list = [0.1] * 1000000
    results = [percentage(value) for value in large_list]
    assert all(result == "10.0%" for result in results)

# Boundary Values
def test_percentage_boundary_values():
    assert percentage(0.0000001, 10) == "0.0000100000%"
    assert percentage(0.9999999, 10) == "99.9999900000%"

# Extreme Values
def test_percentage_extreme_values():
    assert percentage(1e10) == "1000000000000.0%"
    assert percentage(-1e10) == "-1000000000000.0%"

# Decimal Precision Handling
def test_percentage_rounding_behavior():
    assert percentage(0.125, 1) == "12.5%"
    assert percentage(0.125, 2) == "12.50%"
    assert percentage(0.124, 1) == "12.4%"

# Invalid Types
def test_percentage_invalid_types():
    with pytest.raises(TypeError):
        percentage("string")
    with pytest.raises(TypeError):
        percentage([0.1, 0.2])

🔘 (none found) − ⏪ Replay Tests

#### Why these changes?
We initially refactored the code to opt for a more modern and efficient way of string formatting using f-strings.
Then, we combined this with lazy evaluation to remove unnecessary computations.
In the final stages, we micro-optimized by introducing constant pre-calculation and single-line conditionals.

#### Correctness
The better micro-optimized code maintains the same functionality as the original code.
- Checks if the value is None and returns "-" if it is.
- Multiplies the value by 100 and formats it as a percentage with the specified number of decimal places if the value is not None.
Thus, it produces the same outputs for the same inputs and has the same side effects.

#### How is this faster?
The use of f-strings improves string formatting speed.
Lazy evaluation immediately returns for None values, avoiding unnecessary calculations.
Removing repeated computations (e.g., pre-calculating constant multipliers) reduces the computational overhead.
Single-line conditionals make the execution path shorter and more efficient.
@codeflash-ai codeflash-ai bot added the ⚡️ codeflash Optimization PR opened by Codeflash AI label Jun 28, 2024
@codeflash-ai codeflash-ai bot requested a review from aphexcx June 28, 2024 23:48
Copy link

@misrasaurabh1 misrasaurabh1 left a comment

Choose a reason for hiding this comment

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

seems faster and seems important

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
⚡️ codeflash Optimization PR opened by Codeflash AI
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant