use JACK thread creation functions to create process-graph threads; provide GUI contr...
authorPaul Davis <paul@linuxaudiosystems.com>
Thu, 24 Jun 2010 14:13:45 +0000 (14:13 +0000)
committerPaul Davis <paul@linuxaudiosystems.com>
Thu, 24 Jun 2010 14:13:45 +0000 (14:13 +0000)
git-svn-id: svn://localhost/ardour2/branches/3.0@7296 d708f5d6-7413-0410-9779-e7cbd77b26cf

gtk2_ardour/midi_region_view.cc
gtk2_ardour/rc_option_editor.cc
libs/ardour/ardour/audioengine.h
libs/ardour/ardour/graph.h
libs/ardour/ardour/rc_configuration_vars.h
libs/ardour/audioengine.cc
libs/ardour/delivery.cc
libs/ardour/graph.cc
libs/pbd/cpus.cc [new file with mode: 0644]
libs/pbd/pbd/cpus.h [new file with mode: 0644]
libs/pbd/wscript

index 486e09900fe2a117bbcf9cc033409c1090570011..92fe545c919d91d38e209e76ad6dff2a00bd16ba 100644 (file)
@@ -2256,8 +2256,8 @@ MidiRegionView::trim_note (CanvasNoteEvent* event, Evoral::MusicalTime front_del
 {
        bool change_start = false;
        bool change_length = false;
-       Evoral::MusicalTime new_start;
-       Evoral::MusicalTime new_length;
+       Evoral::MusicalTime new_start = 0;
+       Evoral::MusicalTime new_length = 0;
 
        /* NOTE: the semantics of the two delta arguments are slightly subtle:
 
@@ -2685,7 +2685,7 @@ MidiRegionView::paste (nframes64_t pos, float times, const MidiCutBuffer& mcb)
        Evoral::MusicalTime beat_delta;
        Evoral::MusicalTime paste_pos_beats;
        Evoral::MusicalTime duration;
-       Evoral::MusicalTime end_point;
+       Evoral::MusicalTime end_point = 0;
 
        duration = (*mcb.notes().rbegin())->end_time() - (*mcb.notes().begin())->time();
        paste_pos_beats = frames_to_beats (pos - _region->position());
index 83b3e498cd40deb87e0a0b731eb0a4cf0808f109..14fca7a4173a4e2b24fdcacbc26295c868f8ac0b 100644 (file)
@@ -5,6 +5,7 @@
 #include <gtkmm2ext/slider_controller.h>
 
 #include "pbd/fpu.h"
+#include "pbd/cpus.h"
 
 #include "midi++/manager.h"
 #include "midi++/factory.h"
@@ -930,6 +931,28 @@ RCOptionEditor::RCOptionEditor ()
 {
        /* MISC */
 
+        uint32_t hwcpus = hardware_concurrency ();
+
+        if (hwcpus > 1) {
+                add_option (_("Misc"), new OptionEditorHeading (_("DSP CPU Utilization")));
+                
+                ComboOption<uint32_t>* procs = new ComboOption<uint32_t> (
+                        "processor-usage",
+                        _("Signal processing uses: "),
+                        sigc::mem_fun (*_rc_config, &RCConfiguration::get_processor_usage),
+                        sigc::mem_fun (*_rc_config, &RCConfiguration::set_processor_usage)
+                        );
+                
+                procs->add (-1, _("All but one"));
+                procs->add (0, _("All available processors"));
+                
+                for (uint32_t i = 2; i < hwcpus; ++i) {
+                        procs->add (1, string_compose (_("%1 processors"), i));
+                }
+                
+                add_option (_("Misc"), procs);
+        }
+
        add_option (_("Misc"), new OptionEditorHeading (_("Metering")));
 
        ComboOption<float>* mht = new ComboOption<float> (
index 5e2657c56c427a53739afdc88c3fa1e6ceea22a1..9a0104b8fe08748b50c4338ac84f8a250531adcc 100644 (file)
@@ -245,6 +245,8 @@ _      the regular process() call to session->process() is not made.
        static AudioEngine* instance() { return _instance; }
        void died ();
 
+        pthread_t create_process_thread (boost::function<void()>, size_t stacksize);
+
   private:
        static AudioEngine*       _instance;
 
@@ -316,6 +318,17 @@ _     the regular process() call to session->process() is not made.
        static gint      m_meter_exit;
 
         ProcessThread* _main_thread;
+
+        struct ThreadData {
+            AudioEngine* engine;
+            boost::function<void()> f;
+            size_t stacksize;
+            
+            ThreadData (AudioEngine* ae, boost::function<void()> fp, size_t stacksz) 
+            : engine (ae) , f (fp) , stacksize (stacksz) {}
+        };
+        
+        static void* _start_process_thread (void*);
 };
 
 } // namespace ARDOUR
index 6226ed56020dbecd25146432cf9bec01a0f5e9dc..f38ef1272161393c5d8f1edebfba77118fba8b0f 100644 (file)
@@ -85,7 +85,7 @@ class Graph : public SessionHandleRef
         virtual void session_going_away ();
 
     private:
-        std::list<Glib::Thread *> _thread_list;
+        std::list<pthread_t> _thread_list;
         volatile bool _quit_threads;
         
        node_list_t _nodes_rt[2];
index 92397c149f4fd8d222c1985945f14ed6c0be98c1..e98f396b95ee66c708a2c33f18a3bb8f07df08ce 100644 (file)
@@ -153,6 +153,7 @@ CONFIG_VARIABLE (bool, show_waveforms_while_recording, "show-waveforms-while-rec
 CONFIG_VARIABLE (WaveformScale, waveform_scale, "waveform-scale", Linear)
 CONFIG_VARIABLE (WaveformShape, waveform_shape, "waveform-shape", Traditional)
 CONFIG_VARIABLE (bool, allow_special_bus_removal, "allow-special-bus-removal", false)
+CONFIG_VARIABLE (int32_t, processor_usage, "processor-usage", -1)
 
 /* denormal management */
 
index 903fbb227dcde8cdbd0dfab0fed89a1cc587d134..2282a20809c3c5767a028a132366feb77d9ce437 100644 (file)
@@ -25,6 +25,9 @@
 #include <sstream>
 
 #include <glibmm/timer.h>
+#include <jack/jack.h>
+#include <jack/thread.h>
+
 #include "pbd/pthread_utils.h"
 #include "pbd/stacktrace.h"
 #include "pbd/unknown_type.h"
@@ -1480,3 +1483,30 @@ AudioEngine::is_realtime () const
        GET_PRIVATE_JACK_POINTER_RET (_jack,false);
        return jack_is_realtime (_priv_jack);
 }
+
+pthread_t
+AudioEngine::create_process_thread (boost::function<void()> f, size_t stacksize)
+{
+        GET_PRIVATE_JACK_POINTER_RET (_jack, 0);
+        pthread_t thread;
+        ThreadData* td = new ThreadData (this, f, stacksize);
+
+        if (jack_client_create_thread (_priv_jack, &thread, jack_client_real_time_priority (_priv_jack), 
+                                       jack_is_realtime (_priv_jack), _start_process_thread, td)) {
+                return -1;
+        } 
+
+        return thread;
+}
+
+void*
+AudioEngine::_start_process_thread (void* arg)
+{
+        ThreadData* td = reinterpret_cast<ThreadData*> (arg);
+        boost::function<void()> f = td->f;
+        delete td;
+
+        f ();
+
+        return 0;
+}
index cb8dc539a24e3063cec8af3ddcd262e25b08d6a3..7bacb1c058d1beaa7ad5248dd4d1a0e860a74882 100644 (file)
@@ -481,7 +481,7 @@ Delivery::target_gain ()
                return 0.0;
        }
 
