brintos

brintos / llvm-project-archived public Read only

0
0
Text · 19.0 KiB · 45b52af Raw
493 lines · python
1"""Test queues inspection SB APIs."""2 3import os4import lldb5from lldbsuite.test.decorators import *6from lldbsuite.test.lldbtest import *7from lldbsuite.test import lldbutil8 9 10class TestQueues(TestBase):11    @skipUnlessDarwin12    @add_test_categories(["pyapi"])13    def test_with_python_api_queues(self):14        """Test queues inspection SB APIs."""15        self.build()16        self.queues()17 18    @skipUnlessDarwin19    @add_test_categories(["pyapi"])20    def test_queue_specific_breakpoints(self):21        self.build()22        self.queue_specific_breakpoints()23 24    @skipUnlessDarwin25    @add_test_categories(["pyapi"])26    def test_with_python_api_queues_with_backtrace(self):27        """Test queues inspection SB APIs."""28        self.build()29        self.queues_with_libBacktraceRecording()30 31    def setUp(self):32        # Call super's setUp().33        TestBase.setUp(self)34        # Find the line numbers that we will step to in main:35        self.main_source = "main.c"36 37    def check_queue_for_valid_queue_id(self, queue):38        self.assertNotEqual(39            queue.GetQueueID(),40            0,41            "Check queue %s for valid QueueID (got 0x%x)"42            % (queue.GetName(), queue.GetQueueID()),43        )44 45    def check_running_and_pending_items_on_queue(46        self, queue, expected_running, expected_pending47    ):48        self.assertEqual(49            queue.GetNumPendingItems(),50            expected_pending,51            "queue %s should have %d pending items, instead has %d pending items"52            % (queue.GetName(), expected_pending, (queue.GetNumPendingItems())),53        )54        self.assertEqual(55            queue.GetNumRunningItems(),56            expected_running,57            "queue %s should have %d running items, instead has %d running items"58            % (queue.GetName(), expected_running, (queue.GetNumRunningItems())),59        )60 61    def describe_threads(self):62        desc = []63        for x in self.inferior_process:64            id = x.GetIndexID()65            reason_str = lldbutil.stop_reason_to_str(x.GetStopReason())66 67            location = "\t".join(68                [69                    lldbutil.get_description(x.GetFrameAtIndex(i))70                    for i in range(x.GetNumFrames())71                ]72            )73            desc.append(74                "thread %d: %s (queue id: %s) at\n\t%s"75                % (id, reason_str, x.GetQueueID(), location)76            )77        print("\n".join(desc))78 79    def check_number_of_threads_owned_by_queue(self, queue, number_threads):80        if queue.GetNumThreads() != number_threads:81            self.describe_threads()82 83        self.assertEqual(84            queue.GetNumThreads(),85            number_threads,86            "queue %s should have %d thread executing, but has %d"87            % (queue.GetName(), number_threads, queue.GetNumThreads()),88        )89 90    def check_queue_kind(self, queue, kind):91        expected_kind_string = "Unknown"92        if kind == lldb.eQueueKindSerial:93            expected_kind_string = "Serial queue"94        if kind == lldb.eQueueKindConcurrent:95            expected_kind_string = "Concurrent queue"96        actual_kind_string = "Unknown"97        if queue.GetKind() == lldb.eQueueKindSerial:98            actual_kind_string = "Serial queue"99        if queue.GetKind() == lldb.eQueueKindConcurrent:100            actual_kind_string = "Concurrent queue"101        self.assertEqual(102            queue.GetKind(),103            kind,104            "queue %s is expected to be a %s but it is actually a %s"105            % (queue.GetName(), expected_kind_string, actual_kind_string),106        )107 108    def check_queues_threads_match_queue(self, queue):109        for idx in range(0, queue.GetNumThreads()):110            t = queue.GetThreadAtIndex(idx)111            self.assertTrue(112                t.IsValid(),113                "Queue %s's thread #%d must be valid" % (queue.GetName(), idx),114            )115            self.assertEqual(116                t.GetQueueID(),117                queue.GetQueueID(),118                "Queue %s has a QueueID of %d but its thread #%d has a QueueID of %d"119                % (queue.GetName(), queue.GetQueueID(), idx, t.GetQueueID()),120            )121            self.assertEqual(122                t.GetQueueName(),123                queue.GetName(),124                "Queue %s has a QueueName of %s but its thread #%d has a QueueName of %s"125                % (queue.GetName(), queue.GetName(), idx, t.GetQueueName()),126            )127            self.assertEqual(128                t.GetQueue().GetQueueID(),129                queue.GetQueueID(),130                "Thread #%d's Queue's QueueID of %d is not the same as the QueueID of its owning queue %d"131                % (idx, t.GetQueue().GetQueueID(), queue.GetQueueID()),132            )133 134    def check_queue_breakpoints(self, queue1, queue2, queue_breakpoint):135        queue1_thread = queue1.GetThreadAtIndex(0)136        queue2_thread = queue2.GetThreadAtIndex(0)137 138        self.assertEqual(139            queue_breakpoint.GetQueueName(),140            queue1.GetName(),141            "The breakpoint was set for queue %s, but the breakpoint's queue name is %s"142            % (queue_breakpoint.GetQueueName(), queue1.GetName()),143        )144        self.assertEqual(145            queue_breakpoint.GetHitCount(),146            1,147            "The breakpoint for queue %s has not been hit"148            % (queue_breakpoint.GetQueueName()),149        )150        self.assertStopReason(151            queue1_thread.GetStopReason(),152            lldb.eStopReasonBreakpoint,153            "Queue %s is not stopped at breakpoint %d"154            % (queue1.GetName(), queue_breakpoint.GetID()),155        )156        self.assertNotEqual(157            queue2_thread.GetStopReason(),158            lldb.eStopReasonBreakpoint,159            "Queue %s is stopped at breakpoint %d, but this breakpoint should only be hit for queue %s"160            % (161                queue2.GetName(),162                queue_breakpoint.GetID(),163                queue_breakpoint.GetQueueName(),164            ),165        )166 167    def queues(self):168        """Test queues inspection SB APIs without libBacktraceRecording."""169        exe = self.getBuildArtifact("a.out")170 171        target = self.dbg.CreateTarget(exe)172        self.assertTrue(target, VALID_TARGET)173        self.main_source_spec = lldb.SBFileSpec(self.main_source)174        break1 = target.BreakpointCreateByName("stopper", "a.out")175        self.assertTrue(break1, VALID_BREAKPOINT)176        process = target.LaunchSimple([], None, self.get_process_working_directory())177        self.assertTrue(process, PROCESS_IS_VALID)178        threads = lldbutil.get_threads_stopped_at_breakpoint(process, break1)179        if len(threads) != 1:180            self.fail("Failed to stop at breakpoint 1.")181 182        self.inferior_process = process183 184        queue_submittor_1 = lldb.SBQueue()185        queue_performer_1 = lldb.SBQueue()186        queue_performer_2 = lldb.SBQueue()187        queue_performer_3 = lldb.SBQueue()188        for idx in range(0, process.GetNumQueues()):189            q = process.GetQueueAtIndex(idx)190            if q.GetName() == "com.apple.work_submittor_1":191                queue_submittor_1 = q192            if q.GetName() == "com.apple.work_performer_1":193                queue_performer_1 = q194            if q.GetName() == "com.apple.work_performer_2":195                queue_performer_2 = q196            if q.GetName() == "com.apple.work_performer_3":197                queue_performer_3 = q198 199        self.assertTrue(200            queue_submittor_1.IsValid()201            and queue_performer_1.IsValid()202            and queue_performer_2.IsValid()203            and queue_performer_3.IsValid(),204            "Got all four expected queues: %s %s %s %s"205            % (206                queue_submittor_1.IsValid(),207                queue_performer_1.IsValid(),208                queue_performer_2.IsValid(),209                queue_performer_3.IsValid(),210            ),211        )212 213        self.check_queue_for_valid_queue_id(queue_submittor_1)214        self.check_queue_for_valid_queue_id(queue_performer_1)215        self.check_queue_for_valid_queue_id(queue_performer_2)216        self.check_queue_for_valid_queue_id(queue_performer_3)217 218        self.check_number_of_threads_owned_by_queue(queue_submittor_1, 1)219        self.check_number_of_threads_owned_by_queue(queue_performer_1, 1)220        self.check_number_of_threads_owned_by_queue(queue_performer_2, 1)221        self.check_number_of_threads_owned_by_queue(queue_performer_3, 4)222 223        self.check_queue_kind(queue_submittor_1, lldb.eQueueKindSerial)224        self.check_queue_kind(queue_performer_1, lldb.eQueueKindSerial)225        self.check_queue_kind(queue_performer_2, lldb.eQueueKindSerial)226        self.check_queue_kind(queue_performer_3, lldb.eQueueKindConcurrent)227 228        self.check_queues_threads_match_queue(queue_submittor_1)229        self.check_queues_threads_match_queue(queue_performer_1)230        self.check_queues_threads_match_queue(queue_performer_2)231        self.check_queues_threads_match_queue(queue_performer_3)232 233        # We have threads running with all the different dispatch QoS service234        # levels - find those threads and check that we can get the correct235        # QoS name for each of them.236 237        user_initiated_thread = lldb.SBThread()238        user_interactive_thread = lldb.SBThread()239        utility_thread = lldb.SBThread()240        background_thread = lldb.SBThread()241        for th in process.threads:242            if th.GetName() == "user initiated QoS":243                user_initiated_thread = th244            if th.GetName() == "user interactive QoS":245                user_interactive_thread = th246            if th.GetName() == "utility QoS":247                utility_thread = th248            if th.GetName() == "background QoS":249                background_thread = th250 251        self.assertTrue(252            user_initiated_thread.IsValid(), "Found user initiated QoS thread"253        )254        self.assertTrue(255            user_interactive_thread.IsValid(), "Found user interactive QoS thread"256        )257        self.assertTrue(utility_thread.IsValid(), "Found utility QoS thread")258        self.assertTrue(background_thread.IsValid(), "Found background QoS thread")259 260        stream = lldb.SBStream()261        self.assertTrue(262            user_initiated_thread.GetInfoItemByPathAsString(263                "requested_qos.printable_name", stream264            ),265            "Get QoS printable string for user initiated QoS thread",266        )267        self.assertEqual(268            stream.GetData(),269            "User Initiated",270            "user initiated QoS thread name is valid",271        )272        stream.Clear()273        self.assertTrue(274            user_interactive_thread.GetInfoItemByPathAsString(275                "requested_qos.printable_name", stream276            ),277            "Get QoS printable string for user interactive QoS thread",278        )279        self.assertEqual(280            stream.GetData(),281            "User Interactive",282            "user interactive QoS thread name is valid",283        )284        stream.Clear()285        self.assertTrue(286            utility_thread.GetInfoItemByPathAsString(287                "requested_qos.printable_name", stream288            ),289            "Get QoS printable string for utility QoS thread",290        )291        self.assertEqual(292            stream.GetData(), "Utility", "utility QoS thread name is valid"293        )294        stream.Clear()295        self.assertTrue(296            background_thread.GetInfoItemByPathAsString(297                "requested_qos.printable_name", stream298            ),299            "Get QoS printable string for background QoS thread",300        )301        self.assertEqual(302            stream.GetData(), "Background", "background QoS thread name is valid"303        )304 305    @skipIfDarwin  # rdar://50379398306    def queues_with_libBacktraceRecording(self):307        """Test queues inspection SB APIs with libBacktraceRecording present."""308        exe = self.getBuildArtifact("a.out")309 310        if not os.path.isfile(311            "/Applications/Xcode.app/Contents/Developer/usr/lib/libBacktraceRecording.dylib"312        ):313            self.skipTest(314                "Skipped because libBacktraceRecording.dylib was present on the system."315            )316 317        if not os.path.isfile("/usr/lib/system/introspection/libdispatch.dylib"):318            self.skipTest(319                "Skipped because introspection libdispatch dylib is not present."320            )321 322        target = self.dbg.CreateTarget(exe)323        self.assertTrue(target, VALID_TARGET)324 325        self.main_source_spec = lldb.SBFileSpec(self.main_source)326 327        break1 = target.BreakpointCreateByName("stopper", "a.out")328        self.assertTrue(break1, VALID_BREAKPOINT)329 330        # Now launch the process, and do not stop at entry point.331        libbtr_path = "/Applications/Xcode.app/Contents/Developer/usr/lib/libBacktraceRecording.dylib"332        if self.getArchitecture() in [333            "arm",334            "arm64",335            "arm64e",336            "arm64_32",337            "armv7",338            "armv7k",339        ]:340            libbtr_path = "/Developer/usr/lib/libBacktraceRecording.dylib"341 342        process = target.LaunchSimple(343            [],344            [345                "DYLD_INSERT_LIBRARIES=%s" % (libbtr_path),346                "DYLD_LIBRARY_PATH=/usr/lib/system/introspection",347            ],348            self.get_process_working_directory(),349        )350 351        self.assertTrue(process, PROCESS_IS_VALID)352 353        # The stop reason of the thread should be breakpoint.354        threads = lldbutil.get_threads_stopped_at_breakpoint(process, break1)355        if len(threads) != 1:356            self.fail("Failed to stop at breakpoint 1.")357 358        self.inferior_process = process359 360        libbtr_module_filespec = lldb.SBFileSpec("libBacktraceRecording.dylib")361        libbtr_module = target.FindModule(libbtr_module_filespec)362        if not libbtr_module.IsValid():363            self.skipTest(364                "Skipped because libBacktraceRecording.dylib was not loaded into the process."365            )366 367        self.assertGreaterEqual(368            process.GetNumQueues(), 4, "Found the correct number of queues."369        )370 371        queue_submittor_1 = lldb.SBQueue()372        queue_performer_1 = lldb.SBQueue()373        queue_performer_2 = lldb.SBQueue()374        queue_performer_3 = lldb.SBQueue()375        for idx in range(0, process.GetNumQueues()):376            q = process.GetQueueAtIndex(idx)377            if "LLDB_COMMAND_TRACE" in os.environ:378                print("Queue  with id %s has name %s" % (q.GetQueueID(), q.GetName()))379            if q.GetName() == "com.apple.work_submittor_1":380                queue_submittor_1 = q381            if q.GetName() == "com.apple.work_performer_1":382                queue_performer_1 = q383            if q.GetName() == "com.apple.work_performer_2":384                queue_performer_2 = q385            if q.GetName() == "com.apple.work_performer_3":386                queue_performer_3 = q387            if q.GetName() == "com.apple.main-thread":388                if q.GetNumThreads() == 0:389                    print("Cannot get thread <=> queue associations")390                    return391 392        self.assertTrue(393            queue_submittor_1.IsValid()394            and queue_performer_1.IsValid()395            and queue_performer_2.IsValid()396            and queue_performer_3.IsValid(),397            "Got all four expected queues: %s %s %s %s"398            % (399                queue_submittor_1.IsValid(),400                queue_performer_1.IsValid(),401                queue_performer_2.IsValid(),402                queue_performer_3.IsValid(),403            ),404        )405 406        self.check_queue_for_valid_queue_id(queue_submittor_1)407        self.check_queue_for_valid_queue_id(queue_performer_1)408        self.check_queue_for_valid_queue_id(queue_performer_2)409        self.check_queue_for_valid_queue_id(queue_performer_3)410 411        self.check_running_and_pending_items_on_queue(queue_submittor_1, 1, 0)412        self.check_running_and_pending_items_on_queue(queue_performer_1, 1, 3)413        self.check_running_and_pending_items_on_queue(queue_performer_2, 1, 9999)414        self.check_running_and_pending_items_on_queue(queue_performer_3, 4, 0)415 416        self.check_number_of_threads_owned_by_queue(queue_submittor_1, 1)417        self.check_number_of_threads_owned_by_queue(queue_performer_1, 1)418        self.check_number_of_threads_owned_by_queue(queue_performer_2, 1)419        self.check_number_of_threads_owned_by_queue(queue_performer_3, 4)420 421        self.check_queue_kind(queue_submittor_1, lldb.eQueueKindSerial)422        self.check_queue_kind(queue_performer_1, lldb.eQueueKindSerial)423        self.check_queue_kind(queue_performer_2, lldb.eQueueKindSerial)424        self.check_queue_kind(queue_performer_3, lldb.eQueueKindConcurrent)425 426        self.check_queues_threads_match_queue(queue_submittor_1)427        self.check_queues_threads_match_queue(queue_performer_1)428        self.check_queues_threads_match_queue(queue_performer_2)429        self.check_queues_threads_match_queue(queue_performer_3)430 431        self.assertTrue(432            queue_performer_2.GetPendingItemAtIndex(0).IsValid(),433            "queue 2's pending item #0 is valid",434        )435        self.assertEqual(436            queue_performer_2.GetPendingItemAtIndex(0)437            .GetAddress()438            .GetSymbol()439            .GetName(),440            "doing_the_work_2",441            "queue 2's pending item #0 should be doing_the_work_2",442        )443        self.assertEqual(444            queue_performer_2.GetNumPendingItems(),445            9999,446            "verify that queue 2 still has 9999 pending items",447        )448        self.assertTrue(449            queue_performer_2.GetPendingItemAtIndex(9998).IsValid(),450            "queue 2's pending item #9998 is valid",451        )452        self.assertEqual(453            queue_performer_2.GetPendingItemAtIndex(9998)454            .GetAddress()455            .GetSymbol()456            .GetName(),457            "doing_the_work_2",458            "queue 2's pending item #0 should be doing_the_work_2",459        )460        self.assertFalse(461            queue_performer_2.GetPendingItemAtIndex(9999).IsValid(),462            "queue 2's pending item #9999 is invalid",463        )464 465    def queue_specific_breakpoints(self):466        # Run the executable until the stopper function and get the breakpoint467        # that's created from that. Then set the queue name of the breakpoint468        # to be the name of the main thread469        (470            target,471            process,472            main_thread,473            queue_breakpoint,474        ) = lldbutil.run_to_name_breakpoint(self, "stopper", only_one_thread=False)475        queue_breakpoint.SetQueueName(main_thread.GetQueue().GetName())476 477        # Create a submittor queue478        queue_submittor_1 = lldb.SBQueue()479        for idx in range(0, process.GetNumQueues()):480            q = process.GetQueueAtIndex(idx)481            if q.GetName() == "com.apple.work_submittor_1":482                queue_submittor_1 = q483 484        self.assertTrue(485            queue_submittor_1.IsValid(),486            "Unable to get expected queue com.apple.work_submittor_1, instead got queue %s"487            % (queue_submittor_1.GetName()),488        )489 490        self.check_queue_breakpoints(491            main_thread.GetQueue(), queue_submittor_1, queue_breakpoint492        )493