惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

G
Google Developers Blog
阮一峰的网络日志
阮一峰的网络日志
博客园 - 聂微东
F
Fortinet All Blogs
H
Help Net Security
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
D
DataBreaches.Net
MyScale Blog
MyScale Blog
B
Blog
I
InfoQ
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
GbyAI
GbyAI
Google DeepMind News
Google DeepMind News
IT之家
IT之家
The GitHub Blog
The GitHub Blog
有赞技术团队
有赞技术团队
博客园_首页
L
LangChain Blog
V
V2EX
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
T
The Blog of Author Tim Ferriss
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
Microsoft Azure Blog
Microsoft Azure Blog
博客园 - Franky

C

C 语言快速通关教程 2026(共 96 集) - V2EX 各位大佬, C 語言該怎麼練習啊 分享一个代码优化导致的死循环 人再笨还能写不出内存安全的 C? 想念 C C11 的 _Generic,现实当中用得多不多?(尤其是公司项目) 坑爹的 GBK:大家都应该去用 UTF-8 分享一个用 AI 学习 C 语言的例子 一个简单的 C 程序,但是不明白区别在哪里 我这段 C 代码可以在编译时候输出结构体的大小,你们还有什么好点子, show me the code! 这段话是否正确?「取余这个运算,只有 Python 是对的。当初 C 这个老师教错了,那么一大票学生也就只敢跟着老师错。只有 Python 敢于站出来坚持正确答案。」 C 中可变参数如何直接传递到 printf() C 的内存打印实现 函数能否实现透传不定长度参数,最终由 printf 打印 请大佬帮忙修改一份 elf 文件里的数值 Linux 上 C 的程序遇到个异常退出问题,局部变量大小有限制?? C 语言新手求助:如何在 vscode 中使用第三方库? 将资源嵌入到可执行文件中并保持目录结构 一个简单实用的 C 工程示例, 附简洁的 Makefile 关于 C 语言的相关问题 轮子更新: C/C++ 跨平台小工具库 为什么下列程序进行的是无符号乘法? 用 riscv64- Linux -gnu-gcc 编译的 c 文件为啥能在 x8664 下运行? char *s = "0123"和 char s[] = "0123"的区别 有人能完整地解释一下 int (*daytab) [13]和 int *daytab[13]吗 在 c 语言中, int a;是 declaration 还是 definition 一个简单(奇怪)的 C 语言问题 c 语言中打印指针的值打印的是 OS 分配的虚拟地址的值吗?要怎么知道 OS 给这个 c 程序进程分配的虚拟地址的大小呢? gcc 是怎么找到 system 函数的定义(实现)的? 用 C 实现轻量级表达式完成策略定制化和模板内容生成
C 语言函数资源开销可观测性
monkeyNik · 2024-01-27 · via C

之前的文章提及过开源 C 语言库Melon函数模板。使用函数模板来扩展函数功能。

今天,我们介绍 Melon 中的span组件,使用它来轻松监控函数的调用耗时情况。

概述

Melon 中的资源开销( span )组件是用来测量 C 语言函数开销的,这个模块需要配合函数模板模块一同使用,因此也需要定义MLN_FUNC_FLAG才会使得函数模板功能启用,进而实现函数开销的跟踪。

目前支持的开销如下:

  • 时间开销

头文件

#include "mln_span.h"

模块名

span

在 Melon 中支持模块选择性编译,因此可以选择指定的模块进行编译,脚本将自行计算该模块所依赖的 Melon 中的其他模块并一同进行编译。

示例

下面我们一起看一个多线程的示例,用来展示mln_span接口的使用以及在多线程环境下的效果。

//a.c

#include <pthread.h>
#include "mln_span.h"
#include "mln_func.h"

MLN_FUNC(int, abc, (int a, int b), (a, b), {
    return a + b;
})

MLN_FUNC(static int, bcd, (int a, int b), (a, b), {
    return abc(a, b) + abc(a, b);
})

MLN_FUNC(static int, cde, (int a, int b), (a, b), {
    return bcd(a, b) + bcd(a, b);
})

void *pentry(void *args)
{
    int i;
    mln_span_start();
    for (i = 0; i < 10; ++i) {
        cde(i, i + 1);
    }

    mln_span_stop();
    mln_span_dump();
    mln_span_release();
    return NULL;
}

int main(void)
{
    int i;
    pthread_t pth;


    pthread_create(&pth, NULL, pentry, NULL);

    for (i = 0; i < 10; ++i) {
        bcd(i, i + 1);
    }

    pthread_join(pth, NULL);

    return 0;
}

前面我们说过,span 组件需要配合函数模板组件一同使用。这里我们使用函数模板组件定义了三个函数abc, bcd, cde