-        MuteMaster::MutePoint mp;
+        MuteMaster::MutePoint mp = MuteMaster::Main; // stupid gcc uninit warning
         
         switch (_role) {
         case Main:
index ae5758107a9aa41fe8c7caefcdb150061c5d0313..54e619aef89d73adfed11e49fab87392df529f43 100644 (file)
 
 */
 
-#ifdef __linux__
-#include <unistd.h>
-#elif defined(__APPLE__) || defined(__FreeBSD__)
-#include <sys/types.h>
-#include <sys/sysctl.h>
-#endif
-
 #include <stdio.h>
 #include <cmath>
 
 #include "pbd/compose.h"
+#include "pbd/cpus.h"
 
 #include "ardour/debug.h"
 #include "ardour/graph.h"
 using namespace ARDOUR;
 using namespace PBD;
 
-static unsigned int 
-hardware_concurrency()
-{
-#if defined(PTW32_VERSION) || defined(__hpux)
-        return pthread_num_processors_np();
-#elif defined(__APPLE__) || defined(__FreeBSD__)
-        int count;
-        size_t size=sizeof(count);
-        return sysctlbyname("hw.ncpu",&count,&size,NULL,0)?0:count;
-#elif defined(HAVE_UNISTD) && defined(_SC_NPROCESSORS_ONLN)
-        int const count=sysconf(_SC_NPROCESSORS_ONLN);
-        return (count>0)?count:0;
-#else
-        return 0;
-#endif
-}
 
 Graph::Graph (Session & session) 
         : SessionHandleRef (session) 
@@ -81,10 +59,34 @@ Graph::Graph (Session & session)
         _graph_empty = true;
 
         int num_cpu = hardware_concurrency();
-        info << string_compose (_("Using %1 CPUs via %1 threads\n"), num_cpu) << endmsg;
-        _thread_list.push_back( Glib::Thread::create( sigc::mem_fun( *this, &Graph::main_thread), 100000, true, true, Glib::THREAD_PRIORITY_NORMAL) );
-        for (int i=1; i<num_cpu; i++)
-                _thread_list.push_back( Glib::Thread::create( sigc::mem_fun( *this, &Graph::helper_thread), 100000, true, true, Glib::THREAD_PRIORITY_NORMAL) );
+        int num_threads = num_cpu;
+        int pu = Config->get_processor_usage ();
+
+        if (pu < 0) {
+                /* use "pu" less cores for DSP than appear to be available
+                 */
+
+                if (pu < num_threads) {
+                        num_threads += pu; // pu is negative
+                } else {
+                        num_threads = 1;
+                }
+        } else {
+                /* use "pu" cores, if available
+                 */
+
+                if (pu <= num_threads) {
+                        num_threads = pu;
+                } 
+        }
+
+        info << string_compose (_("Using %2 threads on %1 CPUs"), num_cpu, num_threads) << endmsg;
+
+        _thread_list.push_back (AudioEngine::instance()->create_process_thread (boost::bind (&Graph::main_thread, this), 100000));
+
+        for (int i = 1; i < num_threads; ++i) {
+                _thread_list.push_back (AudioEngine::instance()->create_process_thread (boost::bind (&Graph::helper_thread, this), 100000));
+        }
 }
 
 void
