[Lldb-commits] [lldb] r168228 - in /lldb/trunk: include/lldb/API/ include/lldb/Core/ include/lldb/Target/ scripts/Python/interface/ source/API/ source/Plugins/Process/gdb-remote/ source/Target/ tools/debugserver/source/ tools/debugserver/source/MacOSX/

Han Ming Ong hanming at apple.com
Fri Nov 16 16:21:04 PST 2012


Author: hanming
Date: Fri Nov 16 18:21:04 2012
New Revision: 168228

URL: http://llvm.org/viewvc/llvm-project?rev=168228&view=rev
Log:
<rdar://problem/12720514> Sub-TLF: Provide service to profile the inferior

This allows client to query profiling states on the inferior.

Modified:
    lldb/trunk/include/lldb/API/SBProcess.h
    lldb/trunk/include/lldb/Core/Broadcaster.h
    lldb/trunk/include/lldb/Target/Process.h
    lldb/trunk/scripts/Python/interface/SBProcess.i
    lldb/trunk/source/API/SBProcess.cpp
    lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
    lldb/trunk/source/Target/Process.cpp
    lldb/trunk/tools/debugserver/source/DNB.cpp
    lldb/trunk/tools/debugserver/source/DNB.h
    lldb/trunk/tools/debugserver/source/DNBDefs.h
    lldb/trunk/tools/debugserver/source/MacOSX/MachProcess.cpp
    lldb/trunk/tools/debugserver/source/MacOSX/MachProcess.h
    lldb/trunk/tools/debugserver/source/MacOSX/MachTask.cpp
    lldb/trunk/tools/debugserver/source/MacOSX/MachTask.h
    lldb/trunk/tools/debugserver/source/MacOSX/MachVMMemory.cpp
    lldb/trunk/tools/debugserver/source/MacOSX/MachVMMemory.h
    lldb/trunk/tools/debugserver/source/RNBContext.cpp
    lldb/trunk/tools/debugserver/source/RNBContext.h
    lldb/trunk/tools/debugserver/source/RNBRemote.cpp
    lldb/trunk/tools/debugserver/source/RNBRemote.h
    lldb/trunk/tools/debugserver/source/debugserver.cpp

Modified: lldb/trunk/include/lldb/API/SBProcess.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/API/SBProcess.h?rev=168228&r1=168227&r2=168228&view=diff
==============================================================================
--- lldb/trunk/include/lldb/API/SBProcess.h (original)
+++ lldb/trunk/include/lldb/API/SBProcess.h Fri Nov 16 18:21:04 2012
@@ -30,7 +30,8 @@
         eBroadcastBitStateChanged   = (1 << 0),
         eBroadcastBitInterrupt      = (1 << 1),
         eBroadcastBitSTDOUT         = (1 << 2),
-        eBroadcastBitSTDERR         = (1 << 3)
+        eBroadcastBitSTDERR         = (1 << 3),
+        eBroadcastBitProfileData    = (1 << 4)
     };
 
     SBProcess ();
@@ -74,6 +75,9 @@
     size_t
     GetSTDERR (char *dst, size_t dst_len) const;
 
+    size_t
+    GetAsyncProfileData(char *dst, size_t dst_len) const;
+    
     void
     ReportEventState (const lldb::SBEvent &event, FILE *out) const;
 

Modified: lldb/trunk/include/lldb/Core/Broadcaster.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Core/Broadcaster.h?rev=168228&r1=168227&r2=168228&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Core/Broadcaster.h (original)
+++ lldb/trunk/include/lldb/Core/Broadcaster.h Fri Nov 16 18:21:04 2012
@@ -233,7 +233,8 @@
 ///             eBroadcastBitStateChanged   = (1 << 0),
 ///             eBroadcastBitInterrupt      = (1 << 1),
 ///             eBroadcastBitSTDOUT         = (1 << 2),
-///             eBroadcastBitSTDERR         = (1 << 3)
+///             eBroadcastBitSTDERR         = (1 << 3),
+///             eBroadcastBitProfileData    = (1 << 4)
 ///         };
 ///     \endcode
 //----------------------------------------------------------------------

Modified: lldb/trunk/include/lldb/Target/Process.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Target/Process.h?rev=168228&r1=168227&r2=168228&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Target/Process.h (original)
+++ lldb/trunk/include/lldb/Target/Process.h Fri Nov 16 18:21:04 2012
@@ -1344,7 +1344,8 @@
         eBroadcastBitStateChanged   = (1 << 0),
         eBroadcastBitInterrupt      = (1 << 1),
         eBroadcastBitSTDOUT         = (1 << 2),
-        eBroadcastBitSTDERR         = (1 << 3)
+        eBroadcastBitSTDERR         = (1 << 3),
+        eBroadcastBitProfileData    = (1 << 4)
     };
 
     enum
@@ -2942,6 +2943,35 @@
 
     Error
     DeallocateMemory (lldb::addr_t ptr);
+    
+//    virtual Error
+//    DoGetProfileData (uint64_t &elapsed_usec,
+//                      uint64_t &task_used_usec,
+//                      int &num_threads,
+//                      uint64_t **threads_id,
+//                      uint64_t **threads_used_usec,
+//                      mach_vm_size_t &rprvt,
+//                      mach_vm_size_t &rsize,
+//                      mach_vm_size_t &vprvt,
+//                      mach_vm_size_t &vsize,
+//                      mach_vm_size_t &dirty_size)
+//    {
+//        Error error;
+//        error.SetErrorStringWithFormat("error: wrong method called.");
+//        return error;
+//    }
+//    
+//    Error
+//    GetProfileData (uint64_t &elapsed_usec,
+//                    uint64_t &task_used_usec,
+//                    int &num_threads,
+//                    uint64_t **threads_id,
+//                    uint64_t **threads_used_usec,
+//                    mach_vm_size_t &rprvt,
+//                    mach_vm_size_t &rsize,
+//                    mach_vm_size_t &vprvt,
+//                    mach_vm_size_t &vsize,
+//                    mach_vm_size_t &dirty_size);
 
     //------------------------------------------------------------------
     /// Get any available STDOUT.
@@ -2998,6 +3028,24 @@
         return 0;
     }
 
+    //------------------------------------------------------------------
+    /// Get any available profile data.
+    ///
+    /// @param[out] buf
+    ///     A buffer that will receive any profile data bytes that are
+    ///     currently available.
+    ///
+    /// @param[out] buf_size
+    ///     The size in bytes for the buffer \a buf.
+    ///
+    /// @return
+    ///     The number of bytes written into \a buf. If this value is
+    ///     equal to \a buf_size, another call to this function should
+    ///     be made to retrieve more profile data.
+    //------------------------------------------------------------------
+    virtual size_t
+    GetAsyncProfileData (char *buf, size_t buf_size, Error &error);
+    
     //----------------------------------------------------------------------
     // Process Breakpoints
     //----------------------------------------------------------------------
@@ -3443,6 +3491,8 @@
     Mutex        				m_stdio_communication_mutex;
     std::string                 m_stdout_data;
     std::string                 m_stderr_data;
