From 0f5bdd666fa66bd279f8629a670d8058780a613d Mon Sep 17 00:00:00 2001 From: Paul Davis Date: Thu, 24 Jun 2010 14:13:45 +0000 Subject: [PATCH] use JACK thread creation functions to create process-graph threads; provide GUI control over number of threads-relative-to-number-of-CPUS git-svn-id: svn://localhost/ardour2/branches/3.0@7296 d708f5d6-7413-0410-9779-e7cbd77b26cf --- gtk2_ardour/midi_region_view.cc | 6 +-- gtk2_ardour/rc_option_editor.cc | 23 ++++++++ libs/ardour/ardour/audioengine.h | 13 +++++ libs/ardour/ardour/graph.h | 2 +- libs/ardour/ardour/rc_configuration_vars.h | 1 + libs/ardour/audioengine.cc | 30 +++++++++++ libs/ardour/delivery.cc | 2 +- libs/ardour/graph.cc | 61 ++++++++++++---------- libs/pbd/cpus.cc | 49 +++++++++++++++++ libs/pbd/pbd/cpus.h | 28 ++++++++++ libs/pbd/wscript | 2 + 11 files changed, 183 insertions(+), 34 deletions(-) create mode 100644 libs/pbd/cpus.cc create mode 100644 libs/pbd/pbd/cpus.h diff --git a/gtk2_ardour/midi_region_view.cc b/gtk2_ardour/midi_region_view.cc index 486e09900f..92fe545c91 100644 --- a/gtk2_ardour/midi_region_view.cc +++ b/gtk2_ardour/midi_region_view.cc @@ -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()); diff --git a/gtk2_ardour/rc_option_editor.cc b/gtk2_ardour/rc_option_editor.cc index 83b3e498cd..14fca7a417 100644 --- a/gtk2_ardour/rc_option_editor.cc +++ b/gtk2_ardour/rc_option_editor.cc @@ -5,6 +5,7 @@ #include #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* procs = new ComboOption ( + "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* mht = new ComboOption ( diff --git a/libs/ardour/ardour/audioengine.h b/libs/ardour/ardour/audioengine.h index 5e2657c56c..9a0104b8fe 100644 --- a/libs/ardour/ardour/audioengine.h +++ b/libs/ardour/ardour/audioengine.h @@ -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, 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 f; + size_t stacksize; + + ThreadData (AudioEngine* ae, boost::function fp, size_t stacksz) + : engine (ae) , f (fp) , stacksize (stacksz) {} + }; + + static void* _start_process_thread (void*); }; } // namespace ARDOUR diff --git a/libs/ardour/ardour/graph.h b/libs/ardour/ardour/graph.h index 6226ed5602..f38ef12721 100644 --- a/libs/ardour/ardour/graph.h +++ b/libs/ardour/ardour/graph.h @@ -85,7 +85,7 @@ class Graph : public SessionHandleRef virtual void session_going_away (); private: - std::list _thread_list; + std::list _thread_list; volatile bool _quit_threads; node_list_t _nodes_rt[2]; diff --git a/libs/ardour/ardour/rc_configuration_vars.h b/libs/ardour/ardour/rc_configuration_vars.h index 92397c149f..e98f396b95 100644 --- a/libs/ardour/ardour/rc_configuration_vars.h +++ b/libs/ardour/ardour/rc_configuration_vars.h @@ -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 */ diff --git a/libs/ardour/audioengine.cc b/libs/ardour/audioengine.cc index 903fbb227d..2282a20809 100644 --- a/libs/ardour/audioengine.cc +++ b/libs/ardour/audioengine.cc @@ -25,6 +25,9 @@ #include #include +#include +#include + #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 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 (arg); + boost::function f = td->f; + delete td; + + f (); + + return 0; +} diff --git a/libs/ardour/delivery.cc b/libs/ardour/delivery.cc index cb8dc539a2..7bacb1c058 100644 --- a/libs/ardour/delivery.cc +++ b/libs/ardour/delivery.cc @@ -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: diff --git a/libs/ardour/graph.cc b/libs/ardour/graph.cc index ae5758107a..54e619aef8 100644 --- a/libs/ardour/graph.cc +++ b/libs/ardour/graph.cc @@ -18,17 +18,11 @@ */ -#ifdef __linux__ -#include -#elif defined(__APPLE__) || defined(__FreeBSD__) -#include -#include -#endif - #include #include #include "pbd/compose.h" +#include "pbd/cpus.h" #include "ardour/debug.h" #include "ardour/graph.h" @@ -45,22 +39,6 @@ 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; iget_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::iterator i=_thread_list.begin(); i!=_thread_list.end(); i++) { - (*i)->join(); + for (std::list::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 index 0000000000..ba4ba32fe4 --- /dev/null +++ b/libs/pbd/cpus.cc @@ -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 +#elif defined(__APPLE__) || defined(__FreeBSD__) +#include +#include +#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 index 0000000000..1488f30068 --- /dev/null +++ b/libs/pbd/pbd/cpus.h @@ -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 + +extern uint32_t hardware_concurrency (); + +#endif /* __libpbd_cpus_h__ */ diff --git a/libs/pbd/wscript b/libs/pbd/wscript index 7052ad98ca..a558a04da2 100644 --- a/libs/pbd/wscript +++ b/libs/pbd/wscript @@ -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 -- 2.30.2