Skip to content

Commit

Permalink
autotest: add basic benchmark/
Browse files Browse the repository at this point in the history
  • Loading branch information
rouault committed Oct 11, 2023
1 parent bd1c534 commit b880cad
Show file tree
Hide file tree
Showing 10 changed files with 494 additions and 5 deletions.
6 changes: 3 additions & 3 deletions .github/workflows/cmake_builds.yml
Original file line number Diff line number Diff line change
Expand Up @@ -430,7 +430,7 @@ jobs:
- name: Install dependency
shell: bash -l {0}
run: |
conda install --yes --quiet curl libiconv icu python=3.10 swig numpy pytest pytest-env filelock zlib lxml jsonschema
conda install --yes --quiet curl libiconv icu python=3.10 swig numpy pytest pytest-env pytest-benchmark filelock zlib lxml jsonschema
# FIXME: remove libnetcdf=4.9.2=nompi_h5902ca5_107 pinning as soon as https://github.com/conda-forge/libnetcdf-feedstock/issues/182 is resolved
conda install --yes --quiet proj geos hdf4 hdf5 kealib \
libnetcdf=4.9.2=nompi_h5902ca5_107 openjpeg poppler libtiff libpng xerces-c expat libxml2 kealib json-c \
Expand Down Expand Up @@ -517,7 +517,7 @@ jobs:
- name: Install dependency
shell: bash -l {0}
run: |
conda install --yes --quiet proj pytest pytest-env filelock lxml
conda install --yes --quiet proj pytest pytest-env pytest-benchmark filelock lxml
- name: Configure
shell: bash -l {0}
run: |
Expand Down Expand Up @@ -655,7 +655,7 @@ jobs:
- name: Install dependency
shell: bash -l {0}
run: |
conda install --yes --quiet --name gdalenv curl libiconv icu python=3.9 swig numpy pytest pytest-env filelock zlib clcache lxml
conda install --yes --quiet --name gdalenv curl libiconv icu python=3.9 swig numpy pytest pytest-env pytest-benchmark filelock zlib clcache lxml
conda install --yes --quiet --name gdalenv -c conda-forge libgdal
- name: Configure
shell: bash -l {0}
Expand Down
3 changes: 2 additions & 1 deletion autotest/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,8 @@ endfunction ()
osr
gnm
pyscripts
utilities)
utilities
benchmark)
if (NOT "${CMAKE_BINARY_DIR}" STREQUAL "${CMAKE_SOURCE_DIR}")
if (SKIP_COPYING_AUTOTEST_SUBDIRS)
message(STATUS "Skipping copying ${CMAKE_CURRENT_SOURCE_DIR}/${tgt}")
Expand Down
54 changes: 54 additions & 0 deletions autotest/benchmark/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
#!/usr/bin/env pytest
# -*- coding: utf-8 -*-
###############################################################################
# $Id$
#
# Project: GDAL/OGR Test Suite
# Purpose: Benchmarking
# Author: Even Rouault <even dot rouault at spatialys.com>
#
###############################################################################
# Copyright (c) 2023, Even Rouault <even dot rouault at spatialys.com>
#
# Permission is hereby granted, free of charge, to any person obtaining a
# copy of this software and associated documentation files (the "Software"),
# to deal in the Software without restriction, including without limitation
# the rights to use, copy, modify, merge, publish, distribute, sublicense,
# and/or sell copies of the Software, and to permit persons to whom the
# Software is furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included
# in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
# DEALINGS IN THE SOFTWARE.
###############################################################################

import os

from osgeo import gdal


def pytest_report_header(config):
gdal_header_info = ""

if os.path.exists("/sys/devices/system/cpu/intel_pstate/no_turbo"):
content = open("/sys/devices/system/cpu/intel_pstate/no_turbo", "rb").read()
if content[0] == b"0"[0]:
gdal_header_info += "\n"
gdal_header_info += "WARNING WARNING\n"
gdal_header_info += "---------------\n"
gdal_header_info += "Intel TurboBoost is enabled. Benchmarking results will not be accurate.\n"
gdal_header_info += "Disable TurboBoost with: 'echo 1 | sudo tee /sys/devices/system/cpu/intel_pstate/no_turbo'\n"
gdal_header_info += "---------------\n"
gdal_header_info += "WARNING WARNING\n"

