This is an automated email from the ASF dual-hosted git repository.

jt2594838 pushed a commit to branch add_bitmap_long_imple
in repository https://gitbox.apache.org/repos/asf/tsfile.git

commit d3b9b33df42f7d054a22082c57851541206e1395
Author: Tian Jiang <[email protected]>
AuthorDate: Tue Jul 21 09:43:23 2026 +0800

    Add BitMap performance test report
---
 java/tsfile/BitMapPerformanceTestReport.md | 119 +++++++++++++++++++++++++++++
 1 file changed, 119 insertions(+)

diff --git a/java/tsfile/BitMapPerformanceTestReport.md 
b/java/tsfile/BitMapPerformanceTestReport.md
new file mode 100644
index 000000000..9f1da4c2e
--- /dev/null
+++ b/java/tsfile/BitMapPerformanceTestReport.md
@@ -0,0 +1,119 @@
+<!--
+
+    Licensed to the Apache Software Foundation (ASF) under one
+    or more contributor license agreements.  See the NOTICE file
+    distributed with this work for additional information
+    regarding copyright ownership.  The ASF licenses this file
+    to you under the Apache License, Version 2.0 (the
+    "License"); you may not use this file except in compliance
+    with the License.  You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing,
+    software distributed under the License is distributed on an
+    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+    KIND, either express or implied.  See the License for the
+    specific language governing permissions and limitations
+    under the License.
+
+-->
+
+# BitMap 长度 64 双实现测试报告
+
+## 测试结论
+
+测试通过。`BitMapLongImpl` 在长度为 64 
时显著降低内存占用,并在单点读写、全量状态判断、`markAll/reset`、`clone`、`merge` 和 `append` 等主要位操作上优于 
`BitMapArrayImpl`。
+
+需要关注的代价是:`BitMapLongImpl` 调用字节数组序列化接口时需要临时生成 `byte[]`,因此 
`getByteArray`、`getTruncatedByteArray` 和从字节数组构造的性能较慢。优化后的 
`equals/equalsInRange` 不再生成临时数组,Long 实现比 Array 实现快约 43.6%;`hashCode` 
同样已消除临时数组,但逐字节计算仍比 JVM 优化后的 `Arrays.hashCode` 慢约 34.5%。
+
+## 测试信息
+
+| 项目 | 内容 |
+| --- | --- |
+| 测试时间 | 2026-07-20 19:23–19:28(Asia/Hong_Kong) |
+| Git 分支 | `develop` |
+| Git 基线 | `b8825b18`,包含工作区内本次 BitMap 修改 |
+| 操作系统 | Windows 11 amd64,10.0.26200.0 |
+| 处理器 | Intel64 Family 6 Model 151,24 个逻辑处理器 |
+| JDK | Oracle Java 21.0.8,64-bit HotSpot VM |
+| Maven | Apache Maven 3.9.11 |
+| BitMap 长度 | 64 |
+
+执行命令:
+
+```powershell
+mvn.cmd -P with-java -pl java/tsfile -am test `
+  "-Dtest=BitMapTest,TabletTest,FloatDecoderTest,BitMapPerformanceTest" `
+  "-Dtsfile.runPerformanceTests=true" `
+  "-Dsurefire.failIfNoSpecifiedTests=false"
+```
+
+## 正确性与回归测试
+
+| 测试类 | 用例数 | Failure | Error | Skipped | 耗时 |
+| --- | ---: | ---: | ---: | ---: | ---: |
+| `BitMapTest` | 15 | 0 | 0 | 0 | 68.998 s |
+| `TabletTest` | 15 | 0 | 0 | 0 | 0.268 s |
+| `FloatDecoderTest` | 7 | 0 | 0 | 0 | 0.251 s |
+| `BitMapPerformanceTest` | 1 | 0 | 0 | 0 | 1.592 s |
+| **合计** | **38** | **0** | **0** | **0** | **71.109 s** |
+
+Long 专用 `hashCode` 路径完成后,又定向执行了跨实现 equals/hash、动态工厂选择和性能测试,共 3 个用例,结果同样为 0 
Failure、0 Error、0 Skipped。
+
+验证范围包括:
+
+- public 构造函数固定使用 `BitMapArrayImpl`,`createDynamicBitMap` 在长度不大于 64 时选择 
`BitMapLongImpl`,以及 `64 -> 65` 扩容迁移;
+- 单点和范围标记、重置、全量状态判断;
+- 长度 64 的完整范围操作、字节数组转换、克隆,以及 Array–Long 双向 equals、范围比较和哈希一致性;
+- `merge` 的长度、源偏移和目标偏移穷举组合;
+- Tablet 序列化、反序列化、追加和空值位图处理;
+- Float 编解码中 BitMap 的序列化与反序列化路径。
+
+## 性能测试方法
+
+- 两种实现均通过相同的 `BitMap` 公共接口执行;
+- 每项测试预热 3 轮、测量 7 轮,交替改变两种实现的执行顺序;
+- 报告值为 7 轮测量的中位数,单位为 ns/op;
+- 写操作使用变化中的位置和状态,序列化/复制结果写入逃逸容器,降低 JIT 消除实际操作的可能;
+- `Long/Array < 1` 表示 `BitMapLongImpl` 更快,`Long/Array > 1` 表示 
`BitMapArrayImpl` 更快。
+
+## 性能结果
+
+| 操作 | ArrayImpl ns/op | LongImpl ns/op | Long/Array | 结果 |
+| --- | ---: | ---: | ---: | --- |
+| `isMarked` | 0.542 | 0.358 | 0.660x | Long 快约 34.0% |
+| `isAllMarked/isAllUnmarked` | 5.173 | 1.715 | 0.331x | Long 快约 66.9% |
+| `mark/unmark`(单次写) | 1.300 | 1.107 | 0.852x | Long 快约 14.8% |
+| `markRange/unmarkRange`(单次写) | 3.048 | 2.301 | 0.755x | Long 快约 24.5% |
+| `markAll/reset`(单次写) | 3.066 | 0.541 | 0.176x | Long 快约 82.4% |
+| `getByteArray` | 1.497 | 4.858 | 3.246x | Long 慢约 3.25 倍 |
+| `getTruncatedByteArray` | 8.987 | 14.068 | 1.565x | Long 慢约 56.5% |
+| 从 `byte[]` 构造 | 8.027 | 10.218 | 1.273x | Long 慢约 27.3% |
+| `clone` | 10.432 | 4.014 | 0.385x | Long 快约 61.5% |
+| `merge` | 9.943 | 2.748 | 0.276x | Long 快约 72.4% |
+| `append` | 85.240 | 61.024 | 0.716x | Long 快约 28.4% |
+| `getRegion` | 114.356 | 88.900 | 0.777x | Long 快约 22.3% |
+| `equals/equalsInRange` | 5.402 | 3.045 | 0.564x | Long 快约 43.6% |
+| `hashCode` | 4.412 | 5.933 | 1.345x | Long 慢约 34.5% |
+| `toString` | 151.272 | 125.010 | 0.826x | Long 快约 17.4% |
+
+## 内存占用
+
+内存数据由 `RamUsageEstimator` 按当前 JVM 的对象头、引用宽度和 8 字节对象对齐规则估算,包含 `BitMap` 
外层对象、具体实现对象以及数组实现的 `byte[]`。
+
+| 场景 | BitMapArrayImpl | BitMapLongImpl | 节省 |
+| --- | ---: | ---: | ---: |
+| 单个长度 64 的 BitMap | 72 bytes | 40 bytes | 32 bytes,44.44% |
+| 1,000,000 个 BitMap(含引用数组) | 76,000,016 bytes | 44,000,016 bytes | 32,000,000 
bytes,约 30.52 MiB |
+
+## 分析与建议
+
+1. 对以标记、查询、合并和克隆为主的长度不大于 64 的 BitMap,使用 `BitMapLongImpl` 可以同时获得更低内存占用和更好的性能。
+2. `getByteArray` 是 Long 实现最明显的性能退化点,因为每次调用都需要将 `long` 
展开为新的字节数组。应避免在高频路径中重复调用,可在调用方一次生成后复用结果。
+3. `equals`、`equalsInRange` 和 `hashCode` 已改为实现层直接计算,不再间接生成字节数组。Long 的 equals 
组合已优于 Array;Long 的 hashCode 虽已显著降低成本,但仍可考虑针对固定 9 字节序列进一步展开计算。
+4. public 构造函数保留数组实现及其可变 `byte[]` 兼容语义;需要按长度节省内存时,应显式使用 `createDynamicBitMap`。
+
+## 限制
+
+本测试是项目内 JUnit 微基准,不是 JMH 基准。预热、中位数统计、交替执行和逃逸容器可以降低常见测量误差,但绝对 ns/op 仍会受到 CPU 
频率、JIT 编译、GC 和后台负载影响。跨机器或跨 JVM 比较时应在相同环境中重新运行,重点观察相对倍率而非绝对耗时。

Reply via email to