lxl_lxl 发表于 2015-9-2 13:46:24

为什么FatFs的f_lseek函数执行时间从会几us到几秒钟增加,见图

我在测试播放一个2GB的无压缩BMP编码的avi视频文件,分辨率320*240 (主芯片STM32F407)

测试发现刚开始播放的速度能到7fps(主要播放速度受读SD速度限制,一张320*240,24位的图片就225KB了),

可是速度会慢慢的下降,慢慢的降到零点几fps

调试跟踪发现是卡在了f_lseek 文件偏移函数中

复位后,刚开始f_lseek用时才几us,随着播放,几秒钟后就升到了几百个ms,在过多一会甚至是用时1秒多..

刚刚移植了2015年9月份的 R0.11版本,也是如此,不知道大家有没有遇见过这样的问题


见图:(这个是f_lseek函数用时537ms的图片,大概播放了20多秒就降到了500多毫秒了)

lxl_lxl 发表于 2015-9-2 13:52:15

测试过,SD卡的读速度一直都拨动不大,问题在于f_lseek

myxiaonia 发表于 2015-9-2 14:14:11

那你跟一下这个f_lseek吧,看看瓶颈到底在哪里

lxl_lxl 发表于 2015-9-2 14:39:02

myxiaonia 发表于 2015-9-2 14:14
那你跟一下这个f_lseek吧,看看瓶颈到底在哪里

是的,就是卡在这里,一直循环很久,但刚开始又不会

while (ofs > bcs) {                                                /* Cluster following loop */
                                        clst = get_fat(fp->fs, clst);        /* Follow cluster chain if not in write mode */
                                        if (clst == 0xFFFFFFFF) ABORT(fp->fs, FR_DISK_ERR);
                                        if (clst <= 1 || clst >= fp->fs->n_fatent) ABORT(fp->fs, FR_INT_ERR);
                                        fp->clust = clst;
                                        fp->fptr += bcs;
                                        ofs -= bcs;
                        }

aozima 发表于 2015-9-2 14:54:44

在同个已cache的sector中,当然很快。
如果新的位置还要读磁盘,那可想而知了。

所以最好应用这块好好优化,即使用seek也不要乱跳。

myxiaonia 发表于 2015-9-2 15:03:57

aozima 发表于 2015-9-2 14:54
在同个已cache的sector中,当然很快。
如果新的位置还要读磁盘,那可想而知了。



按理说fat缓存时会缓存至少512字节的fat表区域,如果视频文件是连续存放的话也会有不少扇区的连续的,这个fat缓存就会连续命中,不可能出现一直性能下降的问题

而是像周期波一样

lxl_lxl 发表于 2015-9-2 15:39:09

myxiaonia 发表于 2015-9-2 15:03
按理说fat缓存时会缓存至少512字节的fat表区域,如果视频文件是连续存放的话也会有不少扇区的连续的,这 ...

有道理

有个细节忘记说了

实际上,在一个循环中,我用了两次f_lseek,

一次是找到视频流头后用了f_lseek,因为有音频数据,要跳过音频数据。也就是说不使用跳过的这些音频数据。这些数据大约4KB,卡的就只有这一次,另一次永远也不会卡哦

另一次是用于循环读取视频流中一帧的图片数据(225KB),我一次读取10KB。这次调用f_lseek没有卡过,很流畅

zzm24 发表于 2015-9-2 16:44:50

开启FATFS的FAST_SEEK宏,open文件时创建 CLMT ,类似将FAT表压缩储存,以后seek就不用再去读FAT表了

/* Using fast seek feature */

    DWORD clmt;                  /* Cluster link map table buffer */

    res = f_open(fp, fname, FA_READ | FA_WRITE);   /* Open a file */

    res = f_lseek(fp, ofs1);               /* This is normal seek (cltbl is nulled on file open) */

    fp->cltbl = clmt;                      /* Enable fast seek feature (cltbl != NULL) */
    clmt = SZ_TBL;                      /* Set table size */
    res = f_lseek(fp, CREATE_LINKMAP);   /* Create CLMT */
    ...

    res = f_lseek(fp, ofs2);               /* This is fast seek */

