A7R6 RAW 无损裁切

技术硬件实验 · 2026-08-26

A7R6 RAW无损裁切:CPU–GPU–SSD混合流水线实测

不是让CPU和GPU重复做同一件事,而是让它们各自负责擅长的阶段:CPU解析ARW并并行读取,Metal批量完成无损SOF3解码与精确ROI裁切,CPU再把Bayer16顺序写入内部SSD。三个阶段通过有界队列并行推进;整个裁切与暂存阶段不缩放、不去马赛克、不改像素。

1000张端到端实测 / 594张有框8851个真实SOF3 tile / 707个ROIApple M5 · 10 CPU核 / 10 GPU核 / 32GB真实Bayer16临时分片 + fsync所有抽样裁切逐值一致
1.491 s本地输入完整三级流水线;1000张、3072 tiles/批
670.8 图/s端到端吞吐;同时处理读取、GPU解码裁切与落盘
29.46%相对三段串行执行所隐藏的延迟;节省622.5ms
8.01 GB受控运行峰值内存footprint;无swap增量
Executive decision

生产方案确定为三级混合流水线

最终持久化层是无损Bayer16,而不是RGB8、JPEG或模型张量。它保留ARW有效14-bit样本,把模型相关的去马赛克、色彩、归一化与resize推迟到YOLO Pose、YOLO CLS和SAM各自的输入预处理。

01

CPU负责控制与I/O

TIFF/ARW解析、metadata读取、物理offset合并、12线程pread、GPU批次构建,以及最终索引和顺序pwrite。这些工作分支多、系统调用密集,更适合CPU。

02

GPU负责大批量规则计算

Metal以“一个线程解一个独立tile”的方式并行SOF3 Huffman、predictor-1重建、四分量到Bayer16重排与精确ROI裁切。大批量时比10核自写CPU解码高5.27×。

03

SSD承担必需的临时落盘

所有数据无法常驻内存,因此CPU writer把结果写成大分片并建立索引。模型消费者读取Bayer16后再做各自预处理;不创建大量小文件,也不对临时数据做zlib-6二次压缩。

明确边界:任何时候都不缩放或修改裁切结果。

该阶段只把传感器样本从ARW的SOF3 tile恢复为精确ROI内的uint16 little-endian单平面Bayer;有效值仍是0–16383的14-bit数据。没有黑电平扣除、白平衡、去马赛克、tone、颜色空间转换、量化、归一化或resize。

本地实测组合估算官方资料约束与边界
Chapter 01 · End-to-end

端到端:三段在N+1 / N / N−1上并行

1000张工作负载被分成有界批次。队列深度为1:读取器只允许领先GPU一个批次,writer只落后一个批次,既能重叠执行,又不会让统一内存无限增长。

CPU · Stage 1ARW解析、合并读取、组批读TIFF/ARW metadata;同图多框共享tile;按物理offset把8851个tile合并为2230段;12线程pread;构造Metal输入与ROI描述符。
GPU · Stage 2SOF3解码 + Bayer16 ROIHuffman熵解码、predictor-1重建、256×256×4分量重排为512×512 Bayer,并只输出ROI。像素值不变。
CPU + SSD · Stage 3索引、16MiB顺序写、fsync结果写入内部SSD临时shard,记录offset、length、几何与RAW metadata;完成后fsync。实测后删除测试分片。

稳态重叠方式

CPU读取
Batch NBatch N+1Batch N+2
Metal
Batch NBatch N+1
CPU写SSD
N−1N

示意图用于说明依赖关系,不按绝对时间比例绘制。GPU处理N时,读取器准备N+1,writer写N−1;有界队列形成背压。

最佳本地完整运行:每批最多3072 tiles

