Commits

Anonymous committed fe81d29

Add fast_push_back from DataModel; fix gcc43 compilation problems.

Comments (0)

Files changed (14)

+2009-03-20  scott snyder  <snyder@bnl.gov>
+
+	* Tagging CxxUtils-00-00-22
+
+	* CxxUtils/fast_push_back.h, test/fast_push_back_test.cxx,
+	test/fast_push_back1_test.cxx, share/fast_push_back_test.ref,
+	share/fast_push_back_test1.ref: Copied here from DataModel.
+	* cmt/requirements: Add the tests.
+
+	* src/procmaps.cxx: Add missing #include.
+	* src/PtrAccessSEGVHandler.cxx: Add missing #include.
+	* test/SEGVHandler_test.cxx: Add missing #include.
+
+	* test/procmaps_test.cxx (nop): Fix compilation warning.
+
+	* share/PageAccessControl_test.ref, share/SEGVHandler_test.ref,
+	share/procmaps_test.ref: (new)
+
 2009-03-11  Sebastien Binet  <binet@farnsworth>
 
 	* tagging CxxUtils-00-00-21

CxxUtils/fast_push_back.h

+// This file's extension implies that it's C, but it's really -*- C++ -*-.
+// $Id: fast_push_back.h,v 1.1 2009-03-20 18:59:19 ssnyder Exp $
+/**
+ * @file  CxxUtils/fast_push_back.h
+ * @author scott snyder
+ * @date Jan, 2007
+ * @brief Helper to speed up inserting into an STL vector.
+ *
+ * Here's the issue.  Suppose one has a class like this:
+ *
+ *@code
+ *  class C
+ *  {
+ *    C (int x, int y);
+ *    ~C();
+ *  };
+ @endcode
+ *
+ * and you want to insert elements into a @c std::vector<C>.
+ * You might do something like this:
+ *
+ *@code
+ *  v.push_back (C (0, 1));
+ @endcode
+ *
+ * Note what this does though:
+ *
+ *  - We first make a temporary instance of @c C using @c C's constructor,
+ *    to pass to @c push_back.
+ *  - @c push_back will somehow allocate the memory within the vector
+ *    where the new element will reside.
+ *  - @c push_back will copy-construct the new element, using
+ *    a placement @c new.
+ *  - Finally, we need to destroy the temporary @c C we created.
+ *
+ * Note that one constructor/destructor here is superfluous.
+ * In some cases, this can have a significant effect on performance
+ * (this was observed in filling calorimeter towers with cells).
+ * So, we'd like to be able to eliminate this superfluous ctor/dtor pair.
+ *
+ * Suppose that in addition to @c push_back, @c std::vector had a method
+ * @c uninitialized_push_back.  This would do the memory allocation
+ * (the second bullet above), but would then return the pointer rather
+ * than constructing the element itself.  The caller is then free to
+ * construct the element using whatever constructor is convenient.
+ * For example,
+ *
+ *@code
+ *  new (v.uninitialized_push_back()) C (0, 1);
+ @endcode
+ *
+ * would call only the single @c constructor, with no destructors.
+ *
+ * Of course, @c uninitialized_push_back doesn't exist; and further,
+ * there doesn't seem to be any way to add that functionality
+ * to an existing @c std::vector in a portable way.
+ *
+ * However, for some compilers, we can define such an operation
+ * if we're permitted to use knowledge of the internals of
+ * @c std::vector.  Thus, this file selects for compilers/versions
+ * that we know, and defines a @c uninitialized_push_back operation
+ * if possible.
+ *
+ * The entry points here are the functions @c fast_push_back.
+ * These take as arguments first the container, followed by the
+ * arguments to use for the element's constructor.  If an
+ * @c uninitialized_push_back is defined, then @c fast_push_back
+ * will use it.  Otherwise, a slower, portable implementation will be used.
+ * So, using this header, the example above would be written:
+ *
+ *@code
+ *  SG::fast_push_back (v, 0, 1);
+ @endcode
+ *
+ * We support up to four arguments to the element constructor.
+ *
+ * Note that there's standard solution for this in the new C++0x standard.
+ * In that version, @c vector supports an emplacement @c push_back,
+ * where instead of
+ *
+ *@code
+ *  v.push_back (C (0, 1));
+ @endcode
+ *
+ * one can do 
+ *
+ *@code
+ *  v.push_back (0, 1);
+ @endcode
+ *
+ * to avoid the extra constructors.  We'll use this form if we know
+ * that it's available in the compiler version being used.
+ */
+
+
+#ifndef DATAMODEL_TOOLS_FAST_PUSH_BACK_H
+#define DATAMODEL_TOOLS_FAST_PUSH_BACK_H
+
+#include <vector>
+
+
+namespace CxxUtils {
+
+
+// If __GXX_EXPERIMENTAL_CXX0X__ is on, then we have emplacement push_back.
+#ifdef __GXX_EXPERIMENTAL_CXX0X__
+# define HAVE_SG_EMPLACEMENT
+#endif
+
+
+// Implementation of @c uninitialized_push_back for gcc.
+#if defined(__GNUC__) && !defined(HAVE_SG_EMPLACEMENT)
+
+// We have it.
+// (The conditional is for testing purposes.)
+#ifndef HAVE_SG_UNINITIALIZED_PUSH_BACK
+#define HAVE_SG_UNINITIALIZED_PUSH_BACK 1
+#endif
+
+
+// Helper class used to get access to std::vector's
+// protected _M_finish member.
+template <typename V>
+struct vhelper
+  : public V
+{
+  typename V::pointer uninitialized_push_back()
+  {
+    typename V::size_type sz = this->size();
+    if (sz == this->capacity()) {
+      // ??? Ignoring possible overflow here...
+      this->reserve (sz ? sz*2 : 1);
+    }
+
+    return this->_M_impl._M_finish++;
+  }
+};
+
+
+// This is uninitialized_push_back for gcc.
+template <typename V>
+inline
+typename V::pointer uninitialized_push_back (V& v)
+{
+  return (reinterpret_cast<vhelper<V>&> (v)).uninitialized_push_back();
+}
+
+
+#endif // __GNUC__
+
+
+/**
+ * @brief Construct and push an element onto a vector.
+ * @param v The vector onto which to push the element.
+ *
+ * The element will be default-constructed.
+ * A superfluous ctor/dtor pair will be avoided, if possible.
+ */
+template <typename V>
+inline
+void fast_push_back (V& v)
+{
+#ifdef HAVE_SG_EMPLACEMENT
+  v.push_back ();
+#else
+# ifdef HAVE_SG_UNINITIALIZED_PUSH_BACK
+  new (uninitialized_push_back (v)) typename V::value_type;
+# else
+  v.push_back (typename V::value_type ());
+# endif
+#endif
+}
+
+
+/**
+ * @brief Construct and push an element onto a vector.
+ * @param v The vector onto which to push the element.
+ * @param x1 The first argument to the element's constructor.
+ *
+ * A superfluous ctor/dtor pair will be avoided, if possible.
+ */
+template <typename V, typename T1>
+inline
+void fast_push_back (V& v, const T1& x1)
+{
+#ifdef HAVE_SG_EMPLACEMENT
+  v.push_back (x1);
+#else
+# ifdef HAVE_SG_UNINITIALIZED_PUSH_BACK
+  new (uninitialized_push_back (v)) typename V::value_type (x1);
+# else
+  v.push_back (typename V::value_type (x1));
+# endif
+#endif
+}
+
+
+/**
+ * @brief Construct and push an element onto a vector.
+ * @param v The vector onto which to push the element.
+ * @param x1 The first argument to the element's constructor.
+ *
+ * A superfluous ctor/dtor pair will be avoided, if possible.
+ */
+template <typename V, typename T1>
+inline
+void fast_push_back (V& v, T1& x1)
+{
+#ifdef HAVE_SG_EMPLACEMENT
+  v.push_back (x1);
+#else
+# ifdef HAVE_SG_UNINITIALIZED_PUSH_BACK
+  new (uninitialized_push_back (v)) typename V::value_type (x1);
+# else
+  v.push_back (typename V::value_type (x1));
+# endif
+#endif
+}
+
+
+/**
+ * @brief Construct and push an element onto a vector.
+ * @param v The vector onto which to push the element.
+ * @param x1 The first argument to the element's constructor.
+ * @param x2 The second argument to the element's constructor.
+ *
+ * A superfluous ctor/dtor pair will be avoided, if possible.
+ */
+template <typename V, typename T1, typename T2>
+inline
+void fast_push_back (V& v, const T1& x1, const T2& x2)
+{
+#ifdef HAVE_SG_EMPLACEMENT
+  v.push_back (x1, x2);
+#else
+# ifdef HAVE_SG_UNINITIALIZED_PUSH_BACK
+  new (uninitialized_push_back (v)) typename V::value_type (x1, x2);
+# else
+  v.push_back (typename V::value_type (x1, x2));
+# endif
+#endif
+}
+
+
+/**
+ * @brief Construct and push an element onto a vector.
+ * @param v The vector onto which to push the element.
+ * @param x1 The first argument to the element's constructor.
+ * @param x2 The second argument to the element's constructor.
+ *
+ * A superfluous ctor/dtor pair will be avoided, if possible.
+ */
+template <typename V, typename T1, typename T2>
+inline
+void fast_push_back (V& v, T1& x1, const T2& x2)
+{
+#ifdef HAVE_SG_EMPLACEMENT
+  v.push_back (x1, x2);
+#else
+# ifdef HAVE_SG_UNINITIALIZED_PUSH_BACK
+  new (uninitialized_push_back (v)) typename V::value_type (x1, x2);
+# else
+  v.push_back (typename V::value_type (x1, x2));
+# endif
+#endif
+}
+
+
+/**
+ * @brief Construct and push an element onto a vector.
+ * @param v The vector onto which to push the element.
+ * @param x1 The first argument to the element's constructor.
+ * @param x2 The second argument to the element's constructor.
+ * @param x3 The third argument to the element's constructor.
+ *
+ * A superfluous ctor/dtor pair will be avoided, if possible.
+ */
+template <typename V, typename T1, typename T2, typename T3>
+inline
+void fast_push_back (V& v, const T1& x1, const T2& x2, const T3& x3)
+{
+#ifdef HAVE_SG_EMPLACEMENT
+  v.push_back (x1, x2, x3);
+#else
+# ifdef HAVE_SG_UNINITIALIZED_PUSH_BACK
+  new (uninitialized_push_back (v)) typename V::value_type (x1, x2, x3);
+# else
+  v.push_back (typename V::value_type (x1, x2, x3));
+# endif
+#endif
+}
+
+
+/**
+ * @brief Construct and push an element onto a vector.
+ * @param v The vector onto which to push the element.
+ * @param x1 The first argument to the element's constructor.
+ * @param x2 The second argument to the element's constructor.
+ * @param x3 The third argument to the element's constructor.
+ *
+ * A superfluous ctor/dtor pair will be avoided, if possible.
+ */
+template <typename V, typename T1, typename T2, typename T3>
+inline
+void fast_push_back (V& v, T1& x1, const T2& x2, const T3& x3)
+{
+#ifdef HAVE_SG_EMPLACEMENT
+  v.push_back (x1, x2, x3);
+#else
+# ifdef HAVE_SG_UNINITIALIZED_PUSH_BACK
+  new (uninitialized_push_back (v)) typename V::value_type (x1, x2, x3);
+# else
+  v.push_back (typename V::value_type (x1, x2, x3));
+# endif
+#endif
+}
+
+
+/**
+ * @brief Construct and push an element onto a vector.
+ * @param v The vector onto which to push the element.
+ * @param x1 The first argument to the element's constructor.
+ * @param x2 The second argument to the element's constructor.
+ * @param x3 The third argument to the element's constructor.
+ * @param x4 The fourth argument to the element's constructor.
+ *
+ * A superfluous ctor/dtor pair will be avoided, if possible.
+ */
+template <typename V, typename T1, typename T2, typename T3, typename T4>
+inline
+void fast_push_back (V& v,
+                     const T1& x1, const T2& x2, const T3& x3, const T4& x4)
+{
+#ifdef HAVE_SG_EMPLACEMENT
+  v.push_back (x1, x2, x3, x4);
+#else
+# ifdef HAVE_SG_UNINITIALIZED_PUSH_BACK
+  new (uninitialized_push_back (v)) typename V::value_type (x1, x2, x3, x4);
+# else
+  v.push_back (typename V::value_type (x1, x2, x3, x4));
+# endif
+#endif
+}
+
+
+/**
+ * @brief Construct and push an element onto a vector.
+ * @param v The vector onto which to push the element.
+ * @param x1 The first argument to the element's constructor.
+ * @param x2 The second argument to the element's constructor.
+ * @param x3 The third argument to the element's constructor.
+ * @param x4 The fourth argument to the element's constructor.
+ *
+ * A superfluous ctor/dtor pair will be avoided, if possible.
+ */
+template <typename V, typename T1, typename T2, typename T3, typename T4>
+inline
+void fast_push_back (V& v,
+                     T1& x1, const T2& x2, const T3& x3, const T4& x4)
+{
+#ifdef HAVE_SG_EMPLACEMENT
+  v.push_back (x1, x2, x3, x4);
+#else
+# ifdef HAVE_SG_UNINITIALIZED_PUSH_BACK
+  new (uninitialized_push_back (v)) typename V::value_type (x1, x2, x3, x4);
+# else
+  v.push_back (typename V::value_type (x1, x2, x3, x4));
+# endif
+#endif
+}
+
+
+} // namespace CxxUtils
+
+
+#endif // not DATAMODEL_TOOLS_FAST_PUSH_BACK_H
 apply_pattern UnitTest_run unit_test=procmaps
 apply_pattern UnitTest_run unit_test=sincos
 apply_pattern UnitTest_run unit_test=copyif