+    Mutex                       m_profile_data_comm_mutex;
+    std::string                 m_profile_data;
     MemoryCache                 m_memory_cache;
     AllocatedMemoryCache        m_allocated_memory_cache;
     bool                        m_should_detach;   /// Should we detach if the process object goes away with an explicit call to Kill or Detach?
@@ -3518,6 +3568,9 @@
     void
     AppendSTDERR (const char *s, size_t len);
     
+    void
+    BroadcastAsyncProfileData(const char *s, size_t len);
+    
     static void
     STDIOReadThreadBytesReceived (void *baton, const void *src, size_t src_len);
     

Modified: lldb/trunk/scripts/Python/interface/SBProcess.i
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/scripts/Python/interface/SBProcess.i?rev=168228&r1=168227&r2=168228&view=diff
==============================================================================
--- lldb/trunk/scripts/Python/interface/SBProcess.i (original)
+++ lldb/trunk/scripts/Python/interface/SBProcess.i Fri Nov 16 18:21:04 2012
@@ -43,7 +43,8 @@
         eBroadcastBitStateChanged   = (1 << 0),
         eBroadcastBitInterrupt      = (1 << 1),
         eBroadcastBitSTDOUT         = (1 << 2),
-        eBroadcastBitSTDERR         = (1 << 3)
+        eBroadcastBitSTDERR         = (1 << 3),
+        eBroadcastBitProfileData    = (1 << 4)
     };
 
     SBProcess ();
@@ -96,6 +97,9 @@
     size_t
     GetSTDERR (char *dst, size_t dst_len) const;
 
+    size_t
+    GetAsyncProfileData(char *dst, size_t dst_len) const;
+    
     void
     ReportEventState (const lldb::SBEvent &event, FILE *out) const;
 

Modified: lldb/trunk/source/API/SBProcess.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/API/SBProcess.cpp?rev=168228&r1=168227&r2=168228&view=diff
==============================================================================
--- lldb/trunk/source/API/SBProcess.cpp (original)
+++ lldb/trunk/source/API/SBProcess.cpp Fri Nov 16 18:21:04 2012
@@ -366,6 +366,29 @@
     return bytes_read;
 }
 
+size_t
+SBProcess::GetAsyncProfileData(char *dst, size_t dst_len) const
+{
+    size_t bytes_read = 0;
+    ProcessSP process_sp(GetSP());
+    if (process_sp)
+    {
+        Error error;
+        bytes_read = process_sp->GetAsyncProfileData (dst, dst_len, error);
+    }
+    
+    LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+    if (log)
+        log->Printf ("SBProcess(%p)::GetProfileData (dst=\"%.*s\", dst_len=%llu) => %llu",
+                     process_sp.get(),
+                     (int) bytes_read,
+                     dst,
+                     (uint64_t)dst_len,
+                     (uint64_t)bytes_read);
+    
+    return bytes_read;
+}
+
 void
 SBProcess::ReportEventState (const SBEvent &event, FILE *out) const
 {

Modified: lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp?rev=168228&r1=168227&r2=168228&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp (original)
+++ lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp Fri Nov 16 18:21:04 2012
@@ -647,6 +647,16 @@
                     }
                     break;
 
+                case 'A':
+                    // Async miscellaneous reply. Right now, only profile data is coming through this channel.
+                    {
+                        const std::string& profile_data = response.GetStringRef();
+                        const char *data_cstr = profile_data.c_str();
+                        data_cstr++; // Move beyond 'A'
+                        process->BroadcastAsyncProfileData (data_cstr, profile_data.size()-1);
+                    }
+                    break;
+
                 case 'E':
                     // ERROR
                     state = eStateInvalid;

Modified: lldb/trunk/source/Target/Process.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Target/Process.cpp?rev=168228&r1=168227&r2=168228&view=diff
==============================================================================
--- lldb/trunk/source/Target/Process.cpp (original)
+++ lldb/trunk/source/Target/Process.cpp Fri Nov 16 18:21:04 2012
@@ -953,6 +953,8 @@
     m_stdio_communication_mutex (Mutex::eMutexTypeRecursive),
     m_stdout_data (),
     m_stderr_data (),
+    m_profile_data_comm_mutex (Mutex::eMutexTypeRecursive),
+    m_profile_data (),
     m_memory_cache (*this),
     m_allocated_memory_cache (*this),
     m_should_detach (false),
@@ -972,6 +974,7 @@
     SetEventName (eBroadcastBitInterrupt, "interrupt");
     SetEventName (eBroadcastBitSTDOUT, "stdout-available");
     SetEventName (eBroadcastBitSTDERR, "stderr-available");
+    SetEventName (eBroadcastBitProfileData, "profile-data-available");
     
     m_private_state_control_broadcaster.SetEventName (eBroadcastInternalStateControlStop  , "control-stop"  );
     m_private_state_control_broadcaster.SetEventName (eBroadcastInternalStateControlPause , "control-pause" );
@@ -981,7 +984,8 @@
                                       eBroadcastBitStateChanged |
                                       eBroadcastBitInterrupt |
                                       eBroadcastBitSTDOUT |
-                                      eBroadcastBitSTDERR);
+                                      eBroadcastBitSTDERR |
+                                      eBroadcastBitProfileData);
 
     m_private_state_listener.StartListeningForEvents(&m_private_state_broadcaster,
                                                      eBroadcastBitStateChanged |
@@ -2546,6 +2550,12 @@
     return error;
 }
 
+//Error
+//Process::GetProfileData (uint64_t &elapsed_usec, uint64_t &task_used_usec, int &num_threads, uint64_t **threads_id, uint64_t **threads_used_usec, mach_vm_size_t &rprvt, mach_vm_size_t &rsize, mach_vm_size_t &vprvt, mach_vm_size_t &vsize, mach_vm_size_t &dirty_size)
+//{
+//    return DoGetProfileData(elapsed_usec, task_used_usec, num_threads, threads_id, threads_used_usec, rprvt, rsize, vprvt, vsize, dirty_size);
+//}
+//
 ModuleSP
 Process::ReadModuleFromMemory (const FileSpec& file_spec, 
                                lldb::addr_t header_addr, 
@@ -3999,6 +4009,40 @@
     BroadcastEventIfUnique (eBroadcastBitSTDERR, new ProcessEventData (shared_from_this(), GetState()));
 }
 
+void
+Process::BroadcastAsyncProfileData(const char *s, size_t len)
+{
+    Mutex::Locker locker (m_profile_data_comm_mutex);
+    m_profile_data.append (s, len);
+    BroadcastEventIfUnique (eBroadcastBitProfileData, new ProcessEventData (shared_from_this(), GetState()));
+}
+
+size_t
+Process::GetAsyncProfileData (char *buf, size_t buf_size, Error &error)
+{
+    Mutex::Locker locker(m_profile_data_comm_mutex);
+    size_t bytes_available = m_profile_data.size();
+    if (bytes_available > 0)
+    {
+        LogSP log (lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
+        if (log)
+            log->Printf ("Process::GetProfileData (buf = %p, size = %llu)", buf, (uint64_t)buf_size);
+        if (bytes_available > buf_size)
+        {
+            memcpy(buf, m_profile_data.c_str(), buf_size);
+            m_profile_data.erase(0, buf_size);
+            bytes_available = buf_size;
+        }
+        else
+        {
+            memcpy(buf, m_profile_data.c_str(), bytes_available);
+            m_profile_data.clear();
+        }
+    }
+    return bytes_available;
+}
+
+
 //------------------------------------------------------------------
 // Process STDIO
 //------------------------------------------------------------------

Modified: lldb/trunk/tools/debugserver/source/DNB.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/debugserver/source/DNB.cpp?rev=168228&r1=168227&r2=168228&view=diff
==============================================================================
--- lldb/trunk/tools/debugserver/source/DNB.cpp (original)
+++ lldb/trunk/tools/debugserver/source/DNB.cpp Fri Nov 16 18:21:04 2012
@@ -1217,6 +1217,38 @@
     return -1;
 }
 
