Our current benchmark only shows results for a single core, we need to see both for the single core and the multi thread score, code : import time
import numpy as np
import argparse
import psutil
from numba import njit, prange

def get_cpu_frequencies():
    """
    Retrieve the current, minimum, and maximum CPU frequencies for each core.
    """
    freq = psutil.cpu_freq(percpu=True)
    frequencies = {
        'current': [f.current for f in freq if f],
        'min': [f.min for f in freq if f],
        'max': [f.max for f in freq if f],
    }
    return frequencies


@njit(parallel=True, fastmath=True, cache=True)
def benchmark_fp_operation(x_fp, y_fp, num_iterations, operation):
    """
    Benchmark a specific floating-point operation using Numba's JIT compilation and parallelization.

    Parameters:
    - x_fp: NumPy array of float64.
    - y_fp: NumPy array of float64.
    - num_iterations: Number of iterations to perform.
    - operation: String indicating the operation ('add', 'sub', 'mul', 'div').

    Returns:
    - total: Accumulated result to prevent loop optimization.
    """
    total = 0.0
    for i in prange(num_iterations):
        idx = i % x_fp.size
        if operation == 'add':
            a = x_fp[idx] + y_fp[idx]
            total += a
        elif operation == 'sub':
            b = x_fp[idx] - y_fp[idx]
            total += b
        elif operation == 'mul':
            c = x_fp[idx] * y_fp[idx]
            total += c
        elif operation == 'div':
            d = x_fp[idx] / y_fp[idx]  # Assuming y_fp has no zeros
            total += d
    return total


@njit(parallel=True, fastmath=True, cache=True)
def benchmark_int_operation(x_int, y_int, num_iterations, operation):
    """
    Benchmark a specific integer operation using Numba's JIT compilation and parallelization.

    Parameters:
    - x_int: NumPy array of int64.
    - y_int: NumPy array of int64.
    - num_iterations: Number of iterations to perform.
    - operation: String indicating the operation ('add', 'sub', 'mul', 'div').

    Returns:
    - total: Accumulated result to prevent loop optimization.
    """
    total = 0
    for i in prange(num_iterations):
        idx = i % x_int.size
        if operation == 'add':
            a = x_int[idx] + y_int[idx]
            total += a
        elif operation == 'sub':
            b = x_int[idx] - y_int[idx]
            total += b
        elif operation == 'mul':
            c = x_int[idx] * y_int[idx]
            total += c
        elif operation == 'div':
            d = x_int[idx] // y_int[idx]  # Assuming y_int has no zeros
            total += d
    return total


def single_operation_benchmark(op_type, operation, num_iterations, x_array, y_array):
    """
    Perform a benchmark for a specific operation type.

    Parameters:
    - op_type: 'FP' for floating-point or 'INT' for integer operations.
    - operation: 'add', 'sub', 'mul', 'div'.
    - num_iterations: Number of iterations to perform.
    - x_array: NumPy array for the first operand.
    - y_array: NumPy array for the second operand.

    Returns:
    - gops: Giga Operations Per Second.
    """
    start_time = time.perf_counter()
    if op_type == "FP":
        total = benchmark_fp_operation(x_array, y_array, num_iterations, operation)
    elif op_type == "INT":
        total = benchmark_int_operation(x_array, y_array, num_iterations, operation)
    else:
        raise ValueError("Invalid operation type")
    end_time = time.perf_counter()

    elapsed_time = end_time - start_time
    # Each iteration performs one operation
    ops = num_iterations / elapsed_time  # Operations per second
    gops = ops / 1e9  # Convert to Giga Operations Per Second

    return gops, elapsed_time, total  # Return total to prevent optimization