+apply_pattern UnitTest_run unit_test=fast_push_back
+apply_pattern UnitTest_run unit_test=fast_push_back1
 
 end_private

share/PageAccessControl_test.ref

+*** PageAccessControl_test starts ***
+PageAccessControl::protectPage DEBUG: set protection 0 for page range 0x804e000 - 0x804efff containing address range=0x804e980 - 0x804e983
+PageAccessControl::restorePageProt DEBUG: restored protection 7 for page 0x804e000 containing address 0x804e000 
+ FIXME NOT Freeing memory at (nil) 
+accessing restored pointer 2
+*** PageAccessControl_test OK ***

share/SEGVHandler_test.ref

+*** SEGVHandler_test starts ***
+sigaction installing handler returned 0
+@pInt=0x805d018
+PageAccessControl::protectPage DEBUG: set protection 0 for page range 0x805d000 - 0x805dfff containing address range=0x805d018 - 0x805d01b
+page fault @address=0x805d024
+page fault signo=11
+page fault errno=0
+this page fault failed because you tried to access a protected address
+PageAccessControl::restorePageProt DEBUG: restored protection 7 for page 0x805d000 containing address 0x805d000 
+ FIXME NOT Freeing memory at (nil) 
+@pString=0x805d028
+@pPair=0x805d050
+PageAccessControl::protectPage DEBUG: set protection 0 for page range 0x805d000 - 0x805dfff containing address range=0x805d028 - 0x805d02b
+PageAccessControl::protectPage DEBUG: set protection 0 for page range 0x805d000 - 0x805dfff containing address range=0x805d050 - 0x805d05b
+page fault @address=0x805d05c
+page fault signo=11
+page fault errno=0
+this page fault failed because you tried to access a protected address
+PageAccessControl::restorePageProt DEBUG: restored protection 7 for page 0x805d000 containing address 0x805d000 
+ FIXME NOT Freeing memory at (nil) 
+try to read 12
+accessing pInt 11
+reading again from pInt 11
+try to write 33
+read 33
+reading from string bar
+reading again from string bar
+reading double from pair 2
+reading again double from pair 2
+try to read 33
+read 33
+accessed ptrs
+@0x805d024
+@0x805d05c
+*** SEGVHandler_test OK ***