阶段运行位置1000张累计服务时间等效速率资源峰值 / 说明
读取与组批CPU,12线程956.95ms约3.03GB/s输入本地F_NOCACHE;含metadata、offset合并和批次构建
SOF3 + ROIApple M5 GPU788.80ms墙钟;572.31ms设备时间约11.22k tiles/s墙钟Metal allocation峰值4.68GB
Bayer16分片写CPU单writer + 内部SSD365.94ms + fsync 1.46ms约8.08GB/s输出16MiB顺序pwrite;真实写2.958GB
三段若串行—2.113s473图/s各段服务时间直接相加
三级流水线CPU + GPU + SSD重叠1.491s670.8图/s;5937.6 tiles/s隐藏622.5ms,即29.46%

资源消耗

最大RSS5.44GB
峰值footprint8.01GB / 32GB统一内存
峰值Metal allocation4.68GB
swap受控运行前后无变化
memory throttling0 pages throttled

正确性闭环

输出总字节与精确计算一致
临时shard字节与输出一致
抽样ROI逐样本值一致
GPU错误tile0
测试临时文件验证后已清理
本地瓶颈与卡端瓶颈不同。

在本地完整实测的3072批次上,累计最长的是CPU读取/组批(956.95ms),其次是GPU(788.80ms),writer明显更短;三段可较好重叠。换回CFexpress后,实测卡读取单独就要2.064秒/1000张,成为明确的物理瓶颈,GPU和SSD写入可隐藏在卡读取之后。

Chapter 02 · Fidelity

真实工作负载与“无损裁切”的含义

报告只把上游框当作既定几何输入,不评价前级检测正确性。1000张样本用于覆盖真实tile分布与长尾;裁切阶段不生成可观看的图像,而是恢复传感器CFA样本供后续神经网络预处理。

1000张端到端负载

总照片1000张
有框照片594张
ROI707个
唯一tile8851个
合并后读取段2230段
压缩输入2.900GB
Bayer16 ROI输出2.958GB

ARW不是普通有损JPG

ARW是相机RAW容器;本批A7R6文件的传感器payload使用JPEG家族里的SOF3 lossless sequential编码。它与日常8-bit有损JPEG不是同一种用途:Huffman解码和predictor重建能精确恢复原14-bit样本。

“ARW一定无损”也不能作为普遍结论;本报告的无损性来自对这批文件编码模式与逐值输出的验证。

一个SOF3 tile:256 × 256 × 4个14-bit分量,解码容器为uint16 四分量位置:C0=左上,C1=右上,C2=左下,C3=右下 重排后:512 × 512单平面Bayer16 字节恒等:256 × 256 × 4 × 2 = 512 × 512 × 2 = 524,288 bytes 精确ROI:只复制框内CFA样本;不缩放、不插值、不改数值

每条ROI必须伴随的元数据

样本与几何

source id、原RAW尺寸、active area、原始bbox、ROI宽高、行步长、shard offset/length。

CFA与位深

14-bit有效精度、Bayer pattern、裁切起点奇偶校正、little-endian uint16、black/white level。

相机颜色信息

白平衡增益、相机矩阵、色彩相关tag。保存但不在裁切阶段应用。

方向与追溯

orientation、原文件标识、版本与checksum,使后续预处理可复现并能回到ARW。

ROI是Region of Interest,即“感兴趣区域”。

这里就是上游框映射到RAW坐标后的矩形裁切范围。ROI裁切只减少后续要保存和处理的区域;它不代表resize,也不意味着可以改变画面内容。

Chapter 03 · CPU versus GPU

串行发生在tile内部,并行发生在tile之间

SOF3单tile的变长码和predictor具有顺序依赖;GPU不能把一个tile任意拆散。但不同tile互相独立,足够大的批次能用数千线程并行多个tile。小批次下GPU启动与低占用反而输给CPU。

解码器 / 工况批量中位时间吞吐判断
libjpeg-turbo + 重排,CPU 10线程256真实tiles43.60ms5871 tiles/s成熟兼容回退路径
自写SOF3融合解码,CPU 10线程256真实tiles38.35ms6676 tiles/s比libjpeg路径快12.05%
Metal融合解码,小批量256真实tiles118.36ms墙钟2163 tiles/sGPU未吃满,不应逐图提交
Metal融合解码,真实不同输入峰值6144 tiles174.76ms设备时间35,157 tiles/s约为CPU 10线程的5.27×
Metal缓存复用上界8192 tiles191.08ms设备时间42,872 tiles/s只表示计算/占用上界,不当作真实I/O结果

