diff --git a/swe-paddle/tasks/PaddlePaddle__Paddle-40111/README.md b/swe-paddle/tasks/PaddlePaddle__Paddle-40111/README.md new file mode 100644 index 000000000..7804ac238 --- /dev/null +++ b/swe-paddle/tasks/PaddlePaddle__Paddle-40111/README.md @@ -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. diff --git a/swe-paddle/tasks/PaddlePaddle__Paddle-40111/environment/README.md b/swe-paddle/tasks/PaddlePaddle__Paddle-40111/environment/README.md new file mode 100644 index 000000000..7b28432a7 --- /dev/null +++ b/swe-paddle/tasks/PaddlePaddle__Paddle-40111/environment/README.md @@ -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. diff --git a/swe-paddle/tasks/PaddlePaddle__Paddle-40111/instruction.md b/swe-paddle/tasks/PaddlePaddle__Paddle-40111/instruction.md new file mode 100644 index 000000000..528620671 --- /dev/null +++ b/swe-paddle/tasks/PaddlePaddle__Paddle-40111/instruction.md @@ -0,0 +1,19 @@ +# 补齐 profiler 的时间区间统计能力 + +## 详细描述 + +Profiler 收集到的事件通常由一组开始时间和结束时间组成。同一批事件里可能存在重叠、包含、首尾相接或顺序打乱的区间。生成统计结果时,如果直接把每段时间相加,容易重复计算;在计算两类事件同时发生的时间或排除某类事件的耗时时,也容易遗漏边界情况。 + +需要为 profiler 提供一套统一的时间区间处理能力,能够整理单组区间,并计算两组区间合并、重叠和相减后的结果。调用方传入的区间可能已经排序,也可能是无序的,空列表和零长度区间也应得到稳定结果。 + +## 验收说明 + +- 能正确汇总区间长度,并将重叠或首尾相接的区间整理为有序且不重复的结果。 +- 两组区间的合并、交集和相减在部分重叠、完全包含、互不相交等情况下均返回正确结果。 +- 已排序、未排序、空列表和零长度区间都能正常处理,现有 profiler scheduler 行为保持不变。 + +## 技术要求 + +- 熟悉 Python 列表与区间处理。 +- 熟悉 profiler 事件时间统计的基本含义。 +- 能处理排序、边界和空输入等情况。 diff --git a/swe-paddle/tasks/PaddlePaddle__Paddle-40111/proposal.md b/swe-paddle/tasks/PaddlePaddle__Paddle-40111/proposal.md new file mode 100644 index 000000000..971cdb6de --- /dev/null +++ b/swe-paddle/tasks/PaddlePaddle__Paddle-40111/proposal.md @@ -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 和对应单测,专注于同一统计问题。 diff --git a/swe-paddle/tasks/PaddlePaddle__Paddle-40111/solution/code.patch b/swe-paddle/tasks/PaddlePaddle__Paddle-40111/solution/code.patch new file mode 100644 index 000000000..aefe229cf --- /dev/null +++ b/swe-paddle/tasks/PaddlePaddle__Paddle-40111/solution/code.patch @@ -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 diff --git a/swe-paddle/tasks/PaddlePaddle__Paddle-40111/tests/test.patch b/swe-paddle/tasks/PaddlePaddle__Paddle-40111/tests/test.patch new file mode 100644 index 000000000..3c0daf911 --- /dev/null +++ b/swe-paddle/tasks/PaddlePaddle__Paddle-40111/tests/test.patch @@ -0,0 +1,284 @@ +diff --git a/python/paddle/fluid/tests/unittests/test_newprofiler_helper.py b/python/paddle/fluid/tests/unittests/test_newprofiler_helper.py +new file mode 100644 +index 0000000000000000000000000000000000000000..05e792003545688cfef3f1c7bd48ecf4d27daafe +--- /dev/null ++++ b/python/paddle/fluid/tests/unittests/test_newprofiler_helper.py +@@ -0,0 +1,137 @@ ++# 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. ++ ++from __future__ import print_function ++ ++import unittest ++ ++import paddle.profiler.statistic_helper as statistic_helper ++ ++ ++class TestStatisticHelper(unittest.TestCase): ++ def test_sum_ranges_case1(self): ++ src = [(1, 3), (4, 10), (11, 15)] ++ self.assertEqual(statistic_helper.sum_ranges(src), 12) ++ ++ def test_sum_ranges_case2(self): ++ src = [(3, 3), (5, 5), (7, 7)] ++ self.assertEqual(statistic_helper.sum_ranges(src), 0) ++ ++ def test_merge_self_ranges_case1(self): ++ src = [(1, 5), (2, 7), (4, 9), (14, 19)] ++ dst = statistic_helper.merge_self_ranges(src) ++ self.assertEqual(dst, [(1, 9), (14, 19)]) ++ src = [(4, 9), (14, 19), (1, 5), (2, 7)] ++ dst = statistic_helper.merge_self_ranges(src) ++ self.assertEqual(dst, [(1, 9), (14, 19)]) ++ ++ def test_merge_self_ranges_case2(self): ++ src = [(1, 1), (2, 3), (4, 7), (5, 12)] ++ dst = statistic_helper.merge_self_ranges(src) ++ self.assertEqual(dst, [(1, 1), (2, 3), (4, 12)]) ++ src = [(5, 12), (1, 1), (2, 3), (4, 7)] ++ dst = statistic_helper.merge_self_ranges(src) ++ self.assertEqual(dst, [(1, 1), (2, 3), (4, 12)]) ++ ++ def test_merge_ranges_case1(self): ++ src1 = [(1, 2), (5, 7), (9, 14)] ++ src2 = [(1, 2), (4, 9), (13, 15)] ++ dst = statistic_helper.merge_ranges(src1, src2) ++ self.assertEqual(dst, [(1, 2), (4, 15)]) ++ dst = statistic_helper.merge_ranges(src1, src2, True) ++ self.assertEqual(dst, [(1, 2), (4, 15)]) ++ src1 = [] ++ src2 = [] ++ dst = statistic_helper.merge_ranges(src1, src2, True) ++ self.assertEqual(dst, []) ++ src1 = [(1, 2), (3, 5)] ++ src2 = [] ++ dst = statistic_helper.merge_ranges(src1, src2, True) ++ self.assertEqual(dst, src1) ++ src1 = [] ++ src2 = [(1, 2), (3, 5)] ++ dst = statistic_helper.merge_ranges(src1, src2, True) ++ self.assertEqual(dst, src2) ++ src1 = [(3, 4), (1, 2), (17, 19)] ++ src2 = [(6, 9), (13, 15)] ++ dst = statistic_helper.merge_ranges(src1, src2) ++ self.assertEqual(dst, [(1, 2), (3, 4), (6, 9), (13, 15), (17, 19)]) ++ dst = statistic_helper.merge_ranges(src2, src1) ++ self.assertEqual(dst, [(1, 2), (3, 4), (6, 9), (13, 15), (17, 19)]) ++ src1 = [(1, 2), (5, 9), (12, 13)] ++ src2 = [(6, 8), (9, 15)] ++ dst = statistic_helper.merge_ranges(src1, src2) ++ self.assertEqual(dst, [(1, 2), (5, 15)]) ++ dst = statistic_helper.merge_ranges(src2, src1) ++ self.assertEqual(dst, [(1, 2), (5, 15)]) ++ ++ def test_merge_ranges_case2(self): ++ src1 = [(3, 4), (1, 2), (9, 14)] ++ src2 = [(6, 9), (13, 15)] ++ dst = statistic_helper.merge_ranges(src1, src2) ++ self.assertEqual(dst, [(1, 2), (3, 4), (6, 15)]) ++ src2 = [(9, 14), (1, 2), (5, 7)] ++ src1 = [(4, 9), (1, 2), (13, 15)] ++ dst = statistic_helper.merge_ranges(src1, src2) ++ self.assertEqual(dst, [(1, 2), (4, 15)]) ++ ++ def test_intersection_ranges_case1(self): ++ src1 = [(1, 7), (9, 12), (14, 18)] ++ src2 = [(3, 8), (10, 13), (15, 19)] ++ dst = statistic_helper.intersection_ranges(src1, src2) ++ self.assertEqual(dst, [(3, 7), (10, 12), (15, 18)]) ++ dst = statistic_helper.intersection_ranges(src1, src2, True) ++ self.assertEqual(dst, [(3, 7), (10, 12), (15, 18)]) ++ src1 = [] ++ src2 = [] ++ dst = statistic_helper.intersection_ranges(src1, src2, True) ++ self.assertEqual(dst, []) ++ src1 = [(3, 7), (10, 12)] ++ src2 = [(2, 9), (11, 13), (15, 19)] ++ dst = statistic_helper.intersection_ranges(src1, src2) ++ self.assertEqual(dst, [(3, 7), (11, 12)]) ++ dst = statistic_helper.intersection_ranges(src2, src1) ++ self.assertEqual(dst, [(3, 7), (11, 12)]) ++ ++ def test_intersection_ranges_case2(self): ++ src2 = [(9, 12), (1, 7), (14, 18)] ++ src1 = [(10, 13), (3, 8), (15, 19), (20, 22)] ++ dst = statistic_helper.intersection_ranges(src1, src2) ++ self.assertEqual(dst, [(3, 7), (10, 12), (15, 18)]) ++ src2 = [(1, 7), (14, 18), (21, 23)] ++ src1 = [(6, 9), (10, 13)] ++ dst = statistic_helper.intersection_ranges(src1, src2, True) ++ self.assertEqual(dst, [(6, 7)]) ++ ++ def test_subtract_ranges_case1(self): ++ src1 = [(1, 10), (12, 15)] ++ src2 = [(3, 7), (9, 11)] ++ dst = statistic_helper.subtract_ranges(src1, src2, True) ++ self.assertEqual(dst, [(1, 3), (7, 9), (12, 15)]) ++ src1 = [(1, 10), (12, 15)] ++ src2 = [] ++ dst = statistic_helper.subtract_ranges(src1, src2, True) ++ self.assertEqual(dst, src1) ++ dst = statistic_helper.subtract_ranges(src2, src1, True) ++ self.assertEqual(dst, src2) ++ ++ def test_subtract_ranges_case2(self): ++ src2 = [(12, 15), (1, 10)] ++ src1 = [(9, 11), (3, 7)] ++ dst = statistic_helper.subtract_ranges(src1, src2) ++ self.assertEqual(dst, [(10, 11)]) ++ ++ ++if __name__ == '__main__': ++ unittest.main() +diff --git a/test/swe_paddle/test_pr40111_profiler_ranges.py b/test/swe_paddle/test_pr40111_profiler_ranges.py +new file mode 100644 +index 0000000000000000000000000000000000000000..88ee5e8cfed30186a8e8ed404356d338a9c7c232 +--- /dev/null ++++ b/test/swe_paddle/test_pr40111_profiler_ranges.py +@@ -0,0 +1,76 @@ ++import importlib.util ++from pathlib import Path ++import sys ++import types ++ ++ ++REPO_ROOT = Path(__file__).resolve().parents[2] ++TARGET_REL = "python/paddle/profiler/statistic_helper.py" ++UPSTREAM_TEST_REL = ( ++ "python/paddle/fluid/tests/unittests/" ++ "test_newprofiler_helper.py" ++) ++ ++ ++def _load_module(name, path): ++ spec = importlib.util.spec_from_file_location(name, path) ++ module = importlib.util.module_from_spec(spec) ++ spec.loader.exec_module(module) ++ return module ++ ++ ++def _install_checkout_statistic_helper(): ++ target = REPO_ROOT / TARGET_REL ++ ++ if target.exists(): ++ helper = _load_module( ++ "paddle.profiler.statistic_helper", ++ target, ++ ) ++ else: ++ helper = types.ModuleType( ++ "paddle.profiler.statistic_helper" ++ ) ++ ++ def unavailable(*args, **kwargs): ++ raise NotImplementedError( ++ "profiler statistic range operations " ++ "are unavailable" ++ ) ++ ++ for name in ( ++ "sum_ranges", ++ "merge_self_ranges", ++ "merge_ranges", ++ "intersection_ranges", ++ "subtract_ranges", ++ ): ++ setattr(helper, name, unavailable) ++ ++ paddle_module = sys.modules.get("paddle") ++ if paddle_module is None: ++ paddle_module = types.ModuleType("paddle") ++ paddle_module.__path__ = [] ++ ++ profiler_module = types.ModuleType("paddle.profiler") ++ profiler_module.__path__ = [] ++ profiler_module.statistic_helper = helper ++ paddle_module.profiler = profiler_module ++ ++ sys.modules["paddle"] = paddle_module ++ sys.modules["paddle.profiler"] = profiler_module ++ sys.modules[ ++ "paddle.profiler.statistic_helper" ++ ] = helper ++ ++ ++_install_checkout_statistic_helper() ++ ++_upstream = _load_module( ++ "swe_pr40111_upstream_tests", ++ REPO_ROOT / UPSTREAM_TEST_REL, ++) ++ ++ ++class TestStatisticHelper(_upstream.TestStatisticHelper): ++ pass +diff --git a/test/swe_paddle/test_pr40111_profiler_scheduler.py b/test/swe_paddle/test_pr40111_profiler_scheduler.py +new file mode 100644 +index 0000000000000000000000000000000000000000..8a0e559b3fd4b235abddf72e4650ce4eefca6924 +--- /dev/null ++++ b/test/swe_paddle/test_pr40111_profiler_scheduler.py +@@ -0,0 +1,53 @@ ++import ast ++from enum import Enum ++from pathlib import Path ++from typing import Callable ++from warnings import warn ++ ++ ++REPO_ROOT = Path(__file__).resolve().parents[2] ++ ++ ++def _load_existing_profiler_scheduler(): ++ path = REPO_ROOT / "python/paddle/profiler/profiler.py" ++ tree = ast.parse(path.read_text(), filename=str(path)) ++ body = [ ++ node ++ for node in tree.body ++ if ( ++ isinstance(node, ast.ClassDef) ++ and node.name == "ProfilerState" ++ ) ++ or ( ++ isinstance(node, ast.FunctionDef) ++ and node.name == "make_scheduler" ++ ) ++ ] ++ namespace = { ++ "Enum": Enum, ++ "Callable": Callable, ++ "warn": warn, ++ } ++ module = ast.Module(body=body, type_ignores=[]) ++ ast.fix_missing_locations(module) ++ exec(compile(module, str(path), "exec"), namespace) ++ return namespace["ProfilerState"], namespace["make_scheduler"] ++ ++ ++def test_p2p_existing_profiler_scheduler_state_sequence(): ++ state, make_scheduler = _load_existing_profiler_scheduler() ++ scheduler = make_scheduler( ++ closed=1, ++ ready=1, ++ record=2, ++ repeat=1, ++ skip_first=1, ++ ) ++ assert [scheduler(step) for step in range(6)] == [ ++ state.CLOSED, ++ state.CLOSED, ++ state.READY, ++ state.RECORD, ++ state.RECORD_AND_RETURN, ++ state.CLOSED, ++ ] diff --git a/swe-paddle/tasks/PaddlePaddle__Paddle-40111/tests/test.sh b/swe-paddle/tasks/PaddlePaddle__Paddle-40111/tests/test.sh new file mode 100644 index 000000000..10aa29e66 --- /dev/null +++ b/swe-paddle/tasks/PaddlePaddle__Paddle-40111/tests/test.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash + +set -euo pipefail +python -m pytest test/swe_paddle/test_pr40111_profiler_ranges.py -q