public inbox for libstdc++@gcc.gnu.org
 help / color / mirror / Atom feed
* [committed] libstdc++: Optimize std::any_cast by replacing indirect call
@ 2021-06-04 17:02 Tim Adye
  2021-06-04 17:05 ` Jonathan Wakely
  0 siblings, 1 reply; 2+ messages in thread
From: Tim Adye @ 2021-06-04 17:02 UTC (permalink / raw)
  To: libstdc++, gcc-patches; +Cc: Tim Adye, Axel Naumann

[-- Attachment #1: Type: text/plain, Size: 1093 bytes --]

This significantly improves the performance of std::any_cast, by
avoiding an indirect call to the _S_manage function through a function
pointer. Before we make that indirect call we've already established
that the contained value has the expected type, which means we also know
the manager type, and so can call one of its members directly.

We also know the precise type in the any::emplace functions, because
we've just constructed that type, so we can use the new member there
too. That doesn't seem to affect performance, but we might as well use
the new _S_access function anyway.

Signed-off-by: Tim Adye <Tim.Adye@cern.ch>
Signed-off-by: Jonathan Wakely <jwakely@redhat.com>

libstdc++-v3/ChangeLog:

	* include/std/any (any::_Manager::_S_access): New static
	function to access the contained value.
	(any::emplace, __any_caster): Use _S_access member of the
	manager type.

Tested powerpc64le-linux. Committed to trunk.

This patch was contributed by Tim Adye and accepted in line with the
new policy announced in https://gcc.gnu.org/pipermail/gcc/2021-June/236182.html

Thanks, Tim!


[-- Attachment #2: patch.txt --]
[-- Type: text/plain, Size: 3119 bytes --]

commit f6bb145c0bff19767931d37733be11c8acc6fa00
Author: Tim Adye <Tim.Adye@cern.ch>
Date:   Fri Jun 4 15:59:38 2021

    libstdc++: Optimize std::any_cast by replacing indirect call
    
    This significantly improves the performance of std::any_cast, by
    avoiding an indirect call to the _S_manage function through a function
    pointer. Before we make that indirect call we've already established
    that the contained value has the expected type, which means we also know
    the manager type, and so can call one of its members directly.
    
    We also know the precise type in the any::emplace functions, because
    we've just constructed that type, so we can use the new member there
    too. That doesn't seem to affect performance, but we might as well use
    the new _S_access function anyway.
    
    Signed-off-by: Tim Adye <Tim.Adye@cern.ch>
    Signed-off-by: Jonathan Wakely <jwakely@redhat.com>
    
    libstdc++-v3/ChangeLog:
    
            * include/std/any (any::_Manager::_S_access): New static
            function to access the contained value.
            (any::emplace, __any_caster): Use _S_access member of the
            manager type.

diff --git a/libstdc++-v3/include/std/any b/libstdc++-v3/include/std/any
index 391e43339a0..21120a9146f 100644
--- a/libstdc++-v3/include/std/any
+++ b/libstdc++-v3/include/std/any
@@ -263,9 +263,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       {
 	using _VTp = decay_t<_Tp>;
 	__do_emplace<_VTp>(std::forward<_Args>(__args)...);
-	any::_Arg __arg;
-	this->_M_manager(any::_Op_access, this, &__arg);
-	return *static_cast<_VTp*>(__arg._M_obj);
+	return *any::_Manager<_VTp>::_S_access(_M_storage);
       }
 
     /// Emplace with an object created from @p __il and @p __args as
@@ -276,9 +274,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       {
 	using _VTp = decay_t<_Tp>;
 	__do_emplace<_VTp, _Up>(__il, std::forward<_Args>(__args)...);
-	any::_Arg __arg;
-	this->_M_manager(any::_Op_access, this, &__arg);
-	return *static_cast<_VTp*>(__arg._M_obj);
+	return *any::_Manager<_VTp>::_S_access(_M_storage);
       }
 
     // modifiers
@@ -384,6 +380,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	    void* __addr = &__storage._M_buffer;
 	    ::new (__addr) _Tp(std::forward<_Args>(__args)...);
 	  }
+
+	static _Tp*
+	_S_access(const _Storage& __storage)
+	{
+	  // The contained object is in __storage._M_buffer
+	  const void* __addr = &__storage._M_buffer;
+	  return static_cast<_Tp*>(const_cast<void*>(__addr));
+	}
       };
 
     // Manage external contained object.
@@ -405,6 +409,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	  {
 	    __storage._M_ptr = new _Tp(std::forward<_Args>(__args)...);
 	  }
+	static _Tp*
+	_S_access(const _Storage& __storage)
+	{
+	  // The contained object is in *__storage._M_ptr
+	  return static_cast<_Tp*>(__storage._M_ptr);
+	}
       };
   };
 
@@ -511,9 +521,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 #endif
 	  )
 	{
-	  any::_Arg __arg;
-	  __any->_M_manager(any::_Op_access, __any, &__arg);
-	  return __arg._M_obj;
+	  return any::_Manager<_Up>::_S_access(__any->_M_storage);
 	}
       return nullptr;
     }

^ permalink raw reply	[flat|nested] 2+ messages in thread

* Re: [committed] libstdc++: Optimize std::any_cast by replacing indirect call
  2021-06-04 17:02 [committed] libstdc++: Optimize std::any_cast by replacing indirect call Tim Adye
@ 2021-06-04 17:05 ` Jonathan Wakely
  0 siblings, 0 replies; 2+ messages in thread
