C/C++中gettext国际化系统的性能开销

Rob*_*y75 6 c c++ performance overhead gettext

我刚刚完成了http://www.gnu.org/software/gettext/manual/gettext.html的文档,并且根本没有关于性能开销的讨论.在互联网上,我发现只有其他语言(PHP和Java)的性能讨论,但没有C/C++的性能讨论.

因此我的问题:

  1. 启动使用gettext的程序时的性能开销是什么(加载共享库?如何将翻译加载到内存中?是在启动时还是按需加载所有翻译?)

  2. 在程序的正常运行期间,性能损失是多少?(即需要翻译时)程序内存占用量增加多少以及内存如何组织?当程序空闲时,程序的某些部分是否有更高的危险/可能性?(如果翻译存储在内存的一个非常不同的部分而不是程序的其余部分,那么根据我的理解,页面错误的可能性高于程序的非国际化版本)

  3. 在"C"-locale下运行的程序是否也会遭受这些性能损失?

非常感谢.

Mat*_*son 3

鉴于此方法的替代方案是拥有大量构建,每个构建都包含如下内容:

\n\n
int main()\n{\n    printf(\n#ifdef SWEDISH\n           "Hej v\xc3\xa4rlden\\n"\n#elsif ENGLISH\n           "Hello, World\\n"\n#elsif PORTUGUESE\n           "Ol\xc3\xa1, Mundo\\n"\n#else  \n   #error Language not specified. \n#endif\n    );\n    return 0l;\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

相反,我们得到:

\n\n
int main()\n{\n   printf(gettext("Hello, World\\n")); \n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

这很容易阅读和理解。

\n\n

我不知道 gettext 实现的确切结构,但我希望加载后它是一个哈希表。可能是二叉树,但哈希表似乎更明智。

\n\n

至于确切的开销,很难给出一个数字 - 特别是,正如您所说,如果将某些内容交换到磁盘,并且磁盘已停止,则需要 3-4 秒才能使磁盘达到速度。那么你如何量化这一点呢?gettext是的,如果系统正忙于执行内存密集型操作,则所需的页面可能会被换出。

\n\n

如果文件非常大,加载消息文件应该只是一个很大的开销,但同样,如果磁盘不旋转,并且文件没有缓存,那么将会有几秒钟的开销。再次,如何量化。文件的大小显然与翻译(或母语)消息的实际大小成正比。

\n\n

关于第2点:

\n\n

据我所知,在 Linux 和 Windows 中,页面的交换都是基于“最近最少使用”(或其他一些使用统计),这与它们所在的位置无关。显然,翻译后的消息与实际代码位于不同的位置 - 源文件中没有 15 种不同翻译的列表,因此翻译是在运行时加载的,并且将位于与代码本身不同的位置。但是,其开销类似于以下之间的开销差异:

\n\n
static const char *msg = "Hello, World\\n";\n
Run Code Online (Sandbox Code Playgroud)\n\n

\n\n
static const char *msg = strdup("Hello, World\\n"); \n
Run Code Online (Sandbox Code Playgroud)\n\n

无论如何,考虑到文本字符串通常都保存在程序的二进制文件中,我认为它们与执行代码的“接近度”与堆中某处​​动态分配的内存没有显着不同。如果您足够频繁地调用该gettext函数,该内存将保持“当前”状态并且不会被换出。如果一段时间没有打电话gettext,它可能会被换掉。但这适用于“最近没有使用过存储在可执行文件中的字符串,因此它们被交换了”。

\n\n

3)我认为英语(或“未选择语言”)与任何其他语言变体的处理方式完全相同。

\n\n

我会进一步挖掘一下,首先需要早餐......

\n\n

非常不科学:

\n\n
#include <libintl.h>\n#include <cstdio>\n#include <cstring>\n\nstatic __inline__ unsigned long long rdtsc(void)\n{\n    unsigned hi, lo;\n    __asm__ __volatile__ ("rdtsc" : "=a"(lo), "=d"(hi));\n    return ( (unsigned long long)lo)|( ((unsigned long long)hi)<<32 );\n}\n\n\nint main()\n{\n    char str[10000] = {};\n    char *s = str;\n    unsigned long long time;\n\n    for(int i = 0; i < 10; i++)\n    {\n    time = rdtsc();\n    s += sprintf(s, "Hello, World %d", i);\n    time = rdtsc() - time;\n    printf("Time =%lld\\n", time);\n    }\n    printf("s = %s\\n", str);\n    s = str;\n\n    strcpy(s, "");\n    for(int i = 0; i < 10; i++)\n    {\n    time = rdtsc();\n    s += sprintf(s, gettext("Hello, World %d"), i);\n    time = rdtsc() - time;\n    printf("Time =%lld\\n", time);\n    }\n    printf("s = %s\\n", str);\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

给出以下结果:

\n\n
$ g++ -Wall -O2 intl.cpp\n$ ./a.out\nTime =138647\nTime =9528\nTime =6710\nTime =5537\nTime =5785\nTime =5427\nTime =5406\nTime =5453\nTime =5644\nTime =5431\ns = Hello, World 0Hello, World 1Hello, World 2Hello, World 3Hello, World 4Hello, World 5Hello, World 6Hello, World 7Hello, World 8Hello, World 9\nTime =85965\nTime =11929\nTime =10123\nTime =10226\nTime =10628\nTime =9613\nTime =9515\nTime =9336\nTime =9440\nTime =9095\ns = Hello, World 0Hello, World 1Hello, World 2Hello, World 3Hello, World 4Hello, World 5Hello, World 6Hello, World 7Hello, World 8Hello, World 9\n
Run Code Online (Sandbox Code Playgroud)\n\n

中的代码dcigettext.c混合使用了平面字符串数组中的二分搜索和将字符串哈希为 PJW 哈希的哈希函数(请参阅:http://www.cs.hmc.edu/~geoff/classes/hmc)。 cs070.200101/homework10/hashfuncs.html)。

\n\n

因此,一旦应用程序启动,开销似乎“刚刚明显”(计算时钟周期时),但并不巨大。

\n\n

在这两种情况下,运行第一次所需的确切时间sprintf有所不同,所以我不会说“使用 gettext”使 sprintf 在第一次调用时更快 - 只是这次运行“运气不好”(我还有其他一些代码的变体,并且它们在第一次调用时变化很大sprintf,而在以后的调用中变化较小)。可能是一些需要额外时间的设置(可能是缓存[printf很可能导致缓存被其他垃圾覆盖]、分支预测等)...

\n\n

现在,这显然不能回答您有关寻呼等问题。而且我也没有尝试对我的“Hello,World”消息进行瑞典语、葡萄牙语或德语翻译。我仍然相信它并不大,除非您确实每秒运行 100 个应用程序的实例化,并且该应用程序除了在进行一些简单计算后将消息打印到屏幕上之外没有做太多事情,当然,这可能很重要。

\n\n

找出它有多大差异的唯一真正方法是使用而#define _(x) x不是编译相同的应用程序#define _(x) gettext(x),然后看看您是否注意到任何差异。

\n\n

我仍然认为“调出”是转移注意力。如果机器处于高内存压力下,那么无论如何它都会运行缓慢(如果我编写一段在我的机器上分配 16GB [我的机器中有 16GB RAM] 的代码,几乎除了键盘本身之外的所有东西(可以使数字锁定 LED 闪烁)并且鼠标指针本身(可以在屏幕上移动鼠标指针)无响应)。

\n