C++ 的 runtime exception是没有扩展性的

https://groups.google.com/forum/#!topic/seastar-dev/RuK-OajeqHk

https://www.google.com/search?ei=gTH-Wtr5O4WQsAW-io7wCQ&q=dl_iterate_phdr+gcc+exception&oq=dl_iterate_phdr+gcc+exception&gs_l=psy-ab.3...5055.7797.0.8041.10.8.0.0.0.0.382.997.3-3.3.0....0...1.1.64.psy-ab..7.1.306...33i160k1.0.dDZSKQ-pAA4

g++/glibc combination provides a c++ runtime with non scaleable 
c++ exception. This is dues to global locks in stack unwinding code. 
    
To summarize all the locks we have now and their purpose: 
 1. There is a lock in _Unwind_Find_FDE (libgcc) that protects 
    list of FDEs registered with __register_frame* functions. 
    The catch is that dynamically linked binary do not do that, 
    so all that it protects is checking that a certain list is empty. 
    This lock no longer relevant in gcc7 since there is a path there 
    checks that list is empty outside of the lock. 
 2. The lock in dl_iterate_phdr (glibc) that protects loaded object 
    list against runtime object loading/unloading.

To get rid of the first lock one has to use gcc7.

To get rid of the second one we can use the fact that we do not 
load/unload objects dynamically (at least for now). To do that we 
can mirror all elf header information in seastar and provide our 
own dl_iterate_phdr symbol which uses this mirror without locking. 
    
Unfortunately there is another gotcha in this approach: dl_iterate_phdr 
supplied by glibc never calls more then one callback simultaneously as an 
unintended consequences of the lock there, but unfortunately libgcc relies 
on that to maintain small cache of translations. The access to the cache is 
not protected by any lock since up until now only one callback could have 
run at a time. But luckily libgcc cannot use the cache if older version 
of dl_phdr_info is provided to the callback because the older version 
did not have an indication that loaded object list may have changed, 
so libgcc does not know when cache should be invalidated and disables it 
entirely. By calling the callback with old version of dl_phdr_info from 
our dl_iterate_phdr we can effectively make libgcc callback thread safe.