if "debug" in gdal.VersionInfo(""):
gdal_header_info += "WARNING: Running benchmarks on debug build. Results will not be accurate.\n"

return gdal_header_info
73 changes: 73 additions & 0 deletions autotest/benchmark/test_gdalwarp.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
#!/usr/bin/env pytest
# -*- coding: utf-8 -*-
###############################################################################
# $Id$
#
# Project: GDAL/OGR Test Suite
# Purpose: Benchmarking of gdalwarp
# Author: Even Rouault <even dot rouault at spatialys.com>
#
###############################################################################
# Copyright (c) 2023, Even Rouault <even dot rouault at spatialys.com>
#
# Permission is hereby granted, free of charge, to any person obtaining a
# copy of this software and associated documentation files (the "Software"),
# to deal in the Software without restriction, including without limitation
# the rights to use, copy, modify, merge, publish, distribute, sublicense,
# and/or sell copies of the Software, and to permit persons to whom the
# Software is furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included
# in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
# DEALINGS IN THE SOFTWARE.
###############################################################################

import gdaltest
import pytest

from osgeo import gdal, osr

# Must be set to run the test_XXX functions under the benchmark fixture
pytestmark = pytest.mark.usefixtures("decorate_with_benchmark")


@pytest.fixture()
def source_ds_filename(tmp_vsimem):
filename = str(tmp_vsimem / "source.tif")
if "debug" in gdal.VersionInfo(""):
size = 1024
else:
size = 4096
ds = gdal.GetDriverByName("GTiff").Create(
filename, size, size, 3, options=["TILED=YES"]
)
srs = osr.SpatialReference()
srs.ImportFromEPSG(32631)
ds.SetSpatialRef(srs)
ds.SetGeoTransform([400000, 1, 0, 4500000, 0, -1])
ds.GetRasterBand(1).Fill(1)
ds.GetRasterBand(2).Fill(2)
ds.GetRasterBand(3).Fill(3)
ds = None
return filename


@pytest.mark.parametrize("num_threads", ["1", "ALL_CPUS"])
@pytest.mark.parametrize("resample_alg", ["near", "cubic"])
def test_gdalwarp(tmp_vsimem, source_ds_filename, num_threads, resample_alg):
filename = str(tmp_vsimem / "test_gdalwarp.tif")
if gdal.VSIStatL(filename):
gdal.Unlink(filename)
with gdaltest.config_option("GDAL_NUM_THREADS", num_threads):
gdal.Warp(
filename,
source_ds_filename,
options=f"-co TILED=YES -r {resample_alg} -t_srs EPSG:4326",
)
183 changes: 183 additions & 0 deletions autotest/benchmark/test_gtiff.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
#!/usr/bin/env pytest
# -*- coding: utf-8 -*-
###############################################################################
# $Id$
#
# Project: GDAL/OGR Test Suite
# Purpose: Benchmarking of GeoTIFF driver
# Author: Even Rouault <even dot rouault at spatialys.com>
#
###############################################################################
# Copyright (c) 2023, Even Rouault <even dot rouault at spatialys.com>
#
# Permission is hereby granted, free of charge, to any person obtaining a
# copy of this software and associated documentation files (the "Software"),
# to deal in the Software without restriction, including without limitation
# the rights to use, copy, modify, merge, publish, distribute, sublicense,
# and/or sell copies of the Software, and to permit persons to whom the
# Software is furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included
# in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
# DEALINGS IN THE SOFTWARE.
###############################################################################

import array
from threading import Thread

import gdaltest
import pytest

from osgeo import gdal

# Must be set to run the test_XXX functions under the benchmark fixture
pytestmark = pytest.mark.usefixtures("decorate_with_benchmark")


def test_gtiff_byte():
gdal.Open("../gcore/data/byte.tif")


def test_gtiff_byte_get_srs():
ds = gdal.Open("../gcore/data/byte.tif")
ds.GetSpatialRef()


@pytest.mark.parametrize("with_optim", [True, False])
def test_gtiff_multithread_write(with_optim):
num_threads = gdal.GetNumCPUs()
nbands = 1
compression = "DEFLATE"
buffer_pixel_interleaved = True
width = 2048
height = 2048

