[kstars] kstars: Profiling Code: Count trigonometric calls on dms, and profile them.

Akarsh Simha akarsh at kde.org
Thu Sep 29 02:19:15 UTC 2016


Git commit 25b07e4593ce0c0a41cdb3b706a16a2418fed826 by Akarsh Simha.
Committed on 28/09/2016 at 22:16.
Pushed by asimha into branch 'master'.

Profiling Code: Count trigonometric calls on dms, and profile them.

Profiling code I: fraction of dms objects that have sin/cos called

This is profiling code to find out what fraction of dms objects hae
sin/cos called on them. This is useful to figure out if it makes sense
to cache sin/cos values in the constructor itself. It turns out that
this might not be a wise decision since the profiling results in at
least some context says that it can be as low as 25%:

[24 0:15:36 D] KStars::~KStars (186) - Constructed  68504224  dms
objects, of which  17021346  had trigonometric functions called on
them =  24.8471 %

In a different run, it was a bit higher, but still less than 50%.

This suggests that it might not be wise to compute and cache sin / cos
values upon construction

Profiling code II: determine how many trig calls on dms are redundant

The initial results of this profiling seem to be staggering! If the
simulation clock is running, so we are actually recomputing
coordinates, nearly 50% of trigonometric function calls seem to be
redundant! This might justify caching the values of sine and cosine
upon first computation within dms() itself. This will add a
conditional, which can lead to a potential branch mispredict, and some
extra stuff, so I'd guess ~ 20 CPU cycles; however, it would save an
expensive (~110 CPU cycles) trigonometric function computation almost
50% of the time. Given that a significant fraction (~27% under some
particular conditions) of KStars' time is spent on computing sine and
cosine, it might be well worth it to save these calls.

CCMAIL: kstars-devel at kde.org

M  +19   -0    kstars/auxiliary/dms.cpp
M  +85   -7    kstars/auxiliary/dms.h
M  +9    -0    kstars/kstars.cpp

http://commits.kde.org/kstars/25b07e4593ce0c0a41cdb3b706a16a2418fed826

diff --git a/kstars/auxiliary/dms.cpp b/kstars/auxiliary/dms.cpp
index bf30535..be1de35 100644
--- a/kstars/auxiliary/dms.cpp
+++ b/kstars/auxiliary/dms.cpp
@@ -23,22 +23,41 @@
 
 #include <cstdlib>
 