lxl_lxl 发表于 2015-9-2 17:26:17

zzm24 发表于 2015-9-2 16:44
开启FATFS的FAST_SEEK宏,open文件时创建 CLMT ,类似将FAT表压缩储存,以后seek就不用再去读FAT表了

/* U ...

真的非常感谢你

问题总算解决了,播放视频一下子快起来了

而且这对于告诉读写大文件非常有利,现在f_lseek函数执行时间总保持在0.6ms左右,太兴奋了

相信很多人都不知道这个,学习了

snoopyzz 发表于 2015-9-2 18:23:10

0.11版里是 #define _USE_FASTSEEK    1

cheungman 发表于 2016-1-8 18:29:34

我以前也碰到f_lseek的定位大文件的问题, 后来多加了一个f_lseek函数, 加入延时10us, 然后没问题了, 原来是FAST_SEEK宏的原因啊.

yuanzhongda 发表于 2018-7-23 16:58:23

lxl_lxl 发表于 2015-9-2 17:26
真的非常感谢你

问题总算解决了,播放视频一下子快起来了


你好,我用fastseek无法多次写入了,能不能把fastseek的那段代码分享一下

zhongsandaoren 发表于 2018-7-23 17:14:38

这就解决了

yuanzhongda 发表于 2018-7-24 10:28:44

zhongsandaoren 发表于 2018-7-23 17:14
这就解决了

你好,我用fastseek无法多次写入了,你知道具体是如何解决的吗

qiangxiaochen 发表于 2018-7-27 11:39:20

zzm24 发表于 2015-9-2 16:44
开启FATFS的FAST_SEEK宏,open文件时创建 CLMT ,类似将FAT表压缩储存,以后seek就不用再去读FAT表了

/* U ...

15年的贴子,被我找到了,并且帮助我解决了问题,非常感谢!
/* Using fast seek function */

    DWORD clmt;                  /* Cluster link map table buffer */

    res = f_open(fp, fname, FA_READ | FA_WRITE);   /* Open a file */

    res = f_lseek(fp, ofs1);               /* This is normal seek (cltbl is nulled on file open) */

    fp->cltbl = clmt;                      /* Enable fast seek function (cltbl != NULL) */
    clmt = SZ_TBL;                      /* Set table size */
    res = f_lseek(fp, CREATE_LINKMAP);   /* Create CLMT */
    ...

    res = f_lseek(fp, ofs2);               /* This is fast seek */
======================分割线:下面是我实际使用时的解决办法==============================
#define SZ_TBL20
static DataWrite(void)//周期执行函数,周期往文件里写数据
{
       static DWORD clmt;                  /* Cluster link map table buffer */

    res = f_open(fp, fname, FA_READ | FA_WRITE);   /* Open a file */
    if(clmt == 0x00)
   {
           res = f_lseek(fp, f_sizeof(fp));               /* This is normal seek (cltbl is nulled on file open) */
       faddata.cltbl = clmt;
       clmt = SZ_TBL;
       res = f_lseek(fp,CREATE_LINKMAP);
}
else fp->cltbl = clmt;//每次f_open后,fp->cltbl会变成NULL,所以要把第clmt的地址再次赋值给cltbl
res = f_seek(fp,f_size(fp));
res = f_write(fp,WriteDataBuf,strlen(WriteDataBuf),&bw);
res = f_close(fp);
}

ZXF_CUG 发表于 2018-7-27 15:08:54

以前没注意,学习了

advarx21ic 发表于 2018-7-27 15:47:29

学习了,谢谢
页: [1]
查看完整版本: 为什么FatFs的f_lseek函数执行时间从会几us到几秒钟增加,见图