From edc797cd3335ab7cb6620992f89fccb2b1c85c3f Mon Sep 17 00:00:00 2001 From: Water-Melon Date: Sat, 20 Jan 2024 01:38:30 +0800 Subject: [PATCH] chore(doc): update function template docs --- docs/book/cn/func.md | 202 +++++++++++++++++++++++++++++++++++++++ docs/book/cn/template.md | 2 +- docs/book/en/func.md | 202 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 405 insertions(+), 1 deletion(-) diff --git a/docs/book/cn/func.md b/docs/book/cn/func.md index 574ac2a9..7080e2d7 100644 --- a/docs/book/cn/func.md +++ b/docs/book/cn/func.md @@ -155,3 +155,205 @@ exit a.c bcd 10 ``` 正如`MLN_FUNC`中说明的,使用这个宏定义函数时,实际的函数会被添加`__`前缀,而原本给出的名字则是一个包装器。 + + + +### 函数耗时示例 + +首先创建两个文件`span.c`和`span.h`。 + +#### span.h + +```c +#include +#include "mln_array.h" + +typedef struct mln_span_s { + struct timeval begin; + struct timeval end; + const char *file; + const char *func; + int line; + mln_array_t subspans; + struct mln_span_s *parent; +} mln_span_t; + +extern int mln_span_start(void); +extern void mln_span_stop(void); +extern void mln_span_dump(void); +extern void mln_span_release(void); +``` + +#### span.c + +```c +#include +#include +#include "span.h" +#include "mln_stack.h" +#define MLN_FUNC_FLAG +#include "mln_func.h" + +static mln_stack_t *callstack = NULL; +static mln_span_t *root = NULL; + +static void mln_span_entry(const char *file, const char *func, int line); +static void mln_span_exit(const char *file, const char *func, int line); +static mln_span_t *mln_span_new(mln_span_t *parent, const char *file, const char *func, int line); +static void mln_span_free(mln_span_t *s); + +static mln_span_t *mln_span_new(mln_span_t *parent, const char *file, const char *func, int line) +{ + mln_span_t *s; + struct mln_array_attr attr; + + if (parent != NULL) { + s = (mln_span_t *)mln_array_push(&parent->subspans); + } else { + s = (mln_span_t *)malloc(sizeof(mln_span_t)); + } + if (s == NULL) return NULL; + + memset(&s->begin, 0, sizeof(struct timeval)); + memset(&s->end, 0, sizeof(struct timeval)); + s->file = file; + s->func = func; + s->line = line; + attr.pool = NULL; + attr.pool_alloc = NULL; + attr.pool_free = NULL; + attr.free = (array_free)mln_span_free; + attr.size = sizeof(mln_span_t); + attr.nalloc = 7; + if (mln_array_init(&s->subspans, &attr) < 0) { + if (parent == NULL) free(s); + return NULL; + } + s->parent = parent; + return s; +} + +static void mln_span_free(mln_span_t *s) +{ + if (s == NULL) return; + mln_array_destroy(&s->subspans); + if (s->parent == NULL) free(s); +} + +int mln_span_start(void) +{ + struct mln_stack_attr sattr; + + mln_func_entry_callback_set(mln_span_entry); + mln_func_exit_callback_set(mln_span_exit); + + sattr.free_handler = NULL; + sattr.copy_handler = NULL; + if ((callstack = mln_stack_init(&sattr)) == NULL) + return -1; + + return 0; +} + +void mln_span_stop(void) +{ + mln_func_entry_callback_set(NULL); + mln_func_exit_callback_set(NULL); + mln_stack_destroy(callstack); +} + +void mln_span_release(void) +{ + mln_span_free(root); +} + +static void mln_span_format_dump(mln_span_t *span, int blanks) +{ + int i; + mln_span_t *sub; + + for (i = 0; i < blanks; ++i) + printf(" "); + printf("| %s at %s:%d takes %lu (us)\n", \ + span->func, span->file, span->line, \ + (span->end.tv_sec * 1000000 + span->end.tv_usec) - (span->begin.tv_sec * 1000000 + span->begin.tv_usec)); + + for (i = 0; i < mln_array_nelts(&(span->subspans)); ++i) { + sub = ((mln_span_t *)mln_array_elts(&(span->subspans))) + i; + mln_span_format_dump(sub, blanks + 2); + } +} + +void mln_span_dump(void) +{ + if (root != NULL) + mln_span_format_dump(root, 0); +} + +static void mln_span_entry(const char *file, const char *func, int line) +{ + mln_span_t *span; + + if ((span = mln_span_new(mln_stack_top(callstack), file, func, line)) == NULL) { + fprintf(stderr, "new span failed\n"); + exit(1); + } + if (mln_stack_push(callstack, span) < 0) { + fprintf(stderr, "push span failed\n"); + exit(1); + } + if (root == NULL) root = span; + gettimeofday(&span->begin, NULL); +} + +static void mln_span_exit(const char *file, const char *func, int line) +{ + mln_span_t *span = mln_stack_pop(callstack); + if (span == NULL) { + fprintf(stderr, "call stack crashed\n"); + exit(1); + } + gettimeofday(&span->end, NULL); +} +``` + +接下来,创建一个开发者自定义的程序`a.c`: + +```c +#include "span.h" +#define MLN_FUNC_FLAG +#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); +}) + +int main(void) +{ + mln_span_start(); + bcd(1, 2); + mln_span_stop(); + mln_span_dump(); + mln_span_release(); + return 0; +} +``` + +编译程序: + +```bash +cc -o a a.c span.c -I /usr/local/melon/include/ -L /usr/local/melon/lib/ -lmelon -ggdb +``` + +执行一下,可以看到如下输出: + +``` +| bcd at a.c:13 takes 1 (us) + | abc at a.c:9 takes 0 (us) + | abc at a.c:9 takes 0 (us) +``` + diff --git a/docs/book/cn/template.md b/docs/book/cn/template.md index 20cee7c7..284fb855 100644 --- a/docs/book/cn/template.md +++ b/docs/book/cn/template.md @@ -4,4 +4,4 @@ 在Melon中,利用C语言宏实现了如下模板组件: -- 函数定义 +- 函数模板 diff --git a/docs/book/en/func.md b/docs/book/en/func.md index 798e28d6..89620bb3 100644 --- a/docs/book/en/func.md +++ b/docs/book/en/func.md @@ -153,3 +153,205 @@ exit a.c abc 5 exit a.c bcd 10 6 ``` + + + +### Function time-consuming example + +First create two files `span.c` and `span.h`. + +#### span.h + +```c +#include +#include "mln_array.h" + +typedef struct mln_span_s { + struct timeval begin; + struct timeval end; + const char *file; + const char *func; + int line; + mln_array_t subspans; + struct mln_span_s *parent; +} mln_span_t; + +extern int mln_span_start(void); +extern void mln_span_stop(void); +extern void mln_span_dump(void); +extern void mln_span_release(void); +``` + +#### span.c + +```c +#include +#include +#include "span.h" +#include "mln_stack.h" +#define MLN_FUNC_FLAG +#include "mln_func.h" + +static mln_stack_t *callstack = NULL; +static mln_span_t *root = NULL; + +static void mln_span_entry(const char *file, const char *func, int line); +static void mln_span_exit(const char *file, const char *func, int line); +static mln_span_t *mln_span_new(mln_span_t *parent, const char *file, const char *func, int line); +static void mln_span_free(mln_span_t *s); + +static mln_span_t *mln_span_new(mln_span_t *parent, const char *file, const char *func, int line) +{ + mln_span_t *s; + struct mln_array_attr attr; + + if (parent != NULL) { + s = (mln_span_t *)mln_array_push(&parent->subspans); + } else { + s = (mln_span_t *)malloc(sizeof(mln_span_t)); + } + if (s == NULL) return NULL; + + memset(&s->begin, 0, sizeof(struct timeval)); + memset(&s->end, 0, sizeof(struct timeval)); + s->file = file; + s->func = func; + s->line = line; + attr.pool = NULL; + attr.pool_alloc = NULL; + attr.pool_free = NULL; + attr.free = (array_free)mln_span_free; + attr.size = sizeof(mln_span_t); + attr.nalloc = 7; + if (mln_array_init(&s->subspans, &attr) < 0) { + if (parent == NULL) free(s); + return NULL; + } + s->parent = parent; + return s; +} + +static void mln_span_free(mln_span_t *s) +{ + if (s == NULL) return; + mln_array_destroy(&s->subspans); + if (s->parent == NULL) free(s); +} + +int mln_span_start(void) +{ + struct mln_stack_attr sattr; + + mln_func_entry_callback_set(mln_span_entry); + mln_func_exit_callback_set(mln_span_exit); + + sattr.free_handler = NULL; + sattr.copy_handler = NULL; + if ((callstack = mln_stack_init(&sattr)) == NULL) + return -1; + + return 0; +} + +void mln_span_stop(void) +{ + mln_func_entry_callback_set(NULL); + mln_func_exit_callback_set(NULL); + mln_stack_destroy(callstack); +} + +void mln_span_release(void) +{ + mln_span_free(root); +} + +static void mln_span_format_dump(mln_span_t *span, int blanks) +{ + int i; + mln_span_t *sub; + + for (i = 0; i < blanks; ++i) + printf(" "); + printf("| %s at %s:%d takes %lu (us)\n", \ + span->func, span->file, span->line, \ + (span->end.tv_sec * 1000000 + span->end.tv_usec) - (span->begin.tv_sec * 1000000 + span->begin.tv_usec)); + + for (i = 0; i < mln_array_nelts(&(span->subspans)); ++i) { + sub = ((mln_span_t *)mln_array_elts(&(span->subspans))) + i; + mln_span_format_dump(sub, blanks + 2); + } +} + +void mln_span_dump(void) +{ + if (root != NULL) + mln_span_format_dump(root, 0); +} + +static void mln_span_entry(const char *file, const char *func, int line) +{ + mln_span_t *span; + + if ((span = mln_span_new(mln_stack_top(callstack), file, func, line)) == NULL) { + fprintf(stderr, "new span failed\n"); + exit(1); + } + if (mln_stack_push(callstack, span) < 0) { + fprintf(stderr, "push span failed\n"); + exit(1); + } + if (root == NULL) root = span; + gettimeofday(&span->begin, NULL); +} + +static void mln_span_exit(const char *file, const char *func, int line) +{ + mln_span_t *span = mln_stack_pop(callstack); + if (span == NULL) { + fprintf(stderr, "call stack crashed\n"); + exit(1); + } + gettimeofday(&span->end, NULL); +} +``` + +Next, create a developer-defined program `a.c`: + +```c +#include "span.h" +#define MLN_FUNC_FLAG +#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); +}) + +int main(void) +{ + mln_span_start(); + bcd(1, 2); + mln_span_stop(); + mln_span_dump(); + mln_span_release(); + return 0; +} +``` + +Compile the program: + +```bash +cc -o a a.c span.c -I /usr/local/melon/include/ -L /usr/local/melon/lib/ -lmelon -ggdb +``` + +Execute it and you can see the following output: + +``` +| bcd at a.c:13 takes 1 (us) + | abc at a.c:9 takes 0 (us) + | abc at a.c:9 takes 0 (us) +``` +