From: Jonathan Wakely @ 2021-06-04 17:05 UTC (permalink / raw)
  To: libstdc++, gcc-patches; +Cc: Axel Naumann, Tim Adye

Apparently my mailer decided to sent this email as From: Tim, rather
than me. Sorry for any confusion.  The patch is from Tim, but the
email to the lists was sent by me (jwakely). Hopefully this one will
have the right From: header on it!


On 04/06/21 18:02 +0100, Tim Adye wrote:
>This significantly improves the performance of std::any_cast, by
>avoiding an indirect call to the _S_manage function through a function
>pointer. Before we make that indirect call we've already established
>that the contained value has the expected type, which means we also know
>the manager type, and so can call one of its members directly.
>
>We also know the precise type in the any::emplace functions, because
>we've just constructed that type, so we can use the new member there
>too. That doesn't seem to affect performance, but we might as well use
>the new _S_access function anyway.
>
>Signed-off-by: Tim Adye <Tim.Adye@cern.ch>
>Signed-off-by: Jonathan Wakely <jwakely@redhat.com>
>
>libstdc++-v3/ChangeLog:
>
>	* include/std/any (any::_Manager::_S_access): New static
>	function to access the contained value.
>	(any::emplace, __any_caster): Use _S_access member of the
>	manager type.
>
>Tested powerpc64le-linux. Committed to trunk.
>
>This patch was contributed by Tim Adye and accepted in line with the
>new policy announced in https://gcc.gnu.org/pipermail/gcc/2021-June/236182.html
>
>Thanks, Tim!
>

>commit f6bb145c0bff19767931d37733be11c8acc6fa00
>Author: Tim Adye <Tim.Adye@cern.ch>
>Date:   Fri Jun 4 15:59:38 2021
>
>    libstdc++: Optimize std::any_cast by replacing indirect call
>
>    This significantly improves the performance of std::any_cast, by
>    avoiding an indirect call to the _S_manage function through a function
>    pointer. Before we make that indirect call we've already established
>    that the contained value has the expected type, which means we also know
>    the manager type, and so can call one of its members directly.
>
>    We also know the precise type in the any::emplace functions, because
>    we've just constructed that type, so we can use the new member there
>    too. That doesn't seem to affect performance, but we might as well use
>    the new _S_access function anyway.
>
>    Signed-off-by: Tim Adye <Tim.Adye@cern.ch>
>    Signed-off-by: Jonathan Wakely <jwakely@redhat.com>
>
>    libstdc++-v3/ChangeLog:
>
>            * include/std/any (any::_Manager::_S_access): New static
>            function to access the contained value.
>            (any::emplace, __any_caster): Use _S_access member of the
>            manager type.
>
>diff --git a/libstdc++-v3/include/std/any b/libstdc++-v3/include/std/any
>index 391e43339a0..21120a9146f 100644
>--- a/libstdc++-v3/include/std/any
>+++ b/libstdc++-v3/include/std/any
>@@ -263,9 +263,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>       {
> 	using _VTp = decay_t<_Tp>;
> 	__do_emplace<_VTp>(std::forward<_Args>(__args)...);
>-	any::_Arg __arg;
>-	this->_M_manager(any::_Op_access, this, &__arg);
>-	return *static_cast<_VTp*>(__arg._M_obj);
>+	return *any::_Manager<_VTp>::_S_access(_M_storage);
>       }
>
>     /// Emplace with an object created from @p __il and @p __args as
>@@ -276,9 +274,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>       {
> 	using _VTp = decay_t<_Tp>;
> 	__do_emplace<_VTp, _Up>(__il, std::forward<_Args>(__args)...);
>-	any::_Arg __arg;
>-	this->_M_manager(any::_Op_access, this, &__arg);
>-	return *static_cast<_VTp*>(__arg._M_obj);
>+	return *any::_Manager<_VTp>::_S_access(_M_storage);
>       }
>
>     // modifiers
>@@ -384,6 +380,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
> 	    void* __addr = &__storage._M_buffer;
> 	    ::new (__addr) _Tp(std::forward<_Args>(__args)...);
> 	  }
>+
>+	static _Tp*
>+	_S_access(const _Storage& __storage)
>+	{
>+	  // The contained object is in __storage._M_buffer
>+	  const void* __addr = &__storage._M_buffer;
>+	  return static_cast<_Tp*>(const_cast<void*>(__addr));
>+	}
>       };
>
>     // Manage external contained object.
>@@ -405,6 +409,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
> 	  {
> 	    __storage._M_ptr = new _Tp(std::forward<_Args>(__args)...);
> 	  }
>+	static _Tp*
>+	_S_access(const _Storage& __storage)
>+	{
>+	  // The contained object is in *__storage._M_ptr
>+	  return static_cast<_Tp*>(__storage._M_ptr);
>+	}
>       };
>   };
>
>@@ -511,9 +521,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
> #endif
> 	  )
> 	{
>-	  any::_Arg __arg;
>-	  __any->_M_manager(any::_Op_access, __any, &__arg);
>-	  return __arg._M_obj;
>+	  return any::_Manager<_Up>::_S_access(__any->_M_storage);
> 	}
>       return nullptr;
>     }


^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2021-06-04 17:05 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-06-04 17:02 [committed] libstdc++: Optimize std::any_cast by replacing indirect call Tim Adye
2021-06-04 17:05 ` Jonathan Wakely

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).