From ef8d96c29c73b9da8cdaa2b8b4737862c85ccc20 Mon Sep 17 00:00:00 2001
From: Vadim Zeitlin <vadim@wxwidgets.org>
Date: Mon, 6 Dec 1999 12:31:04 +0000
Subject: [PATCH] wxThread::GetCPUCount() and SetConcurrency() added and
 documented

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@4837 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
---
 docs/changes.txt            |  4 ++-
 docs/latex/wx/thread.tex    | 21 ++++++++++++
 include/wx/thread.h         | 15 +++++++++
 samples/console/console.cpp |  6 ++--
 src/common/textfile.cpp     |  5 +++
 src/msw/thread.cpp          | 11 +++++++
 src/unix/threadpsx.cpp      | 66 +++++++++++++++++++++++++++++++++++++
 7 files changed, 125 insertions(+), 3 deletions(-)

diff --git a/docs/changes.txt b/docs/changes.txt
index 861a746147..ee12fcb7d0 100644
--- a/docs/changes.txt
+++ b/docs/changes.txt
@@ -6,7 +6,9 @@ next release (2.1.12 or 2.2?)
 
 wxBase:
 
-- wxThread class modified to support both detached and joinable threads
+- wxThread class modified to support both detached and joinable threads, also
+  added new GetCPUCount() and SetConcurrency() functions (useful under Solaris
+  only so far)
 - wxLog functions are now (more) MT-safe
 - wxStopWatch class, timer functions have more chances to return correct
   results for your platform (use ANSI function where available)
diff --git a/docs/latex/wx/thread.tex b/docs/latex/wx/thread.tex
index cfdbc20879..f7c4a1997e 100644
--- a/docs/latex/wx/thread.tex
+++ b/docs/latex/wx/thread.tex
@@ -127,6 +127,16 @@ joinable threads and is the value returned by \helpref{Wait}{wxthreadwait}.
 This function is called by wxWindows itself and should never be called
 directly.
 
+\membersection{wxThread::GetCPUCount}\label{wxthreadgetcpucount}
+
+\func{static int}{GetCPUCount}{\void}
+
+Returns the number of system CPUs or -1 if the value is unknown.
+
+\wxheading{See also}
+
+\helpref{SetConcurrency}{wxthreadsetconcurrency}
+
 \membersection{wxThread::GetId}\label{wxthreadgetid}
 
 \constfunc{unsigned long}{GetId}{\void}
@@ -253,6 +263,17 @@ Resumes a thread suspended by the call to \helpref{Pause}{wxthreadpause}.
 
 This function can only be called from another thread context.
 
+\membersection{wxThread::SetConcurrency}\label{wxthreadsetconcurrency}
+
+\func{static bool}{SetConcurrency}{\param{size\_t }{level}}
+
+Sets the thread concurrency level for this process. This is, roughly, the
+number of threads that the system tries to schedule to run in parallel.
+The value of $0$ for {\it level} may be used to set the default one.
+
+Returns TRUE on success or FALSE otherwise (for example, if this function is
+not implemented for this platform (currently everything except Solaris)).
+
 \membersection{wxThread::TestDestroy}\label{wxthreadtestdestroy}
 
 \func{bool}{TestDestroy}{\void}
diff --git a/include/wx/thread.h b/include/wx/thread.h
index 7c9df994de..a4c4b465df 100644
--- a/include/wx/thread.h
+++ b/include/wx/thread.h
@@ -280,6 +280,21 @@ public:
         // NB: at least under MSW worker threads can not call ::wxSleep()!
     static void Sleep(unsigned long milliseconds);
 
+        // get the number of system CPUs - useful with SetConcurrency()
+        // (the "best" value for it is usually number of CPUs + 1)
+        //
+        // Returns -1 if unknown, number of CPUs otherwise
+    static int GetCPUCount();
+
+        // sets the concurrency level: this is, roughly, the number of threads
+        // the system tries to schedule to run in parallel. 0 means the
+        // default value (usually acceptable, but may not yield the best
+        // performance for this process)
+        //
+        // Returns TRUE on success, FALSE otherwise (if not implemented, for
+        // example)
+    static bool SetConcurrency(size_t level);
+
     // constructor only creates the C++ thread object and doesn't create (or
     // start) the real thread
     wxThread(wxThreadKind kind = wxTHREAD_DETACHED);
diff --git a/samples/console/console.cpp b/samples/console/console.cpp
index 981a302ac3..0a08f86c14 100644
--- a/samples/console/console.cpp
+++ b/samples/console/console.cpp
@@ -32,8 +32,8 @@
 //#define TEST_ARRAYS
 //#define TEST_LOG
 //#define TEST_STRINGS
