用户空间与内核空间数据交换的方式(1)------debugfs

本文深入探讨了内核调试信息输出的挑战及解决方案,着重介绍了debugfs这一工具,它允许内核开发者在需要时通过虚拟文件系统向用户空间应用提供调试信息。文中详细解释了如何使用debugfs创建目录、文件、以及特定变量控制的API,并通过示例代码展示了其实现过程。此外,还介绍了如何在内核中启用和使用debugfs,以及在用户态使用它的一系列步骤。

http://yuxu9710108.blog.163.com/blog/static/23751534201110985032582/

 内核开发者经常需要向用户空间应用输出一些调试信息,在稳定的系统中可能根本不需 要这些调试信息,但是在开发过程中,为了搞清楚内核的行为,调试信息非常必要,printk可能是用的最多的,但它并不是最好的,调试信息只是在开发中用 于调试,而printk将一直输出,因此开发完毕后需要清除不必要 的printk语句,另外如果开发者希望用户空间应用能够改变内核行为时,printk就无法实现。因此,需要一种新的机制,那只有在需要的时候使用,它 在需要时通过在一个虚拟文件系统中创建一个或多个文件来向用户空间应用提供调试信息。
有几种方式可以实现上述要求:
 (1)使用procfs,在/proc创建文件输出调试信息,但是procfs对于大于一个内存页(对于x86是4K)的输出比较麻烦,而且速度慢,有时回出现一些意想不到的问题。
 (2)使用sysfs(2.6内核引入的新的虚拟文件系统),在很多情况下,调试信息可以存放在那里,但是sysfs主要用于系统管理,它希望每一个文件对应内核的一个变量,如果使用它输出复杂的数据结构或调试信息是非常困难的。
 (3)使用libfs创建一个新的文件系统,该方法极其灵活,开发者可以为新文件系统设置一些规则,使用libfs使得创建新文件系统更加简单,但是仍然超出了一个开发者的想象。
 (4) 为了使得开发者更加容易使用这样的机制,Greg Kroah-Hartman开发了debugfs(在2.6.11中第一次引入),它是一个虚拟文件系统,专门用于输出调试信息,该文件系统非常小,很容 易使用,可以在配置内核时选择是否构件到内核中,在不选择它的情况下,使用它提供的API的内核部分不需要做任何改动。
使用debugfs的开发者首先需要在文件系统中创建一个目录,下面函数用于在debugfs文件系统下创建一个目录:

    
struct dentry * debugfs_create_dir( const char * name, struct dentry * parent);

参数name是要创建的目录名,参数parent指定创建目录的父目录的dentry,如果为NULL,目录将创建在debugfs文件系统的根目 录下。如果返回为-ENODEV,表示内核没有把debugfs编译到其中,如果返回为NULL,表示其他类型的创建失败,如果创建目录成功,返回指向该 目录对应的dentry条目的指针。
下面函数用于在debugfs文件系统中创建一个文件: 

    
struct dentry * debugfs_create_file( const char * name, mode_t mode, struct dentry * parent,
void * data, struct file_operations * fops);

参数name指定要创建的文件名,参数mode指定该文件的访问许可,参数parent指向该文件所在目录,参数data为该文件特定的一些数据, 参数fops为实现在该文件上进行文件操作的fiel_operations结构指针,在很多情况下,由seq_file提供的文件操作实现就足够了,因 此使用debugfs很容易,当然,在一些情况下,开发者可能仅需要使用用户应用可以控制的变量来调试,debugfs也提供了4个这样的API方便开发 者使用:

    
struct dentry * debugfs_create_u8( const char * name, mode_t mode, struct dentry * parent, u8 * value); struct dentry * debugfs_create_u16( const char * name, mode_t mode, struct dentry * parent, u16 * value); struct dentry * debugfs_create_u32( const char * name, mode_t mode, struct dentry * parent, u32 * value); struct dentry * debugfs_create_bool( const char * name, mode_t mode, struct dentry * parent, u32 * value);

 参数name和mode指定文件名和访问许可,参数value为需要让用户应用控制的内核变量指针。
当内核模块卸载时,Debugfs并不会自动清除该模块创建的目录或文件,因此对于创建的每一个文件或目录,开发者必须调用下面函数清除:
 

    
void debugfs_remove( struct dentry * dentry);