+const char *
+DNBProcessGetProfileDataAsCString (nub_process_t pid)
+{
+    MachProcessSP procSP;
+    if (GetProcessSP (pid, procSP))
+        return procSP->Task().GetProfileDataAsCString();
+    
+    return NULL;
+}
+
+//nub_bool_t
+//DNBProcessGetProfileData (nub_process_t pid, uint64_t &elapsed_usec, uint64_t &task_used_usec, int &num_threads, uint64_t **threads_id, uint64_t **threads_used_usec, mach_vm_size_t &rprvt, mach_vm_size_t &rsize, mach_vm_size_t &vprvt, mach_vm_size_t &vsize, mach_vm_size_t &dirty_size)
+//{
+//    MachProcessSP procSP;
+//    if (GetProcessSP (pid, procSP))
+//        return procSP->Task().GetProfileData(elapsed_usec, task_used_usec, num_threads, threads_id, threads_used_usec, rprvt, rsize, vprvt, vsize, dirty_size);
+//    
+//    return false;
+//}
+//
+nub_bool_t
+DNBProcessSetAsyncEnableProfiling (nub_process_t pid, nub_bool_t enable, uint64_t interval_usec)
+{
+    MachProcessSP procSP;
+    if (GetProcessSP (pid, procSP))
+    {
+        procSP->SetAsyncEnableProfiling(enable, interval_usec);
+        return true;
+    }
+    
+    return false;    
+}
 
 //----------------------------------------------------------------------
 // Formatted output that uses memory and registers from process and
@@ -2072,6 +2104,15 @@
 }
 
 nub_size_t
+DNBProcessGetAvailableProfileData (nub_process_t pid, char *buf, nub_size_t buf_size)
+{
+    MachProcessSP procSP;
+    if (GetProcessSP (pid, procSP))
+        return procSP->GetAsyncProfileData (buf, buf_size);
+    return 0;
+}
+
+nub_size_t
 DNBProcessGetStopCount (nub_process_t pid)
 {
     MachProcessSP procSP;

Modified: lldb/trunk/tools/debugserver/source/DNB.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/debugserver/source/DNB.h?rev=168228&r1=168227&r2=168228&view=diff
==============================================================================
--- lldb/trunk/tools/debugserver/source/DNB.h (original)
+++ lldb/trunk/tools/debugserver/source/DNB.h Fri Nov 16 18:21:04 2012
@@ -67,6 +67,8 @@
 nub_addr_t      DNBProcessMemoryAllocate    (nub_process_t pid, nub_size_t size, uint32_t permissions) DNB_EXPORT;
 nub_bool_t      DNBProcessMemoryDeallocate  (nub_process_t pid, nub_addr_t addr) DNB_EXPORT;
 int             DNBProcessMemoryRegionInfo  (nub_process_t pid, nub_addr_t addr, DNBRegionInfo *region_info) DNB_EXPORT;
+const char *    DNBProcessGetProfileDataAsCString (nub_process_t pid) DNB_EXPORT; // Process owns the returned string. Do not free.
+nub_bool_t      DNBProcessSetAsyncEnableProfiling   (nub_process_t pid, nub_bool_t enable, uint64_t interval_usec) DNB_EXPORT;
 
 //----------------------------------------------------------------------
 // Process status
@@ -88,6 +90,7 @@
 nub_addr_t      DNBProcessLookupAddress                 (nub_process_t pid, const char *name, const char *shlib) DNB_EXPORT;
 nub_size_t      DNBProcessGetAvailableSTDOUT            (nub_process_t pid, char *buf, nub_size_t buf_size) DNB_EXPORT;
 nub_size_t      DNBProcessGetAvailableSTDERR            (nub_process_t pid, char *buf, nub_size_t buf_size) DNB_EXPORT;
+nub_size_t      DNBProcessGetAvailableProfileData       (nub_process_t pid, char *buf, nub_size_t buf_size) DNB_EXPORT;
 nub_size_t      DNBProcessGetStopCount                  (nub_process_t pid) DNB_EXPORT;
 uint32_t        DNBProcessGetCPUType                    (nub_process_t pid) DNB_EXPORT; 
 

Modified: lldb/trunk/tools/debugserver/source/DNBDefs.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/debugserver/source/DNBDefs.h?rev=168228&r1=168227&r2=168228&view=diff
==============================================================================
--- lldb/trunk/tools/debugserver/source/DNBDefs.h (original)
+++ lldb/trunk/tools/debugserver/source/DNBDefs.h Fri Nov 16 18:21:04 2012
@@ -134,11 +134,13 @@
     eEventProcessStoppedStateChanged = 1 << 1,  // The process has changed state to stopped
     eEventSharedLibsStateChange = 1 << 2,       // Shared libraries loaded/unloaded state has changed
     eEventStdioAvailable = 1 << 3,              // Something is available on stdout/stderr
-    eEventProcessAsyncInterrupt = 1 << 4,               // Gives the ability for any infinite wait calls to be interrupted
+    eEventProfileDataAvailable = 1 << 4,        // Profile data ready for retrieval
+    eEventProcessAsyncInterrupt = 1 << 5,       // Gives the ability for any infinite wait calls to be interrupted
     kAllEventsMask = eEventProcessRunningStateChanged |
                      eEventProcessStoppedStateChanged |
                      eEventSharedLibsStateChange |
                      eEventStdioAvailable |
+                     eEventProfileDataAvailable |
                      eEventProcessAsyncInterrupt
 };
 

Modified: lldb/trunk/tools/debugserver/source/MacOSX/MachProcess.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/debugserver/source/MacOSX/MachProcess.cpp?rev=168228&r1=168227&r2=168228&view=diff
==============================================================================
--- lldb/trunk/tools/debugserver/source/MacOSX/MachProcess.cpp (original)
+++ lldb/trunk/tools/debugserver/source/MacOSX/MachProcess.cpp Fri Nov 16 18:21:04 2012
@@ -83,6 +83,11 @@
     m_stdio_mutex       (PTHREAD_MUTEX_RECURSIVE),
     m_stdout_data       (),
     m_thread_actions    (),
+    m_profile_enabled   (false),
+    m_profile_interval_usec (0),
+    m_profile_thread    (0),
+    m_profile_data_mutex(PTHREAD_MUTEX_RECURSIVE),
+    m_profile_data      (),
     m_thread_list        (),
     m_exception_messages (),
     m_exception_messages_mutex (PTHREAD_MUTEX_RECURSIVE),
