C/C++ 函数调用以及Linux中系统调用 开销介绍:介绍C/C函数调用以及Linux中系统调用的开销情况

简介: C/C++ 函数调用以及Linux中系统调用 开销介绍:介绍C/C函数调用以及Linux中系统调用的开销情况

函数调用开销的原因

1.参数入栈,将函数参数入栈,这是现在函数调用的标准方式。所以参数越多,开销越大

2.将控制权转移至函数中.

3.建立新的栈帧,也就是当前函数使用的“一片”栈空间,使用ebp的值来标识新的栈帧,因此要将原栈帧首地址保存下来,方便回到原来的即调用者的栈帧。

4.恢复原栈帧,然后将控制权转移至调用者.


不同函数的开销

  • 普通函数

C/C++ 普通函数的开销包括函数调用、参数传递、局部变量的创建和销毁等。
其中函数调用是最主要的开销,因为每次函数调用都需要保存当前函数的返回地址和上下文信息,然后跳转到被调用函数的代码段执行,最后再返回到调用函数的代码段继续执行。
这个过程会涉及到栈的操作,所以栈的使用也是C/C++普通函数开销的一部分。

  • 模板函数

模板函数需要在编译时进行实例化,会增加内存消耗,调用时开销与普通函数一致

  • 内联 、宏函数

宏函数和内联函数在某些方面确实有相似之处,它们都可以避免函数调用的开销,直接将函数的代码插入到调用处。但是,它们之间还是存在一些区别。
首先,宏函数是在预处理阶段展开的,展开结果是一个代码块,没有函数的调用栈,没有参数的传递,没有返回值的处理,因此宏函数在展开时可能会出现代码膨胀、重复计算等问题,进而影响其效率。
其次,宏函数在展开时是直接替换代码的,没有类型检查和作用域限制,可能会导致一些潜在的问题。例如,宏函数中的变量可能会与调用它的代码块中的变量重名,从而引发错误。
相比之下,内联函数在编译时展开,展开结果是一个函数体,可以进行类型检查、作用域限制等,避免了宏函数可能存在的问题。此外,内联函数还可以使用函数参数和返回值,避免了宏函数可能存在的重复计算等问题。
因此,虽然宏函数和内联函数在某些方面有相似之处,但是在实现方式和效率上还是存在一定的差异。在具体的应用场景中,需要根据实际情况进行选择和权衡。

  • 虚函数

C++虚函数运行时调用的额外开销产生于虚函数表的查找和函数指针的间接调用。

  • 内建函数

内建函数(built-in function)是编译器内置的函数,它们通常在编译时被处理,而不是在运行时调用,因此,使用内建函数通常不会引入函数调用的开销。
不过,内建函数的优化和性能表现与编译器和编译器的优化设置有关。在某些情况下,编译器可能会选择将内建函数作为普通函数来处理,这样就会引入函数调用的开销。此外,某些内建函数可能会导致代码大小增加,从而降低缓存性能。


内建函数的优化程度可以很高,是因为它是由编译器特殊处理的函数,通常采用特殊的汇编指令或者是库函数来实现,可以在一定程度上消除函数调用的开销。
在某些情况下,内建函数的优化效果可能高于内联函数,例如编译器可以使用特殊的指令或者硬件加速来实现内建函数,从而达到很高的优化效果。

因此不同函数的开销对比:内联 、宏函数 、内建函数< 普通函数、模板函数 < 虚函数


系统调用开销

当一个程序需要访问操作系统提供的服务时,它需要通过系统调用来请求操作系统执行相应的操作。

  • Linux 系统调用的流程如下:
  1. 应用程序通过系统调用库函数(如 glibc)中的接口向内核发起系统调用请求。
  2. 系统调用库函数将系统调用号和参数传递给内核。
  3. 内核根据系统调用号找到相应的系统调用处理函数,并将参数从用户空间拷贝到内核空间。
  4. 内核执行系统调用处理函数,完成相应的操作,并将结果返回给用户空间。
  5. 系统调用库函数将结果从内核空间拷贝到用户空间,并返回给应用程序。
  • Linux 系统调用的开销通常比普通函数的开销要高几倍,因为系统调用需要从用户态切换到内核态,这个过程需要进行一些额外的操作,比如保存和恢复 CPU 寄存器、切换内存地址空间等。
  • 系统调用虽然使用了“快速系统调用”指令,但耗时仍大约在200ns+,多的可能到十几us
  • 每个系统调用内核要进行许多工作,大约需要执行1000条左右的CPU指令

Shell 之 time 命令(检测命令执行时间)

“time a simple command or give resource usage”,
即测量命令的执行时间,或者给出系统资源的使用情况。

