-
-
Notifications
You must be signed in to change notification settings - Fork 2.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Ticket #5272 - Avoid unnecesary memory allocations in OGR shapefile provider #26
Conversation
Implements a heap allocation mechanism for optionally enable personal memory allocation
@ahuarte47 Alvaro, a few comments :
My proposition to have code that enforces the above assumptions and will abort in an obvious way if they are not met :
All in all, I'm wondering if the gain of 10%-20% isn't due to the fact that your implementation sharedCalloc() no longer zeroes the memory (once it has reached its maximum size). Perhaps using malloc() when calloc() isn't strictly required would be sufficient ? And with my idea of a bAlwaysAllocZMArrays argument, we could probably avoid any calloc() at all for GDAL use case. I wouldn't expect a malloc() to be so costly, but I might be wrong. |
Hi Even, I will make a test table comparing the current implementation of SHPReadObject/SHPDestroyObject (1), replacing calloc by malloc (2), and my SHPReadObjectH/SHPDestroyObjectH (3). Anyway, I have not implemented SAHeapHooks for general use, but directly related with a pair SHPReadObjectH/SHPDestroyObjectH. Really 'Realloc' and 'Malloc' spare. It is possible the name choosed not be the correct. My intention is that the developper use the pair SHPReadObjectH/SHPDestroyObjectH always related to one SAHeapHooks and as temporal data. (e.g. OgrFeatureIterator does for enumerate a feature request) I have defined SASetupDefaultHeapHooks() as a helper function, I know that it is not used now. your you erase that function? |
Regarding SASetupDefaultHeapHooks(), as I said, I don't see the point in defining the function in a GDAL specific file (shp_vsi.c) if it is not used by GDAL. It just adds untested and unused code. It could perhaps make sense in the shapelib equivalent file whose name I don't remember (you would need to look at shapelib code). But I'm not the shapelib gatekeeper, so FrankW's opinion would be more appropriate. |
Test: (1) SHPReadObject/SHPDestroyObject with calloc Soft/hard: WindowsXP+SP3, 32bits, 4gb RAM Code: SHPHandle shp = NULL; if ((shp = SHPOpenLL(fileName, "rb", hooks))!=NULL)
} Results: http://www.igeo.pt/scrif/crif/CRIF2011shp.zip Rustic parcels of cadastre of navarra (Polygon2D of 542658 records, 458mb) Regards |
Hi Even, I have modified my code with your advice in the last commit |
Regarding your above tests, when you replace calloc() by malloc(), you still do 4 malloc()s for X,Y,Z,M. What do you get if you do only 1 malloc, but without the hook ? I'm trying to see if we can maximize the performance_gain / code_complexity_and_maintanability ratio. |
Yes, (1) makes 4 calloc's, (2) makes 4 malloc's, (3) makes 1 malloc when needed, If the layer are points, N records 1 malloc. I change the original code for make 1 malloc or 1 calloc and send results. |
Hi Even, I have tested all combinations: 1 = 4 calloc using current lib (original)
Although the options (3) and (4) improve considerably the result, it change the current behavior of the shape lib because current applications calling to SHPReadObject/SHPDestroyObject and freeing one unique XYZM pointer will crash. I would use the option (5), It preserve the behavior of current applications using SHPReadObject/SHPDestroyObject, it memset the coordinate pointers as now, and comparing with option (6) no change worth. What do you think ? |
Alvaro, your tenacity prevailed ;-) and I've committed a patch strongly inspired by your work (see http://trac.osgeo.org/gdal/ticket/5272#comment:7). It should have same performance as case (6), and perhaps even a bit better since the SHPObject itself is reused. |
Hi Even, thank you very much for your patience! I see your pull request it is perfect for me (I gets same speed imporvement even bit more), the idea was use a shared buffer for geometry as a shared buffer is used in the dbf manager. QGIS users will thank: Also I see your improvement parsing the integer attributes! Even, but I think that there is a possible bit memory leak if the developper call two times to the 'SHPSetFastModeReadObject' function. If you like I propose some this....
It avoids the memory leak and the developer can disable the 'fastmode' Now, I am going to test filemapping using boost and send results |
This should perhaps help fixing, or at least workarounding, the following issue seen randomly on the gcc52_stdcpp14_sanitize Travis-CI target. e.g on https://api.travis-ci.org/v3/job/351015753/log.txt Running gdrivers/gdalhttp.py... TEST: http_1 ... success ERROR 1: Range downloading not supported by this server! ERROR 1: Request for 8-407 failed TEST: http_2 ... success TEST: http_3 ... success ERROR 4: `/vsicurl/ftp://download.osgeo.org/gdal/data/gtiff/utm.tif' not recognized as a supported file format. TEST: http_4 ... HTTP service for ftp://download.osgeo.org/gdal/data/gtiff/utm.tif is down (HTTP Error: ftp error: 425 Security: Bad IP connecting.) cannot open URL skip TEST: http_5 ... success ERROR 1: JSON parsing error: unexpected character (at offset 0) TEST: http_6 ... success ==31274==WARNING: AddressSanitizer failed to allocate 0x62d00019040f bytes ==31274==AddressSanitizer's allocator is terminating the process instead of returning 0 ==31274==If you don't like this behavior set allocator_may_return_null=1 ==31274==AddressSanitizer CHECK failed: ../../.././libsanitizer/sanitizer_common/sanitizer_allocator.cc:147 "((0)) != (0)" (0x0, 0x0) #0 0x7f3f527259f4 (/home/travis/build/OSGeo/gdal/install-gcc-5.2.0/lib64/libasan.so.2.0.0+0x9e9f4) #1 0x7f3f5272a453 in __sanitizer::CheckFailed(char const*, int, char const*, unsigned long long, unsigned long long) (/home/travis/build/OSGeo/gdal/install-gcc-5.2.0/lib64/libasan.so.2.0.0+0xa3453) #2 0x7f3f526a7461 (/home/travis/build/OSGeo/gdal/install-gcc-5.2.0/lib64/libasan.so.2.0.0+0x20461) #3 0x7f3f527286d5 (/home/travis/build/OSGeo/gdal/install-gcc-5.2.0/lib64/libasan.so.2.0.0+0xa16d5) #4 0x7f3f526acb3d (/home/travis/build/OSGeo/gdal/install-gcc-5.2.0/lib64/libasan.so.2.0.0+0x25b3d) #5 0x7f3f526adbd5 (/home/travis/build/OSGeo/gdal/install-gcc-5.2.0/lib64/libasan.so.2.0.0+0x26bd5) #6 0x7f3f5271e32e in realloc (/home/travis/build/OSGeo/gdal/install-gcc-5.2.0/lib64/libasan.so.2.0.0+0x9732e) #7 0x7f3f3ea2a940 in VSIRealloc /home/travis/build/OSGeo/gdal/gdal/port/cpl_vsisimple.cpp:814 #8 0x7f3f3e8e3958 in VSICurlHandleWriteFunc /home/travis/build/OSGeo/gdal/gdal/port/cpl_vsil_curl.cpp:839 #9 0x7f3f2ff61442 in Curl_client_write (/usr/lib/x86_64-linux-gnu/libcurl-gnutls.so.4+0x16442) #10 0x7f3f2ff8bc46 in Curl_pp_readresp (/usr/lib/x86_64-linux-gnu/libcurl-gnutls.so.4+0x40c46) #11 0x7f3f2ff621ab (/usr/lib/x86_64-linux-gnu/libcurl-gnutls.so.4+0x171ab) #12 0x7f3f2ff64546 (/usr/lib/x86_64-linux-gnu/libcurl-gnutls.so.4+0x19546) #13 0x7f3f2ff61bbf (/usr/lib/x86_64-linux-gnu/libcurl-gnutls.so.4+0x16bbf) #14 0x7f3f2ff61cd1 (/usr/lib/x86_64-linux-gnu/libcurl-gnutls.so.4+0x16cd1) #15 0x7f3f2ff6776b in Curl_disconnect (/usr/lib/x86_64-linux-gnu/libcurl-gnutls.so.4+0x1c76b) #16 0x7f3f2ff7c170 in curl_multi_cleanup (/usr/lib/x86_64-linux-gnu/libcurl-gnutls.so.4+0x31170) #17 0x7f3f3e902c6b in ClearCache /home/travis/build/OSGeo/gdal/gdal/port/cpl_vsil_curl.cpp:2913 #18 0x7f3f3e8fc9f7 in ~VSICurlFilesystemHandler /home/travis/build/OSGeo/gdal/gdal/port/cpl_vsil_curl.cpp:2564 #19 0x7f3f3e8fcf23 in ~VSICurlFilesystemHandler /home/travis/build/OSGeo/gdal/gdal/port/cpl_vsil_curl.cpp:2569 #20 0x7f3f3e9e4a02 in VSIFileManager::~VSIFileManager() /home/travis/build/OSGeo/gdal/gdal/port/cpl_vsil.cpp:1805 #21 0x7f3f3e9e5baa in VSICleanupFileManager /home/travis/build/OSGeo/gdal/gdal/port/cpl_vsil.cpp:1966 #22 0x7f3f3e533e42 in GDALDriverManager::~GDALDriverManager() /home/travis/build/OSGeo/gdal/gdal/gcore/gdaldrivermanager.cpp:262 #23 0x7f3f3e53418d in GDALDriverManager::~GDALDriverManager() /home/travis/build/OSGeo/gdal/gdal/gcore/gdaldrivermanager.cpp:329 #24 0x7f3f3e53a14e in GDALDestroyDriverManager /home/travis/build/OSGeo/gdal/gdal/gcore/gdaldrivermanager.cpp:898 #25 0x7f3f27794ea3 in ffi_call_unix64 (/usr/lib/python2.7/lib-dynload/_ctypes.so+0x1aea3) #26 0x7f3f277948c4 in ffi_call (/usr/lib/python2.7/lib-dynload/_ctypes.so+0x1a8c4) #27 0x7f3f277852c1 in _ctypes_callproc (/usr/lib/python2.7/lib-dynload/_ctypes.so+0xb2c1) #28 0x7f3f27785aa1 (/usr/lib/python2.7/lib-dynload/_ctypes.so+0xbaa1) #29 0x4c2645 in PyObject_Call (/usr/bin/python2.7+0x4c2645) #30 0x537589 in PyEval_EvalFrameEx (/usr/bin/python2.7+0x537589) #31 0x5376f1 in PyEval_EvalFrameEx (/usr/bin/python2.7+0x5376f1) #32 0x5376f1 in PyEval_EvalFrameEx (/usr/bin/python2.7+0x5376f1) #33 0x53e2af in PyEval_EvalCodeEx (/usr/bin/python2.7+0x53e2af) #34 0x536c45 in PyRun_StringFlags (/usr/bin/python2.7+0x536c45) #35 0x53ecb4 in PyRun_SimpleStringFlags (/usr/bin/python2.7+0x53ecb4) #36 0x51e62d in Py_Main (/usr/bin/python2.7+0x51e62d) #37 0x7f3f504657ec in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x217ec) #38 0x41bad0 (/usr/bin/python2.7+0x41bad0) git-svn-id: https://svn.osgeo.org/gdal/trunk@41669 f0d54148-0727-0410-94bb-9a71ac55c965
This pull request implements a shared memory buffer in OGRShapeLayer in order to avoid each individual heap allocations of each temporal SHPObject readed.
Until now, N objects readed allocates N XYZM temporal coordinates array. Now, it uses a memory buffer shared between the N reading requests.
In the most favorable case, N records (e.g. geometry points) executes only one heap allocation.
This patch improves the heap management and speed up the data reading.