[1-9]Profiling Code Using clock_gettime

本文介绍如何利用clock_gettime函数获取高分辨率计时器,用于代码性能剖析。通过选择合适的时钟类型(如CLOCK_REALTIME、CLOCK_PROCESS_CPUTIME_ID、CLOCK_THREAD_CPUTIME_ID),并计算两次调用之间的间隔,可以精确测量函数执行时间。示例代码展示了如何在实际应用中使用该函数,并注意其引入的微小额外开销。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Keeping track of what I do
Profiling Code Usingclock_gettime:http://www.guyrutenberg.com/2007/09/22/profiling-code-using-clock_gettime/

with 45 comments
After raising the issue of the low resolution problem of the timer provided byclock() in Resolution Problems in clock(), I’ve ended the post by mentioning to two more functions that should provide high-resolution timers suitable for profiling code. In this post I will discuss one of them,clock_gettime().

The clock_gettime() provides access to several useful timers with the resolution of nanoseconds. First, the prototype for the function is as follows:
int clock_gettime(clockid_t clk_id, struct timespect *tp);
The clk_id allows us to select a specific clock from the several
offered by the system, which includes:
CLOCK_REALTIME, a system-wide realtime clock.
CLOCK_PROCESS_CPUTIME_ID, high-resolution timer provided by the CPU for each process.
CLOCK_THREAD_CPUTIME_ID, high-resolution timer provided by the CPU for each of the threads.
Usually, there are more clocks provided, but I find these three the most useful as they allow to get the execution time spent in the system level, process level and the thread level.
The current clock time, for the chosen clock is stored int the struct provided by the*tp pointer. The timespec struct is defined as follows:
struct timespec {
	time_t tv_sec; /* seconds */
	long tv_nsec; /* nanoseconds */
};
To time the processing time some function took, one should call clock_gettime() twice. Once before the function call and once right after it and subtract the returned timings to get the actual runtime.
Getting the difference between two timespec structs isn’t very complicated and can be acheived using the functiondiff() defined bellow:
timespec diff(timespec start, timespec end)
{
	timespec temp;
	if ((end.tv_nsec-start.tv_nsec)<0) {
		temp.tv_sec = end.tv_sec-start.tv_sec-1;
		temp.tv_nsec = 1000000000+end.tv_nsec-start.tv_nsec;
	} else {
		temp.tv_sec = end.tv_sec-start.tv_sec;
		temp.tv_nsec = end.tv_nsec-start.tv_nsec;
	}
	return temp;
}
Now let’s move to some real example:
#include <iostream>
#include <time.h>
using namespace std;
 
timespec diff(timespec start, timespec end);
 
int main()
{
	timespec time1, time2;
	int temp;
	clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &time1);
	for (int i = 0; i< 242000000; i++)
		temp+=temp;
	clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &time2);
	cout<<diff(time1,time2).tv_sec<<":"<<diff(time1,time2).tv_nsec<<endl;
	return 0;
}
 
timespec diff(timespec start, timespec end)
{
	timespec temp;
	if ((end.tv_nsec-start.tv_nsec)<0) {
		temp.tv_sec = end.tv_sec-start.tv_sec-1;
		temp.tv_nsec = 1000000000+end.tv_nsec-start.tv_nsec;
	} else {
		temp.tv_sec = end.tv_sec-start.tv_sec;
		temp.tv_nsec = end.tv_nsec-start.tv_nsec;
	}
	return temp;
}
To use clock_gettime you need to include time.h and to link tolibrt.a. If you use gcc just make sure you add -lrt to your list of arguments.
Play a bit with the length of the for loop. As you can see clock_gettime provides much more accurate results and can register very short processing time too. Just remember that as the case with any profiling functions, this function adds a little overhead to your program, so make sure you disable the profiling code, using preprocessor commands for example, in the production release.
26/9/2007 – Update

You may want to take a look at The Revised String Iteration Benchmark post for another, larger, example of usingclock_gettime to time performance of code.