#如果你想查看一条命令(比如 ls)到底执行了多长时间,我们可以这样做:
[roc@linux ~]$ time ls
program  public_html  repo  rocscm
real    0m0.002s
user    0m0.002s
sys     0m0.000s

(1) real:从进程 ls 开始执行到完成所耗费的 CPU 总时间。该时间包括 ls 进程执行时实际使用的 CPU 时间,ls 进程耗费在阻塞上的时间(如等待完成 I/O 操作)和其他进程所耗费的时间(Linux 是多进程系统,ls 在执行过程中,可能会有别的进程抢占 CPU)。

(2) user:进程 ls 执行用户态代码所耗费的 CPU 时间。该时间仅指 ls 进程执行时实际使用的 CPU 时间,而不包括其他进程所使用的时间和本进程阻塞的时间。

(3) sys:进程 ls 在内核态运行所耗费的 CPU 时间,即执行内核系统调用所耗费的 CPU 时间。

说明:单核处理器:real_time≥ (user_time+sys_time) ,多核则不一定。

目录
相关文章
|
2月前
|
网络协议 安全 Linux
Linux C/C++之IO多路复用(select)
这篇文章主要介绍了TCP的三次握手和四次挥手过程,TCP与UDP的区别,以及如何使用select函数实现IO多路复用,包括服务器监听多个客户端连接和简单聊天室场景的应用示例。
98 0
|
2月前
|
存储 Linux C语言
Linux C/C++之IO多路复用(aio)
这篇文章介绍了Linux中IO多路复用技术epoll和异步IO技术aio的区别、执行过程、编程模型以及具体的编程实现方式。
106 1
Linux C/C++之IO多路复用(aio)
|
2月前
|
资源调度 Linux 调度
Linux c/c++之进程基础
这篇文章主要介绍了Linux下C/C++进程的基本概念、组成、模式、运行和状态,以及如何使用系统调用创建和管理进程。
48 0
|
2月前
|
网络协议 Linux 调度
深入探索Linux操作系统的心脏:内核与系统调用####
本文旨在揭开Linux操作系统中最为核心的部分——内核与系统调用的神秘面纱,通过生动形象的语言和比喻,让读者仿佛踏上了一段奇妙的旅程,从宏观到微观,逐步深入了解这两个关键组件如何协同工作,支撑起整个操作系统的运行。不同于传统的技术解析,本文将以故事化的方式,带领读者领略Linux内核的精妙设计与系统调用的魅力所在,即便是对技术细节不甚了解的读者也能轻松享受这次知识之旅。 ####
|
2月前
|
缓存 算法 安全
深入理解Linux操作系统的心脏:内核与系统调用####
【10月更文挑战第20天】 本文将带你探索Linux操作系统的核心——其强大的内核和高效的系统调用机制。通过深入浅出的解释,我们将揭示这些技术是如何协同工作以支撑起整个系统的运行,同时也会触及一些常见的误解和背后的哲学思想。无论你是开发者、系统管理员还是普通用户,了解这些基础知识都将有助于你更好地利用Linux的强大功能。 ####
49 1
|
2月前
|
Ubuntu Linux 编译器
Linux/Ubuntu下使用VS Code配置C/C++项目环境调用OpenCV
通过以上步骤,您已经成功在Ubuntu系统下的VS Code中配置了C/C++项目环境,并能够调用OpenCV库进行开发。请确保每一步都按照您的系统实际情况进行适当调整。
519 3
|
2月前
|
资源调度 Linux 调度
Linux C/C++之线程基础
这篇文章详细介绍了Linux下C/C++线程的基本概念、创建和管理线程的方法,以及线程同步的各种机制,并通过实例代码展示了线程同步技术的应用。
34 0
Linux C/C++之线程基础
|
2月前
|
Linux C++
Linux C/C++之IO多路复用(poll,epoll)
这篇文章详细介绍了Linux下C/C++编程中IO多路复用的两种机制:poll和epoll,包括它们的比较、编程模型、函数原型以及如何使用这些机制实现服务器端和客户端之间的多个连接。
36 0
Linux C/C++之IO多路复用(poll,epoll)
|
2月前
|
网络协议 Linux 网络性能优化
Linux C/C++之TCP / UDP通信
这篇文章详细介绍了Linux下C/C++语言实现TCP和UDP通信的方法,包括网络基础、通信模型、编程示例以及TCP和UDP的优缺点比较。
50 0
Linux C/C++之TCP / UDP通信
|
2月前
|
消息中间件 Linux API
Linux c/c++之IPC进程间通信
这篇文章详细介绍了Linux下C/C++进程间通信(IPC)的三种主要技术:共享内存、消息队列和信号量,包括它们的编程模型、API函数原型、优势与缺点,并通过示例代码展示了它们的创建、使用和管理方法。
41 0
Linux c/c++之IPC进程间通信