decalage2 / olefile

olefile is a Python package to parse, read and write Microsoft OLE2 files (also called Structured Storage, Compound File Binary Format or Compound Document File Format), such as Microsoft Office 97-2003 documents, vbaProject.bin in MS Office 2007+ files, Image Composer and FlashPix files, Outlook messages, StickyNotes, several Microscopy file formats, McAfee antivirus quarantine files, etc.
http://www.decalage.info/olefile
Other
231 stars 77 forks source link

speedup fix - avoid creating new array everytime #145

Open jucas1 opened 3 years ago

jucas1 commented 3 years ago

fix for performance bottleneck for larger fat tables.

decalage2 commented 3 years ago

Hi @jucas1, thanks a lot for this PR. Do you have a sample where it makes a big difference? I would just like to test the improvement.

jucas1 commented 3 years ago

@decalage2 Hello, Unfortunately, I can't publish my test files (production CAD files). They are SolidWorks data format type (.sldprt, .sldasm). Speedup will take effect in any OLE container with large directories (In some cases .sld* dirs have hundreds to thousands items). I made simple benchmark:

from array import array
a = array("Q", range(100))

%%timeit
biga = a[:]
for _ in range(200):
    biga = biga + a
336 µs ± 6.63 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

%%timeit
biga = a[:]
for _ in range(200):
    biga.extend(a)
17 µs ± 301 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

%%timeit
biga = a[:]
for _ in range(10000):
    biga = biga + a
3.5 s ± 43.8 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

%%timeit
biga = a[:]
for _ in range(10000):
    biga.extend(a)
1.31 ms ± 29.8 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

Concatenating arrays using "+" operator have exponential cost, while .extend cost is almost linear. In my use-case that did 5-10x speedup (for batch processing).

Also "+=" operator will make effect, and surprisingly is even slightly faster than .extend:

%%timeit
biga = a[:]
for _ in range(10000):
    biga += a
1.12 ms ± 3.28 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
ztravis commented 1 year ago

+1 for this change, storing the used stream indexes in a list makes parsing quadratic in the number of streams; changing to use a set is a very easy fix.