真实不同输入:GPU tile吞吐

4096
28.0k/s
6144
35.2k/s
7840
33.7k/s
8192
33.5k/s
9216
30.8k/s

输入来自28个不同ARW、共7840个唯一tile和2.458GB压缩字节;超过7840后仅循环剩余部分。

为什么完整流水线不选6144

6144是“纯GPU算子”的吞吐峰值,不是“整机端到端”的最佳点。完整流水线在3072达到1.491秒,而6144退化到2.961秒。

超大批次需要约7.30GB Metal allocation,统一内存缓冲的分配、清零与搬运增加;总批次数从3降到2,也减少了流水线稳态重叠,首批填充和末批排空占比更高。

因此算子峰值与流水线峰值必须分开调参。

完整三级流水线批量扫描

tiles/批批次数端到端墙钟中位读/组批中位GPU墙钟中位写盘峰值Metal
768122.535s85.1ms173.1ms42.5ms1.25GB
102492.218s109.6ms183.1ms43.4ms1.65GB
153661.709s161.6ms200.7ms69.4ms2.41GB
204851.678s212.6ms222.5ms93.4ms3.15GB
256041.536s284.7ms237.8ms92.7ms3.95GB
307231.491s335.4ms264.7ms112.7ms4.68GB
358431.550s395.3ms262.4ms139.5ms4.26GB
409631.709s456.6ms301.5ms207.6ms6.17GB
614422.961s793.6ms798.7ms238.6ms7.30GB
CPU解码器仍然有价值,但不与GPU重复处理同一批。

生产路径优先把大批量交给Metal;自写CPU解码可处理尾批、小批、GPU不可用或不支持的SOF3变体,libjpeg-turbo则作为兼容回退。所谓“专用CPU版本”是针对ARM64通用CPU核优化的软件,并不是调用了CPU内部的JPEG ASIC。

Chapter 04 · Storage

Bayer16是无损暂存格式,也是更简单的计算格式

ARW传感器样本只有14个有效bit;Bayer16不会凭空增加信息,只是为每个样本分配一个自然对齐的16-bit槽位。它删除了14-bit位打包/解包步骤,便于GPU写出、CPU顺序落盘和模型loader读取。

格式1000张未压缩输出旧CPU端到端中位处理要求结论
紧凑14-bit位流2.589GB2.129s逐行跨字节位打包;消费者还要解包更小,但多一道计算和不规则写入
Bayer16 uint16 LE2.958GB1.832s有效14-bit值直接写入16-bit槽位旧CPU路径快13.97%;本方案采用

16-bit比紧凑14-bit大14.28%。表中旧CPU时间用于比较容器处理成本;新的CPU–GPU–SSD三级流水线为另一套实现,其1000张完整墙钟是1.491秒,不能直接把两张表相减。

没有丢失RAW信息

每个0–16383样本原值不变;CFA pattern、black/white level、WB、相机矩阵、active area和orientation保存在索引。后续可以采用不同中性化方案。

不做二次压缩

zlib-6是DEFLATE压缩的中等压缩级别。旧测试把2.589GB压到2.382GB,只省7.96%,但墙钟从2.13秒增到13.60秒,约6.4×更慢。

大分片而非小文件

内部SSD写512MB–2GB shard,索引记录每条ROI的offset和length;writer以16MiB块顺序pwrite。这样减少文件系统元数据和随机写。

为什么必须落盘仍能保持流水线。

2.958GB只是1000张样本;全量与后续多个消费者无法全部驻留统一内存。方案不尝试把全批放下,而是让每个GPU批次在writer确认写入后立即释放,内存上限由批次和深度为1的有界队列决定。下游按shard流式读取,消费完成并有checkpoint后再回收。