然后我们在main函数中启动一个线程,并在线程入口函数内,调用mln_span_start开启资源消耗跟踪。然后调用cde函数十次。而在main函数中,在创建线程后,循环调用bcd函数十次,最后等待线程退出,程序结束。

我们对这段程序进行编译:

cc -o a a.c -I /usr/local/melon/include/ -L /usr/local/melon/lib/ -lmelon -DMLN_FUNC_FLAG -lpthread

注意,这里-DMLN_FUNC_FLAG是用来启用函数模板模块的功能。如果不定义这个宏,那么使用MLN_FUNC定义的函数就是普通 C 语言函数,不会启用任何跟踪能力。

编译好后运行程序,可以看到类似如下的输出:

| pentry at a.c:20 takes 92 (us)
  | cde at a.c:13 takes 4 (us)
    | bcd at a.c:9 takes 1 (us)
      | abc at a.c:5 takes 0 (us)
      | abc at a.c:5 takes 0 (us)
    | bcd at a.c:9 takes 1 (us)
      | abc at a.c:5 takes 0 (us)
      | abc at a.c:5 takes 0 (us)
  | cde at a.c:13 takes 5 (us)
    | bcd at a.c:9 takes 0 (us)
      | abc at a.c:5 takes 0 (us)
      | abc at a.c:5 takes 0 (us)
    | bcd at a.c:9 takes 2 (us)
      | abc at a.c:5 takes 0 (us)
      | abc at a.c:5 takes 0 (us)
  | cde at a.c:13 takes 24 (us)
    | bcd at a.c:9 takes 1 (us)
      | abc at a.c:5 takes 0 (us)
      | abc at a.c:5 takes 0 (us)
    | bcd at a.c:9 takes 21 (us)
      | abc at a.c:5 takes 0 (us)
      | abc at a.c:5 takes 0 (us)
  | cde at a.c:13 takes 5 (us)
    | bcd at a.c:9 takes 1 (us)
      | abc at a.c:5 takes 0 (us)
      | abc at a.c:5 takes 0 (us)
    | bcd at a.c:9 takes 1 (us)
      | abc at a.c:5 takes 0 (us)
      | abc at a.c:5 takes 0 (us)
  | cde at a.c:13 takes 3 (us)
    | bcd at a.c:9 takes 2 (us)
      | abc at a.c:5 takes 0 (us)
      | abc at a.c:5 takes 0 (us)
    | bcd at a.c:9 takes 1 (us)
      | abc at a.c:5 takes 0 (us)
      | abc at a.c:5 takes 0 (us)
  | cde at a.c:13 takes 30 (us)
    | bcd at a.c:9 takes 24 (us)
      | abc at a.c:5 takes 0 (us)
      | abc at a.c:5 takes 1 (us)
    | bcd at a.c:9 takes 6 (us)
      | abc at a.c:5 takes 0 (us)
      | abc at a.c:5 takes 0 (us)
  | cde at a.c:13 takes 3 (us)
    | bcd at a.c:9 takes 2 (us)
      | abc at a.c:5 takes 0 (us)
      | abc at a.c:5 takes 0 (us)
    | bcd at a.c:9 takes 1 (us)
      | abc at a.c:5 takes 0 (us)
      | abc at a.c:5 takes 0 (us)
  | cde at a.c:13 takes 3 (us)
    | bcd at a.c:9 takes 2 (us)
      | abc at a.c:5 takes 0 (us)
      | abc at a.c:5 takes 1 (us)
    | bcd at a.c:9 takes 1 (us)
      | abc at a.c:5 takes 0 (us)
      | abc at a.c:5 takes 0 (us)
  | cde at a.c:13 takes 7 (us)
    | bcd at a.c:9 takes 1 (us)
      | abc at a.c:5 takes 0 (us)
      | abc at a.c:5 takes 0 (us)
    | bcd at a.c:9 takes 2 (us)
      | abc at a.c:5 takes 0 (us)
      | abc at a.c:5 takes 1 (us)
  | cde at a.c:13 takes 3 (us)
    | bcd at a.c:9 takes 2 (us)
      | abc at a.c:5 takes 1 (us)
      | abc at a.c:5 takes 0 (us)
    | bcd at a.c:9 takes 0 (us)
      | abc at a.c:5 takes 0 (us)
      | abc at a.c:5 takes 0 (us)

最后

感兴趣的小伙伴欢迎访问Melon 的 Github进行试用。Melon 是一个跨平台的 C 语言库,内含多种数据结构、算法和常用组件。Melon 并不是一个纯粹的数据结构和算法库,而是致力于提供开发中常用的组件,如:内存池、线程池、多进程框架、可观测性等。Melon 提供中英文文档,内含各模块接口说明和示例代码,便于开发者快速上手。

感谢阅读!