@@ -286,6 +291,11 @@
         PTHREAD_MUTEX_LOCKER(locker, m_exception_messages_mutex);
         m_exception_messages.clear();
     }
+    if (m_profile_thread)
+    {
+        pthread_join(m_profile_thread, NULL);
+        m_profile_thread = NULL;
+    }
 }
 
 
@@ -297,6 +307,26 @@
     return ::pthread_create (&m_stdio_thread, NULL, MachProcess::STDIOThread, this) == 0;
 }
 
+void
+MachProcess::SetAsyncEnableProfiling(bool enable, uint64_t interval_usec)
+{
+    m_profile_enabled = enable;
+    m_profile_interval_usec = interval_usec;
+    
+    if (m_profile_enabled && (m_profile_thread == 0))
+    {
+        StartProfileThread();
+    }
+}
+
+bool
+MachProcess::StartProfileThread()
+{
+    DNBLogThreadedIf(LOG_PROCESS, "MachProcess::%s ( )", __FUNCTION__);
+    // Create the thread that profiles the inferior and reports back if enabled
+    return ::pthread_create (&m_profile_thread, NULL, MachProcess::ProfileThread, this) == 0;
+}
+
 
 nub_addr_t
 MachProcess::LookupSymbol(const char *name, const char *shlib)
@@ -1311,6 +1341,74 @@
     return NULL;
 }
 
+
+void
+MachProcess::SignalAsyncProfileData (const char *info)
+{
+    DNBLogThreadedIf(LOG_PROCESS, "MachProcess::%s (%s) ...", __FUNCTION__, info);
+    PTHREAD_MUTEX_LOCKER (locker, m_profile_data_mutex);
+    m_profile_data.append(info);
+    m_events.SetEvents(eEventProfileDataAvailable);
+    
+    // Wait for the event bit to reset if a reset ACK is requested
+    m_events.WaitForResetAck(eEventProfileDataAvailable);
+}
+
+
+size_t
+MachProcess::GetAsyncProfileData (char *buf, size_t buf_size)
+{
+    DNBLogThreadedIf(LOG_PROCESS, "MachProcess::%s (&%p[%llu]) ...", __FUNCTION__, buf, (uint64_t)buf_size);
+    PTHREAD_MUTEX_LOCKER (locker, m_profile_data_mutex);
+    size_t bytes_available = m_profile_data.size();
+    if (bytes_available > 0)
+    {
+        if (bytes_available > buf_size)
+        {
+            memcpy(buf, m_profile_data.data(), buf_size);
+            m_profile_data.erase(0, buf_size);
+            bytes_available = buf_size;
+        }
+        else
+        {
+            memcpy(buf, m_profile_data.data(), bytes_available);
+            m_profile_data.clear();
+        }
+    }
+    return bytes_available;
+}
+
+
+void *
+MachProcess::ProfileThread(void *arg)
+{
+    MachProcess *proc = (MachProcess*) arg;
+    DNBLogThreadedIf(LOG_PROCESS, "MachProcess::%s ( arg = %p ) thread starting...", __FUNCTION__, arg);
+
+    while (proc->IsProfilingEnabled())
+    {
+        nub_state_t state = proc->GetState();
+        if (state == eStateRunning)
+        {
+            const char *data = proc->Task().GetProfileDataAsCString();
+            if (data)
+            {
+                proc->SignalAsyncProfileData(data);
+            }
+        }
+        else if ((state == eStateUnloaded) || (state == eStateDetached) || (state == eStateUnloaded))
+        {
+            // Done. Get out of this thread.
+            break;
+        }
+        
+        // A simple way to set up the profile interval. We can also use select() or dispatch timer source if necessary.
+        usleep(proc->ProfileInterval());
+    }
+    return NULL;
+}
+
+
 pid_t
 MachProcess::AttachForDebug (pid_t pid, char *err_str, size_t err_len)
 {

Modified: lldb/trunk/tools/debugserver/source/MacOSX/MachProcess.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/debugserver/source/MacOSX/MachProcess.h?rev=168228&r1=168227&r2=168228&view=diff
==============================================================================
--- lldb/trunk/tools/debugserver/source/MacOSX/MachProcess.h (original)
+++ lldb/trunk/tools/debugserver/source/MacOSX/MachProcess.h Fri Nov 16 18:21:04 2012
@@ -144,6 +144,17 @@
     void                    ExceptionMessageBundleComplete ();
     void                    SharedLibrariesUpdated ();
     nub_size_t              CopyImageInfos (struct DNBExecutableImageInfo **image_infos, bool only_changed);
+    
+    //----------------------------------------------------------------------
+    // Profile functions
+    //----------------------------------------------------------------------
+    void                    SetAsyncEnableProfiling (bool enable, uint64_t internal_usec);
+    bool                    IsProfilingEnabled () { return m_profile_enabled; }
+    uint64_t                ProfileInterval () { return m_profile_interval_usec; }
+    bool                    StartProfileThread ();
+    static void *           ProfileThread (void *arg);
+    void                    SignalAsyncProfileData (const char *info);
+    size_t                  GetAsyncProfileData (char *buf, size_t buf_size);
 
     //----------------------------------------------------------------------
     // Accessors
@@ -266,6 +277,13 @@
     pthread_t                   m_stdio_thread;             // Thread ID for the thread that watches for child process stdio
     PThreadMutex                m_stdio_mutex;              // Multithreaded protection for stdio
     std::string                 m_stdout_data;
+    
+    bool                        m_profile_enabled;          // A flag to indicate if profiling is enabled
+    uint64_t                    m_profile_interval_usec;    // If enable, the profiling interval in microseconds
+    pthread_t                   m_profile_thread;           // Thread ID for the thread that profiles the inferior
+    PThreadMutex                m_profile_data_mutex;       // Multithreaded protection for profile info data
+    std::string                 m_profile_data;             // Profile data, must be protected by m_profile_data_mutex
+    
     DNBThreadResumeActions      m_thread_actions;           // The thread actions for the current MachProcess::Resume() call
     MachException::Message::collection
                                 m_exception_messages;       // A collection of exception messages caught when listening to the exception port

Modified: lldb/trunk/tools/debugserver/source/MacOSX/MachTask.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/debugserver/source/MacOSX/MachTask.cpp?rev=168228&r1=168227&r2=168228&view=diff
==============================================================================
--- lldb/trunk/tools/debugserver/source/MacOSX/MachTask.cpp (original)
+++ lldb/trunk/tools/debugserver/source/MacOSX/MachTask.cpp Fri Nov 16 18:21:04 2012
@@ -23,6 +23,8 @@
 #include <mach/mach_vm.h>
 
 // C++ Includes
+#include <sstream>
+
 // Other libraries and framework includes
 // Project includes
 #include "CFUtils.h"
@@ -224,6 +226,132 @@
     return ret;
 }
 
