Measuring CPU performance with a parallelized vector sum#

The example compares the time spend in computing the sum of all coefficients of a matrix when the function walks through the coefficients by rows or by columns when the computation is parallelized.

Vector Sum#

from tqdm import tqdm
import numpy
import matplotlib.pyplot as plt
from pandas import DataFrame
from onnx_extended.ext_test_case import measure_time, unit_test_going
from onnx_extended.validation.cpu._validation import (
    vector_sum_array as vector_sum,
    vector_sum_array_parallel as vector_sum_parallel,
)

obs = []
dims = [500, 700, 800, 900, 1000, 1100, 1200, 1300, 1400, 1500, 1600, 1700, 1800, 2000]
if unit_test_going():
    dims = dims[:3]
for dim in tqdm(dims):
    values = numpy.ones((dim, dim), dtype=numpy.float32).ravel()
    diff = abs(vector_sum(dim, values, True) - dim**2)

    res = measure_time(lambda: vector_sum(dim, values, True), max_time=0.5)

    obs.append(
        dict(
            dim=dim,
            size=values.size,
            time=res["average"],
            direction="rows",
            time_per_element=res["average"] / dim**2,
            diff=diff,
        )
    )

    res = measure_time(lambda: vector_sum_parallel(dim, values, True), max_time=0.5)

    obs.append(
        dict(
            dim=dim,
            size=values.size,
            time=res["average"],
            direction="rows//",
            time_per_element=res["average"] / dim**2,
            diff=diff,
        )
    )

    diff = abs(vector_sum(dim, values, False) - dim**2)
    res = measure_time(lambda: vector_sum_parallel(dim, values, False), max_time=0.5)

    obs.append(
        dict(
            dim=dim,
            size=values.size,
            time=res["average"],
            direction="cols//",
            time_per_element=res["average"] / dim**2,
            diff=diff,
        )
    )


df = DataFrame(obs)
piv = df.pivot(index="dim", columns="direction", values="time_per_element")
print(piv)
  0%|          | 0/14 [00:00<?, ?it/s]
  7%|7         | 1/14 [00:01<00:24,  1.89s/it]
 14%|#4        | 2/14 [00:03<00:21,  1.83s/it]
 21%|##1       | 3/14 [00:05<00:19,  1.76s/it]
 29%|##8       | 4/14 [00:07<00:17,  1.76s/it]
 36%|###5      | 5/14 [00:09<00:16,  1.88s/it]
 43%|####2     | 6/14 [00:10<00:14,  1.83s/it]
 50%|#####     | 7/14 [00:12<00:12,  1.85s/it]
 57%|#####7    | 8/14 [00:14<00:11,  1.86s/it]
 64%|######4   | 9/14 [00:16<00:09,  1.88s/it]
 71%|#######1  | 10/14 [00:18<00:07,  1.87s/it]
 79%|#######8  | 11/14 [00:20<00:05,  1.94s/it]
 86%|########5 | 12/14 [00:22<00:03,  1.92s/it]
 93%|#########2| 13/14 [00:24<00:01,  1.89s/it]
100%|##########| 14/14 [00:26<00:00,  1.95s/it]
100%|##########| 14/14 [00:26<00:00,  1.88s/it]
direction        cols//          rows        rows//
dim
500        1.496619e-08  1.234545e-09  1.523612e-08
700        8.187623e-09  1.302480e-09  7.868350e-09
800        6.330473e-09  1.184594e-09  6.008078e-09
900        4.782857e-09  1.337167e-09  5.010942e-09
1000       4.322850e-09  1.254221e-09  2.841871e-09
1100       4.027298e-09  1.420177e-09  2.996122e-09
1200       3.576997e-09  1.341742e-09  2.434894e-09
1300       4.569081e-09  1.463800e-09  1.950575e-09
1400       3.733452e-09  1.502885e-09  2.999804e-09
1500       3.811822e-09  1.416122e-09  2.017804e-09
1600       2.845311e-09  1.298302e-09  1.482510e-09
1700       2.480905e-09  1.260247e-09  2.650386e-10
1800       2.741477e-09  1.134161e-09  2.431954e-10
2000       4.428924e-09  1.185919e-09  2.907648e-10

Plots#

piv_diff = df.pivot(index="dim", columns="direction", values="diff")
piv_time = df.pivot(index="dim", columns="direction", values="time")

fig, ax = plt.subplots(1, 3, figsize=(12, 6))
piv.plot(ax=ax[0], logx=True, title="Comparison between two summation")
piv_diff.plot(ax=ax[1], logx=True, logy=True, title="Summation errors")
piv_time.plot(ax=ax[2], logx=True, logy=True, title="Total time")
fig.savefig("plot_bench_cpu_vector_sum_parallel.png")
Comparison between two summation, Summation errors, Total time
/home/xadupre/.local/lib/python3.10/site-packages/pandas/plotting/_matplotlib/core.py:744: UserWarning: Data has no positive values, and therefore cannot be log-scaled.
  labels = axis.get_majorticklabels() + axis.get_minorticklabels()

The summation by rows is much faster as expected. That explains why it is usually more efficient to transpose the first matrix before a matrix multiplication. Parallelization is faster.

Total running time of the script: ( 0 minutes 27.395 seconds)

Gallery generated by Sphinx-Gallery