./build/riscv64-nemu-interpreter: invalid option -- &#39;/&#39; Usage: ./build/riscv64-nemu-interpreter [OPTION...] IMAGE [args] -b,--batch run with batch mode -I,--max-instr max number of instructions executed -l,--log=FILE output log to FILE --small-log=FILE output log to a limited size FILE, but log is always up to date -d,--diff=REF_SO run DiffTest with reference REF_SO -p,--port=PORT run DiffTest with port PORT -D,--statdir=STAT_DIR store simpoint bbv, cpts, and stats in STAT_DIR -w,--workload=WORKLOAD the name of sub_dir of this run in STAT_DIR -C,--config=CONFIG running configuration -c,--restore restoring from CPT FILE -r,--cpt-restorer=R binary of gcpt restorer -S,--simpoint-dir=SIMPOINT_DIR simpoints dir -u,--uniform-cpt uniformly take cpt with fixed interval --cpt-interval=INTERVAL cpt interval: the profiling period for simpoint; the checkpoint interval for uniform cpt --warmup-interval=INTERVAL warmup interval: the warmup interval for SimPoint cpt --cpt-mmode force to take cpt in mmode, which might not work. --manual-oneshot-cpt Manually take one-shot cpt by send signal. --manual-uniform-cpt Manually take uniform cpt by send signal. --checkpoint-format Specify the checkpoint format(&#39;gz&#39; or &#39;zstd&#39;), default: &#39;gz&#39;. --simpoint-profile simpoint profiling --dont-skip-boot profiling/checkpoint immediately after boot --mem_use_record_file result output file for analyzing the memory use segment -M,--dump-mem=DUMP_FILE dump memory into FILE -R,--dump-reg=DUMP_FILE dump register value into FILE
03-28
<think>好的,我现在需要解决用户在NEMU RISC-V模拟器运行时遇到的“无效选项错误”(invalid option error)。首先,用户的问题提到了错误信息,所以我要先理解这个错误通常是由什么原因引起的。 根据经验,这种错误通常是因为在命令行参数中使用了不被支持的选项或格式不正确。NEMU作为模拟器,其命令行参数可能有特定的格式要求,比如需要特定的标志(flags)或者选项名称。用户可能在运行命令时拼写错误,或者使用了过时的参数。 接下来,我需要回忆NEMU的常见用法,尤其是RISC-V版本的参数。例如,运行NEMU时可能需要指定架构(如-riscv),镜像文件(-i),或者日志选项(-l)。用户可能错误地输入了不存在的选项,比如将-riscv写成-risc-v,或者多打了空格,导致解析错误。 然后,我应该考虑如何验证这些可能性。用户可能需要检查他们的命令是否严格按照文档中的格式书写。例如,是否每个选项后面都跟了正确的参数,是否有必需的选项被遗漏了。比如,忘记指定镜像文件可能会导致错误,但更可能的错误是选项本身无效。 另外,Makefile中的依赖关系也可能影响构建是否正确。如果用户自行编译了NEMU,可能因为依赖未正确更新而导致生成的可执行文件不支持某些选项。这时候,清理构建并重新编译(make clean && make)可能会解决问题,确保所有依赖项正确更新,避免旧配置残留。 还需要考虑版本差异。用户使用的NEMU版本是否与文档或教程中的一致?不同版本可能选项有所不同,导致同样的命令在新旧版本中表现不同。建议用户检查版本信息,并查阅对应版本的文档。 最后,用户可能需要查看帮助信息,使用-h或--help选项来列出所有支持的选项,从而确认自己使用的选项是否存在或拼写正确。如果帮助信息中没有某个选项,那么显然该选项无效,需要修正。 总结起来,解决步骤可能包括:检查命令拼写、验证选项是否存在、重新构建模拟器、查阅文档版本、使用帮助信息确认选项。这些步骤应该能帮助用户定位并解决问题。</think>关于NEMU RISC-V模拟器出现"invalid option"错误的解决方案,请按照以下步骤排查: 1. **验证命令格式** - 确认命令参数符合规范:`./build/riscv64-nemu-interpreter [选项] <镜像文件>` - 检查选项前必须包含双短横线,例如:`--diff=REF_SO`而非`-diff=REF_SO` - 常见有效选项: ``` --log=<日志文件路径> --wave=<波形文件路径> --diff=<参考实现路径> --enable-fork ``` 2. **检查镜像文件参数** - 必须作为最后一个参数 - 确保镜像文件路径正确且具有可读权限 - 示例正确格式: ```bash ./build/riscv64-nemu-interpreter --diff=ref_so riscv64-xxx-image ``` 3. **依赖关系重建** 若修改过源代码,建议执行: ```bash make clean make defconfig make -j$(nproc) ``` 这会清除旧构建并重新生成依赖关系文件(.d文件),确保头文件修改被正确识别[^1] 4. **调试建议** - 使用`--help`查看最新选项列表 - 启用详细日志:`--log=nemu.log -d` - 检查终端输出中具体的错误位置标识
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值