Skip to content

Utils

Collections of utility functions for easybench.

ResultType

Bases: TypedDict

Type of benchmark result.

Source code in easybench/utils.py
16
17
18
19
20
21
class ResultType(TypedDict):
    """Type of benchmark result."""

    times: NotRequired[list[float]]
    memory: NotRequired[list[float]]
    output: NotRequired[list[object]]

StatType

Bases: TypedDict

Type of benchmark statistics.

Source code in easybench/utils.py
24
25
26
27
28
29
30
31
class StatType(TypedDict):
    """Type of benchmark statistics."""

    avg: NotRequired[float]
    min: NotRequired[float]
    max: NotRequired[float]
    avg_memory: NotRequired[float]
    max_memory: NotRequired[float]

calculate_statistics(results)

Calculate statistics from benchmark results.

Parameters:

Name Type Description Default
results ResultsType

Dictionary of benchmark results

required

Returns:

Type Description
StatsType

Dictionary of calculated statistics

Source code in easybench/utils.py
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
def calculate_statistics(
    results: ResultsType,
) -> StatsType:
    """
    Calculate statistics from benchmark results.

    Args:
        results: Dictionary of benchmark results

    Returns:
        Dictionary of calculated statistics

    """
    stats: StatsType = {}
    for method_name, data in results.items():
        if "times" in data and len(data["times"]) != 0:
            times = data["times"]
            stats[method_name] = {
                "avg": sum(times) / len(times),
                "min": min(times),
                "max": max(times),
            }
        else:
            stats[method_name] = {}

        if "memory" in data and len(data["memory"]) != 0:
            memory_values = data["memory"]
            avg_memory = sum(memory_values) / len(memory_values)
            max_memory = max(memory_values)
            stats[method_name].update(
                {"avg_memory": avg_memory, "max_memory": max_memory},
            )

    return stats

get_bench_env()

Collect environment information relevant to benchmarking.

Returns:

Type Description
dict[str, Any]

Dictionary containing benchmark-relevant environment details

Source code in easybench/utils.py
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
def get_bench_env() -> dict[str, Any]:
    """
    Collect environment information relevant to benchmarking.

    Returns:
        Dictionary containing benchmark-relevant environment details

    """
    env_info: dict[str, Any] = {}

    # OS information (affects performance)
    env_info["os"] = {
        "system": platform.system(),
        "release": platform.release(),
        "version": platform.version(),
        "architecture": platform.architecture()[0],
        "machine": platform.machine(),
    }

    # CPU information (major performance factor)
    env_info["cpu"] = {
        "count": os.cpu_count() or "Unknown",
        "processor": platform.processor(),
    }

    # Python runtime environment (affects execution speed)
    env_info["python"] = {
        "version": platform.python_version(),
        "implementation": platform.python_implementation(),
        "compiler": platform.python_compiler(),
    }

    # Add Pyodide info if applicable
    if "pyodide" in sys.modules:
        pyodide = sys.modules["pyodide"]
        env_info["python"]["environment"] = "pyodide"
        env_info["python"]["pyodide_version"] = getattr(
            pyodide,
            "__version__",
            "unknown",
        )

    # Performance counter information (affects measurement precision)
    perf_info = time.get_clock_info("perf_counter")
    env_info["perf_counter"] = {
        "resolution": perf_info.resolution,
        "implementation": perf_info.implementation,
        "monotonic": perf_info.monotonic,
        "timer_overhead": measure_timer_overhead(),
    }

    return env_info

measure_timer_overhead(iterations=1000000)

Measure the overhead of the time.perf_counter() function.

Source code in easybench/utils.py
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
def measure_timer_overhead(iterations: int = 1_000_000) -> float:
    """Measure the overhead of the time.perf_counter() function."""
    # Variable to prevent loop optimization
    counter = 0

    # 1. Measure loop overhead only
    start_empty = time.perf_counter()
    for _ in range(iterations):
        counter += 1
    end_empty = time.perf_counter()
    loop_overhead = end_empty - start_empty

    # 2. Measure loop with timer calls
    start_with_timer = time.perf_counter()
    for _ in range(iterations):
        counter += 1
        time.perf_counter()
    end_with_timer = time.perf_counter()
    total_time = end_with_timer - start_with_timer

    # 3. Calculate timer function overhead
    # Use `counter` instead of `iterations` in the calculation
    # to ensure loop and variable are not optimized away in any interpreter
    return (total_time - loop_overhead) / (counter / 2)

visual_ljust(text, width, fillchar=' ')

Ljust for visual width.

Parameters:

Name Type Description Default
text str

The input string to pad.

required
width int

Target visual width.

required
fillchar str

Character used for padding. Defaults to a space.

' '

Returns:

Name Type Description
str str

Padded string with the specified visual width.

Source code in easybench/utils.py
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
def visual_ljust(text: str, width: int, fillchar: str = " ") -> str:
    """
    Ljust for visual width.

    Args:
        text (str): The input string to pad.
        width (int): Target visual width.
        fillchar (str, optional): Character used for padding. Defaults to a space.

    Returns:
        str: Padded string with the specified visual width.

    """
    current_width = visual_width(text)
    padding_width = max(0, width - current_width)
    return text + (fillchar * padding_width)

visual_rjust(text, width, fillchar=' ')

Rjust for visual width.

Parameters:

Name Type Description Default
text str

The input string to pad.

required
width int

Target visual width.

required
fillchar str

Character used for padding. Defaults to a space.

' '

Returns:

Name Type Description
str str

Right-padded string with the specified visual width.

Source code in easybench/utils.py
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
def visual_rjust(text: str, width: int, fillchar: str = " ") -> str:
    """
    Rjust for visual width.

    Args:
        text (str): The input string to pad.
        width (int): Target visual width.
        fillchar (str, optional): Character used for padding. Defaults to a space.

    Returns:
        str: Right-padded string with the specified visual width.

    """
    current_width = visual_width(text)
    padding_width = max(0, width - current_width)
    return (fillchar * padding_width) + text

visual_width(text)

Calculate the visual width of a string.

Assuming
  • Fullwidth ('F') and Wide ('W') characters count as 2.
  • All other characters count as 1.

This function is useful for determining display width, especially for East Asian characters in fixed-width terminal environments.

Parameters:

Name Type Description Default
text str

The input string.

required

Returns:

Name Type Description
int int

The total visual width of the string.

Source code in easybench/utils.py
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
def visual_width(text: str) -> int:
    """
    Calculate the visual width of a string.

    Assuming:
        - Fullwidth ('F') and Wide ('W') characters count as 2.
        - All other characters count as 1.

    This function is useful for determining display width, especially for
    East Asian characters in fixed-width terminal environments.

    Args:
        text (str): The input string.

    Returns:
        int: The total visual width of the string.

    """
    width = 0
    for ch in text:
        ea_width = unicodedata.east_asian_width(ch)
        if ea_width in ("F", "W"):  # Fullwidth or Wide
            width += 2
        else:
            width += 1  # Narrow, Halfwidth, Ambiguous, Neutral
    return width