Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 44 additions & 0 deletions swe-paddle/tasks/PaddlePaddle__Paddle-40111/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# PaddlePaddle__Paddle-40111

This directory converts Paddle PR #40111 into a SWE-Paddle community task candidate.

## Source

| Field | Value |
| --- | --- |
| Repo | `PaddlePaddle/Paddle` |
| PR | [#40111](https://github.com/PaddlePaddle/Paddle/pull/40111) |
| PR title | `add profiler statistic helper` |
| Base commit | `10325a82e1032c3397b6f6611f558eb18ede0b07` |
| Merged at | `2022-03-08T01:55:55Z` |
| Task type | `feature_enhancement` |
| Resource | CPU |

## Summary

Add deterministic interval operations for profiler statistics, including duration summation, normalization, union, intersection, and subtraction.

## Why This Is A Good SWE-Paddle Candidate

- The 225-line Python production change contains substantial interval-processing logic with meaningful edge cases.
- The source PR includes a focused 137-line unit test file, preserved byte-for-byte in the task patch.
- Tests cover sorted and unsorted input, overlap, containment, adjacency, disjoint ranges, empty ranges, and zero-length ranges.
- Verification is deterministic and CPU-only, with no operator execution, graph mode, model loading, network, or external service.

## Files

- `proposal.md`: candidate proposal for maintainer triage.
- `instruction.md`: self-contained problem statement for the coding agent.
- `solution/code.patch`: gold patch from the merged PR.
- `tests/test.patch`: exact upstream tests plus checkout-loading support and separate P2P coverage.
- `tests/test.sh`: minimal target test command.
- `environment/README.md`: environment notes for reproduction.
- `README.md`: task overview and verification entrypoint.

## Verification

```bash
bash tests/test.sh
```

Expected behavior: applying `tests/test.patch` to `base_commit` should keep the existing profiler scheduler case passing while the interval operations fail; applying both `tests/test.patch` and `solution/code.patch` should pass all target tests.
27 changes: 27 additions & 0 deletions swe-paddle/tasks/PaddlePaddle__Paddle-40111/environment/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Environment Notes

This candidate is part of the SWE-Paddle community task set.

## Expected Environment

- Repository: `PaddlePaddle/Paddle`
- Base commit: `10325a82e1032c3397b6f6611f558eb18ede0b07`
- Resource: CPU
- GPU required: no
- Build path: no source build is required; the exact upstream test file loads the checkout Python module directly.

## Run Order

1. Check out `PaddlePaddle/Paddle` at the base commit.
2. Apply `tests/test.patch`.
3. Run `bash tests/test.sh`; the target behavior should fail before the fix.
4. Apply `solution/code.patch`.
5. Run `bash tests/test.sh` again; the target behavior should pass after the gold patch.

## Minimal Test Command

```bash
bash tests/test.sh
```

The verifier is responsible for deriving stable F2P and P2P node IDs from repeated runs.
19 changes: 19 additions & 0 deletions swe-paddle/tasks/PaddlePaddle__Paddle-40111/instruction.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# 补齐 profiler 的时间区间统计能力

## 详细描述

Profiler 收集到的事件通常由一组开始时间和结束时间组成。同一批事件里可能存在重叠、包含、首尾相接或顺序打乱的区间。生成统计结果时,如果直接把每段时间相加,容易重复计算;在计算两类事件同时发生的时间或排除某类事件的耗时时,也容易遗漏边界情况。

需要为 profiler 提供一套统一的时间区间处理能力,能够整理单组区间,并计算两组区间合并、重叠和相减后的结果。调用方传入的区间可能已经排序,也可能是无序的,空列表和零长度区间也应得到稳定结果。

## 验收说明

- 能正确汇总区间长度,并将重叠或首尾相接的区间整理为有序且不重复的结果。
- 两组区间的合并、交集和相减在部分重叠、完全包含、互不相交等情况下均返回正确结果。
- 已排序、未排序、空列表和零长度区间都能正常处理,现有 profiler scheduler 行为保持不变。

## 技术要求

- 熟悉 Python 列表与区间处理。
- 熟悉 profiler 事件时间统计的基本含义。
- 能处理排序、边界和空输入等情况。
55 changes: 55 additions & 0 deletions swe-paddle/tasks/PaddlePaddle__Paddle-40111/proposal.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# Task Proposal: PaddlePaddle__Paddle-40111

## 1. 来源信息

- Instance ID:`PaddlePaddle__Paddle-40111`
- PR 链接:https://github.com/PaddlePaddle/Paddle/pull/40111
- PR 标题:`add profiler statistic helper`
- `base_commit`:`10325a82e1032c3397b6f6611f558eb18ede0b07`
- merged 时间:`2022-03-08T01:55:55Z`
- 你的身份:熟悉该模块的 contributor
- 后续联系人:TBD

## 2. 问题一句话

为 profiler 增加可靠的时间区间归并、交集和差集计算,避免统计重叠事件时重复计时或漏计。

## 3. 为什么适合作为 SWE-Paddle 样本

- **真实性**:来源 PR 为 profiler 性能统计补充了实际需要的时间区间运算能力。
- **代表性**:覆盖排序、重叠、包含、相邻、空输入以及两个区间集合之间的组合运算。
- **边界清楚**:production change 仅新增一个 225 行 Python helper,不涉及算子、模型加载或图执行。
- **非平凡性**:多个双指针分支需要保持有序输出并正确处理边界,无法靠单点特判完成。
- **环境友好性**:来源 PR 的 137 行单测保持 exact blob;测试直接加载 checkout 文件,可在纯 CPU 环境运行。

## 4. 任务类型和标签

- 任务类型:`feature_enhancement`
- 执行后端:`cpu`
- 设备范围:`cpu_only`
- 模块标签:`[profiler, statistics, intervals, python]`

## 5. 验证思路

- 目标测试命令:`bash tests/test.sh`
- 目标测试文件:`test/swe_paddle/test_pr40111_profiler_ranges.py`
- 修复前预期:现有 profiler scheduler 的 P2P 通过;来源 PR 的 merge、intersection 与 subtract 用例因区间工具缺失而失败。
- 修复后预期:P2P 和来源 PR 的全部 10 个区间测试通过;`tests/test.sh` 通过 adapter 运行 exact upstream test file。
- P2P 候选:现有 profiler scheduler 在 closed、ready、record 和 record-and-return 状态之间的切换顺序保持不变。

## 6. 环境与资源

- 资源需求:CPU
- Paddle 来源:`PaddlePaddle/Paddle` source checkout at `base_commit`
- 是否能提供 Docker:暂无
- patch 类型:Python-only
- 环境建议:无需 source build 或 Paddle wheel;adapter 直接执行 checkout 中的 Python 文件和 exact upstream tests。
- 最小测试命令:`bash tests/test.sh`
- 是否有 oracle 日志:由 SWE-Paddle verifier 结果另行维护

## 7. 风险自查

- 泄露风险:instruction 只说明所需区间行为,不描述 Gold patch 的循环结构或局部变量。
- 环境风险:测试不访问网络,不加载模型,也不依赖 GPU、算子或动态图/静态图。
- flaky 风险:所有输入均为确定性的整数区间,没有计时、并发或随机因素。
- 拆分风险:来源 PR 只新增一个 production helper 和对应单测,专注于同一统计问题。
231 changes: 231 additions & 0 deletions swe-paddle/tasks/PaddlePaddle__Paddle-40111/solution/code.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,231 @@
diff --git a/python/paddle/profiler/statistic_helper.py b/python/paddle/profiler/statistic_helper.py
new file mode 100644
index 0000000000000000000000000000000000000000..1f11649928a7fe72b0a4ae6f368c3c92debf060c
--- /dev/null
+++ b/python/paddle/profiler/statistic_helper.py
@@ -0,0 +1,225 @@
+# Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved.
+#
+# Licensed 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.
+import collections
+
+
+def sum_ranges(ranges):
+ result = 0
+ for time_range in ranges:
+ result += (time_range[1] - time_range[0])
+ return result
+
+
+def merge_self_ranges(src_ranges, is_sorted=False):
+ merged_ranges = []
+ if len(src_ranges) > 0:
+ if not is_sorted:
+ src_ranges.sort(key=lambda x: x[0])
+ cur_indx = 0
+ merged_ranges.append((src_ranges[cur_indx][0], src_ranges[cur_indx][1]))
+ for cur_indx in range(1, len(src_ranges)):
+ if src_ranges[cur_indx][1] > merged_ranges[-1][1]:
+ if src_ranges[cur_indx][0] <= merged_ranges[-1][1]:
+ merged_ranges[-1] = (merged_ranges[-1][0],
+ src_ranges[cur_indx][1])
+ else:
+ merged_ranges.append(
+ (src_ranges[cur_indx][0], src_ranges[cur_indx][1]))
+ return merged_ranges
+
+
+def merge_ranges(range_list1, range_list2, is_sorted=False):
+ merged_ranges = []
+ if not is_sorted:
+ range_list1 = merge_self_ranges(range_list1)
+ range_list2 = merge_self_ranges(range_list2)
+ len1 = len(range_list1)
+ len2 = len(range_list2)
+ if len1 == 0 and len2 == 0:
+ return merged_ranges
+ elif len1 == 0:
+ return range_list2
+ elif len2 == 0:
+ return range_list1
+ else:
+ indx1 = 0
+ indx2 = 0
+ range1 = range_list1[indx1]
+ range2 = range_list2[indx2]
+ if range1[0] < range2[0]:
+ merged_ranges.append(range1)
+ indx1 += 1
+ else:
+ merged_ranges.append(range2)
+ indx2 += 1
+ while indx1 < len1 and indx2 < len2:
+ range1 = range_list1[indx1]
+ range2 = range_list2[indx2]
+ if range1[0] < range2[0]:
+ if range1[1] > merged_ranges[-1][1]:
+ if range1[0] <= merged_ranges[-1][1]:
+ merged_ranges[-1] = (merged_ranges[-1][0], range1[1])
+ else:
+ merged_ranges.append((range1[0], range1[1]))
+ indx1 += 1
+ else:
+ indx1 += 1
+ else:
+ if range2[1] > merged_ranges[-1][1]:
+ if range2[0] <= merged_ranges[-1][1]:
+ merged_ranges[-1] = (merged_ranges[-1][0], range2[1])
+ else:
+ merged_ranges.append((range2[0], range2[1]))
+ indx2 += 1
+ else:
+ indx2 += 1
+
+ while indx1 < len1:
+ range1 = range_list1[indx1]
+ if range1[1] > merged_ranges[-1][1]:
+ if range1[0] <= merged_ranges[-1][1]:
+ merged_ranges[-1] = (merged_ranges[-1][0], range1[1])
+ else:
+ merged_ranges.append((range1[0], range1[1]))
+ indx1 += 1
+ else:
+ indx1 += 1
+ while indx2 < len2:
+ if range2[1] > merged_ranges[-1][1]:
+ if range2[0] <= merged_ranges[-1][1]:
+ merged_ranges[-1] = (merged_ranges[-1][0], range2[1])
+ else:
+ merged_ranges.append((range2[0], range2[1]))
+ indx2 += 1
+ else:
+ indx2 += 1
+ return merged_ranges
+
+
+def intersection_ranges(range_list1, range_list2, is_sorted=False):
+ result_range = []
+ if len(range_list1) == 0 or len(range_list2) == 0:
+ return result_range
+ if not is_sorted:
+ range_list1 = merge_self_ranges(range_list1)
+ range_list2 = merge_self_ranges(range_list2)
+
+ len1 = len(range_list1)
+ len2 = len(range_list2)
+ indx1 = 0
+ indx2 = 0
+ range1 = range_list1[indx1]
+ range2 = range_list2[indx2]
+ while indx1 < len1 and indx2 < len2:
+ if range2[1] <= range1[0]:
+ indx2 += 1
+ if indx2 == len2:
+ break
+ range2 = range_list2[indx2]
+
+ elif range2[0] <= range1[0] and range2[1] < range1[1]:
+ assert (range2[1] > range1[0])
+ result_range.append((range1[0], range2[1]))
+ range1 = (range2[1], range1[1])
+ indx2 += 1
+ if indx2 == len2:
+ break
+ range2 = range_list2[indx2]
+
+ elif range2[0] <= range1[0]:
+ assert (range2[1] >= range1[1])
+ result_range.append(range1)
+ range2 = (range1[1], range2[1])
+ indx1 += 1
+ if indx1 == len1:
+ break
+ range1 = range_list1[indx1]
+
+ elif range2[1] < range1[1]:
+ assert (range2[0] > range1[0])
+ result_range.append(range2)
+ range1 = (range2[1], range1[1])
+ indx2 += 1
+ if indx2 == len2:
+ break
+ range2 = range_list2[indx2]
+
+ elif range2[0] < range1[1]:
+ assert (range2[1] >= range1[1])
+ result_range.append((range2[0], range1[1]))
+ range2 = (range1[1], range2[1])
+ indx1 += 1
+ if indx1 == len1:
+ break
+ range1 = range_list1[indx1]
+
+ else:
+ assert (range2[0] >= range1[1])
+ indx1 += 1
+ if indx1 == len1:
+ break
+ range1 = range_list1[indx1]
+ return result_range
+
+
+def subtract_ranges(range_list1, range_list2, is_sorted=False):
+ result_range = []
+ if not is_sorted:
+ range_list1 = merge_self_ranges(range_list1)
+ range_list2 = merge_self_ranges(range_list2)
+ if len(range_list1) == 0:
+ return result_range
+ if len(range_list2) == 0:
+ return range_list1
+
+ len1 = len(range_list1)
+ len2 = len(range_list2)
+ indx1 = 0
+ indx2 = 0
+ range1 = range_list1[indx1]
+ range2 = range_list2[indx2]
+
+ while indx1 < len(range_list1):
+ if indx2 == len(range_list2):
+ result_range.append(range1)
+ indx1 += 1
+ if indx1 == len1:
+ break
+ range1 = range_list1[indx1]
+ elif range2[1] <= range1[0]:
+ indx2 += 1
+ if indx2 != len2:
+ range2 = range_list2[indx2]
+ elif range2[0] <= range1[0] and range2[1] < range1[1]:
+ range1 = (range2[1], range1[1])
+ indx2 += 1
+ if indx2 != len2:
+ range2 = range_list2[indx2]
+ elif range2[0] <= range1[0]:
+ assert (range2[1] >= range1[1])
+ range2 = (range1[1], range2[1])
+ indx1 += 1
+ if indx1 != len1:
+ range1 = range_list1[indx1]
+ elif range2[0] < range1[1]:
+ assert (range2[0] > range1[0])
+ result_range.append((range1[0], range2[0]))
+ range1 = (range2[0], range1[1])
+ else:
+ assert (range2[0] >= range1[1])
+ result_range.append(range1)
+ indx1 += 1
+ if indx1 != len1:
+ range1 = range_list1[indx1]
+ return result_range
Loading