参数dentry为上面创建文件和目录的函数返回的dentry指针。
在下面给出了一个使用debufs的示例模块 debugfs_exam.c,为了保证该模块正确运行,必须让内核支持debugfs, debugfs是一个调试功能,因此它位于主菜单Kernel hacking,并且必须选择Kernel debugging选项才能选择,它的选项名称为Debug Filesystem。为了在用户态使用debugfs,用户必须mount它,下面是在作者系统上的使用输出:

    
$ mkdir - p / debugfs $ mount - t debugfs debugfs / debugfs $ insmod . / debugfs_exam.ko $ ls / debugfs debugfs - exam $ ls / debugfs / debugfs - exam u8_var u16_var u32_var bool_var $ cd / debugfs / debugfs - exam $ cat u8_var 0 $ echo 200 > u8_var $ cat u8_var 200 $ cat bool_var N $ echo 1 > bool_var $ cat bool_var Y
    
// kernel module: debugfs_exam.c #include < linux / config.h > #include < linux / module.h > #include < linux / debugfs.h > #include < linux / types.h > /* dentry:目录项,是Linux文件系统中某个索引节点(inode)的链接。这个索引节点可以是文件,也可以是目录。 Linux用数据结构dentry来描述fs中和某个文件索引节点相链接的一个目录项(能是文件,也能是目录)。   (1)未使用(unused)状态:该dentry对象的引用计数d_count的值为0,但其d_inode指针仍然指向相关
的的索引节点。该目录项仍然包含有效的信息,只是当前没有人引用他。这种dentry对象在回收内存时可能会被释放。   (2)正在使用(inuse)状态:处于该状态下的dentry对象的引用计数d_count大于0,且其d_inode指向相关
的inode对象。这种dentry对象不能被释放。   (3)负(negative)状态:和目录项相关的inode对象不复存在(相应的磁盘索引节点可能已被删除), dentry
对象的d_inode指针为NULL。但这种dentry对象仍然保存在dcache中,以便后续对同一文件名的查找能够快速完成。
这种dentry对象在回收内存时将首先被释放。 */ static struct dentry * root_entry, * u8_entry, * u16_entry, * u32_entry, * bool_entry; static u8 var8; static u16 var16; static u32 var32; static u32 varbool; static int __init exam_debugfs_init( void ) { root_entry = debugfs_create_dir( " debugfs-exam " , NULL); if ( ! root_entry) { printk( " Fail to create proc dir: debugfs-exam\n " ); return 1 ; } u8_entry = debugfs_create_u8( " u8-var " , 0644 , root_entry, & var8); u16_entry = debugfs_create_u16( " u16-var " , 0644 , root_entry, & var16); u32_entry = debugfs_create_u32( " u32-var " , 0644 , root_entry, & var32); bool_entry = debugfs_create_bool( " bool-var " , 0644 , root_entry, & varbool); return 0 ; } static void __exit exam_debugfs_exit( void ) { debugfs_remove(u8_entry); debugfs_remove(u16_entry); debugfs_remove(u32_entry); debugfs_remove(bool_entry); debugfs_remove(root_entry); } module_init(exam_debugfs_init); module_exit(exam_debugfs_exit); MODULE_LICENSE( " GPL " );


测试代码:

位于kernel/drivers/test/debugfs_test.c

编辑Makefile文件

# DEBUGFS
obj-y                   += debugfs_test.o


#include <linux/module.h>
#include <linux/debugfs.h>
#include <linux/types.h>


static struct dentry *root_entry, *parent_entry, *child_entry;
static u64 testvalue;
static char note[] = "Good";

static int value_get(void *data, u64 *val)
{
    char *note = (char *)data;

    printk("%s",note);
    *val = testvalue;
    return 0;
}

static int value_set(void *data, u64 val)
{
    char *note = (char *)data;
    
    printk("%s",note);
    testvalue = val;
    return 0;
}

DEFINE_SIMPLE_ATTRIBUTE(value_fops,value_get, value_set, "%lld\n");

static int __init exam_debugfs_init(void)
{
    root_entry = debugfs_create_dir("debugfs-exam", NULL);
    if (!root_entry) {
        printk("Fail to create proc dir: debugfs-exam\n");
        return 1;
    }

    parent_entry = debugfs_create_dir("parent", root_entry);
    
    child_entry = debugfs_create_file("testvalue", S_IRUGO | S_IWUSR, parent_entry, note, &value_fops);
                                  
           return 0;
}

static void __exit exam_debugfs_exit(void)
{
    debugfs_remove_recursive(root_entry);
}

module_init(exam_debugfs_init);
module_exit(exam_debugfs_exit);
MODULE_LICENSE("GPL");


#mount -t debugfs none /data/debugfs

#cd data/debugfs

#cd debugfs-exam

#cat testvalue

#echo 100 > testvalue