+#ifdef COUNT_DMS_SINCOS_CALLS
+long unsigned dms::dms_constructor_calls = 0;
+long unsigned dms::dms_with_sincos_called = 0;
+long unsigned dms::trig_function_calls = 0;
+long unsigned dms::redundant_trig_function_calls = 0;
+#endif
+
 void dms::setD(const int &d, const int &m, const int &s, const int &ms) {
     D = (double)abs(d) + ((double)m + ((double)s + (double)ms/1000.)/60.)/60.;
     if (d<0) {D = -1.0*D;}
+#ifdef COUNT_DMS_SINCOS_CALLS
+    m_cosDirty = m_sinDirty = true;
+#endif
 }
 
 void dms::setH( const double &x ) {
     setD( x*15.0 );
+#ifdef COUNT_DMS_SINCOS_CALLS
+    m_cosDirty = m_sinDirty = true;
+#endif
 }
 
 void dms::setH(const int &h, const int &m, const int &s, const int &ms) {
     D = 15.0*((double)abs(h) + ((double)m + ((double)s + (double)ms/1000.)/60.)/60.);
     if (h<0) {D = -1.0*D;}
+#ifdef COUNT_DMS_SINCOS_CALLS
+    m_cosDirty = m_sinDirty = true;
+#endif
 }
 
 void dms::setRadians( const double &Rad ) {
     setD( Rad/DegToRad );
+#ifdef COUNT_DMS_SINCOS_CALLS
+    m_cosDirty = m_sinDirty = true;
+#endif
 }
 
 bool dms::setFromString( const QString &str, bool isDeg ) {
diff --git a/kstars/auxiliary/dms.h b/kstars/auxiliary/dms.h
index 8ff8e8c..28ce633 100644
--- a/kstars/auxiliary/dms.h
+++ b/kstars/auxiliary/dms.h
@@ -25,6 +25,7 @@
 
 #include <cmath>
 
+#define COUNT_DMS_SINCOS_CALLS true
 
 /** @class dms
  * @short An angle, stored as degrees, but expressible in many ways.
@@ -43,7 +44,15 @@
 class dms {
 public:
     /** Default constructor. */
-    dms() : D( NaN::d ) {}
+    dms() : D( NaN::d )
+#ifdef COUNT_DMS_SINCOS_CALLS
+        , m_sinCosCalled(false), m_sinDirty( true ), m_cosDirty( true )
+#endif
+    {
+#ifdef COUNT_DMS_SINCOS_CALLS
+        ++dms_constructor_calls;
+#endif
+    }
 
     /** @short Set the floating-point value of the angle according to the four integer arguments.
      * @param d degree portion of angle (int).  Defaults to zero.
@@ -51,14 +60,30 @@ public:
      * @param s arcsecond portion of angle (int).  Defaults to zero.
      * @param ms arcsecond portion of angle (int).  Defaults to zero.
      */
-    explicit dms( const int &d, const int &m=0, const int &s=0, const int &ms=0 ) { setD( d, m, s, ms ); }
+    explicit dms( const int &d, const int &m=0, const int &s=0, const int &ms=0 )
+#ifdef COUNT_DMS_SINCOS_CALLS
+        : m_sinCosCalled(false), m_sinDirty( true ), m_cosDirty( true )
+#endif
+    { setD( d, m, s, ms );
+#ifdef COUNT_DMS_SINCOS_CALLS
+        ++dms_constructor_calls;
+#endif
+}
 
     /** @short Construct an angle from a double value.
      *
      * Creates an angle whose value in Degrees is equal to the argument.
      * @param x angle expressed as a floating-point number (in degrees)
      */
-    explicit dms( const double &x ) : D(x) {}
+    explicit dms( const double &x ) : D(x)
+#ifdef COUNT_DMS_SINCOS_CALLS
+        , m_sinCosCalled(false), m_sinDirty( true ), m_cosDirty( true )
+#endif
+    {
+#ifdef COUNT_DMS_SINCOS_CALLS
+        ++dms_constructor_calls;
+#endif
+    }
 
     /** @short Construct an angle from a string representation.
      *
@@ -73,7 +98,15 @@ public:
      * @param isDeg if true, value is in degrees; if false, value is in hours.
      * @sa setFromString()
      */
-    explicit dms( const QString &s, bool isDeg=true ) { setFromString( s, isDeg ); }
+    explicit dms( const QString &s, bool isDeg=true )
+#ifdef COUNT_DMS_SINCOS_CALLS
+        : m_sinCosCalled(false), m_sinDirty( true ), m_cosDirty( true )
+#endif
+    { setFromString( s, isDeg );
+#ifdef COUNT_DMS_SINCOS_CALLS
+        ++dms_constructor_calls;
+#endif
+    }
 
     /** @return integer degrees portion of the angle
      */
@@ -128,7 +161,11 @@ public:
     /** Sets floating-point value of angle, in degrees.
      * @param x new angle (double)
      */
-    void setD( const double &x ) { D = x; }
+    void setD( const double &x ) {
+#ifdef COUNT_DMS_SINCOS_CALLS
+        m_sinDirty = m_cosDirty = true;
+#endif
+        D = x; }
 
     /** @short Sets floating-point value of angle, in degrees.
      * 
@@ -195,14 +232,32 @@ public:
      * @return the Sine of the angle.
      * @sa cos()
      */
-    double sin() const { return ::sin(D*DegToRad); }
+    double sin() const {
+#ifdef COUNT_DMS_SINCOS_CALLS
+        if( !m_sinCosCalled ) { m_sinCosCalled = true; ++dms_with_sincos_called; }
+        if( m_sinDirty )
+            m_sinDirty = false;
+        else
+            ++redundant_trig_function_calls;
+        ++trig_function_calls;
+#endif
+        return ::sin(D*DegToRad); }
 
     /** @short Compute the Angle's Cosine.
      *
      * @return the Cosine of the angle.
      * @sa sin()
      */
-    double cos() const { return ::cos(D*DegToRad); }
+    double cos() const {
+#ifdef COUNT_DMS_SINCOS_CALLS
+        if( !m_sinCosCalled ) { m_sinCosCalled = true; ++dms_with_sincos_called; }
+        if( m_cosDirty )
+            m_cosDirty = false;
+        else
+            ++redundant_trig_function_calls;
+        ++trig_function_calls;
+#endif
+        return ::cos(D*DegToRad); }
 
     /** @short Express the angle in radians.
      * @return the angle in radians (double)
@@ -261,8 +316,17 @@ public:
     static dms fromString(const QString & s, bool deg);
 
     dms operator - () { return dms(-D); }
+#ifdef COUNT_DMS_SINCOS_CALLS
+    static long unsigned dms_constructor_calls; // counts number of DMS constructor calls
+    static long unsigned dms_with_sincos_called;
+    static long unsigned trig_function_calls; // total number of trig function calls
+    static long unsigned redundant_trig_function_calls; // counts number of redundant trig function calls
+#endif
 private:
     double D;
+#ifdef COUNT_DMS_SINCOS_CALLS
+    mutable bool m_sinDirty, m_cosDirty, m_sinCosCalled;
+#endif
 
     friend dms operator+(dms, dms);
     friend dms operator-(dms, dms);
@@ -294,6 +358,20 @@ inline void dms::SinCos(double& s, double& c) const {
     s = ::sin( radians() );
     c = ::cos( radians() );
 #endif
+#ifdef COUNT_DMS_SINCOS_CALLS
+        if( !m_sinCosCalled ) { m_sinCosCalled = true; ++dms_with_sincos_called; }
+        if( m_sinDirty )
+            m_sinDirty = false;
+        else
+            ++redundant_trig_function_calls;
+
+        if( m_cosDirty )
+            m_cosDirty = false;
+        else
+            ++redundant_trig_function_calls;
+
+        trig_function_calls += 2;
+#endif
 }
 
 /** Overloaded equality operator */
diff --git a/kstars/kstars.cpp b/kstars/kstars.cpp
index d8ca2df..f4076f8 100644
--- a/kstars/kstars.cpp
+++ b/kstars/kstars.cpp
@@ -42,6 +42,9 @@
 #include "observinglist.h"
 //#include "whatsinteresting/wiview.h"
 
+// For profiling only
+#include "auxiliary/dms.h"
+
 #include "kstarsadaptor.h"
 
 #include <config-kstars.h>
@@ -173,6 +176,12 @@ KStars::~KStars()
 
     QSqlDatabase::removeDatabase("userdb");
     QSqlDatabase::removeDatabase("skydb");
+
+#ifdef COUNT_DMS_SINCOS_CALLS
+    qDebug() << "Constructed " << dms::dms_constructor_calls << " dms objects, of which " << dms::dms_with_sincos_called << " had trigonometric functions called on them = " << ( float( dms::dms_with_sincos_called ) / float( dms::dms_constructor_calls ) ) * 100. << "%";
+    qDebug() << "Of the " << dms::trig_function_calls << " calls to sin/cos/sincos on dms objects, " << dms::redundant_trig_function_calls << " were redundant = " << ( ( float( dms::redundant_trig_function_calls ) / float( dms::trig_function_calls ) ) * 100. ) << "%";
+#endif
+
 }
 
 void KStars::clearCachedFindDialog() {



More information about the Kstars-devel mailing list