summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbd <bdunahu@operationnull.com>2025-07-20 13:43:17 -0600
committerbd <bdunahu@operationnull.com>2025-07-20 13:43:17 -0600
commit1eddfd07cad491ce8d216ee3fda72bdd9ecb9eae (patch)
treeaccdf32e5696d1abe0e1916cffd8b22081b1409e
parent2e208349d2e6f8f3d7fbbe853413549da9df0ce0 (diff)
Aergia.get_deepest_traceable_frame refactor, tests
Generators and list comprehension gives correct but less ideal results, matching yappi. Can this be improved in the future?
-rw-r--r--.dir-locals.el4
-rwxr-xr-xaergia/aergia.py19
-rw-r--r--t/async-generator-and-comprehension.py5
-rw-r--r--t/test_functionality.py68
-rw-r--r--t/utils.py2
5 files changed, 80 insertions, 18 deletions
diff --git a/.dir-locals.el b/.dir-locals.el
new file mode 100644
index 0000000..8f02dcf
--- /dev/null
+++ b/.dir-locals.el
@@ -0,0 +1,4 @@
+;;; Directory Local Variables -*- no-byte-compile: t -*-
+;;; For more information see (info "(emacs) Directory Variables")
+
+((python-mode . ((compile-command . "python3 ./run_tests.py"))))
diff --git a/aergia/aergia.py b/aergia/aergia.py
index d8f18ec..83cf0fa 100755
--- a/aergia/aergia.py
+++ b/aergia/aergia.py
@@ -247,20 +247,15 @@ class Aergia(object):
@staticmethod
def get_deepest_traceable_frame(coro):
- if not coro:
- return None
curr = coro
- lframe = None
- while True:
+ ret = None
+ while curr:
frame = getattr(curr, 'cr_frame', None)
- if not frame or not Aergia.should_trace(frame.f_code.co_filename):
- return lframe
-
- lframe = frame
- awaited = getattr(curr, 'cr_await', None)
- if not awaited or not hasattr(awaited, 'cr_frame'):
- return lframe
- curr = awaited
+ # print(frame)
+ if frame and Aergia.should_trace(frame.f_code.co_filename):
+ ret = frame
+ curr = getattr(curr, 'cr_await', None)
+ return ret
@staticmethod
def should_trace(filename):
diff --git a/t/async-generator-and-comprehension.py b/t/async-generator-and-comprehension.py
index ce85f45..2e1b60b 100644
--- a/t/async-generator-and-comprehension.py
+++ b/t/async-generator-and-comprehension.py
@@ -1,4 +1,5 @@
import asyncio
+import yappi
async def async_generator():
@@ -12,4 +13,8 @@ async def main():
print(sum(r))
+yappi.set_clock_type("wall")
+yappi.start()
asyncio.run(main())
+yappi.get_func_stats().print_all()
+yappi.get_thread_stats().print_all()
diff --git a/t/test_functionality.py b/t/test_functionality.py
index 6daf2d3..b60cb46 100644
--- a/t/test_functionality.py
+++ b/t/test_functionality.py
@@ -38,7 +38,8 @@ class BasicUsage(utils.AergiaUnitTestCase):
samples = self.Aergia.get_samples()
- self.assertFuncContains('b', [self.expected_samples(delay * num_times)],
+ self.assertFuncContains('b',
+ [self.expected_samples(delay * num_times)],
samples)
def test_simultaneous_tasks(self):
@@ -54,10 +55,10 @@ class BasicUsage(utils.AergiaUnitTestCase):
self.assertFuncContains('b', [self.expected_samples(delay * 3)],
samples)
- # TODO samples from gather all execution time, should we trace this??
+ # TODO samples from gather all execution time, should we trace this?
self.assertFuncContains('a', [self.expected_samples(delay)], samples)
- def test_alter_thread_task(self):
+ def test_subthread_task(self):
delay = 0.2
async def b(): await asyncio.sleep(delay)
@@ -74,7 +75,7 @@ class BasicUsage(utils.AergiaUnitTestCase):
self.assertFuncContains('c', [], samples)
self.assertFuncContains('b', [self.expected_samples(delay * 3)],
samples)
- # TODO samples from gather all execution time, should we trace this??
+ # TODO samples from gather all execution time, should we trace this?
self.assertFuncContains('a', [self.expected_samples(delay)], samples)
def test_eager_task(self):
@@ -91,6 +92,39 @@ class BasicUsage(utils.AergiaUnitTestCase):
samples = self.Aergia.get_samples()
self.assertFuncContains('a', [self.expected_samples(delay)], samples)
+ def test_async_generator(self):
+ delay = 0.2
+ num_times = 10
+
+ async def b():
+ for i in range(num_times):
+ await asyncio.sleep(delay)
+ yield i
+
+ async def a():
+ lst = []
+ async for item in b():
+ lst.append(item)
+
+ self.Aergia.start()
+ asyncio.run(a())
+ self.Aergia.stop()
+
+ samples = self.Aergia.get_samples()
+ # TODO can we make these results more intuitive?
+ # async generators also do not work at all with yappi.
+ # doing so would be unique to this profiler.
+
+ # self.assertFuncContains('b',
+ # [self.expected_samples(delay * num_times)],
+ # samples)
+ # self.assertFuncContains('a', [], samples)
+
+ self.assertFuncContains('a',
+ [self.expected_samples(delay * num_times)],
+ samples)
+ self.assertFuncContains('b', [], samples)
+
def test_async_gen_and_comp(self):
delay = 0.2
num_times = 10
@@ -108,5 +142,29 @@ class BasicUsage(utils.AergiaUnitTestCase):
self.Aergia.stop()
samples = self.Aergia.get_samples()
- self.assertFuncContains('b', [self.expected_samples(delay * num_times)],
+ # TODO can we make these results more intuitive?
+ # async generators also do not work at all with yappi.
+ # doing so would be unique to this profiler.
+
+ self.assertFuncContains('b', [], samples)
+ self.assertFuncContains('a', [], samples)
+ self.assertFuncContains('<listcomp>',
+ [self.expected_samples(delay * num_times)],
samples)
+
+ def test_deep_await(self):
+ delay = 0.2
+
+ async def c(): await asyncio.sleep(delay)
+ async def b(): await c()
+ async def a(): await b()
+
+ self.Aergia.start()
+ asyncio.run(a())
+ self.Aergia.stop()
+
+ samples = self.Aergia.get_samples()
+
+ self.assertFuncContains('c', [self.expected_samples(delay)], samples)
+ self.assertFuncContains('b', [], samples)
+ self.assertFuncContains('a', [], samples)
diff --git a/t/utils.py b/t/utils.py
index 5772fac..da9a9c1 100644
--- a/t/utils.py
+++ b/t/utils.py
@@ -23,7 +23,7 @@ class AergiaUnitTestCase(unittest.TestCase):
def assertRoughlyEqual(self, v1, v2):
a = abs(v1 - v2)
- self.assertTrue(a <= 1, f'{v1} (expected) not roughly {v2} (actual)')
+ self.assertTrue(a <= 2, f'{v1} (expected) not roughly {v2} (actual)')
def expected_samples(self, total_seconds):
return (total_seconds / self.interval)