You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Android平台使用fio搭配libaio测试原始UFS性能的可行性分析及替代方案咨询

这是个非常实际的问题——Android环境确实和标准Linux桌面/服务器有不少差异,咱们一步步拆解来看:

1. 能否在Android上运行配置ioengine=libaio的fio?

理论上可行,但实际操作门槛很高,需要解决几个核心障碍:

  • libaio的静态链接:Android的Bionic C库默认不包含libaio,你得从Linux内核源码中提取libaio的用户空间代码,用Android NDK交叉编译成静态库,再在编译fio时把它链接进去。还要注意适配目标设备的架构(比如arm64-v8a、armeabi-v7a)。
  • 内核CONFIG_AIO支持:得确认你的手机内核开启了CONFIG_AIO——大部分旗舰机型的内核是开启的(系统后台服务依赖异步IO),但中低端机型不一定。你可以通过查看/proc/config.gz(如果内核暴露的话)判断,或者刷入开启该选项的自定义内核。
  • Root权限与安全风险:访问/dev/block下的UFS设备节点必须要有Root权限,而且直接读写原始块设备可能破坏系统数据,测试前一定要备份,最好用专门的空闲分区(如果能找到的话)。

不过这个流程繁琐,不同机型兼容性差异大,容易出现编译失败或运行崩溃的情况,所以一般不推荐作为首选方案。

2. 替代方案:贴近原始UFS性能的测试方法

如果用libaio不现实,以下几种方案能帮你拿到可靠的带宽、延迟指标:

方案一:用fio的sync/psync引擎搭配O_DIRECT

这是最容易落地的替代方案,无需libaio,依然能绕过文件系统缓存直接访问块设备:

  • 核心配置:使用ioengine=syncioengine=psync,加上direct=1参数(对应O_DIRECT标志)。举两个常用测试命令:
    顺序读测试:
    fio --name=ufs_seq_read --filename=/dev/block/xxx --ioengine=sync --rw=read --bs=128k --size=1G --direct=1 --numjobs=4 --time_based --runtime=60 --group_reporting
    
    随机读测试:
    fio --name=ufs_rand_read --filename=/dev/block/xxx --ioengine=psync --rw=randread --bs=4k --size=1G --direct=1 --numjobs=1 --time_based --runtime=60 --group_reporting
    
  • 优势:fio的NDK交叉编译相对简单(不用额外链接libaio),配置灵活,能输出你需要的带宽、平均延迟、IOPS等核心指标。
  • 注意:同样需要Root权限,测试前务必确认目标块设备是空闲的,避免破坏数据。

方案二:内核侧基准测试工具

如果能获取内核源码或刷入带调试工具的自定义内核,可以用内核级工具,完全绕过用户空间的影响:

  • blkbench:这是Linux内核源码自带的块层基准测试工具,直接在内核空间发起IO,结果最贴近UFS硬件的真实性能。
  • 内核版fio:如果编译内核时开启了fio的内核模块支持,可以用ioengine=kernel的fio配置,但Android原生内核一般不支持,需要自定义编译。

方案三:Android平台专属工具

不少厂商或开源项目提供了适配Android的存储测试工具,省心又可靠:

  • 厂商自带工具:比如三星Galaxy系列的「设备维护」里的存储性能测试、小米的「性能测试工具」等,这些工具已经针对自家设备的UFS做了优化,结果准确且无需Root(部分高级功能可能需要)。
  • 开源Android测试工具:比如StorageBenchmark这类开源项目,可直接安装APK,部分版本支持Root后访问原始块设备,操作简单。
  • Android Studio Profiler:如果需要贴近实际应用场景的UFS表现,Storage Profiler可以分析APP的IO行为,虽然不是直接测原始块设备,但能反映真实使用中的性能。

方案四:自定义测试程序

如果以上工具都不符合需求,你可以用NDK写一个极简的测试程序,核心是用O_DIRECTO_SYNC标志直接读写块设备:

  • 核心代码示例(C语言):
    #include <stdio.h>
    #include <fcntl.h>
    #include <unistd.h>
    #include <stdlib.h>
    #include <time.h>
    
    int main() {
        int fd = open("/dev/block/xxx", O_RDWR | O_DIRECT | O_SYNC);
        if (fd < 0) {
            perror("Failed to open block device");
            return 1;
        }
        // O_DIRECT要求内存页对齐,这里用4096字节对齐
        void *buf = aligned_alloc(4096, 1024 * 1024);
        if (!buf) {
            perror("Failed to allocate aligned buffer");
            close(fd);
            return 1;
        }
    
        struct timespec start, end;
        clock_gettime(CLOCK_MONOTONIC, &start);
        ssize_t ret = read(fd, buf, 1024 * 1024);
        clock_gettime(CLOCK_MONOTONIC, &end);
    
        double duration = (end.tv_sec - start.tv_sec) + (end.tv_nsec - start.tv_nsec) / 1e9;
        double bandwidth = (1024.0 * 1024.0) / (duration * 1024.0 * 1024.0); // GB/s
        printf("Bandwidth: %.2f GB/s\n", bandwidth);
    
        free(buf);
        close(fd);
        return 0;
    }
    
  • 优势:完全可控,能自定义IO模式、队列深度、测试时长等,适合做针对性的性能验证。

内容的提问来源于stack exchange,提问作者456 123

火山引擎 最新活动