[Lldb-commits] [lldb] r212671 - Add a new test in api/multiple-debuggers which tries to create 50

Todd Fiala tfiala at google.com
Thu Jul 10 10:40:06 PDT 2014


Yeah I think the stress of running the stress test along with multi-core
debugging causes this one to get *really* stressed :-)

Greg and I have briefly kicked around an idea of having a marker for tests
that are load-sensitive or otherwise should run at a time when none of the
other tests are running.  This is likely one we'd want to bucket that way.
 I'll have more to say about that when I can throw some cycles at it.


On Wed, Jul 9, 2014 at 7:17 PM, Jason Molenda <jmolenda at apple.com> wrote:

> Author: jmolenda
> Date: Wed Jul  9 21:17:31 2014
> New Revision: 212671
>
> URL: http://llvm.org/viewvc/llvm-project?rev=212671&view=rev
> Log:
> Add a new test in api/multiple-debuggers which tries to create 50
> debug sessions simultaneously to expose race conditoin/locking
> issues.
>
> This directory has an inferior program, testprog.cpp that has a
> couple of functions we can put breakpoints on.
>
> It has a driver program, multi-process-driver.cpp, which links
> against the LLDB solib and uses the SB APIs.  It creates 50 pthreads,
> creates a debugger on all of them, launches a debug session of the
> inferior testprog, hits a couple breakpoints, walks the stack,
> continues, etc., and then kills the inferior and ends the debug
> session.
>
> A pass is if all fifty debug sessions complete successfully
> in the alloted time (~60 seconds).
>
> We may need to tweak this one to work correctly on different
> platforms/targets but I wanted to get it checked in to start.
>
>
> Added:
>     lldb/trunk/test/api/multiple-debuggers/
>     lldb/trunk/test/api/multiple-debuggers/Makefile
>     lldb/trunk/test/api/multiple-debuggers/TestMultipleDebuggers.py
>     lldb/trunk/test/api/multiple-debuggers/multi-process-driver.cpp
>     lldb/trunk/test/api/multiple-debuggers/testprog.cpp
>
> Added: lldb/trunk/test/api/multiple-debuggers/Makefile
> URL:
> http://llvm.org/viewvc/llvm-project/lldb/trunk/test/api/multiple-debuggers/Makefile?rev=212671&view=auto
>
> ==============================================================================
> --- lldb/trunk/test/api/multiple-debuggers/Makefile (added)
> +++ lldb/trunk/test/api/multiple-debuggers/Makefile Wed Jul  9 21:17:31
> 2014
> @@ -0,0 +1,7 @@
> +LEVEL = ../../make
> +
> +MAKE_DSYM := NO
> +
> +CXX_SOURCES := multi-process-driver.cpp testprog.cpp
> +
> +include $(LEVEL)/Makefile.rules
>
> Added: lldb/trunk/test/api/multiple-debuggers/TestMultipleDebuggers.py
> URL:
> http://llvm.org/viewvc/llvm-project/lldb/trunk/test/api/multiple-debuggers/TestMultipleDebuggers.py?rev=212671&view=auto
>
> ==============================================================================
> --- lldb/trunk/test/api/multiple-debuggers/TestMultipleDebuggers.py (added)
> +++ lldb/trunk/test/api/multiple-debuggers/TestMultipleDebuggers.py Wed
> Jul  9 21:17:31 2014
> @@ -0,0 +1,46 @@
> +"""Test the lldb public C++ api when doing multiple debug sessions
> simultaneously."""
> +
> +import os, re, StringIO
> +import unittest2
> +from lldbtest import *
> +import lldbutil
> +import lldb
> +import subprocess
> +
> +class TestMultipleSimultaneousDebuggers(TestBase):
> +
> +    mydir = TestBase.compute_mydir(__file__)
> +
> +    def setUp(self):
> +        TestBase.setUp(self)
> +        self.lib_dir = os.environ["LLDB_LIB_DIR"]
> +
> +    @skipIfi386
> +    def test_whatever(self):
> +
> +        self.driver_exe = os.path.join(os.getcwd(),
> "multi-process-driver")
> +        self.buildDriver('multi-process-driver.cpp', self.driver_exe)
> +        self.addTearDownHook(lambda: os.remove(self.driver_exe))
> +
> +        self.inferior_exe = os.path.join(os.getcwd(), "testprog")
> +        self.buildDriver('testprog.cpp', self.inferior_exe)
> +        self.addTearDownHook(lambda: os.remove(self.inferior_exe))
> +
> +        env = {self.dylibPath : self.getLLDBLibraryEnvVal()}
> +
> +# check_call will raise a CalledProcessError if multi-process-driver
> doesn't return
> +# exit code 0 to indicate success.  We can let this exception go - the
> test harness
> +# will recognize it as a test failure.
> +
> +        if self.TraceOn():
> +            print "Running test %s" % self.driver_exe
> +            check_call([self.driver_exe, self.inferior_exe], env=env)
> +        else:
> +            with open(os.devnull, 'w') as fnull:
> +                check_call([self.driver_exe, self.inferior_exe], env=env,
> stdout=fnull, stderr=fnull)
> +
> +if __name__ == '__main__':
> +    import atexit
> +    lldb.SBDebugger.Initialize()
> +    atexit.register(lambda: lldb.SBDebugger.Terminate())
> +    unittest2.main()
>
> Added: lldb/trunk/test/api/multiple-debuggers/multi-process-driver.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/lldb/trunk/test/api/multiple-debuggers/multi-process-driver.cpp?rev=212671&view=auto
>
> ==============================================================================
> --- lldb/trunk/test/api/multiple-debuggers/multi-process-driver.cpp (added)
> +++ lldb/trunk/test/api/multiple-debuggers/multi-process-driver.cpp Wed
> Jul  9 21:17:31 2014
> @@ -0,0 +1,265 @@
> +#include <stdio.h>
> +#include <stdlib.h>
> +
> +
> +#ifdef __APPLE__
> +#include <LLDB/LLDB.h>
> +#include <LLDB/SBCommandInterpreter.h>
> +#include <LLDB/SBCommandReturnObject.h>
> +#include <LLDB/SBDebugger.h>
> +#else
> +#include "lldb/API/LLDB.h"
> +#include <lldb/API/SBCommandInterpreter.h>
> +#include <lldb/API/SBCommandReturnObject.h>
> +#include <lldb/API/SBDebugger.h>
> +#endif
> +
> +#define NUMBER_OF_SIMULTANEOUS_DEBUG_SESSIONS 50
> +
> +#define DEBUG 0
> +
> +using namespace lldb;
> +
> +bool *completed_threads_array = 0;
> +bool *successful_threads_array  = 0;
> +
> +bool
> +wait_for_stop_event (SBProcess process, SBListener listener)
> +{
> +    bool stopped = false;
> +    while (!stopped)
> +    {
> +        SBEvent event;
> +        bool waitfor_ret = listener.WaitForEvent (2, event);
> +        if (event.GetType() == SBProcess::eBroadcastBitStateChanged)
> +        {
> +            if (process.GetState() == StateType::eStateStopped
> +                || process.GetState() == StateType::eStateCrashed
> +                || process.GetState() == StateType::eStateDetached
> +                || process.GetState() == StateType::eStateExited)
> +            {
> +                stopped = true;
> +            }
> +        }
> +    }
> +    return stopped;
> +}
> +
> +bool
> +walk_stack_to_main (SBThread thread)
> +{
> +    if (thread.IsValid() == 0)
> +    {
> +        return false;
> +    }
> +
> +    bool found_main = false;
> +    uint32_t curr_frame = 0;
> +    const uint32_t framecount = thread.GetNumFrames();
> +    while (!found_main && curr_frame < framecount)
> +    {
> +        SBFrame frame = thread.GetFrameAtIndex (curr_frame);
> +        if (strcmp (frame.GetFunctionName(), "main") == 0)
> +        {
> +            found_main = true;
> +            break;
> +        }
> +        curr_frame += 1;
> +    }
> +    return found_main;
> +}
> +
> +void *do_one_debugger (void *in)
> +{
> +    uint64_t threadnum = (uint64_t) in;
> +
> +#if defined (__APPLE__)
> +    char *threadname;
> +    asprintf (&threadname, "thread #%lld", threadnum);
> +    pthread_setname_np (threadname);
> +    free (threadname);
> +#endif
> +
> +#if DEBUG == 1
> +    printf ("#%lld: Starting debug session\n", threadnum);
> +#endif
> +
> +    SBDebugger debugger = lldb::SBDebugger::Create (false);
> +    if (debugger.IsValid ())
> +    {
> +        debugger.SetAsync (true);
> +        SBTarget target =
> debugger.CreateTargetWithFileAndArch("testprog", "x86_64");
> +        SBCommandInterpreter command_interp =
> debugger.GetCommandInterpreter();
> +        if (target.IsValid())
> +        {
> +            SBBreakpoint bar_br = target.BreakpointCreateByName ("bar",
> "testprog");
> +            if (!bar_br.IsValid())
> +            {
> +                printf ("#%lld: failed to set breakpoint on bar,
> exiting.\n", threadnum);
> +                exit (1);
> +            }
> +            SBBreakpoint foo_br = target.BreakpointCreateByName ("foo",
> "testprog");
> +            if (!foo_br.IsValid())
> +            {
> +                printf ("#%lld: Failed to set breakpoint on foo()\n",
> threadnum);
> +            }
> +
> +            SBLaunchInfo launch_info (NULL);
> +            SBError error;
> +            SBProcess process = target.Launch (launch_info, error);
> +            if (process.IsValid())
> +            {
> +                SBListener listener = debugger.GetListener();
> +                SBBroadcaster broadcaster = process.GetBroadcaster();
> +                uint32_t rc = broadcaster.AddListener (listener,
> SBProcess::eBroadcastBitStateChanged);
> +                if (rc == 0)
> +                {
> +                    printf ("adding listener failed\n");
> +                    exit (1);
> +                }
> +
> +                wait_for_stop_event (process, listener);
> +
> +                if (!walk_stack_to_main (process.GetThreadAtIndex(0)))
> +                {
> +                    printf ("#%lld: backtrace while @ foo() failed\n",
> threadnum);
> +                    completed_threads_array[threadnum] = true;
> +                    return (void *) 1;
> +                }
> +
> +                if (strcmp
> (process.GetThreadAtIndex(0).GetFrameAtIndex(0).GetFunctionName(), "foo")
> != 0)
> +                {
> +#if DEBUG == 1
> +                    printf ("#%lld: First breakpoint did not stop at
> foo(), instead stopped at '%s'\n", threadnum,
> process.GetThreadAtIndex(0).GetFrameAtIndex(0).GetFunctionName());
> +#endif
> +                    completed_threads_array[threadnum] = true;
> +                    return (void*) 1;
> +                }
> +
> +                process.Continue();
> +
> +                wait_for_stop_event (process, listener);
> +
> +                if (process.GetState() == StateType::eStateExited)
> +                {
> +                    printf ("#%lld: Process exited\n", threadnum);
> +                    completed_threads_array[threadnum] = true;
> +                    return (void *) 1;
> +                }
> +
> +
> +                if (!walk_stack_to_main (process.GetThreadAtIndex(0)))
> +                {
> +                    printf ("#%lld: backtrace while @ bar() failed\n",
> threadnum);
> +                    completed_threads_array[threadnum] = true;
> +                    return (void *) 1;
> +                }
> +
> +                if (strcmp
> (process.GetThreadAtIndex(0).GetFrameAtIndex(0).GetFunctionName(), "bar")
> != 0)
> +                {
> +                    printf ("#%lld: First breakpoint did not stop at
> bar()\n", threadnum);
> +                    completed_threads_array[threadnum] = true;
> +                    return (void*) 1;
> +                }
> +
> +                process.Kill();
> +
> +                wait_for_stop_event (process, listener);
> +
> +                SBDebugger::Destroy(debugger);
> +
> +#if DEBUG == 1
> +                printf ("#%lld: All good!\n", threadnum);
> +#endif
> +                successful_threads_array[threadnum] = true;
> +                completed_threads_array[threadnum] = true;
> +                return (void*) 0;
> +            }
> +            else
> +            {
> +                printf("#%lld: process failed to launch\n", threadnum);
> +                successful_threads_array[threadnum] = false;
> +                completed_threads_array[threadnum] = true;
> +                return (void*) 0;
> +            }
> +        }
> +        else
> +        {
> +            printf ("#%lld: did not get valid target\n", threadnum);
> +            successful_threads_array[threadnum] = false;
> +            completed_threads_array[threadnum] = true;
> +            return (void*) 0;
> +        }
> +    }
> +    else
> +    {
> +        printf ("#%lld: did not get debugger\n", threadnum);
> +        successful_threads_array[threadnum] = false;
> +        completed_threads_array[threadnum] = true;
> +        return (void*) 0;
> +    }
> +    completed_threads_array[threadnum] = true;
> +    return (void*) 1;
> +}
> +
> +int main ()
> +{
> +    SBDebugger::Initialize();
> +
> +    completed_threads_array = (bool *) malloc (sizeof (bool) *
> NUMBER_OF_SIMULTANEOUS_DEBUG_SESSIONS);
> +    memset (completed_threads_array, 0, sizeof (bool) *
> NUMBER_OF_SIMULTANEOUS_DEBUG_SESSIONS);
> +    successful_threads_array = (bool *) malloc (sizeof (bool) *
> NUMBER_OF_SIMULTANEOUS_DEBUG_SESSIONS);
> +    memset (successful_threads_array, 0, sizeof (bool) *
> NUMBER_OF_SIMULTANEOUS_DEBUG_SESSIONS);
> +
> +    for (uint64_t i = 0; i< NUMBER_OF_SIMULTANEOUS_DEBUG_SESSIONS; i++)
> +    {
> +        pthread_t thread;
> +        pthread_create (&thread, NULL, do_one_debugger, (void*) i);
> +    }
> +
> +
> +    int max_time_to_wait = 20;  // 20 iterations, or 60 seconds
> +    int iter = 0;
> +    while (1)
> +    {
> +        sleep (3);
> +        bool all_done = true;
> +        int successful_threads = 0;
> +        int total_completed_threads = 0;
> +        for (uint64_t i = 0; i < NUMBER_OF_SIMULTANEOUS_DEBUG_SESSIONS;
> i++)
> +        {
> +            if (successful_threads_array[i] == true)
> +                successful_threads++;
> +            if (completed_threads_array[i] == true)
> +                total_completed_threads++;
> +            if (completed_threads_array[i] == false)
> +            {
> +                all_done = false;
> +            }
> +        }
> +        if (all_done)
> +        {
> +#if DEBUG == 1
> +            printf ("All threads completed.\n");
> +            printf ("%d threads completed successfully out of %d\n",
> successful_threads, NUMBER_OF_SIMULTANEOUS_DEBUG_SESSIONS);
> +#endif
> +            SBDebugger::Terminate();
> +            exit(0);
> +        }
> +        else
> +        {
> +#if DEBUG == 1
> +            printf ("%d threads completed so far (%d successfully), out
> of %d\n", total_completed_threads, successful_threads,
> NUMBER_OF_SIMULTANEOUS_DEBUG_SESSIONS);
> +#endif
> +        }
> +        if (iter++ == max_time_to_wait)
> +        {
> +            printf ("reached maximum timeout but only %d threads have
> completed so far (%d successfully), out of %d.  Exiting.\n",
> total_completed_threads, successful_threads,
> NUMBER_OF_SIMULTANEOUS_DEBUG_SESSIONS);
> +            break;
> +        }
> +    }
> +
> +
> +    SBDebugger::Terminate();
> +    exit (1);
> +}
>
> Added: lldb/trunk/test/api/multiple-debuggers/testprog.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/lldb/trunk/test/api/multiple-debuggers/testprog.cpp?rev=212671&view=auto
>
> ==============================================================================
> --- lldb/trunk/test/api/multiple-debuggers/testprog.cpp (added)
> +++ lldb/trunk/test/api/multiple-debuggers/testprog.cpp Wed Jul  9
> 21:17:31 2014
> @@ -0,0 +1,12 @@
> +int bar ()
> +{
> +    return 5;
> +}
> +int foo ()
> +{
> +    return bar() + 5;
> +}
> +int main ()
> +{
> +    return foo();
> +}
>
>
> _______________________________________________
> lldb-commits mailing list
> lldb-commits at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/lldb-commits
>



-- 
Todd Fiala | Software Engineer | tfiala at google.com | 650-943-3180
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/lldb-commits/attachments/20140710/67c57545/attachment.html>


More information about the lldb-commits mailing list