+#define	TIME_VALUE_TO_TIMEVAL(a, r) do {		\
+(r)->tv_sec = (a)->seconds;                     \
+(r)->tv_usec = (a)->microseconds;				\
+} while (0)
+
+// todo: make use of existing MachThread, if there is already one?
+static void update_used_time(task_t task, int &num_threads, uint64_t **threads_id, uint64_t **threads_used_usec, struct timeval &current_used_time)
+{
+	kern_return_t kr;
+	thread_act_array_t threads;
+	mach_msg_type_number_t tcnt;
+    
+	kr = task_threads(task, &threads, &tcnt);
+	if (kr != KERN_SUCCESS)
+        return;
+    
+    num_threads = tcnt;
+    *threads_id = (uint64_t *)malloc(num_threads * sizeof(uint64_t));
+    *threads_used_usec = (uint64_t *)malloc(num_threads * sizeof(uint64_t));
+
+	for (int i = 0; i < tcnt; i++) {
+        thread_identifier_info_data_t identifier_info;
+        mach_msg_type_number_t count = THREAD_IDENTIFIER_INFO_COUNT;
+        kr = thread_info(threads[i], THREAD_IDENTIFIER_INFO, (thread_info_t)&identifier_info, &count);
+        if (kr != KERN_SUCCESS) continue;
+
+		thread_basic_info_data_t basic_info;
+		count = THREAD_BASIC_INFO_COUNT;
+		kr = thread_info(threads[i], THREAD_BASIC_INFO, (thread_info_t)&basic_info, &count);
+		if (kr != KERN_SUCCESS) continue;
+		
+		if ((basic_info.flags & TH_FLAGS_IDLE) == 0) {
+            (*threads_id)[i] = identifier_info.thread_id;
+
+			struct timeval tv;
+			struct timeval thread_tv;
+			TIME_VALUE_TO_TIMEVAL(&basic_info.user_time, &tv);
+			TIME_VALUE_TO_TIMEVAL(&basic_info.user_time, &thread_tv);
+			timeradd(&current_used_time, &tv, &current_used_time);
+			TIME_VALUE_TO_TIMEVAL(&basic_info.system_time, &tv);
+			timeradd(&thread_tv, &tv, &thread_tv);
+			timeradd(&current_used_time, &tv, &current_used_time);
+            uint64_t used_usec = thread_tv.tv_sec * 1000000ULL + thread_tv.tv_usec;
+            (*threads_used_usec)[i] = used_usec;
+		}
+        
+		kr = mach_port_deallocate(mach_task_self(), threads[i]);
+	}
+	kr = mach_vm_deallocate(mach_task_self(), (mach_vm_address_t)(uintptr_t)threads, tcnt * sizeof(*threads));
+}
+
+const char *
+MachTask::GetProfileDataAsCString ()
+{
+    task_t task = TaskPort();
+	if (task == TASK_NULL)
+		return NULL;
+    
+    struct task_basic_info task_info;
+    DNBError err;
+    err = BasicInfo(task, &task_info);
+    
+    if (!err.Success())
+        return NULL;
+    
+    uint64_t elapsed_usec = 0;
+    uint64_t task_used_usec = 0;
+    int num_threads = 0;
+    uint64_t *threads_used_usec = NULL;
+    uint64_t *threads_id = NULL;
+    mach_vm_size_t rprvt = 0;
+    mach_vm_size_t rsize = 0;
+    mach_vm_size_t vprvt = 0;
+    mach_vm_size_t vsize = 0;
+    mach_vm_size_t dirty_size = 0;
+
+    // Get current used time.
+    struct timeval current_used_time;
+    struct timeval tv;
+    TIME_VALUE_TO_TIMEVAL(&task_info.user_time, &current_used_time);
+    TIME_VALUE_TO_TIMEVAL(&task_info.system_time, &tv);
+    timeradd(&current_used_time, &tv, &current_used_time);
+    task_used_usec = current_used_time.tv_sec * 1000000ULL + current_used_time.tv_usec;
+    update_used_time(task, num_threads, &threads_id, &threads_used_usec, current_used_time);
+    
+    struct timeval current_elapsed_time;
+    int res = gettimeofday(&current_elapsed_time, NULL);
+    if (res == 0)
+    {
+        elapsed_usec = current_elapsed_time.tv_sec * 1000000ULL + current_elapsed_time.tv_usec;
+    }
+    
+    if (m_vm_memory.GetMemoryProfile(task, task_info, m_process->GetCPUType(), m_process->ProcessID(), rprvt, rsize, vprvt, vsize, dirty_size))
+    {
+        std::ostringstream profile_data_stream;
+        
+        profile_data_stream << "elapsed_usec:" << elapsed_usec << ';';
+        profile_data_stream << "task_used_usec:" << task_used_usec << ';';
+        
+        profile_data_stream << "threads_info:" << num_threads;
+        for (int i=0; i<num_threads; i++) {
+            profile_data_stream << ',' << threads_id[i];
+            profile_data_stream << ',' << threads_used_usec[i];
+        }
+        profile_data_stream << ';';
+        
+        profile_data_stream << "rprvt:" << rprvt << ';';
+        profile_data_stream << "rsize:" << rsize << ';';
+        profile_data_stream << "vprvt:" << vprvt << ';';
+        profile_data_stream << "vsize:" << vsize << ';';
+        profile_data_stream << "dirty:" << dirty_size << ';';
+        profile_data_stream << "$";
+        
+        m_profile_data = profile_data_stream.str();
+    }
+    else
+    {
+        m_profile_data.clear();
+    }
+    
+    free(threads_id);
+    free(threads_used_usec);
+    
+    return m_profile_data.c_str();
+}
+
 
 //----------------------------------------------------------------------
 // MachTask::TaskPortForProcessID

Modified: lldb/trunk/tools/debugserver/source/MacOSX/MachTask.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/debugserver/source/MacOSX/MachTask.h?rev=168228&r1=168227&r2=168228&view=diff
==============================================================================
--- lldb/trunk/tools/debugserver/source/MacOSX/MachTask.h (original)
+++ lldb/trunk/tools/debugserver/source/MacOSX/MachTask.h Fri Nov 16 18:21:04 2012
@@ -23,6 +23,7 @@
 #include <sys/socket.h>
 // C++ Includes
 #include <map>
+#include <string>
 // Other libraries and framework includes
 // Project includes
 #include "MachException.h"
@@ -65,6 +66,7 @@
             nub_size_t      ReadMemory (nub_addr_t addr, nub_size_t size, void *buf);
             nub_size_t      WriteMemory (nub_addr_t addr, nub_size_t size, const void *buf);
             int             GetMemoryRegionInfo (nub_addr_t addr, DNBRegionInfo *region_info);
+            const char *    GetProfileDataAsCString ();
 
             nub_addr_t      AllocateMemory (nub_size_t size, uint32_t permissions);
             nub_bool_t      DeallocateMemory (nub_addr_t addr);
@@ -121,6 +123,7 @@
 
             typedef std::map <mach_vm_address_t, size_t> allocation_collection;
             allocation_collection m_allocations;
+            std::string m_profile_data;
 
 private:
     MachTask(const MachTask&); // Outlaw

Modified: lldb/trunk/tools/debugserver/source/MacOSX/MachVMMemory.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/debugserver/source/MacOSX/MachVMMemory.cpp?rev=168228&r1=168227&r2=168228&view=diff
==============================================================================
--- lldb/trunk/tools/debugserver/source/MacOSX/MachVMMemory.cpp (original)
+++ lldb/trunk/tools/debugserver/source/MacOSX/MachVMMemory.cpp Fri Nov 16 18:21:04 2012
@@ -15,6 +15,7 @@
 #include "MachVMRegion.h"
 #include "DNBLog.h"
 #include <mach/mach_vm.h>