@@ -98,8 +100,9 @@ Graph::session_going_away()
 
         sem_post( &_callback_start_sem);
 
-        for (std::list<Glib::Thread *>::iterator i=_thread_list.begin(); i!=_thread_list.end(); i++) {
-                (*i)->join();
+        for (std::list<pthread_t>::iterator i = _thread_list.begin(); i != _thread_list.end(); i++) {
+                void* status;
+                pthread_join (*i, &status);
         }
 
         // now drop all references on the nodes.
diff --git a/libs/pbd/cpus.cc b/libs/pbd/cpus.cc
new file mode 100644 (file)
index 0000000..ba4ba32
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+  Copyright (C) 2010 Paul Davis
+  Author: Torben Hohn
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifdef WAF_BUILD
+#include "libpbd-config.h"
+#endif
+
+#ifdef __linux__
+#include <unistd.h>
+#elif defined(__APPLE__) || defined(__FreeBSD__)
+#include <sys/types.h>
+#include <sys/sysctl.h>
+#endif
+
+#include "pbd/cpus.h"
+
+uint32_t
+hardware_concurrency()
+{
+#if defined(PTW32_VERSION) || defined(__hpux)
+        return pthread_num_processors_np();
+#elif defined(__APPLE__) || defined(__FreeBSD__)
+        int count;
+        size_t size=sizeof(count);
+        return sysctlbyname("hw.ncpu",&count,&size,NULL,0)?0:count;
+#elif defined(HAVE_UNISTD) && defined(_SC_NPROCESSORS_ONLN)
+        int const count=sysconf(_SC_NPROCESSORS_ONLN);
+        return (count>0)?count:0;
+#else
+        return 0;
+#endif
+}
diff --git a/libs/pbd/pbd/cpus.h b/libs/pbd/pbd/cpus.h
new file mode 100644 (file)
index 0000000..1488f30
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+  Copyright (C) 2010 Paul Davis
+  Author: Torben Hohn
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef __libpbd_cpus_h__
+#define __libpbd_cpus_h__
+
+#include <stdint.h>
+
+extern uint32_t hardware_concurrency ();
+
+#endif /* __libpbd_cpus_h__ */
index 7052ad98ca280df4a32fb8a28501721cee8f74c4..a558a04da2ab0d5819a873ecee19ff96f864365d 100644 (file)
@@ -40,6 +40,7 @@ def configure(conf):
 
        conf.check(function_name='getmntent', header_name='mntent.h', define_name='HAVE_GETMNTENT')
        conf.check(header_name='execinfo.h', define_name='HAVE_EXECINFO')
+       conf.check(header_name='unistd.h', define_name='HAVE_UNISTD')
 
        conf.write_config_header('libpbd-config.h')
 
@@ -59,6 +60,7 @@ def build(bld):
                controllable.cc
                controllable_descriptor.cc
                 crossthread.cc
+                cpus.cc
                 debug.cc
                enumwriter.cc
                 event_loop.cc