Chapter 05 · Consumer boundary

裁切层只交付Bayer16;模型各自决定“怎么看”

ARW裁切的消费者是YOLO Pose、YOLO CLS与SAM。它们的输入几何还没有完全定下来,因此裁切层绝不能预先缩成固定宽高,也不能统一做一套RGB或归一化。

消费者用途从Bayer16读取后自行完成当前边界
YOLO Pose鸟类特征点标定黑电平、WB、去马赛克、色彩/灰度策略、归一化、letterbox/resize、张量布局输入目标几何待实验确定
YOLO CLS鸟类清晰度分类可采用与Pose不同的中性化、色彩、锐度保留与crop策略输入目标几何待实验确定
SAM分割与后续掩码处理自己的色彩预处理、归一化、resize/letterbox与prompt坐标变换不在裁切阶段固定到1024

现在不实现模型预处理Metal核

黑电平、WB、去马赛克、矩阵、tone、resize、RGB/灰度生成与张量布局将来可以按消费者融合成Metal kernel,以减少中间张量和内存往返;本轮只记录这个方向,不把未实现的性能计入结果。

几何链必须可追踪

模型loader若以后做crop扩边、resize或letterbox,必须从原始ROI和CFA奇偶开始记录完整变换,使Pose关键点、SAM prompt和输出坐标能精确映射回RAW。

已删除旧结论:

不再保存RGB8,不再一律宽高减半,不再预设YOLO detect 1632×1088或SAM 1024,也不在裁切阶段做去马赛克、色彩转换、8-bit量化或归一化。这些操作都属于具体模型的输入预处理。

Chapter 06 · CFexpress

真实卡数据冻结:卡读取仍是最终物理瓶颈

CFexpress卡已经推出,不再重复插卡。下面保留当天已完成的只读测量;卡端端到端数字是把这些测量与新的本地三级流水线组合得到的估算,明确不冒充重新实测。

已冻结测量工况三次结果 / 中位吞吐判断
真实tile只读1000张,2.900GB,12线程,F_NOCACHE2.041 / 2.064 / 2.182s中位1.405GB/s12线程最佳;16线程无收益
旧卡读 + CPU SOF3 + Bayer16 ROI1000张,16 workers2.235 / 2.312 / 2.485s中位1.254GB/s输入说明CPU计算仅在卡读上增加约0.25s量级
内部SSD顺序写16GiB,F_NOCACHE + fsync2.833s6.064GB/s明显快于卡读

卡端推荐768–1024 tiles/批

卡填满这两种批次约需179–239ms;本地测得GPU墙钟约173–183ms,writer约42–43ms。三段时间接近时可以让GPU和SSD写入藏在下一批卡读取后面,同时减少首批填充与末批排空。

卡端完整时间约2.28–2.29秒

组合估算

估算包含最后一批排空,比2.064秒纯卡读只多约0.22秒。它结合了此前真实卡读和今天本地阶段数据;由于卡已推出,这不是新的卡端完整实测。

真实卡读下限:2.064 s / 1000张 推荐卡端批次:768–1024 tiles 卡填充:约179–239 ms/批 对应GPU墙钟:约173–183 ms/批 对应SSD写:约42–43 ms/批 估算完整流水线(含末批排空):2.279–2.290 s / 1000张
是否还有必要继续优化裁切延迟?结论:暂时没有必要做更多算子级微优化。

卡端工作时,1.405GB/s的真实读取已经决定主节拍;GPU解码和内部SSD写入能通过三级流水线被大部分隐藏。接下来的工程优先级应是正确性、容错、队列背压、可恢复shard与metadata,而不是继续压榨几十毫秒。只有改用内部SSD作为长期输入、换更快读卡链路,或模型预处理成为新瓶颈时,才值得重新扫参。

Implementation

落地参数与故障边界

