[En-Nut-Discussion] Improvement for faster mounting of large SD cards
Malte Marwedel
m.marwedel at onlinehome.de
Sat Jan 16 17:52:50 CET 2010
Hello,
I am using a 4GB SD card together with Nut/OS. Unfortunately, mounting a
volume took several minutes. So I looked into the source and found, that
nearly all of the time is needed determining which of the nearly 1000000
clusters is free (PhatCountFreeClusters()). For every cluster the code
made three function calls (Phat32GetClusterLink(), PhatTableLoc(),
PhatSectorLoad()), some pointer arithmetic and uint32_t by uint16_t
division. Together with a stack on a slow external RAM, this took some time.
So I put Phat32GetClusterLink(), PhatTableLoc() together into one
function, avoided the division and reduced the pointer calculations and
PhatSectorLoad() calls.
The downside is of course, that the functional separation of phat32.c
and phatvol.c is mixed together and with the old functions still around,
code is somewhat duplicated. So I have my doubt if it would be good to
add it to the Nut/OS distribution. But if someone has the same problem,
he might be happy about the code here.
Measured mount speeds (ATMega128 with 16MHz and some other interrupts
and threads consuming a few percent of CPU):
cluster size: 4K:
original code: 217 sec
optimized code: 29 sec
As I still was not satisfied with 29 seconds, I simply formatted the
card with a larger cluster size.
cluster size 16K:
original code: 54 sec
optimized code: 8 sec
Regards,
Malte
/*!
* \brief Counts the number of free clusters in a fat32 volume, fast
version.
*
* \param dev Specifies the file system device.
*
* \return The number of free clusters.
*/
static uint32_t PhatFastPhat32FreeClusters(NUTDEVICE * dev) {
PHATVOL *vol = (PHATVOL *) dev->dev_dcb;
uint32_t rc = 0;
uint32_t clust = 0;
uint32_t clustlast = vol->vol_last_clust;
/* Do not seek beyond the end of the chain. */
if (clustlast >= (PHATEOC & PHAT32CMASK)) {
clustlast = (PHATEOC & PHAT32CMASK) -1;
}
uint32_t pos = -4;
uint32_t sect = vol->vol_tab_sect[0];
int sbn = PhatSectorLoad(dev, sect);
uint8_t * sdata = vol->vol_buf[sbn].sect_data;
while (clust < clustlast) {
pos += 4;
/* Load the sector that contains the table entry. */
if (pos >= vol->vol_sectsz) {
pos = 0;
sect++;
sbn = PhatSectorLoad(dev, sect);
if (sbn < 0) {
break;
}
sdata = vol->vol_buf[sbn].sect_data;
}
/* Check if the 32 bit link value is zero */
uint8_t link = sdata[pos];
link |= sdata[pos + 1];
link |= sdata[pos + 2];
link |= sdata[pos + 3];
if (link == 0) {
rc++;
}
clust++;
}
return rc;
}
More information about the En-Nut-Discussion
mailing list