+#include <mach/shared_region.h>
 
 MachVMMemory::MachVMMemory() :
     m_page_size    (kInvalidPageSize),
@@ -88,6 +89,206 @@
     return true;
 }
 
+// rsize and dirty_size is not adjusted for dyld shared cache and multiple __LINKEDIT segment, as in vmmap. In practice, dirty_size doesn't differ much but rsize may. There is performance penalty for the adjustment. Right now, only use the dirty_size.
+static void GetRegionSizes(task_t task, mach_vm_size_t &rsize, mach_vm_size_t &dirty_size)
+{
+    mach_vm_address_t address = 0;
+    mach_vm_size_t size;
+    kern_return_t err = 0;
+    unsigned nestingDepth = 0;
+    mach_vm_size_t pages_resident = 0;
+    mach_vm_size_t pages_dirtied = 0;
+    
+    while (1)
+    {
+        mach_msg_type_number_t	count;
+        struct vm_region_submap_info_64 info;
+        
+        count = VM_REGION_SUBMAP_INFO_COUNT_64;
+        err = mach_vm_region_recurse(task, &address, &size, &nestingDepth, (vm_region_info_t)&info, &count);
+        if (err == KERN_INVALID_ADDRESS)
+        {
+            // It seems like this is a good break too.
+            break;
+        }
+        else if (err)
+        {
+            mach_error("vm_region",err);
+            break; // reached last region
+        }
+        
+        bool should_count = true;
+        if (info.is_submap)
+        { // is it a submap?
+            nestingDepth++;
+            should_count = false;
+        }
+        else
+        {
+            // Don't count malloc stack logging data in the TOTAL VM usage lines.
+            if (info.user_tag == VM_MEMORY_ANALYSIS_TOOL)
+                should_count = false;
+            // Don't count system shared library region not used by this process.
+            if (address >= SHARED_REGION_BASE && address < (SHARED_REGION_BASE + SHARED_REGION_SIZE))
+                should_count = false;
+
+            address = address+size;
+        }
+        
+        if (should_count)
+        {
+            pages_resident += info.pages_resident;
+            pages_dirtied += info.pages_dirtied;
+        }
+    }
+    
+    rsize = pages_resident * vm_page_size;
+    dirty_size = pages_dirtied * vm_page_size;
+}
+
+// Test whether the virtual address is within the architecture's shared region.
+static bool InSharedRegion(mach_vm_address_t addr, cpu_type_t type)
+{
+	mach_vm_address_t base = 0, size = 0;
+    
+	switch(type) {
+		case CPU_TYPE_ARM:
+			base = SHARED_REGION_BASE_ARM;
+			size = SHARED_REGION_SIZE_ARM;
+            break;
+            
+		case CPU_TYPE_X86_64:
+			base = SHARED_REGION_BASE_X86_64;
+			size = SHARED_REGION_SIZE_X86_64;
+            break;
+            
+		case CPU_TYPE_I386:
+			base = SHARED_REGION_BASE_I386;
+			size = SHARED_REGION_SIZE_I386;
+            break;
+            
+		default: {
+            // Log error abut unknown CPU type
+            break;
+		}
+	}
+    
+    
+	return(addr >= base && addr < (base + size));
+}
+
+static void GetMemorySizes(task_t task, cpu_type_t cputype, nub_process_t pid, mach_vm_size_t &rprvt, mach_vm_size_t &vprvt)
+{
+    // Collecting some other info cheaply but not reporting for now.
+    mach_vm_size_t empty = 0;
+	mach_vm_size_t fw_private = 0;
+    
+	mach_vm_size_t aliased = 0;
+	mach_vm_size_t pagesize = vm_page_size;
+    bool global_shared_text_data_mapped = false;
+    
+	for (mach_vm_address_t addr=0, size=0; ; addr += size)
+    {
+		vm_region_top_info_data_t info;
+		mach_msg_type_number_t count = VM_REGION_TOP_INFO_COUNT;
+		mach_port_t object_name;
+		
+		kern_return_t kr = mach_vm_region(task, &addr, &size, VM_REGION_TOP_INFO, (vm_region_info_t)&info, &count, &object_name);
+		if (kr != KERN_SUCCESS) break;
+        
+		if (InSharedRegion(addr, cputype))
+        {
+			// Private Shared
+			fw_private += info.private_pages_resident * pagesize;
+            
+			// Check if this process has the globally shared text and data regions mapped in.  If so, set global_shared_text_data_mapped to TRUE and avoid checking again.
+			if (global_shared_text_data_mapped == FALSE && info.share_mode == SM_EMPTY) {
+				vm_region_basic_info_data_64_t	b_info;
+				mach_vm_address_t b_addr = addr;
+				mach_vm_size_t b_size = size;
+				count = VM_REGION_BASIC_INFO_COUNT_64;
+				
+				kr = mach_vm_region(task, &b_addr, &b_size, VM_REGION_BASIC_INFO, (vm_region_info_t)&b_info, &count, &object_name);
+				if (kr != KERN_SUCCESS) break;
+                
+				if (b_info.reserved) {
+					global_shared_text_data_mapped = TRUE;
+				}
+			}
+			
+			// Short circuit the loop if this isn't a shared private region, since that's the only region type we care about within the current address range.
+			if (info.share_mode != SM_PRIVATE)
+            {
+				continue;
+			}
+		}
+		
+		// Update counters according to the region type.
+		if (info.share_mode == SM_COW && info.ref_count == 1)
+        {
+			// Treat single reference SM_COW as SM_PRIVATE
+			info.share_mode = SM_PRIVATE;
+		}
+        
+		switch (info.share_mode)
+        {
+			case SM_LARGE_PAGE:
+				// Treat SM_LARGE_PAGE the same as SM_PRIVATE
+				// since they are not shareable and are wired.
+			case SM_PRIVATE:
+				rprvt += info.private_pages_resident * pagesize;
+				rprvt += info.shared_pages_resident * pagesize;
+				vprvt += size;
+				break;
+				
+			case SM_EMPTY:
+                empty += size;
+				break;
+				
+			case SM_COW:
+			case SM_SHARED:
+            {
+				if (pid == 0)
+                {
+					// Treat kernel_task specially
+					if (info.share_mode == SM_COW)
+                    {
+						rprvt += info.private_pages_resident * pagesize;
+						vprvt += size;
+					}
+					break;
+				}
+                
+				if (info.share_mode == SM_COW)
+                {
+					rprvt += info.private_pages_resident * pagesize;
+					vprvt += info.private_pages_resident * pagesize;
+				}
+				break;
+            }
+			default:
+                // log that something is really bad.
+				break;
+		}
+	}
+    
+	rprvt += aliased;
+}
+
+nub_bool_t
+MachVMMemory::GetMemoryProfile(task_t task, struct task_basic_info ti, cpu_type_t cputype, nub_process_t pid, mach_vm_size_t &rprvt, mach_vm_size_t &rsize, mach_vm_size_t &vprvt, mach_vm_size_t &vsize, mach_vm_size_t &dirty_size)
+{
+    // This uses vmmap strategy. We don't use the returned rsize for now. We prefer to match top's version since that's what we do for the rest of the metrics.
+    GetRegionSizes(task, rsize, dirty_size);
+    
+    GetMemorySizes(task, cputype, pid, rprvt, vprvt);
+    
+    rsize = ti.resident_size;
+    vsize = ti.virtual_size;
+    
+    return true;
+}
+
 nub_size_t
 MachVMMemory::Read(task_t task, nub_addr_t address, void *data, nub_size_t data_count)
 {

Modified: lldb/trunk/tools/debugserver/source/MacOSX/MachVMMemory.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/debugserver/source/MacOSX/MachVMMemory.h?rev=168228&r1=168227&r2=168228&view=diff
==============================================================================
--- lldb/trunk/tools/debugserver/source/MacOSX/MachVMMemory.h (original)
+++ lldb/trunk/tools/debugserver/source/MacOSX/MachVMMemory.h Fri Nov 16 18:21:04 2012
@@ -28,12 +28,13 @@
     nub_size_t Write(task_t task, nub_addr_t address, const void *data, nub_size_t data_count);
     nub_size_t PageSize();
     nub_bool_t GetMemoryRegionInfo(task_t task, nub_addr_t address, DNBRegionInfo *region_info);
+    nub_bool_t GetMemoryProfile(task_t task, struct task_basic_info ti, cpu_type_t cputype, nub_process_t pid, mach_vm_size_t &rprvt, mach_vm_size_t &rsize, mach_vm_size_t &vprvt, mach_vm_size_t &vsize, mach_vm_size_t &dirty_size);
 
 protected:
     nub_size_t MaxBytesLeftInPage(nub_addr_t addr, nub_size_t count);
 
     nub_size_t WriteRegion(task_t task, const nub_addr_t address, const void *data, const nub_size_t data_count);
-    vm_size_t        m_page_size;
+    vm_size_t   m_page_size;
     DNBError    m_err;
 };
 