参数分“本地输入”和“真实卡输入”两套。最重要的是用字节容量做背压,而不是只按照片数量;长尾大框会让单张照片的tile与输出体积相差数十倍。

本地高吞吐档

批次最多3072 tiles
Stage 112线程读/组批
Stage 2单Metal批;一个线程/独立tile
Stage 3单writer,16MiB pwrite
队列两条depth-1有界队列
峰值footprint约8.01GB

CFexpress低延迟档

批次768–1024 tiles
卡读取12线程;物理offset合并
GPU大批Metal,不逐图提交
writer内部SSD,不写回CFexpress
shard512MB–2GB + 小索引
二次压缩默认关闭
输入与恢复
任务可重放

索引记录source id、ARW checksum、ROI、批次与shard边界;崩溃后从最后确认的shard继续,不要求全部内存状态仍在。

算子回退
Metal → 自写CPU → libjpeg-turbo

支持的标准SOF3批量走GPU;尾批或GPU不可用走CPU;遇到未覆盖布局交给libjpeg兼容路径,并记录而不是静默改像素。

输出提交
先写数据,再提交索引

shard顺序写与fsync完成后原子提交索引;消费者只读取已提交范围,避免进程退出后拿到半条ROI。

持续遥测
按阶段记录等待与服务时间

分别统计read/build、GPU wall/device、writer、队列等待、RSS、footprint、Metal allocation、swap与错误tile,避免只看整体吞吐误判瓶颈。

Audit

证据边界与可复核结论

本报告把完整实测、算子实测、真实卡测量和组合估算分开。没有把“GPU纯算子峰值”写成“整机吞吐”,也没有把卡已推出后的模型推算写成重新实测。

完整实测

本地1000张的读取/组批、Metal SOF3+Bayer16 ROI、真实内部SSD分片写与fsync;9档批量扫描;输出大小、shard大小、抽样ROI、错误tile、RSS、footprint和swap检查。

独立实测

自写CPU与libjpeg-turbo对比;Metal从256到9216 tiles的占用扫描;真实CFexpress 1000张tile只读三次;内部SSD 16GiB顺序写。

组合估算

卡端768–1024 tiles批次及2.279–2.290秒端到端时间。估算依据是已冻结卡读和本地各阶段时间,需在下次卡可用时用同一程序复测。

不在本轮范围

上游框语义正确性;YOLO Pose、YOLO CLS、SAM最终输入几何和精度;模型预处理Metal kernel;推理/训练吞吐;读卡器温度与电源状态。

P50与P99是什么意思?

P50是中位数:一半样本低于它,一半高于它。P99是第99百分位:约99%的样本不超过该值,只剩最慢或最大的约1%更高。百分位不是平均数,也不是最大值;它用于同时描述典型情况和长尾。

Evidence

来源与复核文件

本地JSON与源码是性能和正确性证据;外部链接只用于解释芯片、Metal共享内存与无损JPEG接口能力。

  1. Apple:M5 MacBook Pro技术规格
  2. Apple Metal:统一内存设备属性
  3. Apple Metal:资源存储模式
  4. libjpeg-turbo:无损JPEG与高位深接口
  5. CompactFlash Association:CFexpress卡型与PCIe lane
  6. 完整流水线数据:arw-crop-staged-cpu-gpu-pipeline-m5-2026-08-26.json
  7. GPU占用数据:sof3-gpu-saturation-m5-2026-08-26.json
  8. CPU/GPU算子数据:sof3-decoder-cpu-metal-m5-2026-08-26.json
  9. 旧CPU端到端Bayer16数据:sof3-custom-end-to-end-bayer16-m5-2026-08-26.json
  10. 真实卡与SSD证据:cfa-card-rgb-spool-analysis-2026-08-26.json;只采用其中读取/写入实测,旧RGB决策已废弃。
  11. 完整流水线源码:arw_crop_staged_pipeline_bench.mm
  12. SOF3 CPU/GPU源码:sof3_decode_bench.mm、sof3_gpu_saturation_bench.mm、native_pipeline_bench.cpp