nloops = 10 // nbands
data = array.array("B", [i % 255 for i in range(nbands * width * height)])

def thread_function(num):
filename = "/vsimem/tmp%d.tif" % num
drv = gdal.GetDriverByName("GTiff")
options = ["TILED=YES", "COMPRESS=" + compression]
for i in range(nloops):
ds = drv.Create(filename, width, height, nbands, options=options)
if not with_optim:
# Calling ReadRaster() disables the cache bypass write optimization
ds.GetRasterBand(1).ReadRaster(0, 0, 1, 1)
if nbands > 1:
if buffer_pixel_interleaved:
# Write pixel-interleaved buffer for maximum efficiency
ds.WriteRaster(
0,
0,
width,
height,
data,
buf_pixel_space=nbands,
buf_line_space=width * nbands,
buf_band_space=1,
)
else:
ds.WriteRaster(0, 0, width, height, data)
else:
ds.GetRasterBand(1).WriteRaster(0, 0, width, height, data)
gdal.Unlink(filename)

with gdaltest.SetCacheMax(width * height * nbands * num_threads):

# Spawn num_threads running thread_function
threads_array = []

for i in range(num_threads):
t = Thread(
target=thread_function,
args=[i],
)
t.start()
threads_array.append(t)

for t in threads_array:
t.join()


@pytest.fixture()
def source_ds_4096x4096_filename(tmp_vsimem, request):
filename = str(tmp_vsimem / "source.tif")
ds = gdal.GetDriverByName("GTiff").Create(
filename, 4096, 4096, 3, options=request.param
)
ds.GetRasterBand(1).Fill(1)
ds.GetRasterBand(2).Fill(2)
ds.GetRasterBand(3).Fill(3)
ds = None
return filename


@pytest.mark.parametrize(
"source_ds_4096x4096_filename",
[[], ["TILED=YES"]],
indirect=True,
ids=["source_default", "source_tiled"],
)
@pytest.mark.parametrize(
"options",
[
[],
["TILED=YES"],
["TILED=YES", "COMPRESS=LZW"],
["TILED=YES", "COMPRESS=LZW", "NUM_THREADS=ALL_CPUS"],
],
ids=["dest_default", "dest_tiled", "dest_tiled_lzw", "dest_tiled_lzw_all_cpus"],
)
def test_gtiff_create_copy(tmp_vsimem, source_ds_4096x4096_filename, options):
filename = str(tmp_vsimem / "source.tif")
src_ds = gdal.Open(source_ds_4096x4096_filename)
gdal.GetDriverByName("GTiff").CreateCopy(filename, src_ds, options=options)


@pytest.fixture()
def source_ds_2048x2048_filename(tmp_vsimem, request):
filename = str(tmp_vsimem / "source.tif")
ds = gdal.GetDriverByName("GTiff").Create(
filename, 2048, 2048, 3, options=request.param
)
ds.GetRasterBand(1).Fill(1)
ds.GetRasterBand(2).Fill(2)
ds.GetRasterBand(3).Fill(3)
ds = None
return filename


@pytest.mark.parametrize(
"source_ds_2048x2048_filename", [["TILED=YES"]], indirect=True, ids=["source_tiled"]
)
@pytest.mark.parametrize(
"ovr_alg",
[
"NEAREST",
"BILINEAR",
"CUBIC",
"CUBICSPLINE",
"LANCZOS",
"AVERAGE",
"RMS",
"MODE",
"GAUSS",
],
)
def test_gtiff_build_overviews(tmp_vsimem, source_ds_2048x2048_filename, ovr_alg):
filename = str(tmp_vsimem / "source.tif")
f = gdal.VSIFOpenL(source_ds_2048x2048_filename, "rb")
source_data = gdal.VSIFReadL(gdal.VSIStatL(source_ds_2048x2048_filename).size, 1, f)
gdal.VSIFCloseL(f)
gdal.FileFromMemBuffer(filename, source_data)
ds = gdal.Open(filename, gdal.GA_Update)
ds.BuildOverviews(ovr_alg, [2, 4, 8])
ds.Close()
Loading

0 comments on commit b880cad

Please sign in to comment.