diff --git a/src/tiff_max.py b/src/tiff_max.py new file mode 100644 index 0000000..b1be871 --- /dev/null +++ b/src/tiff_max.py @@ -0,0 +1,18 @@ +import time +from osgeo import gdal + +# 打开图像(默认是只读模式) +start_time = time.time() + +ds = gdal.Open("imgs/ortho.tif", gdal.GA_ReadOnly) +if ds is None: + raise RuntimeError("Failed to open dataset") + +band = ds.GetRasterBand(1) # 取第一个波段 +array = band.ReadAsArray() # 整个波段读入内存(同步) +max_val = array.max() + +end_time = time.time() + +print(f"GDAL Max: {max_val}") +print(f"Time taken: {end_time - start_time:.3f} seconds") diff --git a/src/tile_max_reduce.c b/src/tile_max_reduce.c new file mode 100644 index 0000000..07a05ff --- /dev/null +++ b/src/tile_max_reduce.c @@ -0,0 +1,98 @@ +#include +#include +#include +#include +#include + +int main() +{ + TIFF *tif = TIFFOpen("imgs/ortho.tif", "r"); + if (!tif) + { + printf("Failed to open file.\n"); + return 1; + } + + uint32 tileWidth, tileHeight; + TIFFGetField(tif, TIFFTAG_TILEWIDTH, &tileWidth); + TIFFGetField(tif, TIFFTAG_TILELENGTH, &tileHeight); + printf("Tile size: %dx%d\n", tileWidth, tileHeight); + + uint32 imageWidth, imageHeight; + TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &imageWidth); + TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &imageHeight); + + uint32 tilesAcross = (imageWidth + tileWidth - 1) / tileWidth; + uint32 tilesDown = (imageHeight + tileHeight - 1) / tileHeight; + uint32 totalTiles = tilesAcross * tilesDown; + printf("Tile count: %d x %d = %d\n", tilesAcross, tilesDown, totalTiles); + + uint16 samplesPerPixel; + uint16 bitsPerSample; + + TIFFGetField(tif, TIFFTAG_SAMPLESPERPIXEL, &samplesPerPixel); + TIFFGetField(tif, TIFFTAG_BITSPERSAMPLE, &bitsPerSample); + + printf("Samples per pixel: %d\n", samplesPerPixel); + printf("Bits per sample: %d\n", bitsPerSample); + + uint16 sampleFormat = SAMPLEFORMAT_UINT; + TIFFGetField(tif, TIFFTAG_SAMPLEFORMAT, &sampleFormat); + printf("Sample format: %d\n", sampleFormat); // 1=uint, 2=int, 3=float + + tsize_t tileBufSize = TIFFTileSize(tif); + if (tileBufSize == 0) + { + printf("TIFFTileSize returned 0. Possibly not tiled.\n"); + TIFFClose(tif); + return 1; + } + + // 分配一个缓冲区用于存放一个 tile 的像素数据(未压缩) + uint8_t *tileBuf = (uint8_t *)_TIFFmalloc(tileBufSize); + if (!tileBuf) + { + fprintf(stderr, "Failed to allocate tile buffer.\n"); + TIFFClose(tif); + return 1; + } + + // 全局最大值初始化 + uint8_t globalMax = 0; + + // 遍历每个 tile 并解码为像素数据 + for (uint32 i = 0; i < totalTiles; i++) + { + tsize_t readBytes = TIFFReadEncodedTile(tif, i, tileBuf, tileBufSize); + if (readBytes == -1) + { + fprintf(stderr, "Failed to decode tile %d\n", i); + continue; + } + + // 每 tile 最大值初始化 + uint8_t tileMax = 0; + + // 遍历所有像素(只对第一个波段进行最大值统计) + uint32 numPixels = readBytes / samplesPerPixel; + for (uint32 px = 0; px < numPixels; px++) + { + uint8_t value = tileBuf[px * samplesPerPixel]; // 假设只看第1通道 + if (value > tileMax) + tileMax = value; + } + + // 打印 tile 最大值 + printf("Tile %3d: Max = %3d\n", i, tileMax); + + // Reduce 更新全局最大值 + if (tileMax > globalMax) + globalMax = tileMax; + } + + printf("\n>>> Global Max Value = %d\n", globalMax); + + _TIFFfree(tileBuf); + TIFFClose(tif); + return 0; +} diff --git a/src/tile_max_reduce_io_uring.c b/src/tile_max_reduce_io_uring.c new file mode 100644 index 0000000..ed4b9d0 --- /dev/null +++ b/src/tile_max_reduce_io_uring.c @@ -0,0 +1,152 @@ +// tile_max_reduce_uring_timed.c +#define _POSIX_C_SOURCE 199309L +#include +#include +#include +#include +#include +#include +#include +#include + +#define MAX_TILES 2048 + +// 获取当前时间(秒 + 纳秒)函数 +static double get_time_sec() +{ + struct timespec ts; + clock_gettime(CLOCK_MONOTONIC, &ts); + return ts.tv_sec + ts.tv_nsec * 1e-9; +} + +int main() +{ + const char *filepath = "imgs/ortho.tif"; + + int fd = open(filepath, O_RDONLY); + if (fd < 0) + { + perror("open"); + return 1; + } + + TIFF *tif = TIFFOpen(filepath, "r"); + if (!tif) + { + fprintf(stderr, "Failed to open TIFF with libtiff.\n"); + close(fd); + return 1; + } + + uint32 tileWidth, tileHeight, imageWidth, imageHeight; + TIFFGetField(tif, TIFFTAG_TILEWIDTH, &tileWidth); + TIFFGetField(tif, TIFFTAG_TILELENGTH, &tileHeight); + TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &imageWidth); + TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &imageHeight); + + uint32 tilesAcross = (imageWidth + tileWidth - 1) / tileWidth; + uint32 tilesDown = (imageHeight + tileHeight - 1) / tileHeight; + uint32 totalTiles = tilesAcross * tilesDown; + + if (totalTiles > MAX_TILES) + { + fprintf(stderr, "Too many tiles: %u (limit %d)\n", totalTiles, MAX_TILES); + TIFFClose(tif); + close(fd); + return 1; + } + + tsize_t *byteCounts = NULL; + toff_t *offsets = NULL; + + TIFFGetField(tif, TIFFTAG_TILEBYTECOUNTS, &byteCounts); + TIFFGetField(tif, TIFFTAG_TILEOFFSETS, &offsets); + + // 初始化 io_uring + struct io_uring ring; + io_uring_queue_init(totalTiles, &ring, 0); + + // 内存 buffer + char *buffers[MAX_TILES]; + uint8_t tileMaxes[MAX_TILES]; // 每 tile 最大值 + + // 记录异步读取 + tile max 计算开始时间 + double t_start = get_time_sec(); + + // 提交读请求 + for (uint32 i = 0; i < totalTiles; i++) + { + buffers[i] = malloc(byteCounts[i]); + if (!buffers[i]) + { + fprintf(stderr, "Failed to alloc buffer for tile %u\n", i); + break; + } + + struct io_uring_sqe *sqe = io_uring_get_sqe(&ring); + io_uring_prep_read(sqe, fd, buffers[i], byteCounts[i], offsets[i]); + io_uring_sqe_set_data(sqe, buffers[i]); + } + + io_uring_submit(&ring); + + // 等待结果 & 计算每 tile max + for (uint32 i = 0; i < totalTiles; i++) + { + struct io_uring_cqe *cqe; + int ret = io_uring_wait_cqe(&ring, &cqe); + if (ret < 0) + { + fprintf(stderr, "wait_cqe failed: %d\n", ret); + continue; + } + + char *data = io_uring_cqe_get_data(cqe); + int len = cqe->res; + + uint8_t maxVal = 0; + for (int j = 0; j < len; j++) + { + uint8_t val = (uint8_t)data[j]; + if (val > maxVal) + maxVal = val; + } + + tileMaxes[i] = maxVal; + printf("Tile %3u: Max = %3u\n", i, maxVal); + + io_uring_cqe_seen(&ring, cqe); + } + + double t_io_calc_end = get_time_sec(); + + // reduce 求全局最大值,单独计时 + uint8_t globalMax = 0; + + double t_reduce_start = get_time_sec(); + + for (uint32 i = 0; i < totalTiles; i++) + { + if (tileMaxes[i] > globalMax) + globalMax = tileMaxes[i]; + } + + double t_reduce_end = get_time_sec(); + + printf("\n>>> Global Max Value: %d\n", globalMax); + printf("Time: Async IO + tile max calculation = %.6f seconds\n", t_io_calc_end - t_start); + printf("Time: Reduce global max = %.6f seconds\n", t_reduce_end - t_reduce_start); + + // 清理 + for (uint32 i = 0; i < totalTiles; i++) + { + free(buffers[i]); + } + + io_uring_queue_exit(&ring); + TIFFClose(tif); + close(fd); + + return 0; +} +