Modified: lldb/trunk/tools/debugserver/source/RNBContext.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/debugserver/source/RNBContext.cpp?rev=168228&r1=168227&r2=168228&view=diff
==============================================================================
--- lldb/trunk/tools/debugserver/source/RNBContext.cpp (original)
+++ lldb/trunk/tools/debugserver/source/RNBContext.cpp Fri Nov 16 18:21:04 2012
@@ -148,9 +148,9 @@
     bool done = false;
     while (!done)
     {
-        DNBLogThreadedIf(LOG_RNB_PROC, "RNBContext::%s calling DNBProcessWaitForEvent(pid, eEventProcessRunningStateChanged | eEventProcessStoppedStateChanged | eEventStdioAvailable, true)...", __FUNCTION__);
-        nub_event_t pid_status_event = DNBProcessWaitForEvents (pid, eEventProcessRunningStateChanged | eEventProcessStoppedStateChanged | eEventStdioAvailable, true, NULL);
-        DNBLogThreadedIf(LOG_RNB_PROC, "RNBContext::%s calling DNBProcessWaitForEvent(pid, eEventProcessRunningStateChanged | eEventProcessStoppedStateChanged | eEventStdioAvailable, true) => 0x%8.8x", __FUNCTION__, pid_status_event);
+        DNBLogThreadedIf(LOG_RNB_PROC, "RNBContext::%s calling DNBProcessWaitForEvent(pid, eEventProcessRunningStateChanged | eEventProcessStoppedStateChanged | eEventStdioAvailable | eEventProfileDataAvailable, true)...", __FUNCTION__);
+        nub_event_t pid_status_event = DNBProcessWaitForEvents (pid, eEventProcessRunningStateChanged | eEventProcessStoppedStateChanged | eEventStdioAvailable | eEventProfileDataAvailable, true, NULL);
+        DNBLogThreadedIf(LOG_RNB_PROC, "RNBContext::%s calling DNBProcessWaitForEvent(pid, eEventProcessRunningStateChanged | eEventProcessStoppedStateChanged | eEventStdioAvailable | eEventProfileDataAvailable, true) => 0x%8.8x", __FUNCTION__, pid_status_event);
 
         if (pid_status_event == 0)
         {
@@ -167,6 +167,13 @@
                 ctx.Events().WaitForResetAck(RNBContext::event_proc_stdio_available);
             }
 
+            if (pid_status_event & eEventProfileDataAvailable)
+            {
+                DNBLogThreadedIf(LOG_RNB_PROC, "RNBContext::%s (pid=%4.4x) got profile data event....", __FUNCTION__, pid);
+                ctx.Events().SetEvents (RNBContext::event_proc_profile_data);
+                // Wait for the main thread to consume this notification if it requested we wait for it
+                ctx.Events().WaitForResetAck(RNBContext::event_proc_profile_data);
+            }
 
             if (pid_status_event & (eEventProcessRunningStateChanged | eEventProcessStoppedStateChanged))
             {
@@ -217,6 +224,8 @@
         s += "proc_thread_exiting ";
     if (events & event_proc_stdio_available)
         s += "proc_stdio_available ";
+    if (events & event_proc_profile_data)
+        s += "proc_profile_data ";
     if (events & event_read_packet_available)
         s += "read_packet_available ";
     if (events & event_read_thread_running)

Modified: lldb/trunk/tools/debugserver/source/RNBContext.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/debugserver/source/RNBContext.h?rev=168228&r1=168227&r2=168228&view=diff
==============================================================================
--- lldb/trunk/tools/debugserver/source/RNBContext.h (original)
+++ lldb/trunk/tools/debugserver/source/RNBContext.h Fri Nov 16 18:21:04 2012
@@ -29,13 +29,15 @@
         event_proc_thread_running       = 0x02, // Sticky
         event_proc_thread_exiting       = 0x04,
         event_proc_stdio_available      = 0x08,
-        event_read_packet_available     = 0x10,
-        event_read_thread_running       = 0x20, // Sticky
-        event_read_thread_exiting       = 0x40,
+        event_proc_profile_data         = 0x10,
+        event_read_packet_available     = 0x20,
+        event_read_thread_running       = 0x40, // Sticky
+        event_read_thread_exiting       = 0x80,
 
         normal_event_bits   = event_proc_state_changed |
                               event_proc_thread_exiting |
                               event_proc_stdio_available |
+                              event_proc_profile_data | 
                               event_read_packet_available |
                               event_read_thread_exiting,
 

Modified: lldb/trunk/tools/debugserver/source/RNBRemote.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/debugserver/source/RNBRemote.cpp?rev=168228&r1=168227&r2=168228&view=diff
==============================================================================
--- lldb/trunk/tools/debugserver/source/RNBRemote.cpp (original)
+++ lldb/trunk/tools/debugserver/source/RNBRemote.cpp Fri Nov 16 18:21:04 2012
@@ -193,6 +193,8 @@
     t.push_back (Packet (allocate_memory,               &RNBRemote::HandlePacket_AllocateMemory, NULL, "_M", "Allocate memory in the inferior process."));
     t.push_back (Packet (deallocate_memory,             &RNBRemote::HandlePacket_DeallocateMemory, NULL, "_m", "Deallocate memory in the inferior process."));
     t.push_back (Packet (memory_region_info,            &RNBRemote::HandlePacket_MemoryRegionInfo, NULL, "qMemoryRegionInfo", "Return size and attributes of a memory region that contains the given address"));
+    t.push_back (Packet (get_profile_data,              &RNBRemote::HandlePacket_GetProfileData, NULL, "qGetProfileData", "Return profiling data of the current target."));
+    t.push_back (Packet (set_enable_profiling,          &RNBRemote::HandlePacket_SetAsyncEnableProfiling, NULL, "QSetAsyncEnableProfiling", "Enable or disable the profiling of current target."));
     t.push_back (Packet (watchpoint_support_info,       &RNBRemote::HandlePacket_WatchpointSupportInfo, NULL, "qWatchpointSupportInfo", "Return the number of supported hardware watchpoints"));
 
 }
@@ -226,6 +228,25 @@
     }
 }
 