<think>好的,我现在要处理用户关于Android 12中RKNN开发配置和使用教程的问题。首先,我需要回顾用户提供的引用内容,看看是否有相关的信息。 用户提供了三个引用。引用1提到了RKNN Model Zoo和RKNN Toolkit2的环境配置,包括安装Miniconda3。引用2是关于系统镜像下载,特别是Ubuntu 22.04版本和导出ONNX模型。引用3讨论了RV1808/1126使用RKNN作为MediaPipe推理后端的步骤,包括配置参数如use_rga、use_mmap和data_type的设置,以及反量化的处理。 用户的问题集中在Android 12上,所以需要将引用中的信息与Android系统关联起来。引用3提到了MediaPipe和RKNN的集成,这可能适用于Android开发,但需要确认是否支持Android 12。此外,RKNN Toolkit2的环境配置可能在不同平台上有所不同,用户可能需要针对Android进行调整。 接下来,我需要考虑Android开发中RKNN的一般步骤,比如环境准备、模型转换、集成到Android应用、配置参数和性能优化。结合引用中的信息,模型转换部分可以参考引用2提到的导出ONNX模型,然后使用RKNN Toolkit转换为RKNN格式。引用3中的配置参数(如use_rga、use_mmap、data_type)可能在Android中同样适用,但需要查阅相关文档确认。 可能还需要指导用户如何将RKNN库集成到Android项目中,比如添加依赖项或NDK配置。此外,性能优化方面,引用3提到的反量化处理可能需要特别注意,尤其是在Android设备上的实现。 最后,确保回答结构清晰,分步骤说明,并引用提供的资料。需要验证引用中的信息是否适用于Android 12,例如系统镜像是否支持,或者是否有特定版本的要求。如果某些步骤在引用中没有明确说明,可能需要提示用户参考官方文档或社区资源。</think>### Android 12 RKNN 开发配置与使用教程 #### 1. **环境准备** - **系统镜像与工具链**: 根据引用[2],建议使用Ubuntu 22.04作为开发环境,并下载Orange Pi 5 Pro等支持RKNN的硬件镜像。对于Android 12开发,需确保RKNN Toolkit2适配Android NDK版本(推荐NDK 21+)[^2]。 - **安装RKNN Toolkit2**: 参考引用[1],通过Miniconda3配置Python环境(建议Python 3.8),并安装RKNN Toolkit2以支持模型转换与推理。命令示例: ```bash pip install rknn_toolkit2 ``` #### 2. **模型转换(ONNX转RKNN)** - **导出ONNX模型**: 使用PyTorch或TensorFlow等框架导出模型为ONNX格式(引用[2])。 - **转换为RKNN格式**: 编写RKNN配置文件(`config.yml`),指定输入尺寸、量化方式等参数。示例代码: ```python from rknn.api import RKNN rknn = RKNN() rknn.config(target_platform='rk3568', mean_values=[[127.5]], std_values=[[127.5]]) rknn.load_onnx(model="model.onnx") rknn.build(do_quantization=True, dataset="dataset.txt") rknn.export_rknn("model.rknn") ``` #### 3. **Android项目集成** - **添加RKNN库依赖**: 将编译好的RKNN动态库(`librknnrt.so`)和模型文件(`model.rknn`)放入Android项目的`jniLibs`目录。 - **JNI接口开发**: 通过JNI调用RKNN的C/C++ API实现推理。关键配置参考引用[3]: ```cpp #include <rknn/rknn_runtime.h> rknn_context ctx; int ret = rknn_init(&ctx, model_path, 0, 0, nullptr); ret = rknn_inputs_set(ctx, input_num, input_attrs); ret = rknn_run(ctx, nullptr); ret = rknn_outputs_get(ctx, output_num, output_attrs, nullptr); ``` #### 4. **关键配置参数** - **use_rga与use_mmap**: 根据引用[3],若Android设备不支持硬件加速(如RGA),需将`use_rga`和`use_mmap`设为`false`。 - **数据量化类型**: `data_type`可选`uint8`或`fp32`。若选`uint8`,需手动实现反量化;若选`fp32`,RKNN会自动处理[^3]。 #### 5. **性能优化** - **多线程推理**: 利用Android的`ThreadPoolExecutor`并行处理输入数据。 - **内存优化**: 启用`use_mmap`(若支持)减少内存拷贝开销,或通过零拷贝技术直接操作物理内存。 #### 6. **调试与验证** - **日志输出**: 启用RKNN的调试模式(`RKNN_LOG_LEVEL=DEBUG`)查看详细运行信息。 - **性能分析**: 使用`rknn.query(RKNN_QUERY_PERF_DETAIL)`获取各层耗时,针对性优化模型结构。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值