-//#define TEST_THREADS
-#define TEST_TIME
+#define TEST_THREADS
+//#define TEST_TIME
 //#define TEST_LONGLONG
 
 // ============================================================================
@@ -647,6 +647,8 @@ int main(int argc, char **argv)
 #endif // TEST_LOG
 
 #ifdef TEST_THREADS
+    printf("This system has %d CPUs\n", wxThread::GetCPUCount());
+
     if ( argc > 1 && argv[1][0] == 't' )
         wxLog::AddTraceMask("thread");
 
diff --git a/src/common/textfile.cpp b/src/common/textfile.cpp
index 9b35dfd8de..5c74b3ab57 100644
--- a/src/common/textfile.cpp
+++ b/src/common/textfile.cpp
@@ -145,6 +145,11 @@ wxTextFile::~wxTextFile()
 // file operations
 // ----------------------------------------------------------------------------
 
+bool wxTextFile::Exists() const
+{
+    return wxFile::Exists(m_strFile);
+}
+
 bool wxTextFile::Open(const wxString& strFile)
 {
   m_strFile = strFile;
diff --git a/src/msw/thread.cpp b/src/msw/thread.cpp
index 3ae5d7b979..35838d9a29 100644
--- a/src/msw/thread.cpp
+++ b/src/msw/thread.cpp
@@ -527,6 +527,17 @@ void wxThread::Sleep(unsigned long milliseconds)
     ::Sleep(milliseconds);
 }
 
+int wxThread::GetCPUCount()
+{
+    return -1;
+}
+
+bool wxThread::SetConcurrency(size_t level)
+{
+    // ok only for the default one
+    return level == 0;
+}
+
 // ctor and dtor
 // -------------
 
diff --git a/src/unix/threadpsx.cpp b/src/unix/threadpsx.cpp
index fad73a2df9..34f3cd81b4 100644
--- a/src/unix/threadpsx.cpp
+++ b/src/unix/threadpsx.cpp
@@ -45,6 +45,15 @@
     #include <sched.h>
 #endif
 
+#ifdef HAVE_THR_SETCONCURRENCY
+    #include <thread.h>
+#endif
+
+// we use wxFFile under Linux in GetCPUCount()
+#ifdef __LINUX__
+    #include "wx/ffile.h"
+#endif
+
 // ----------------------------------------------------------------------------
 // constants
 // ----------------------------------------------------------------------------
@@ -834,6 +843,63 @@ void wxThread::Sleep(unsigned long milliseconds)
     wxUsleep(milliseconds);
 }
 
+int wxThread::GetCPUCount()
+{
+#if defined(__LINUX__)
+    // read from proc (can't use wxTextFile here because it's a special file:
+    // it has 0 size but still can be read from)
+    wxLogNull nolog;
+
+    wxFFile file(_T("/proc/cpuinfo"));
+    if ( file.IsOpened() )
+    {
+        // slurp the whole file
+        wxString s;
+        if ( file.ReadAll(&s) )
+        {
+            // (ab)use Replace() to find the number of "processor" strings
+            size_t count = s.Replace(_T("processor"), _T(""));
+            if ( count > 0 )
+            {
+                return count;
+            }
+
+            wxLogDebug(_T("failed to parse /proc/cpuinfo"));
+        }
+        else
+        {
+            wxLogDebug(_T("failed to read /proc/cpuinfo"));
+        }
+    }
+#elif defined(_SC_NPROCESSORS_ONLN)
+    // this works for Solaris
+    int rc = sysconf(_SC_NPROCESSORS_ONLN);
+    if ( rc != -1 )
+    {
+        return rc;
+    }
+#endif // different ways to get number of CPUs
+
+    // unknown
+    return -1;
+}
+
+bool wxThread::SetConcurrency(size_t level)
+{
+#ifdef HAVE_THR_SETCONCURRENCY
+    int rc = thr_setconcurrency(level);
+    if ( rc != 0 )
+    {
+        wxLogSysError(rc, _T("thr_setconcurrency() failed"));
+    }
+
+    return rc == 0;
+#else // !HAVE_THR_SETCONCURRENCY
+    // ok only for the default value
+    return level == 0;
+#endif // HAVE_THR_SETCONCURRENCY/!HAVE_THR_SETCONCURRENCY
+}
+
 // -----------------------------------------------------------------------------
 // creating thread
 // -----------------------------------------------------------------------------
-- 
2.47.2