已合并
add test/profiler #12588
huangyunlong创建于 2024年6月22日
add test/profiler #12588
已合并
huangyunlong创建于 2024年6月22日
refs/pull/12588/head合入到master
5 个文件变更+2278-2
@@ -0,0 +1,7 @@
1+# Python dependencies required for unit tests
2+ 
3+mypy==1.9.0
4+# Pin MyPy version because new errors are likely to appear with each release
5+#Description: linter
6+#Pinned versions: 1.9.0
7+#test that import: test_typing.py, test_type_hints.py
@@ -0,0 +1,736 @@
1+# Owner(s): ["oncall: profiler"]
2+ 
3+import functools
4+import os
5+import re
6+import textwrap
7+import traceback
8+import unittest
9+ 
10+import expecttest
11+ 
12+import torch
13+from torch._C._profiler import _ExtraFields_PyCall, _ExtraFields_PyCCall
14+from torch.testing._internal.common_utils import (
15+ IS_ARM64,
16+ IS_WINDOWS,
17+ run_tests,
18+ skipIfTorchDynamo,
19+ TEST_WITH_CROSSREF,
20+ TestCase,
21+)
22+from torch.utils._pytree import tree_map
23+ 
24+import torch_npu
25+import torch_npu.testing
26+ 
27+# These functions can vary from based on platform and build (e.g. with NPU)
28+# and generally distract from rather than adding to the test.
29+PRUNE_ALL = 1
30+KEEP_ELLIPSES = 2
31+KEEP_NAME_AND_ELLIPSES = 3
32+ 
33+PRUNE_FUNCTIONS = {
34+ "torch/utils/_pytree.py(...): tree_map": KEEP_NAME_AND_ELLIPSES,
35+ "torch/profiler/profiler.py(...): start": KEEP_ELLIPSES,
36+ "torch/profiler/profiler.py(...): stop_trace": KEEP_ELLIPSES,
37+ "torch/profiler/profiler.py(...): _transit_action": KEEP_ELLIPSES,
38+ "<built-in method __exit__ of torch._C.DisableTorchFunctionSubclass object at 0xXXXXXXXXXXXX>": PRUNE_ALL,
39+ "cudaStreamIsCapturing": PRUNE_ALL,
40+ # These show up only on NPU, prune them so the NPU and CPU expected results can be the same
41+ "cudaGetDeviceCount": PRUNE_ALL,
42+ "cudaGetDeviceProperties_v2": PRUNE_ALL,
43+}
44+ 
45+ 
46+class TorchFunctionTensor(torch.Tensor):
47+ @classmethod
48+ def __torch_function__(cls, func, types, args=(), kwargs=None):
49+ return super().__torch_function__(func, types, args, kwargs)
50+ 
51+ 
H
Hhuangyunlong2024年7月2日

已删除

