内核模块调用get_cycles()失败:未知符号,求ARM平台精确计时方案
问题描述
我需要精确计时以测量工频,参考《Linux设备驱动程序》调用<linux/timex.h>里的get_cycles()函数实现,代码能编译,但执行insmod时报错:
insmod: ERROR: could not insert module ./fmod.ko: Unknown symbol in module
硬件平台为ARM架构的i.MX 6UltraLite应用处理器(Arm® Cortex®-A7内核),系统信息:
root@ts-imx6ul:/home/holden# uname -a Linux ts-imx6ul 4.1.15-g9c4c55a #2 SMP PREEMPT Wed May 3 15:57:11 PDT 2023 armvx
用到的代码:
#include <linux/module.h> /* Needed by all modules */ #include <linux/kernel.h> /* Needed for KERN_INFO */ #include <linux/init.h> /* Needed for the macros */ #include <linux/timex.h> static int __init hello_start(void) { printk(KERN_INFO "Loading hello module...\n"); printk(KERN_INFO "Hello world\n"); cycles_t time = get_cycles(); return 0; } static void __exit hello_end(void) { printk(KERN_INFO "Goodbye Mr.\n"); } module_init(hello_start); module_exit(hello_end);
精确计时方案
一、修复get_cycles()未知符号问题
get_cycles()在ARM架构下并非所有内核版本都导出为模块可用符号,针对你的场景可以直接改用Cortex-A7原生的系统计数器寄存器实现:
Cortex-A7属于ARMv7-A架构,支持读取CNTVCT_EL0寄存器获取系统周期计数,这是通用的高精度计时方式,代码示例如下:
#include <linux/module.h> #include <linux/kernel.h> #include <linux/init.h> #include <asm/arch_timer.h> static inline cycles_t my_get_cycles(void) { return read_cntvct_el0(); } static int __init hello_start(void) { printk(KERN_INFO "Loading hello module...\n"); printk(KERN_INFO "Hello world\n"); cycles_t time = my_get_cycles(); printk(KERN_INFO "Current cycle count: %llu\n", (unsigned long long)time); return 0; } static void __exit hello_end(void) { printk(KERN_INFO "Goodbye Mr.\n"); } module_init(hello_start); module_exit(hello_end); MODULE_LICENSE("GPL");
注意:需确保内核配置中CONFIG_ARM_ARCH_TIMER已启用(i.MX6UL平台默认开启该配置)。
二、其他适用于工频测量的精确计时方案
工频测量需要微秒级及以上精度,以下是几种可靠替代方案:
- 内核高精度定时器(hrtimer):适合周期性计时或单次高精度延迟,精度可达纳秒级,可用于捕获信号周期。
- i.MX6UL硬件GPT定时器:直接操作平台自带的通用定时器寄存器,或使用内核提供的定时器API,实现硬件级别的精确计时。
- ktime系列函数:内核提供的
ktime_get()、ktime_get_ns()等函数,返回纳秒级系统时间,适合计算时间差,示例:
#include <linux/ktime.h> static int __init hello_start(void) { ktime_t start, end; s64 delta_ns; start = ktime_get(); // 执行需要计时的操作 end = ktime_get(); delta_ns = ktime_to_ns(ktime_sub(end, start)); printk(KERN_INFO "Time elapsed: %lld ns\n", delta_ns); return 0; }
内容的提问来源于stack exchange,提问作者rich
相关产品推荐
相关产品推荐

