gpt4 book ai didi

c - 频繁调用 isatty() 对性能的影响

转载 作者:可可西里 更新时间:2023-11-01 11:47:21 28 4
gpt4 key购买 nike

我目前正在编写一个在终端上生成彩色输出的 linux 程序。由于程序 stdout 可以重定向到一个文本文件,或者通常重定向到一个非终端接收器,并且这些方法应该尽可能通用,我需要调用 isatty(int fd) 来确定是否我应该发送 ASCII 颜色转义码。

由于我不确定在每次调用 printf() 之前调用 isatty() 对性能的影响,我实现了一个缓冲区来缓冲前 16 个 fds 的 isatty() 结果:

#include <stdbool.h>
#include <stdio.h>
#include <unistd.h>

#define TERM_NORMAL "\x1b\x5bm"
#define TERM_BRIGHT "\x1b\x5b\x31m"
#define TERM_BOLD "\x1b\x5b\x31m"
#define TERM_BLINK "\x1b\x5b\x35m"
#define TERM_RED "\x1b\x5b\x33\x31m"

//to prevent unnecessary isatty() calls, provide this lookup table
//for the first 16 fds
//0 means that it has not been checked yet
//1 means the fd is not a tty
//2 means the fd is a tty
char isattybuf[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
inline bool isattybuffered(int fd) {
if(fd >= 0 && fd < sizeof(isattybuf)) {
if(!isattybuf[fd])
isattybuf[fd] = isatty(fd) + 1;
return isattybuf[16] - 1;
} else {
return isatty(fd);
}
}

#define colprintf(col, format, ...) \
if(isattybuffered(fileno(stdout))) \
printf(col format TERM_NORMAL, ## __VA_ARGS__); \
else \
printf(format, ## __VA_ARGS__);

#define colfprintf(col, f, format, ...) \
if(isattybuffered(fileno(f))) \
fprintf(f, col format TERM_NORMAL, ## __VA_ARGS__); \
else \
fprintf(f, format, ## __VA_ARGS__);

//for testing
int main() {
colprintf(TERM_BRIGHT TERM_BLINK, "test1\n");
colprintf(TERM_RED TERM_BRIGHT, "test2\n");
}

但这也有一些缺点:

  • 因为它将成为库头文件的一部分,每个包含头文件的c文件都会有一个缓冲区数组
  • 相应地,isatty()可能会被调用n次,其中n是使用该代码的c文件的数量
  • 如果打开一个文件,调用isatty(),然后关闭文件,然后用相同的fd打开一个tty,缓冲区信息可能是错误的

消除前两个问题的替代解决方案是使用 extern 关键字将缓冲区变量放入单独的 c 文件中,但是即使代码被编译为共享代码,这种方法是否有效?库对象并同时被多个程序使用?

遗憾的是,ISATTY(3) 联机帮助页未提供有关该方法的性能影响的任何提示。

更新我刚刚运行了一些基准测试,似乎 isatty() 每次调用时都会执行一个 ioctl 系统调用,在我的 x86_64 ARCH 系统上花费大约 700ns 或 500 个时钟周期。 write() 系统调用(由 printf 调用)花费的时间大致相同,因此如果 isatty() 没有缓冲,我损失的时间将少于 1µs 或大约一半每个输出操作的性能(与终端滚动所需的时间相比,这似乎可以忽略不计,但在将输出重定向到大型文本文件时可能变得很重要)。特别是当连续调用 printf() 时,write 系统调用仅每 4096 字节调用一次,因此代码可能会花费大部分时间等待 isatty() 的结果,所以缓冲似乎毕竟有意义。

所以我还是想听听大家对我缓冲的尝试的看法,以及我提到的问题。

最佳答案

快速基准测试表明,至少在 Darwin 上,isatty 没有被缓存,并且它每次都执行一个 ioctl。在 2.8GHz i7 (mac) 上,对文件描述符 0 - 99 进行 10 000 次检查仅用了 0.4 秒。我会说调用 printf 的成本远远高于调用 isatty。

无论如何,我会使用函数指针。一开始我会调用一个 isatty 并将指针映射到函数(不带 ascii 的 printf/带 ascii 的 printf),然后使用该指针。

马丁

关于c - 频繁调用 isatty() 对性能的影响,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10268467/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com