def main():
    parser = argparse.ArgumentParser(description="Enhanced CPU Benchmarking Tool with IPC Estimation")
    parser.add_argument("--iterations", type=int, default=100_000_000, help="Number of iterations per benchmark")
    parser.add_argument("--threads", type=int, default=psutil.cpu_count(logical=False), help="Number of CPU cores to use for benchmarking")
    args = parser.parse_args()

    num_iterations = args.iterations
    num_threads = args.threads

    instructions_per_op = 1  # 1 instruction per operation

    # Pre-generate random data for benchmarking
    print("Pre-generating random data for benchmarks...")
    np.random.seed(42)  # For reproducibility
    size = 1_000_000  # Size of arrays (adjusted for better cache performance)

    # Ensure no zeros to prevent division by zero
    x_fp = np.random.uniform(low=1.0, high=100.0, size=size).astype(np.float64)
    y_fp = np.random.uniform(low=1.0, high=100.0, size=size).astype(np.float64)

    x_int = np.random.randint(low=1, high=1_000_000, size=size).astype(np.int64)
    y_int = np.random.randint(low=1, high=1_000_000, size=size).astype(np.int64)

    print("Data generation complete.\n")

    # Warm-up compilation
    print("Warming up Numba-compiled functions...")
    benchmark_fp_operation(x_fp[:1000], y_fp[:1000], 1000, 'add')
    benchmark_fp_operation(x_fp[:1000], y_fp[:1000], 1000, 'sub')
    benchmark_fp_operation(x_fp[:1000], y_fp[:1000], 1000, 'mul')
    benchmark_fp_operation(x_fp[:1000], y_fp[:1000], 1000, 'div')

    benchmark_int_operation(x_int[:1000], y_int[:1000], 1000, 'add')
    benchmark_int_operation(x_int[:1000], y_int[:1000], 1000, 'sub')
    benchmark_int_operation(x_int[:1000], y_int[:1000], 1000, 'mul')
    benchmark_int_operation(x_int[:1000], y_int[:1000], 1000, 'div')
    print("Warm-up complete.\n")

    # Retrieve CPU frequencies before benchmarks
    print("Retrieving CPU frequencies before benchmarks...")
    frequencies_before = get_cpu_frequencies()
    if frequencies_before['current']:
        avg_freq_before = sum(frequencies_before['current']) / len(frequencies_before['current']) / 1000  # Convert MHz to GHz
        print(f"Average CPU Frequency (Before): {avg_freq_before:.2f} GHz\n")
    else:
        print("CPU frequency information is unavailable.\n")
        avg_freq_before = None

    # Define operations to benchmark
    operations = ['add', 'sub', 'mul', 'div']
    op_types = ['FP', 'INT']

    # Perform benchmarks
    results = {op_type: {} for op_type in op_types}

    for op_type in op_types:
        for operation in operations:
            print(f"Running {op_type} - {operation} benchmark...")
            if op_type == "FP":
                gops, elapsed, total = single_operation_benchmark(op_type, operation, num_iterations, x_fp, y_fp)
            else:
                gops, elapsed, total = single_operation_benchmark(op_type, operation, num_iterations, x_int, y_int)
            results[op_type][operation] = {
                'GOPS': gops,
                'Elapsed Time (s)': elapsed,
                'Total': total
            }
            print(f"  {operation.capitalize()} GOPS: {gops:.3f} GOPS in {elapsed:.2f} seconds\n")

    # Retrieve CPU frequencies after benchmarks
    print("Retrieving CPU frequencies after benchmarks...")
    frequencies_after = get_cpu_frequencies()
    if frequencies_after['current']:
        avg_freq_after = sum(frequencies_after['current']) / len(frequencies_after['current']) / 1000  # GHz
        print(f"Average CPU Frequency (After Benchmarks): {avg_freq_after:.2f} GHz\n")
    else:
        print("CPU frequency information is unavailable after benchmarks.\n")
        avg_freq_after = None

    # Calculate IPC
    ipc_results = {op_type: {} for op_type in op_types}
    for op_type in op_types:
        for operation in operations:
            gops = results[op_type][operation]['GOPS']
            if op_type == "FP":
                freq = avg_freq_before  # Assuming frequency remains stable
            else:
                freq = avg_freq_before
            if freq:
                ipc = (gops * 1e9 * instructions_per_op) / (freq * 1e9)
                ipc_results[op_type][operation] = ipc
            else:
                ipc_results[op_type][operation] = float('nan')

    # Display Results
    print("Benchmark Results:\n")
    for op_type in op_types:
        print(f"{op_type}-Type Operations:")
        for operation in operations:
            gops = results[op_type][operation]['GOPS']
            ipc = ipc_results[op_type][operation]
            print(f"  {operation.capitalize()}: {gops:.3f} GOPS, Estimated IPC: {ipc:.2f}")
        print("\n")

    print(f"CPU Frequencies:")
    if avg_freq_before:
        print(f"  Before Benchmarks: {avg_freq_before:.2f} GHz")
    else:
        print("  Before Benchmarks: N/A")
    if frequencies_after['current']:
        print(f"  After Benchmarks: {avg_freq_after:.2f} GHz")
    else:
        print("  After Benchmarks: N/A")


if __name__ == "__main__":
    main()