重要提示
contrib/masmx* 目录在2017年已被删除(此时我正在处理包含它们的 v1.2.11 .zip 文件),所以以下所有内容都已不再适用(OOTB)。但是它们的引用没有被删除(至少不是从所有地方),因此如果它们被启用(从 CMake),则构建将失败。
但是,我提交了[GitHub]: madler/zlib - Re enable ASM speedups on Win(在 221007上被拒绝),因此以下所有内容再次适用。对于可能从该补丁中受益的方式(一旦/如果它被接受),请参阅 [SO]: How to change username of job in print queue using python & win32print (@CristiFati's answer)(末尾)。
将以上补丁应用于(当前的)
master分支:
使用以下脚本遍历所有配置,运行并汇总结果。
code00.py:
import hashlib as hl
import os
import shutil
import subprocess as sp
import sys
import time
from pprint import pprint as pp
ARCHS = (
"pc064",
"pc032",
)
def print_file_data(file, level=0):
st = os.stat(file)
header = " " * level
print("{:s}File: {:s}\n{:s} Size: {:d}, CTime: {:s}".format(header, file, header, st.st_size, time.ctime(st.st_ctime)))
def main(*argv):
verbose = False
build_dir = os.getcwd()
if argv:
file = argv[0]
if "-v" in argv:
verbose = True
else:
file = "file.onnx"
file_test = file + ".test"
file_gz = file_test + ".gz"
shutil.copy(file, file_test)
md5_src = hl.md5(open(file_test, mode="rb").read()).hexdigest()
print_file_data(file_test)
data = {}
for arch in ARCHS:
if verbose:
print("Arch: {:s}".format(arch))
ad = {}
for typ in ("plain", "masm"):
if verbose:
print(" Type: {:s}".format(typ))
mg = os.path.join(build_dir, "_build", arch, typ, "minigzip.exe")
for level in (1, 5, 9):
shutil.copy(file, file_test)
if verbose:
print("\n Compress (level {:d})".format(level))
proc = sp.Popen([mg, "-{:d}".format(level), file_test])
time_start = time.time()
proc.communicate()
elapsed = time.time() - time_start
if verbose:
print(" Took {:.3f} seconds".format(elapsed))
ad.setdefault("level {:d}".format(level), {}).setdefault("inflate", {})[typ] = elapsed
if verbose:
print_file_data(file_gz, level=2)
if verbose:
print(" Decompress")
proc = sp.Popen([mg, "-d", file_gz])
time_start = time.time()
proc.communicate()
elapsed = time.time() - time_start
if verbose:
print(" Took {:.3f} seconds".format(elapsed))
ad.setdefault("level {:d}".format(level), {}).setdefault("deflate", {})[typ] = elapsed
if verbose:
print_file_data(file_test, level=2)
if hl.md5(open(file_test, mode="rb").read()).hexdigest() != md5_src:
print("!!! File hashes differ !!!")
data[arch] = ad
pp(data, indent=2, sort_dicts=False)
if __name__ == "__main__":
print("Python {:s} {:03d}bit on {:s}\n".format(" ".join(elem.strip() for elem in sys.version.split("\n")),
64 if sys.maxsize > 0x100000000 else 32, sys.platform))
rc = main(*sys.argv[1:])
print("\nDone.")
sys.exit(rc)
输出:
[cfati@CFATI-5510-0:e:\Work\Dev\StackOverflow\q029505121]> "e:\Work\Dev\VEnvs\py_pc064_03.09_test0\Scripts\python.exe" ./code00.py file.onnx
Python 3.9.9 (tags/v3.9.'level 9':ccb0e6a, Nov 15 2021, 18:08:50) [MSC v.1929 64 bit (AMD64)] 064bit on win32
File: file.onnx.test
Size: 255890833, CTime: Sat Sep 3 02:03:05 2022
{ 'pc064': { 'level 1': { 'inflate': { 'plain': 12.552296161651611,
'masm': 11.09960412979126},
'deflate': { 'plain': 1.802419900894165,
'masm': 1.8380048274993896}},
'level 5': { 'inflate': { 'plain': 13.694978713989258,
'masm': 12.098156213760376},
'deflate': { 'plain': 1.756164312362671,
'masm': 1.7628483772277832}},
'level 9': { 'inflate': { 'plain': 13.969024419784546,
'masm': 12.125015497207642},
'deflate': { 'plain': 1.7450010776519775,
'masm': 1.756005048751831}}},
'pc032': { 'level 1': { 'inflate': { 'plain': 13.748999118804932,
'masm': 11.81002926826477},
'deflate': { 'plain': 1.9236936569213867,
'masm': 2.3493638038635254}},
'level 5': { 'inflate': { 'plain': 15.036035299301147,
'masm': 12.898797512054443},
'deflate': { 'plain': 1.8580067157745361,
'masm': 2.282176971435547}},
'level 9': { 'inflate': { 'plain': 15.134005308151245,
'masm': 12.89007306098938},
'deflate': { 'plain': 1.8709957599639893,
'masm': 2.2773334980010986}}}}
Done.
[cfati@CFATI-5510-0:e:\Work\Dev\StackOverflow\q029505121]> "e:\Work\Dev\VEnvs\py_pc064_03.09_test0\Scripts\python.exe" ./code00.py enwik8.txt
Python 3.9.9 (tags/v3.9.'level 9':ccb0e6a, Nov 15 2021, 18:08:50) [MSC v.1929 64 bit (AMD64)] 064bit on win32
File: enwik8.txt.test
Size: 100000000, CTime: Tue Sep 6 00:33:20 2022
{ 'pc064': { 'level 1': { 'inflate': { 'plain': 1.9976372718811035,
'masm': 1.9259986877441406},
'deflate': { 'plain': 0.7285704612731934,
'masm': 0.7076430320739746}},
'level 5': { 'inflate': { 'plain': 4.5627357959747314,
'masm': 4.003000020980835},
'deflate': { 'plain': 0.6933917999267578,
'masm': 0.6450159549713135}},
'level 9': { 'inflate': { 'plain': 8.079626083374023,
'masm': 6.618978977203369},
'deflate': { 'plain': 0.7049713134765625,
'masm': 0.6319396495819092}}},
'pc032': { 'level 1': { 'inflate': { 'plain': 2.1649997234344482,
'masm': 2.1139981746673584},
'deflate': { 'plain': 0.7583539485931396,
'masm': 0.8125534057617188}},
'level 5': { 'inflate': { 'plain': 5.03799843788147,
'masm': 4.2109808921813965},
'deflate': { 'plain': 0.8489999771118164,
'masm': 0.6870477199554443}},
'level 9': { 'inflate': { 'plain': 7.9073097705841064,
'masm': 7.512087821960449},
'deflate': { 'plain': 0.7378275394439697,
'masm': 0.7450006008148193}}}}
Done.
[cfati@CFATI-5510-0:e:\Work\Dev\StackOverflow\q029505121]> cd dbg
[cfati@CFATI-5510-0:e:\Work\Dev\StackOverflow\q029505121\dbg]> "e:\Work\Dev\VEnvs\py_pc064_03.09_test0\Scripts\python.exe" ../code00.py ../file.onnx
Python 3.9.9 (tags/v3.9.'level 9':ccb0e6a, Nov 15 2021, 18:08:50) [MSC v.1929 64 bit (AMD64)] 064bit on win32
File: ../file.onnx.test
Size: 255890833, CTime: Tue Sep 6 00:37:51 2022
{ 'pc064': { 'level 1': { 'inflate': { 'plain': 25.337001085281372,
'masm': 22.544013023376465},
'deflate': { 'plain': 3.915001153945923,
'masm': 2.3709957599639893}},
'level 5': { 'inflate': { 'plain': 28.28699827194214,
'masm': 24.88018822669983},
'deflate': { 'plain': 3.846531867980957,
'masm': 2.2239699363708496}},
'level 9': { 'inflate': { 'plain': 28.81813645362854,
'masm': 23.6450355052948},
'deflate': { 'plain': 3.9910058975219727,
'masm': 2.302088737487793}}},
'pc032': { 'level 1': { 'inflate': { 'plain': 24.923137664794922,
'masm': 20.991183042526245},
'deflate': { 'plain': 3.7310261726379395,
'masm': 2.6056015491485596}},
'level 5': { 'inflate': { 'plain': 27.760021209716797,
'masm': 22.589048624038696},
'deflate': { 'plain': 3.566000461578369,
'masm': 2.55342698097229}},
'level 9': { 'inflate': { 'plain': 28.245535135269165,
'masm': 22.70799994468689},
'deflate': { 'plain': 3.553999423980713,
'masm': 2.5700416564941406}}}}
Done.
[cfati@CFATI-5510-0:e:\Work\Dev\StackOverflow\q029505121\dbg]> "e:\Work\Dev\VEnvs\py_pc064_03.09_test0\Scripts\python.exe" ../code00.py ../enwik8.txt
Python 3.9.9 (tags/v3.9.'level 9':ccb0e6a, Nov 15 2021, 18:08:50) [MSC v.1929 64 bit (AMD64)] 064bit on win32
File: ../enwik8.txt.test
Size: 100000000, CTime: Tue Sep 6 00:39:59 2022
{ 'pc064': { 'level 1': { 'inflate': { 'plain': 4.711355447769165,
'masm': 4.008531808853149},
'deflate': { 'plain': 1.4210000038146973,
'masm': 0.9230430126190186}},
'level 5': { 'inflate': { 'plain': 8.914000034332275,
'masm': 6.604032516479492},
'deflate': { 'plain': 1.3359959125518799,
'masm': 0.8460018634796143}},
'level 9': { 'inflate': { 'plain': 13.503999948501587,
'masm': 9.228030920028687},
'deflate': { 'plain': 1.328040599822998,
'masm': 0.8240146636962891}}},
'pc032': { 'level 1': { 'inflate': { 'plain': 4.435391664505005,
'masm': 3.933983087539673},
'deflate': { 'plain': 1.3369977474212646,
'masm': 0.9399752616882324}},
'level 5': { 'inflate': { 'plain': 8.48900055885315,
'masm': 6.599977731704712},
'deflate': { 'plain': 1.2629964351654053,
'masm': 0.8410165309906006}},
'level 9': { 'inflate': { 'plain': 12.677618026733398,
'masm': 9.191060781478882},
'deflate': { 'plain': 1.251995325088501,
'masm': 0.8130028247833252}}}}
Done.
如上所述,对于大多数人感兴趣的发布版本,使用加速并不能带来太大的速度提升(有时甚至比 C 代码还要慢)。这与缺乏维护有关,也是禁用它们的原因之一。
原始答案
在尝试汇编加速时,我发现这个问题可以在(目前)最新版本 v1.2.11 ([GitHub]: madler/zlib - ZLIB 数据压缩库) 上重现。
这个错误只会发生在以下情况下(显然,操作系统: Win,构建工具链: VStudio 并启用汇编加速):
下面是解压缩过程中的 "callstack"(从上到下相当于从外到内)。
正常情况下,代码库包含以下文件:
inflate(
inflate.c)、
inflate_fast(
inffast.c)等。但是在使用汇编的情况下,还需要包含
inffast8664.c和
inffasx64.asm等文件。问题出现在缺少
#2.2.文件,导致无法构建完整的库。解决方法是在
"${ZLIB_SRC_DIR}/CMakeLists.txt"中添加对
inffast8664.c的引用。
让
CMakeLists.txt 意识到该文件,方法是添加以下内容:
set(ZLIB_SRCS
${ZLIB_SRCS}
contrib/masmx64/inffas8664.c
)
在
if(MSVC)
和
elseif (AMD64)
条件语句之间的第
158行(被包含在其中)。
发布完整的更改。
zlib-1.2.11-msvc_x64_asm_speedups.diff:
@@ -79,10 +79,10 @@
endif()
set(ZLIB_PC ${CMAKE_CURRENT_BINARY_DIR}/zlib.pc)
-configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/zlib.pc.cmakein
- ${ZLIB_PC} @ONLY)
-configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/zconf.h.cmakein
- ${CMAKE_CURRENT_BINARY_DIR}/zconf.h @ONLY)
+configure_file(${CMAKE_CURRENT_SOURCE_DIR}/zlib.pc.cmakein
+ ${ZLIB_PC} @ONLY)
+configure_file(${CMAKE_CURRENT_SOURCE_DIR}/zconf.h.cmakein
+ ${CMAKE_CURRENT_BINARY_DIR}/zconf.h @ONLY)
include_directories(${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_SOURCE_DIR})
@@ -136,30 +136,34 @@
set(ZLIB_ASMS contrib/amd64/amd64-match.S)
endif ()
- if(ZLIB_ASMS)
- add_definitions(-DASMV)
- set_source_files_properties(${ZLIB_ASMS} PROPERTIES LANGUAGE C COMPILE_FLAGS -DNO_UNDERLINE)
- endif()
+ if(ZLIB_ASMS)
+ add_definitions(-DASMV)
+ set_source_files_properties(${ZLIB_ASMS} PROPERTIES LANGUAGE C COMPILE_FLAGS -DNO_UNDERLINE)
+ endif()
endif()
if(MSVC)
if(ASM686)
- ENABLE_LANGUAGE(ASM_MASM)
+ ENABLE_LANGUAGE(ASM_MASM)
set(ZLIB_ASMS
- contrib/masmx86/inffas32.asm
- contrib/masmx86/match686.asm
- )
+ contrib/masmx86/inffas32.asm
+ contrib/masmx86/match686.asm
+ )
elseif (AMD64)
- ENABLE_LANGUAGE(ASM_MASM)
+ ENABLE_LANGUAGE(ASM_MASM)
set(ZLIB_ASMS
- contrib/masmx64/gvmat64.asm
- contrib/masmx64/inffasx64.asm
- )
+ contrib/masmx64/gvmat64.asm
+ contrib/masmx64/inffasx64.asm
+ )
+ set(ZLIB_SRCS
+ ${ZLIB_SRCS}
+ contrib/masmx64/inffas8664.c
+ )
endif()
- if(ZLIB_ASMS)
- add_definitions(-DASMV -DASMINF)
- endif()
+ if(ZLIB_ASMS)
+ add_definitions(-DASMV -DASMINF)
+ endif()
endif()
# parse the full version number from zlib.h and include in ZLIB_FULL_VERSION
上述是一个
diff。请参见
[SO]:如何在PyCharm Community Edition的鼠标右键上下文菜单中运行/调试Django应用程序的UnitTests?(@CristiFati's answer) (
Patching UTRunner部分)了解如何在
Win上应用补丁(基本上,每一行以
一个"+" 符号开头的都要添加,每一行以
一个"-" 符号开头的都要删除)。
我还提交了这个补丁:
[GitHub]: madler/zlib - Ms VisualStudio - Assembler speedups on x64,但后来我关闭了它,因为它包含在最开始的那个补丁中。
e:\Work\Dev\StackOverflow\q029505121\build\x64>"c:\Install\Google\Android_SDK\cmake\3.6.4111459\bin\cmake.exe" -G "NMake Makefiles" -DAMD64=ON "e:\Work\Dev\StackOverflow\q029505121\src\zlib-1.2.11"
-- The C compiler identification is MSVC 19.0.24215.1
-- Check for working C compiler: C:/Install/x86/Microsoft/Visual Studio Community/2015/VC/bin/amd64/cl.exe
-- Check for working C compiler: C:/Install/x86/Microsoft/Visual Studio Community/2015/VC/bin/amd64/cl.exe -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Looking for sys/types.h
-- Looking for sys/types.h - found
-- Looking for stdint.h
-- Looking for stdint.h - found
-- Looking for stddef.h
-- Looking for stddef.h - found
-- Check size of off64_t
-- Check size of off64_t - failed
-- Looking for fseeko
-- Looking for fseeko - not found
-- Looking for unistd.h
-- Looking for unistd.h - not found
-- Renaming
-- E:/Work/Dev/StackOverflow/q029505121/src/zlib-1.2.11/zconf.h
-- to 'zconf.h.included' because this file is included with zlib
-- but CMake generates it automatically in the build directory.
-- The ASM_MASM compiler identification is MSVC
-- Found assembler: C:/Install/x86/Microsoft/Visual Studio Community/2015/VC/bin/amd64/ml64.exe
-- Configuring done
-- Generating done
-- Build files have been written to: E:/Work/Dev/StackOverflow/q029505121/build/x64
e:\Work\Dev\StackOverflow\q029505121\build\x64>"c:\Install\Google\Android_SDK\cmake\3.6.4111459\bin\cmake.exe" --build . --target zlibstatic
Scanning dependencies of target zlibstatic
[ 5%] Building C object CMakeFiles/zlibstatic.dir/adler32.obj
adler32.c
[ 10%] Building C object CMakeFiles/zlibstatic.dir/compress.obj
compress.c
[ 15%] Building C object CMakeFiles/zlibstatic.dir/crc32.obj
crc32.c
[ 21%] Building C object CMakeFiles/zlibstatic.dir/deflate.obj
deflate.c
Assembler code may have bugs -- use at your own risk
[ 26%] Building C object CMakeFiles/zlibstatic.dir/gzclose.obj
gzclose.c
[ 31%] Building C object CMakeFiles/zlibstatic.dir/gzlib.obj
gzlib.c
[ 36%] Building C object CMakeFiles/zlibstatic.dir/gzread.obj
gzread.c
[ 42%] Building C object CMakeFiles/zlibstatic.dir/gzwrite.obj
gzwrite.c
[ 47%] Building C object CMakeFiles/zlibstatic.dir/inflate.obj
inflate.c
[ 52%] Building C object CMakeFiles/zlibstatic.dir/infback.obj
infback.c
[ 57%] Building C object CMakeFiles/zlibstatic.dir/inftrees.obj
inftrees.c
[ 63%] Building C object CMakeFiles/zlibstatic.dir/inffast.obj
inffast.c
Assembler code may have bugs -- use at your own risk
[ 68%] Building C object CMakeFiles/zlibstatic.dir/trees.obj
trees.c
[ 73%] Building C object CMakeFiles/zlibstatic.dir/uncompr.obj
uncompr.c
[ 78%] Building C object CMakeFiles/zlibstatic.dir/zutil.obj
zutil.c
[ 84%] Building C object CMakeFiles/zlibstatic.dir/contrib/masmx64/inffas8664.obj
inffas8664.c
[ 89%] Building ASM_MASM object CMakeFiles/zlibstatic.dir/contrib/masmx64/gvmat64.obj
Microsoft (R) Macro Assembler (x64) Version 14.00.24210.0
Copyright (C) Microsoft Corporation. All rights reserved.
Assembling: E:\Work\Dev\StackOverflow\q029505121\src\zlib-1.2.11\contrib\masmx64\gvmat64.asm
[ 94%] Building ASM_MASM object CMakeFiles/zlibstatic.dir/contrib/masmx64/inffasx64.obj
Microsoft (R) Macro Assembler (x64) Version 14.00.24210.0
Copyright (C) Microsoft Corporation. All rights reserved.
Assembling: E:\Work\Dev\StackOverflow\q029505121\src\zlib-1.2.11\contrib\masmx64\inffasx64.asm
[100%] Linking C static library zlibstatic.lib
[100%] Built target zlibstatic
注释:
更新 #0
[GitHub]: madler/zlib - 在 Windows 上使用 ASM 构建 zlib 会产生错误的结果(@madler 的评论) 表示(强调是我的):
使用了哪些汇编代码?zlib 的 contrib 目录中有一些。顺便说一下,contrib 目录不是 zlib 的一部分。它只是作为方便而存在,由第三方贡献者支持(或不支持)。我将从下一个发布版本中简单地删除有问题的代码。
那么编译警告(每个人都应该看到过(并且很可能忽略了))会怎样呢?
Assembler code may have bugs -- use at your own risk
显然,汇编器加速和VStudio不太相容。而且,在x86(pc032)上,存在一些问题:
一个恶心的问题是在解压缩过程中出现了SegFault(访问冲突)。为此,需要使用
[GitHub]:madler/zlib - inffas32.asm struct/enum binding to zlib 1.2.9(也包含在最初的文件中)。
可能不再适用:
[SO]:module unsafe for SAFESEH image C++ (@NayanaAdassuriya's answer)提出了一种修复方法(虽然它与问题没有直接关系)。简而言之,
inffas32.asm和
链接器的选项
[MS.Docs]:/SAFESEH (Image has Safe Exception Handlers)不匹配。要摆脱它,可以选择以下任意一种方法:
禁用该选项(默认情况下启用x86 Release)
将
/safeseh选项传递给汇编程序(
ml.exe)
在
asm中声明一个
由于我使用
CMake构建
CmdLine,我找到了一个解决方法。在生成
CMakeFiles(但在构建之前)之后,我指定它:
在
flags.make文件中(
ASM_MASM_FLAGS)
由于我构建了一个
静态库(并且对于
Debug构建,我还需要符号),因此我还更改
[MS.Docs]:/Z7, /Zi, /ZI (Debug Information Format),因此我修改了同一文件(
C_FLAGS)
我相信
CMake提供了一种以适当方式执行上述操作的方法,但我没有找到它(也没有彻底调查)。
修复后,一切正常,性能提升类似于
pc064。
如果有人需要,我已经构建并放置了二进制文件在
[GitHub]: CristiFati/Prebuilt-Binaries - (master) Prebuilt-Binaries/ZLib(带 / 不带加速)。