share/fast_push_back1_test.ref

Empty file added.

share/fast_push_back_test.ref

Empty file added.

share/procmaps_test.ref

+*** procmaps_test starts ***
+*** procmaps_test OK ***

src/PtrAccessSEGVHandler.cxx

 
 #include "CxxUtils/PtrAccessSEGVHandler.h"
 #include "CxxUtils/PageAccessControl.h"
+#include <cstdio>
 
 void
 PtrAccessSEGVHandler::handle(int /*signal_number*/,siginfo_t *sigi,void * /*unused*/) {
 #include <algorithm>
 #include <cstdio>
 #include <cstdlib>
+#include <cstring>
 #include "CxxUtils/procmaps.h"
 bool procmaps::s_pmapsLoaded(false);
 procmaps::procmaps_t procmaps::s_pmaps;

test/SEGVHandler_test.cxx

 #include <unistd.h>
 #include <string>
 #include <utility> /* pair */
+#include <cassert>
 #include "CxxUtils/procmaps.h"
 #include "CxxUtils/PageAccessControl.h"
 #include "CxxUtils/PtrAccessSEGVHandler.h"

test/fast_push_back1_test.cxx

+// $Id: fast_push_back1_test.cxx,v 1.1 2009-03-20 18:59:20 ssnyder Exp $
+/**
+ * @file  CxxUtils/tests/fast_push_back1_test.cxx
+ * @author scott snyder
+ * @date Jan, 2007
+ * @brief Regression tests for fast_push_back.
+ *
+ * This is the same as fast_push_back_test, except that we force the use
+ * of the portable version.
+ */
+
+
+#undef NDEBUG
+#define HAVE_SG_UNINITIALIZED_PUSH_BACK 0
+#include "CxxUtils/fast_push_back.h"
+#include <vector>
+#include <cassert>
+
+
+class C
+{
+public:
+  C () : m_a (0), m_b (0), m_c (0), m_d (0) {}
+  C (int a) : m_a (a), m_b (0), m_c (0), m_d (0) {}
+  C (int a, int b) : m_a (a), m_b (b), m_c (0), m_d (0) {}
+  C (int a, int b, int c) : m_a (a), m_b (b), m_c (c), m_d (0) {}
+  C (int a, int b, int c, int d) : m_a (a), m_b (b), m_c (c), m_d (d) {}
+  ~C () {}
+  int m_a;
+  int m_b;
+  int m_c;
+  int m_d;
+};
+
+
+void check (const C& cc, int a=0, int b=0, int c=0, int d=0)
+{
+  assert (cc.m_a == a);
+  assert (cc.m_b == b);
+  assert (cc.m_c == c);
+  assert (cc.m_d == d);
+}
+
+
+void testit()
+{
+  std::vector<C> v;
+
+  for (int i=0; i < 100; i++)
+    CxxUtils::fast_push_back (v);
+  for (int i=0; i < 100; i++)
+    CxxUtils::fast_push_back (v, i);
+  for (int i=0; i < 100; i++)
+    CxxUtils::fast_push_back (v, i, i*2);
+  for (int i=0; i < 100; i++)
+    CxxUtils::fast_push_back (v, i, i*2, i*3);
+  for (int i=0; i < 100; i++)
+    CxxUtils::fast_push_back (v, i, i*2, i*3, i*4);
+
+  int j = 0;
+  for (int i=0; i < 100; i++)
+    check (v[j++]);
+  for (int i=0; i < 100; i++)
+    check (v[j++], i);
+  for (int i=0; i < 100; i++)
+    check (v[j++], i, i*2);
+  for (int i=0; i < 100; i++)
+    check (v[j++], i, i*2, i*3);
+  for (int i=0; i < 100; i++)
+    check (v[j++], i, i*2, i*3, i*4);
+}
+
+
+int main()
+{
+  testit();
+  return 0;
+}
+

test/fast_push_back_test.cxx

+// $Id: fast_push_back_test.cxx,v 1.1 2009-03-20 18:59:20 ssnyder Exp $
+/**
+ * @file  CxxUtils/tests/fast_push_back_test.cxx
+ * @author scott snyder
+ * @date Jan, 2007
+ * @brief Regression tests for fast_push_back.
+ */
+
+
+#undef NDEBUG
+#include "CxxUtils/fast_push_back.h"
+#include <vector>
+#include <cassert>
+
+
+class C
+{
+public:
+  C () : m_a (0), m_b (0), m_c (0), m_d (0) {}
+  C (int a) : m_a (a), m_b (0), m_c (0), m_d (0) {}
+  C (int a, int b) : m_a (a), m_b (b), m_c (0), m_d (0) {}
+  C (int a, int b, int c) : m_a (a), m_b (b), m_c (c), m_d (0) {}
+  C (int a, int b, int c, int d) : m_a (a), m_b (b), m_c (c), m_d (d) {}
+  ~C () {}
+  int m_a;
+  int m_b;
+  int m_c;
+  int m_d;
+};
+
+
+void check (const C& cc, int a=0, int b=0, int c=0, int d=0)
+{
+  assert (cc.m_a == a);
+  assert (cc.m_b == b);
+  assert (cc.m_c == c);
+  assert (cc.m_d == d);
+}
+
+
+void testit()
+{
+  std::vector<C> v;
+
+  for (int i=0; i < 100; i++)
+    CxxUtils::fast_push_back (v);
+  for (int i=0; i < 100; i++)
+    CxxUtils::fast_push_back (v, i);
+  for (int i=0; i < 100; i++)
+    CxxUtils::fast_push_back (v, i, i*2);
+  for (int i=0; i < 100; i++)
+    CxxUtils::fast_push_back (v, i, i*2, i*3);
+  for (int i=0; i < 100; i++)
+    CxxUtils::fast_push_back (v, i, i*2, i*3, i*4);
+
+  int j = 0;
+  for (int i=0; i < 100; i++)
+    check (v[j++]);
+  for (int i=0; i < 100; i++)
+    check (v[j++], i);
+  for (int i=0; i < 100; i++)
+    check (v[j++], i, i*2);
+  for (int i=0; i < 100; i++)
+    check (v[j++], i, i*2, i*3);
+  for (int i=0; i < 100; i++)
+    check (v[j++], i, i*2, i*3, i*4);
+}
+
+
+int main()
+{
+  testit();
+  return 0;
+}
+

test/procmaps_test.cxx

 #endif
   procmaps pmaps(DUMPMAPS);
   //let's start with a code page
-  const procmaps::Entry* pCodeEntry(pmaps.getEntry((void *)&nop));
+  const procmaps::Entry* pCodeEntry(pmaps.getEntry((void *)(unsigned long)&nop));
   assert(pCodeEntry); 
 #ifdef DEBUGIT
   cout << "code entry " << hex << pCodeEntry->begAddress << " "