likedislike
52+class TorchDispatchTensor(torch.Tensor):
53+ @staticmethod
54+ def __new__(cls, elem):
55+ t = torch.Tensor._make_subclass(cls, elem, elem.requires_grad)
56+ t.elem = elem
57+ return t
58+ 
59+ @classmethod
60+ def __torch_dispatch__(cls, func, types, args=(), kwargs=None):
61+ def unwrap(x):
62+ return x.elem if isinstance(x, TorchDispatchTensor) else x
63+ 
64+ def wrap(x):
65+ return TorchDispatchTensor(x) if isinstance(x, torch.Tensor) else x
66+ 
67+ args = tree_map(unwrap, args)
68+ kwargs = tree_map(unwrap, kwargs or {})
69+ 
70+ return tree_map(wrap, func(*args, **kwargs))
71+ 
72+ 
73+class ProfilerTree:
74+ @staticmethod
75+ def test(f):
76+ """Mark unit test that will be using ProfilerTree to test traces.
77+ 
78+ This decorator serves two purposes. First, it provides a method name
79+ that `format` can use to tell where the test runner (which is
80+ environment specific) ends and the unit test begins. Second, it runs
81+ the test with replicates and allows `assertTreesMatch` to adjust
82+ based on which replicate is running.
83+ """
84+ 
85+ @functools.wraps(f)
86+ def begin_unit_test_marker(self, replicates=3):
87+ try:
88+ for i in range(replicates):
89+ self.tree_replicate = i
90+ out = f(self)
91+ if self.tree_replicate is None:
92+ break
93+ return out
94+ finally:
95+ delattr(self, "tree_replicate")
96+ 
97+ return begin_unit_test_marker
98+ 
99+ @classmethod
100+ def format(cls, profiler, indent: int = 0):
101+ def flatten(nodes, depth=0, out=None):
102+ if out is None:
103+ out = []
104+ 
105+ for node in nodes:
106+ cls.validate_node(node)
107+ name = cls.fmt_name(node.name)
108+ prune_level = PRUNE_FUNCTIONS.get(name.strip(), None)
109+ if prune_level is None:
110+ out.append((depth, name))
111+ flatten(node.children, depth + 1, out)
112+ elif prune_level == KEEP_NAME_AND_ELLIPSES:
113+ out.append((depth, name))
114+ if node.children:
115+ out.append((depth + 1, "..."))
116+ elif prune_level == KEEP_ELLIPSES:
117+ out.append((depth, "..."))
118+ else:
119+ assert prune_level == PRUNE_ALL
120+ 
121+ return out
122+ 
123+ flat_nodes = flatten(profiler.kineto_results.experimental_event_tree())
124+ 
125+ # Profiler inserts a `cudaDeviceSynchronize` at the end of profiling.
126+ # and may also insert 'Context Sync' NPU synchronization event.
127+ if flat_nodes and flat_nodes[-2][1] == "cudaDeviceSynchronize":
128+ flat_nodes = flat_nodes[:-2]
129+ 
130+ if flat_nodes and flat_nodes[-1][1] == "cudaDeviceSynchronize":
131+ flat_nodes = flat_nodes[:-1]
132+ 
133+ # Profiler inserts a `hipDeviceSynchronize` at the end of profiling.
134+ if flat_nodes and flat_nodes[-1][1] == "hipDeviceSynchronize":
135+ flat_nodes = flat_nodes[:-1]
136+ 
137+ min_depth = min(
138+ [d + 1 for d, name in flat_nodes if "begin_unit_test_marker" in name] or [0]
139+ )
140+ return textwrap.indent(
141+ "\n".join(
142+ [
143+ f"{' ' * (d - min_depth)}{name.rstrip()}"
144+ for d, name in flat_nodes
145+ if d >= min_depth
146+ ]
147+ ),
148+ " " * indent,
149+ )
150+ 
151+ @staticmethod
152+ def fmt_name(name: str) -> str:
153+ match = re.match(r"^(.*)\.py\(([0-9]+)\): (.*)$", name)
154+ if match:
155+ filename, _, fn = match.groups()
156+ 
157+ # This test can appear as `test/profiler/test_profiler_tree.py`
158+ # depending on where it is run from.
159+ test_file = os.path.splitext(os.path.split(__file__)[1])[0]
160+ if filename.endswith(test_file):
161+ filename = test_file
162+ 
163+ # We test against a string literal, so all paths have to look like POSIX paths.
164+ filename = filename.replace(os.sep, "/")
165+ 
166+ # We don't want to have to update this test every time PyTorch changes.
167+ # At some point we should test some line numbers, but for now it's
168+ # too brittle.
169+ lineno = "..."
170+ 
171+ return f"{filename}.py({lineno}): {fn}"
172+ 
173+ for kernel_pattern in (
174+ "void at::native::elementwise_kernel",
175+ "void at::native::reduce_kernel",
176+ "void at::native::vectorized_elementwise_kernel",
177+ "void at::native::unrolled_elementwise_kernel",
178+ r"void [a-zA-Z0-9]+_kernel", # Nvidia kernels.
179+ ):
180+ name = re.sub(
181+ rf"{kernel_pattern}<.+>\(.+\)$",
182+ f"{kernel_pattern.replace('[a-zA-Z0-9]+', '...')}<...>(...)",
183+ name,
184+ )
185+ 
186+ return re.sub("object at 0x[0-9a-fA-F]+>", "object at 0xXXXXXXXXXXXX>", name)
187+ 
188+ @classmethod
189+ def validate_node(cls, node):
190+ extra_fields = node.extra_fields
191+ if isinstance(extra_fields, (_ExtraFields_PyCall, _ExtraFields_PyCCall)):
192+ # Check that the lineage established by the profiler matches the
193+ # caller recorded by the Python tracer.
194+ parent = node.parent
195+ while parent is not None:
196+ if isinstance(parent.extra_fields, _ExtraFields_PyCall):
197+ break
198+ parent = parent.parent
199+ 
200+ def to_string(frame_state):
201+ return f"{frame_state.file_name}(...): {frame_state.function_name}"
202+ 
203+ if parent:
204+ parent_name = to_string(parent.extra_fields.callsite)
205+ caller_name = to_string(extra_fields.caller)
206+ assert parent_name == caller_name, f"{parent_name} vs. {caller_name}"
207+ 
208+ 
209+@unittest.skipIf(IS_ARM64, "Not working on ARM")
210+class TestProfilerTree(TestCase):
211+ def assertTreesMatch(self, actual: str, expected: str, allow_failure: bool = False):
212+ # Warning: Here be dragons
213+ # Different platforms will have subtly different behavior for Python
214+ # tracing. Observed differences include:
215+ # 1) Windows symbolicates names differently from posix
216+ # 2) The profile callback for c_call does not fire for Tensor.__pow__
217+ # on certain platforms. This is not caused by the function tracer,
218+ # but by cPython itself.
219+ #
220+ # The purpose of these unit tests is to ensure that the profiler is
221+ # doing reasonable things. When these platform dependent variations occur
222+ # simply coerce them into a platform independent form. If you made a
223+ # change in the codebase which changes the trace produced, simply use
224+ # EXPECTTEST_ACCEPT=1 to update the tests to reflect the new structure.
225+ 
226+ # expecttest will not show the diff view if `len(actual) < len(expected)`
227+ if not expecttest.ACCEPT:
228+ actual = actual.ljust(len(expected))
229+ self.maxDiff = None
230+ 
231+ replicate = getattr(self, "tree_replicate", None)
232+ self.assertIsNotNone(
233+ replicate, "Please annotate test with `@ProfilerTree.test`"
234+ )
235+ 
236+ # The profiler should produce deterministic results and should return
237+ # to a clean state after each run. As a result, only the first
238+ # replicate is allowed to update `expected`. If subsequent runs do not
239+ # match it is a bug in the profiler.
240+ if replicate:
241+ self.assertEqual(actual, expected)
242+ else:
243+ try:
244+ self.assertExpectedInline(actual, expected, skip=1)
245+ except AssertionError as e:
246+ if allow_failure:
247+ self.tree_replicate = None
248+ msg = traceback.format_exception_only(type(e), e)[0]
249+ print(msg.split("AssertionError:")[-1])
250+ else:
251+ raise
252+ 
253+ @ProfilerTree.test
254+ @unittest.skipIf(torch.npu.is_available(), "Test not working for NPU")
255+ def test_profiler_experimental_tree(self):
256+ t1, t2 = torch.ones(1, requires_grad=True), torch.ones(1, requires_grad=True)
257+ with torch.profiler.profile() as p:
258+ z = torch.add(t1, t2)
259+ y = torch.ones(1)
260+ loss = (y - z) ** 2
261+ loss.backward()
262+ 
263+ self.assertTreesMatch(
264+ ProfilerTree.format(p.profiler, 12),
265+ """\
266+ aten::add
267+ aten::ones
268+ aten::empty
269+ aten::fill_
270+ aten::sub
271+ aten::pow
272+ aten::result_type
273+ aten::to
274+ aten::ones_like
275+ aten::empty_like
276+ aten::empty_strided
277+ aten::fill_
278+ autograd::engine::evaluate_function: PowBackward0
279+ PowBackward0
280+ aten::pow
281+ aten::result_type
282+ aten::to
283+ aten::copy_
284+ aten::mul
285+ aten::mul
286+ aten::to
287+ aten::_to_copy
288+ aten::empty_strided
289+ aten::copy_
290+ aten::mul
291+ autograd::engine::evaluate_function: SubBackward0
292+ SubBackward0
293+ aten::neg
294+ autograd::engine::evaluate_function: AddBackward0
295+ AddBackward0
296+ autograd::engine::evaluate_function: torch::autograd::AccumulateGrad
297+ torch::autograd::AccumulateGrad
298+ aten::new_empty_strided
299+ aten::empty_strided
300+ aten::copy_
301+ autograd::engine::evaluate_function: torch::autograd::AccumulateGrad
302+ torch::autograd::AccumulateGrad
303+ aten::detach
304+ detach""",
305+ )
306+ 
307+ @ProfilerTree.test
308+ @unittest.skipIf(torch.npu.is_available(), "Test not working for NPU")
309+ def test_profiler_experimental_tree_with_record_function(self):
310+ with torch.profiler.profile() as p:
311+ with torch.autograd.profiler.record_function("Top level Annotation"):
312+ with torch.autograd.profiler.record_function("First Annotation"):
313+ x = torch.ones((1,), requires_grad=True)
314+ 
315+ # Check that we correctly handle the case when a user
316+ # annotation does not call `__exit__`.
317+ _ = torch.autograd.profiler.record_function(
318+ "Second Annotation"
319+ ).__enter__()
320+ 
321+ y = x + 1
322+ with torch.autograd.profiler.record_function("Third Annotation"):
323+ y.backward()
324+ 
325+ # NB: The `aten::zeros` before the record function annotations are due to
326+ # `at::cpp_custom_type_hack`. When we switch to `torch::CustomClassHolder`
327+ # they will disappear.
328+ self.assertTreesMatch(
329+ ProfilerTree.format(p.profiler, 12),
330+ """\
331+ Top level Annotation
332+ First Annotation
333+ aten::ones
334+ aten::empty
335+ aten::fill_
336+ Second Annotation
337+ aten::add
338+ aten::to
339+ aten::_to_copy
340+ aten::empty_strided
341+ aten::copy_
342+ Third Annotation
343+ aten::ones_like
344+ aten::empty_like
345+ aten::empty_strided
346+ aten::fill_
347+ autograd::engine::evaluate_function: AddBackward0
348+ AddBackward0
349+ autograd::engine::evaluate_function: torch::autograd::AccumulateGrad
350+ torch::autograd::AccumulateGrad
351+ aten::new_empty_strided
352+ aten::empty_strided
353+ aten::copy_""",
354+ )
355+ 
356+ @ProfilerTree.test
357+ @unittest.skipIf(torch.npu.is_available(), "Test not working for NPU")
358+ def test_profiler_experimental_tree_with_memory(self):
359+ t1, t2 = torch.ones(1, requires_grad=True), torch.ones(1, requires_grad=True)
360+ with torch.profiler.profile(profile_memory=True) as p:
361+ z = torch.add(t1, t2)
362+ y = torch.ones(1)
363+ loss = (y - z) ** 2
364+ loss.backward()
365+ 
366+ self.assertTreesMatch(
367+ ProfilerTree.format(p.profiler, 12),
368+ """\
369+ aten::add
370+ [memory]
371+ aten::ones
372+ aten::empty
373+ [memory]
374+ aten::fill_
375+ aten::sub
376+ [memory]
377+ aten::pow
378+ aten::result_type
379+ aten::to
380+ [memory]
381+ aten::ones_like
382+ aten::empty_like
383+ aten::empty_strided
384+ [memory]
385+ aten::fill_
386+ autograd::engine::evaluate_function: PowBackward0
387+ PowBackward0
388+ aten::pow
389+ aten::result_type
390+ aten::to
391+ [memory]
392+ aten::copy_
393+ aten::mul
394+ [memory]
395+ aten::mul
396+ aten::to
397+ aten::_to_copy
398+ aten::empty_strided
399+ [memory]
400+ aten::copy_
401+ [memory]
402+ [memory]
403+ [memory]
404+ aten::mul
405+ [memory]
406+ [memory]
407+ [memory]
408+ [memory]
409+ autograd::engine::evaluate_function: SubBackward0
410+ SubBackward0
411+ aten::neg
412+ [memory]
413+ [memory]
414+ autograd::engine::evaluate_function: AddBackward0
415+ AddBackward0
416+ autograd::engine::evaluate_function: torch::autograd::AccumulateGrad
417+ torch::autograd::AccumulateGrad
418+ aten::new_empty_strided
419+ aten::empty_strided
420+ [memory]
421+ aten::copy_
422+ autograd::engine::evaluate_function: torch::autograd::AccumulateGrad
423+ torch::autograd::AccumulateGrad
424+ aten::detach
425+ detach
426+ [memory]""",
427+ )
428+ 
429+ @unittest.skipIf(
430+ TEST_WITH_CROSSREF, "crossref intercepts calls and changes the callsite."
431+ )
432+ @ProfilerTree.test
433+ def test_profiler_experimental_tree_with_memory_and_stack(self):
434+ t1, t2 = torch.ones(1, requires_grad=True), torch.ones(1, requires_grad=True)
435+ with torch.profiler.profile(with_stack=True, profile_memory=True) as p:
436+ z = torch.add(t1, t2)
437+ y = torch.ones(1)
438+ loss = torch.pow(y - z, 2)
439+ loss.backward()
440+ 
441+ self.assertTreesMatch(
442+ ProfilerTree.format(p.profiler, 12),
443+ """\
444+ test_profiler_tree.py(...): test_profiler_experimental_tree_with_memory_and_stack
445+ torch/profiler/profiler.py(...): __enter__
446+ ...
447+ <built-in method add of type object at 0xXXXXXXXXXXXX>
448+ aten::add
449+ [memory]
450+ <built-in method ones of type object at 0xXXXXXXXXXXXX>
451+ aten::ones
452+ aten::empty
453+ [memory]
454+ aten::fill_
455+ aten::sub
456+ [memory]
457+ <built-in method pow of type object at 0xXXXXXXXXXXXX>
458+ aten::pow
459+ aten::result_type
460+ aten::to
461+ [memory]
462+ torch/_tensor.py(...): backward
463+ <built-in function _has_torch_function_unary>
464+ torch/autograd/__init__.py(...): backward
465+ <built-in method _are_functorch_transforms_active of PyCapsule object at 0xXXXXXXXXXXXX>
466+ <built-in function isinstance>
467+ <built-in function isinstance>
468+ <built-in function len>
469+ torch/autograd/__init__.py(...): _tensor_or_tensors_to_tuple
470+ torch/autograd/__init__.py(...): _make_grads
471+ <built-in function isinstance>
472+ <built-in method numel of Tensor object at 0xXXXXXXXXXXXX>
473+ <built-in method ones_like of type object at 0xXXXXXXXXXXXX>
474+ aten::ones_like
475+ aten::empty_like
476+ aten::empty_strided
477+ [memory]
478+ aten::fill_
479+ <built-in method append of list object at 0xXXXXXXXXXXXX>
480+ torch/autograd/graph.py(...): _engine_run_backward
481+ logging/__init__.py(...): getEffectiveLevel
482+ <built-in method run_backward of torch._C._EngineBase object at 0xXXXXXXXXXXXX>
483+ autograd::engine::evaluate_function: PowBackward0
484+ PowBackward0
485+ aten::pow
486+ aten::result_type
487+ aten::to
488+ [memory]
489+ aten::copy_
490+ aten::mul
491+ [memory]
492+ aten::mul
493+ aten::to
494+ aten::_to_copy
495+ aten::empty_strided
496+ [memory]
497+ aten::copy_
498+ [memory]
499+ [memory]
500+ [memory]
501+ aten::mul
502+ [memory]
503+ [memory]
504+ [memory]
505+ [memory]
506+ autograd::engine::evaluate_function: SubBackward0
507+ SubBackward0
508+ aten::neg
509+ [memory]
510+ [memory]
511+ autograd::engine::evaluate_function: AddBackward0
512+ AddBackward0
513+ autograd::engine::evaluate_function: torch::autograd::AccumulateGrad
514+ torch::autograd::AccumulateGrad
515+ aten::new_empty_strided
516+ aten::empty_strided
517+ [memory]
518+ aten::copy_
519+ autograd::engine::evaluate_function: torch::autograd::AccumulateGrad
520+ torch::autograd::AccumulateGrad
521+ aten::detach
522+ detach
523+ [memory]
524+ torch/profiler/profiler.py(...): __exit__
525+ torch/profiler/profiler.py(...): stop
526+ ...""",
527+ )
528+ 
529+ @skipIfTorchDynamo("too slow")
530+ @unittest.skipIf(
531+ TEST_WITH_CROSSREF, "crossref intercepts calls and changes the callsite."
532+ )
533+ @ProfilerTree.test
534+ def test_profiler_experimental_tree_with_stack_and_modules(self):
535+ class MyModule(torch.nn.Module):
536+ def __init__(self):
537+ super().__init__()
538+ self.layers = [
539+ torch.nn.ReLU(),
540+ torch.nn.Linear(1, 1),
541+ torch.nn.ReLU(),
542+ ]
543+ 
544+ def forward(self, x: torch.Tensor) -> torch.Tensor:
545+ for l in self.layers:
546+ x = l(x)
547+ return x
548+ 
549+ model = MyModule()
550+ with torch.profiler.profile(with_stack=True) as p:
551+ for _ in range(2):
552+ model(torch.ones((1,)))
553+ self.maxDiff = None
554+ self.assertTreesMatch(
555+ ProfilerTree.format(p.profiler, 12),
556+ """\
557+ test_profiler_tree.py(...): test_profiler_experimental_tree_with_stack_and_modules
558+ torch/profiler/profiler.py(...): __enter__
559+ ...
560+ <built-in method ones of type object at 0xXXXXXXXXXXXX>
561+ aten::ones
562+ aten::empty
563+ aten::fill_
564+ nn.Module: MyModule_0
565+ torch/nn/modules/module.py(...): _call_impl
566+ <built-in method _get_tracing_state of PyCapsule object at 0xXXXXXXXXXXXX>
567+ test_profiler_tree.py(...): forward
568+ nn.Module: ReLU_0
569+ torch/nn/modules/module.py(...): _call_impl
570+ <built-in method _get_tracing_state of PyCapsule object at 0xXXXXXXXXXXXX>
571+ torch/nn/modules/activation.py(...): forward
572+ torch/nn/functional.py(...): relu
573+ <built-in function _has_torch_function_unary>
574+ <built-in method relu of type object at 0xXXXXXXXXXXXX>
575+ aten::relu
576+ aten::clamp_min
577+ nn.Module: Linear_0
578+ torch/nn/modules/module.py(...): _call_impl
579+ <built-in method _get_tracing_state of PyCapsule object at 0xXXXXXXXXXXXX>
580+ torch/nn/modules/linear.py(...): forward
581+ torch/nn/modules/module.py(...): __getattr__
582+ torch/nn/modules/module.py(...): __getattr__
583+ <built-in function linear>
584+ aten::linear
585+ aten::reshape
586+ aten::view
587+ aten::t
588+ aten::transpose
589+ aten::as_strided
590+ aten::addmm
591+ aten::expand
592+ aten::as_strided
593+ aten::copy_
594+ aten::resolve_conj
595+ aten::resolve_conj
596+ aten::resolve_conj
597+ aten::view
598+ nn.Module: ReLU_1
599+ torch/nn/modules/module.py(...): _call_impl
600+ <built-in method _get_tracing_state of PyCapsule object at 0xXXXXXXXXXXXX>
601+ torch/nn/modules/activation.py(...): forward
602+ torch/nn/functional.py(...): relu
603+ <built-in function _has_torch_function_unary>
604+ <built-in method relu of type object at 0xXXXXXXXXXXXX>
605+ aten::relu
606+ aten::clamp_min
607+ <built-in method ones of type object at 0xXXXXXXXXXXXX>
608+ aten::ones
609+ aten::empty
610+ aten::fill_
611+ nn.Module: MyModule_0
612+ torch/nn/modules/module.py(...): _call_impl
613+ <built-in method _get_tracing_state of PyCapsule object at 0xXXXXXXXXXXXX>
614+ test_profiler_tree.py(...): forward
615+ nn.Module: ReLU_0
616+ torch/nn/modules/module.py(...): _call_impl
617+ <built-in method _get_tracing_state of PyCapsule object at 0xXXXXXXXXXXXX>
618+ torch/nn/modules/activation.py(...): forward
619+ torch/nn/functional.py(...): relu
620+ <built-in function _has_torch_function_unary>
621+ <built-in method relu of type object at 0xXXXXXXXXXXXX>
622+ aten::relu
623+ aten::clamp_min
624+ nn.Module: Linear_0
625+ torch/nn/modules/module.py(...): _call_impl
626+ <built-in method _get_tracing_state of PyCapsule object at 0xXXXXXXXXXXXX>
627+ torch/nn/modules/linear.py(...): forward
628+ torch/nn/modules/module.py(...): __getattr__
629+ torch/nn/modules/module.py(...): __getattr__
630+ <built-in function linear>
631+ aten::linear
632+ aten::reshape
633+ aten::view
634+ aten::t
635+ aten::transpose
636+ aten::as_strided
637+ aten::addmm
638+ aten::expand
639+ aten::as_strided
640+ aten::copy_
641+ aten::resolve_conj
642+ aten::resolve_conj
643+ aten::resolve_conj
644+ aten::view
645+ nn.Module: ReLU_1
646+ torch/nn/modules/module.py(...): _call_impl
647+ <built-in method _get_tracing_state of PyCapsule object at 0xXXXXXXXXXXXX>
648+ torch/nn/modules/activation.py(...): forward
649+ torch/nn/functional.py(...): relu
650+ <built-in function _has_torch_function_unary>
651+ <built-in method relu of type object at 0xXXXXXXXXXXXX>
652+ aten::relu
653+ aten::clamp_min
654+ torch/profiler/profiler.py(...): __exit__
655+ torch/profiler/profiler.py(...): stop
656+ ...""",
657+ )
658+ 
659+ @unittest.skipIf(
660+ TEST_WITH_CROSSREF, "crossref intercepts calls and changes the callsite."
661+ )
662+ @ProfilerTree.test
663+ def test_profiler_experimental_tree_with_stack_and_torch_function(self):
664+ x = TorchFunctionTensor(torch.ones((1,)))
665+ y = torch.ones((1,))
666+ 
667+ # There's some lazy initialization in __torch_function__. If we don't
668+ # run this the first run won't match the replicates.
669+ torch.add(x, y)
670+ 
671+ with torch.profiler.profile(with_stack=True) as p:
672+ torch.add(x, y)
673+ 
674+ self.assertTreesMatch(
675+ ProfilerTree.format(p.profiler, 12),
676+ """\
677+ test_profiler_tree.py(...): test_profiler_experimental_tree_with_stack_and_torch_function
678+ torch/profiler/profiler.py(...): __enter__
679+ ...
680+ <built-in method add of type object at 0xXXXXXXXXXXXX>
681+ test_profiler_tree.py(...): __torch_function__
682+ torch/_tensor.py(...): __torch_function__
683+ <built-in function all>
684+ torch/_tensor.py(...): <genexpr>
685+ <built-in function issubclass>
686+ torch/_tensor.py(...): <genexpr>
687+ <built-in method add of type object at 0xXXXXXXXXXXXX>
688+ aten::add
689+ torch/_tensor.py(...): _convert
690+ <built-in function isinstance>
691+ <built-in function isinstance>
692+ <built-in method as_subclass of Tensor object at 0xXXXXXXXXXXXX>
693+ aten::alias
694+ <built-in function isinstance>
695+ torch/profiler/profiler.py(...): __exit__
696+ torch/profiler/profiler.py(...): stop
697+ ...""",
698+ )
699+ 
700+ @unittest.skipIf(
701+ TEST_WITH_CROSSREF, "crossref intercepts calls and changes the callsite."
702+ )
703+ @ProfilerTree.test
704+ def test_profiler_experimental_tree_with_stack_and_torch_dispatch(self):
705+ x = TorchDispatchTensor(torch.ones((1,)))
706+ y = torch.ones((1,))
707+ 
708+ with torch.profiler.profile(with_stack=True) as p:
709+ x + y
710+ 
711+ self.assertTreesMatch(
712+ ProfilerTree.format(p.profiler, 12),
713+ """\
714+ test_profiler_tree.py(...): test_profiler_experimental_tree_with_stack_and_torch_dispatch
715+ torch/profiler/profiler.py(...): __enter__
716+ ...
717+ aten::add
718+ test_profiler_tree.py(...): __torch_dispatch__
719+ torch/utils/_pytree.py(...): tree_map
720+ ...
721+ torch/utils/_pytree.py(...): tree_map
722+ ...
723+ torch/_ops.py(...): __call__
724+ <built-in method of PyCapsule object at 0xXXXXXXXXXXXX>
725+ aten::add
726+ torch/utils/_pytree.py(...): tree_map
727+ ...
728+ torch/profiler/profiler.py(...): __exit__
729+ torch/profiler/profiler.py(...): stop
730+ ...""",
731+ )
732+ 
733+ 
734+if __name__ == "__main__":
735+ run_tests()
736+
@@ -121,4 +121,8 @@ test/test_jit_llga_fuser.py
121test/test_type_hints.py121test/test_type_hints.py
122test/test_typing.py122test/test_typing.py
123mypy.ini123mypy.ini
124-.ci/docker/requirements-ci.txt124+test/profiler/profiler_utils_mock_events.json
125+test/profiler/test_execution_trace.py
126+test/profiler/test_profiler.py
127+test/profiler/test_record_function.py
128+test/profiler/test_torch_tidy.py
@@ -31405,5 +31405,14 @@
31405 "test_sparse_zeros_trunc_npu_int32 (__main__.TestSparseUnaryUfuncsPRIVATEUSE1)": ["", [""]],31405 "test_sparse_zeros_trunc_npu_int32 (__main__.TestSparseUnaryUfuncsPRIVATEUSE1)": ["", [""]],
31406 "test_sparse_zeros_trunc_npu_int64 (__main__.TestSparseUnaryUfuncsPRIVATEUSE1)": ["", [""]],31406 "test_sparse_zeros_trunc_npu_int64 (__main__.TestSparseUnaryUfuncsPRIVATEUSE1)": ["", [""]],
31407 "test_sparse_zeros_trunc_npu_int8 (__main__.TestSparseUnaryUfuncsPRIVATEUSE1)": ["", [""]],31407 "test_sparse_zeros_trunc_npu_int8 (__main__.TestSparseUnaryUfuncsPRIVATEUSE1)": ["", [""]],
31408- "test_sparse_zeros_trunc_npu_uint8 (__main__.TestSparseUnaryUfuncsPRIVATEUSE1)": ["", [""]]31408+ "test_sparse_zeros_trunc_npu_uint8 (__main__.TestSparseUnaryUfuncsPRIVATEUSE1)": ["", [""]],
31409+ "test_memory_timeline_no_id (__main__.TestMemoryProfilerE2E)": ["", [""]],
31410+ "test_extract_gradients_from_optimizer_set_to_none (__main__.TestIdentifyGradients)": ["", [""]],
31411+ "test_fuzz_symbolize (__main__.TestExperimentalUtils)": ["", [""]],
31412+ "test_profiler_strides (__main__.TestProfiler)": ["", [""]],
31413+ "test_schedule_function_count (__main__.TestProfiler)": ["", [""]],
31414+ "test_profiler_experimental_tree_with_memory_and_stack (__main__.TestProfilerTree)": ["", [""]],
31415+ "test_profiler_experimental_tree_with_stack_and_modules (__main__.TestProfilerTree)": ["", [""]],
31416+ "test_profiler_experimental_tree_with_stack_and_torch_dispatch (__main__.TestProfilerTree)": ["", [""]],
31417+ "test_profiler_experimental_tree_with_stack_and_torch_function (__main__.TestProfilerTree)": ["", [""]]
31409}31418}