+void
+RNBRemote::SendAsyncProfileData ()
+{
+    if (m_ctx.HasValidProcessID())
+    {
+        nub_process_t pid = m_ctx.ProcessID();
+        char buf[256];
+        nub_size_t count;
+        do
+        {
+            count = DNBProcessGetAvailableProfileData(pid, buf, sizeof(buf));
+            if (count > 0)
+            {
+                SendAsyncProfileDataPacket (buf, count);
+            }
+        } while (count > 0);
+    }
+}
+
 rnb_err_t
 RNBRemote::SendHexEncodedBytePacket (const char *header, const void *buf, size_t buf_len, const char *footer)
 {
@@ -262,6 +283,18 @@
     return SendHexEncodedBytePacket("O", buf, buf_size, NULL);
 }
 
+// This makes use of asynchronous bit 'A' in the gdb remote protocol.
+rnb_err_t
+RNBRemote::SendAsyncProfileDataPacket (char *buf, nub_size_t buf_size)
+{
+    if (buf_size == 0)
+        return rnb_success;
+    
+    std::string packet("A");
+    packet.append(buf, buf_size);
+    return SendPacket(packet);
+}
+
 rnb_err_t
 RNBRemote::SendPacket (const std::string &s)
 {
@@ -3428,6 +3461,58 @@
 }
 
 rnb_err_t
+RNBRemote::HandlePacket_GetProfileData (const char *p)
+{
+    nub_process_t pid = m_ctx.ProcessID();
+    if (pid == INVALID_NUB_PROCESS)
+        return SendPacket ("OK");
+
+    const char *data = DNBProcessGetProfileDataAsCString(pid);
+    if (data)
+    {
+        return SendPacket (data);
+    }
+    else
+    {
+        return SendPacket ("OK");
+    }
+}
+
+
+// QSetAsyncEnableProfiling;enable:[0|1]:interval_usec:XXXXXX;
+rnb_err_t
+RNBRemote::HandlePacket_SetAsyncEnableProfiling (const char *p)
+{
+    nub_process_t pid = m_ctx.ProcessID();
+    if (pid == INVALID_NUB_PROCESS)
+        return SendPacket ("");
+
+    StringExtractor packet(p += sizeof ("QSetAsyncEnableProfiling:") - 1);
+    bool enable = false;
+    uint64_t interval_usec = 0;
+    std::string name;
+    std::string value;
+    while (packet.GetNameColonValue(name, value))
+    {
+        if (name.compare ("enable") == 0)
+        {
+            enable  = strtoul(value.c_str(), NULL, 10) > 0;
+        }
+        else if (name.compare ("interval_usec") == 0)
+        {
+            interval_usec  = strtoul(value.c_str(), NULL, 10);
+        }
+    }
+    
+    if (interval_usec == 0)
+    {
+        enable = 0;
+    }
+    DNBProcessSetAsyncEnableProfiling(pid, enable, interval_usec);
+    return SendPacket ("OK");
+}
+
+rnb_err_t
 RNBRemote::HandlePacket_WatchpointSupportInfo (const char *p)
 {
     /* This packet simply returns the number of supported hardware watchpoints.

Modified: lldb/trunk/tools/debugserver/source/RNBRemote.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/debugserver/source/RNBRemote.h?rev=168228&r1=168227&r2=168228&view=diff
==============================================================================
--- lldb/trunk/tools/debugserver/source/RNBRemote.h (original)
+++ lldb/trunk/tools/debugserver/source/RNBRemote.h Fri Nov 16 18:21:04 2012
@@ -112,6 +112,8 @@
         set_list_threads_in_stop_reply, // 'QListThreadsInStopReply:'
         sync_thread_state,              // 'QSyncThreadState:'
         memory_region_info,             // 'qMemoryRegionInfo:'
+        get_profile_data,               // 'qGetProfileData'
+        set_enable_profiling,           // 'QSetAsyncEnableProfiling'
         watchpoint_support_info,        // 'qWatchpointSupportInfo:'
         allocate_memory,                // '_M'
         deallocate_memory,              // '_m'
@@ -210,6 +212,8 @@
     rnb_err_t HandlePacket_AllocateMemory (const char *p);
     rnb_err_t HandlePacket_DeallocateMemory (const char *p);
     rnb_err_t HandlePacket_MemoryRegionInfo (const char *p);
+    rnb_err_t HandlePacket_GetProfileData(const char *p);
+    rnb_err_t HandlePacket_SetAsyncEnableProfiling(const char *p);
     rnb_err_t HandlePacket_WatchpointSupportInfo (const char *p);
 
     rnb_err_t HandlePacket_stop_process (const char *p);
@@ -219,6 +223,8 @@
     rnb_err_t SendSTDOUTPacket (char *buf, nub_size_t buf_size);
     rnb_err_t SendSTDERRPacket (char *buf, nub_size_t buf_size);
     void      FlushSTDIO ();
+    void      SendAsyncProfileData ();
+    rnb_err_t SendAsyncProfileDataPacket (char *buf, nub_size_t buf_size);
 
     RNBContext&     Context() { return m_ctx; }
     RNBSocket&      Comm() { return m_comm; }

Modified: lldb/trunk/tools/debugserver/source/debugserver.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/debugserver/source/debugserver.cpp?rev=168228&r1=168227&r2=168228&view=diff
==============================================================================
--- lldb/trunk/tools/debugserver/source/debugserver.cpp (original)
+++ lldb/trunk/tools/debugserver/source/debugserver.cpp Fri Nov 16 18:21:04 2012
@@ -498,8 +498,9 @@
 
         if (!ctx.ProcessStateRunning())
         {
-            // Clear the stdio bits if we are not running so we don't send any async packets
+            // Clear some bits if we are not running so we don't send any async packets
             event_mask &= ~RNBContext::event_proc_stdio_available;
+            event_mask &= ~RNBContext::event_proc_profile_data;
         }
 
         // We want to make sure we consume all process state changes and have
@@ -519,6 +520,11 @@
                 remote->FlushSTDIO();
             }
 
+            if (set_events & RNBContext::event_proc_profile_data)
+            {
+                remote->SendAsyncProfileData();
+            }
+
             if (set_events & RNBContext::event_read_packet_available)
             {
                 // handleReceivedPacket will take care of resetting the





More information about the lldb-commits mailing list