diff --git a/configure.py b/configure.py 
index facdd8f..33b310b 100755 
--- a/configure.py 
+++ b/configure.py 
@@ -297,6 +297,8 @@ arg_parser.add_argument(‘--static-boost‘, dest = ‘staticboost‘, action = ‘store_ 
 add_tristate(arg_parser, name = ‘hwloc‘, dest = ‘hwloc‘, help = ‘hwloc support‘) 
 arg_parser.add_argument(‘--enable-gcc6-concepts‘, dest=‘gcc6_concepts‘, action=‘store_true‘, default=False, 
                         help=‘enable experimental support for C++ Concepts as implemented in GCC 6‘) 
+arg_parser.add_argument(‘--disable-exception-scalability-workaround‘, dest=‘exception_workaround‘, action=‘store_true‘, default=False, 
+        help=‘disabling override of dl_iterate_phdr symbol to workaround C++ exception scalability issues‘) 
 args = arg_parser.parse_args() 
  
 libnet = [ 
@@ -337,6 +339,7 @@ core = [ 
     ‘net/inet_address.cc‘, 
     ‘rpc/rpc.cc‘, 
     ‘rpc/lz4_compressor.cc‘, 
+    ‘core/exception_hacks.cc‘, 
     ] 
  
 protobuf = [ 
@@ -392,6 +395,9 @@ if args.gcc6_concepts: 
     defines.append(‘HAVE_GCC6_CONCEPTS‘) 
     args.user_cflags += ‘ -fconcepts‘ 
  
+if args.exception_workaround: 
+    defines.append(‘NO_EXCEPTION_HACK‘) 

 if args.staticcxx: 
     libs = libs.replace(‘-lstdc++‘, ‘‘) 
     libs += ‘ -static-libgcc -static-libstdc++‘ 
diff --git a/core/exception_hacks.cc b/core/exception_hacks.cc 
new file mode 100644 
index 0000000..6f04630 
--- /dev/null 
+++ b/core/exception_hacks.cc 
@@ -0,0 +1,108 @@ 
+/* 
+ * This file is open source software, licensed to you under the terms 
+ * of the Apache License, Version 2.0 (the "License").  See the NOTICE file 
+ * distributed with this work for additional information regarding copyright 
+ * ownership.  You may not use this file except in compliance with the License. 
+ * 
+ * You may obtain a copy of the License at 
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0 
+ * 
+ * Unless required by applicable law or agreed to in writing, 
+ * software distributed under the License is distributed on an 
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 
+ * KIND, either express or implied.  See the License for the 
+ * specific language governing permissions and limitations 
+ * under the License. 
+ */ 
+/* 
+ * Copyright (C) 2017 ScyllaDB 
+ */ 

+// The purpose of the hacks here is to workaround C++ exception scalability problem 
+// with gcc and glibc. For the best result gcc-7 is required. 
+// 
+// To summarize all the locks we have now and their purpose: 
+// 1. There is a lock in _Unwind_Find_FDE (libgcc) that protects 
+//    list of FDEs registered with __register_frame* functions. 
+//    The catch is that dynamically linked binary do not do that, 
+//    so all that it protects is checking that a certain list is empty. 
+//    This lock no longer relevant in gcc-7 since there is a path there 
+//    that checks that list is empty outside of the lock and it will be 
+//    always true for us. 
+// 2. The lock in dl_iterate_phdr (glibc) that protects loaded object 
+//    list against runtime object loading/unloading. 
+// 
+// To get rid of the first lock using gcc-7 is required. 
+// 
+// To get rid of the second one we can use the fact that we do not 
+// load/unload objects dynamically (at least for now). To do that we 
+// can mirror all elf header information in seastar and provide our 
+// own dl_iterate_phdr symbol which uses this mirror without locking. 
+// 
+// Unfortunately there is another gotcha in this approach: dl_iterate_phdr 
+// supplied by glibc never calls more then one callback simultaneously as an 
+// unintended consequences of the lock there, but unfortunately libgcc relies 
+// on that to maintain small cache of translations. The access to the cache is 
+// not protected by any lock since up until now only one callback could have 
+// run at a time. But luckily libgcc cannot use the cache if older version 
+// of dl_phdr_info is provided to the callback because the older version 
+// did not have an indication that loaded object list may have changed, 
+// so libgcc does not know when cache should be invalidated and disables it 
+// entirely. By calling the callback with old version of dl_phdr_info from 
+// our dl_iterate_phdr we can effectively make libgcc callback thread safe. 

+#ifndef NO_EXCEPTION_HACK 
+#include <link.h> 
+#include <dlfcn.h> 
+#include <assert.h> 
+#include <vector> 
+#include <cstddef> 
+#include "exception_hacks.hh" 

+namespace seastar { 
+using dl_iterate_fn = int (*) (int (*callback) (struct dl_phdr_info *info, size_t size, void *data), void *data); 

+static dl_iterate_fn dl_iterate_phdr_org() { 
+    static dl_iterate_fn org = [] { 
+        auto org = (dl_iterate_fn)dlsym (RTLD_NEXT, "dl_iterate_phdr"); 
+        assert(org); 
+        return org; 
+    }(); 
+    return org; 
+} 

+static std::vector<dl_phdr_info> phdrs_cache; 

+void init_phdr_cache() { 
+    // Fill out elf header cache for access without locking. 
+    // This assumes no dynamic object loading/unloading after this point 
+    dl_iterate_phdr_org()([] (struct dl_phdr_info *info, size_t size, void *data) { 
+        phdrs_cache.push_back(*info); 
+        return 0; 
+    }, nullptr); 
+} 
+} 

+extern "C" 
+[[gnu::visibility("default")]] 
+[[gnu::externally_visible]] 
+int dl_iterate_phdr(int (*callback) (struct dl_phdr_info *info, size_t size, void *data), void *data) { 
+    if (!seastar::phdrs_cache.size()) { 
+        // Cache is not yet populated, pass through to original function 
+        return seastar::dl_iterate_phdr_org()(callback, data); 
+    } 
+    int r = 0; 
+    for (auto h : seastar::phdrs_cache) { 
+        // Pass dl_phdr_info size that does not include dlpi_adds and dlpi_subs. 
+        // This forces libgcc to disable caching which is not thread safe and 
+        // requires dl_iterate_phdr to serialize calls to callback. Since we do 
+        // not serialize here we have to disable caching. 
+        r = callback(&h, offsetof(dl_phdr_info, dlpi_adds), data); 
+        if (r) { 
+            break; 
+        } 
+    } 
+    return r; 
+} 
+#endif 
diff --git a/core/exception_hacks.hh b/core/exception_hacks.hh 
new file mode 100644 
index 0000000..f5ff51f 
--- /dev/null 
+++ b/core/exception_hacks.hh 
@@ -0,0 +1,24 @@ 
+/* 
+ * This file is open source software, licensed to you under the terms 
+ * of the Apache License, Version 2.0 (the "License").  See the NOTICE file 
+ * distributed with this work for additional information regarding copyright 
+ * ownership.  You may not use this file except in compliance with the License. 
+ * 
+ * You may obtain a copy of the License at 
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0 
+ * 
+ * Unless required by applicable law or agreed to in writing, 
+ * software distributed under the License is distributed on an 
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 
+ * KIND, either express or implied.  See the License for the 
+ * specific language governing permissions and limitations 
+ * under the License. 
+ */ 
+/* 
+ * Copyright (C) 2017 ScyllaDB 
+ */ 

+namespace seastar { 
+void init_phdr_cache(); 
+} 
diff --git a/core/reactor.cc b/core/reactor.cc 
index 2beef59..b4b4e8d 100644 
--- a/core/reactor.cc 
+++ b/core/reactor.cc 
@@ -93,6 +93,7 @@ 
 #include "util/defer.hh" 
 #include "core/metrics.hh" 
 #include "execution_stage.hh" 
+#include "exception_hacks.hh" 
  
 namespace seastar { 
  
@@ -3369,6 +3370,9 @@ smp::get_options_description() 
         ("max-io-requests", bpo::value<unsigned>(), "Maximum amount of concurrent requests to be sent to the disk. Defaults to 128 times the number of processors") 
 #endif 
         ("mbind", bpo::value<bool>()->default_value(true), "enable mbind") 
+#ifndef NO_EXCEPTION_HACK 
+        ("enable-glibc-exception-scaling-workaround", bpo::value<bool>()->default_value(true), "enable workaround for glibc/gcc c++ exception scalablity problem") 
+#endif 
         ; 
     return opts; 
 } 
@@ -3514,6 +3518,12 @@ static void sigabrt_action() noexcept { 
  
 void smp::configure(boost::program_options::variables_map configuration) 
 { 
+#ifndef NO_EXCEPTION_HACK 
+    if (configuration["enable-glibc-exception-scaling-workaround"].as<bool>()) { 
+        init_phdr_cache(); 
+    } 
+#endif 

     // Mask most, to prevent threads (esp. dpdk helper threads) 
     // from servicing a signal.  Individual reactors will unmask signals 
     // as they become prepared to handle them. 
-- 
                        Gleb.

原文地址:https://www.cnblogs.com/diegodu/p/9054745.html

时间: 2024-10-04 09:42:57

C++ 的 runtime exception是没有扩展性的的相关文章

优秀开源项目之三:高性能、高并发、高扩展性和可读性的网络服务器架构State Threads

译文在后面. State Threads for Internet Applications Introduction State Threads is an application library which provides a foundation for writing fast and highly scalable Internet Applications on UNIX-like platforms. It combines the simplicity of the multi

Atitit.软件架构高扩展性and兼容性原理与概论实践attilax总结

1. 什么是可扩展的应用程序?1 2. 松耦合(ioc)2 3. 接口的思考 2 4. 单一用途&模块化,小粒度化2 5. 组合(Composition),而不是继承(inheritance) 2 6. Ocp原则开闭原则2 7. Plugin系统2 8. 流程扩展工作流系统,流程自定义2 9. Ui扩展 html53 10. 数据独立性3 11. 脚本与hotdeploy3 12. 表处理扩展if else (数据与数据处理相互分离)3 13. 系统被扩展的几种形式(方法级别,模块级别)3 1

监控开发之如何开发简单高性能扩展性强的监控系统

关于如何快速开发一套属于自己的运维监控系统. 记得刚入行的时候,对于监控方面,用的是nagios和cacti,现在大多数中小公司好多都开始搞zabbix了,熟悉zabbix的人,知道他的性能的瓶颈其实主要还是在数据库上,尤其是zabbx_server 针对数据库一些不高效逻辑的查询和写入引起的. 同事针对zabbix开发也搞了半年了,和他交流了下,有很多的想法. zabbix 有些查询完全可以从缓存里面取值,比如redis.memcached,不用非要从数据库里面来搞个消耗性能的大查询,有些监控

《.NET 设计规范》第 6 章:扩展性设计

第 6 章:扩展性设计 6.1 扩展机制 考虑用不包含任何虚成员或受保护的成员的非密封类来为框架提供扩展性.这种方法所提供的扩展性广受用户欢迎,而且它的开销也不高. 考虑将受保护的成员用于高级的定制方案. 要在对安全性.文档及兼容性进行分析时,把非密封类中受保护的成员当做公有成员那样来对待. 考虑使用回调函数来允许用户向框架提供自定义的代码供框架执行. 考虑使用事件来允许用户对框架的行为进行定制,这样就不需要用户对面向对象设计有深入的了解. 要优先使用事件,而不是简单的回调函数,其原因在于广大开

数据库扩展性设计:使用二进制解决一条记录关联多个状态的问题

程序开发中,经常遇到一条记录有多个状态位,比如一条商品,他属于热门,新品,特卖.我们的数据库如何设计呢? 一般有几种方法 (1)建立关联表 关联表字段:关系Id,商品Id,属性Id 查询:使用关联表的方式,查询某属性的商品. 程序:写入时,写商品表和关联表: (2)将多个属性存在一个字段中,用|分割 状态存储在一个字段中,比如某条商品属于热卖,新品和特卖,则字段存储的值:01|02|03 SQL查询:使用like 程序处理:(1)取值需要先将01,02,03分割,再处理.(2)写入需要先将01,

深入NGINX:我们如何设计它的性能和扩展性

英文原文:Inside NGINX: How We Designed for Performance & Scale 为了更好地理解设计,你需要了解NGINX是如何工作的.NGINX之所以能在性能上如此优越,是由于其背后的设计.许多web服务器和应用服务器使用简单的线程的(threaded).或基于流程的(process-based)架构, NGINX则以一种复杂的事件驱动(event-driven)的架构脱颖而出,这种架构能支持现代硬件上成千上万的并发连接. Inside NGINX info

服务的扩展性

在编写一个应用时,我们常常考虑的是该应用应该如何实现特定的业务逻辑.但是在逐渐发展出越来越多的用户后,这些应用常常会暴露出一系列问题,如不容易增大容量,容错性差等等.这常常会导致这些应用在市场的拓展过程中无法快速地响应用户的需求,并最终失去商业上的先机. 通常情况下,我们将应用所具有的用来避免这一系列问题的特征称为非功能性需求.相信您已经能够从字面意义上理解这个名词了:功能性需求用来提供对业务逻辑的支持,而非功能性需求则是一系列和业务逻辑无关,却可能影响到产品后续发展的一系列需求.这些需求常常包

构建高扩展性网站

如何构建高扩展性网站?     阅读目录 主要内容 化简方程 分布工作 横向扩展设计 使用正确的工具 不要做重复的工作 积极利用缓存 从错误中吸取教训 数据库原则 容错设计与故障控制 避免或分发状态 异步通信和消息总线 其他原则 参考 本篇通过阅读<高扩展性网站的50条原则>,总结出以下内容. 一方面博主没有实际的架构经验,另一方面知识面也不够宽阔,所以只能系统的总结书中的要点,并根据自己的理解做些归纳. 主要内容 本书从多个方面围绕高扩展性提出了50条建议,一个高扩展性的网站会随着业务的发展

[Android_Exception]Checked 和 Runtime Exception区别

Java里有个很重要的特色是Exception ,也就是说允许程序产生例外状况.而在学Java 的时候,我们也只知道Exception 的写法,却未必真能了解不同种类的Exception 的区别. 首先,您应该知道的是Java 提供了两种Exception 的模式,一种是执行的时候所产生的Exception (Runtime Exception),另外一种则是受控制的Exception (Checked Exception). 所有的Checked Exception 均从java.lang.E