async io tile_max

This commit is contained in:
along 2025-07-13 16:49:57 +08:00
parent 1fdd74dc32
commit c683cbde4d
3 changed files with 268 additions and 0 deletions

18
src/tiff_max.py Normal file
View File

@ -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")

98
src/tile_max_reduce.c Normal file
View File

@ -0,0 +1,98 @@
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <tiffio.h>
#include <limits.h>
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;
}

View File

@ -0,0 +1,152 @@
// tile_max_reduce_uring_timed.c
#define _POSIX_C_SOURCE 199309L
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <fcntl.h>
#include <unistd.h>
#include <liburing.h>
#include <tiffio.h>
#include <time.h>
#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;
}