hosted/multidrive: Speed up readdir()/get_dir_info().

The two functions need to check whether they are called for a specific path
to implement the virtual mount point for the external storage. This
is statistically rare and a hit on the common case. Therefore speed up
the common case by performing integer comparision first, and only expensive
string construction and comparision if that succeeds.

Change-Id: I3c41fe073e1f4f8eb62d2b8556a36937c9cb8290
This commit is contained in:
Thomas Martitz 2014-02-24 23:07:37 +01:00
parent 3a3d26eee2
commit c27c3f10fd
2 changed files with 37 additions and 18 deletions

View File

@ -28,6 +28,7 @@
#include <unistd.h>
#include "config.h"
#include "rbpaths.h"
#include "crc32.h"
#include "file.h" /* MAX_PATH */
#include "logf.h"
#include "gcc_extensions.h"
@ -52,9 +53,11 @@
#if (CONFIG_PLATFORM & PLATFORM_ANDROID)
static const char rbhome[] = "/sdcard";
#endif
#if (CONFIG_PLATFORM & (PLATFORM_SDL|PLATFORM_MAEMO|PLATFORM_PANDORA)) && !defined(__PCTOOL__)
#elif (CONFIG_PLATFORM & (PLATFORM_SDL|PLATFORM_MAEMO|PLATFORM_PANDORA)) && !defined(__PCTOOL__)
const char *rbhome;
#else
/* YPR0, YPR1 */
static const char rbhome[] = HOME_DIR;
#endif
#if !(defined(SAMSUNG_YPR0) || defined(SAMSUNG_YPR1)) && !defined(__PCTOOL__)
@ -62,9 +65,6 @@ const char *rbhome;
* over the ones where Rockbox is installed to. Classic example would be
* $HOME/.config/rockbox.org vs /usr/share/rockbox */
#define HAVE_SPECIAL_DIRS
#define IS_HOME(p) (!strcmp(p, rbhome))
#else
#define IS_HOME(p) (!strcmp(p, HOME_DIR))
#endif
/* flags for get_user_file_path() */
@ -75,6 +75,7 @@ const char *rbhome;
#define IS_FILE (1<<1)
#ifdef HAVE_MULTIDRIVE
static uint32_t rbhome_hash;
/* A special link is created under e.g. HOME_DIR/<microSD1>, e.g. to access
* external storage in a convinient location, much similar to the mount
* point on our native targets. Here they are treated as symlink (one which
@ -103,9 +104,9 @@ static const char *handle_special_links(const char* link, unsigned flags,
}
#endif
#ifdef HAVE_SPECIAL_DIRS
void paths_init(void)
{
#ifdef HAVE_SPECIAL_DIRS
/* make sure $HOME/.config/rockbox.org exists, it's needed for config.cfg */
#if (CONFIG_PLATFORM & PLATFORM_ANDROID)
mkdir("/sdcard/rockbox", 0777);
@ -133,9 +134,14 @@ void paths_init(void)
snprintf(config_dir, sizeof(config_dir), "%s/.config/rockbox.org/rocks.data", home);
mkdir(config_dir, 0777);
#endif
#endif /* HAVE_SPECIAL_DIRS */
#ifdef HAVE_MULTIDRIVE
rbhome_hash = crc_32((const void *) rbhome, strlen(rbhome), 0xffffffff);
#endif /* HAVE_MULTIDRIVE */
}
#ifdef HAVE_SPECIAL_DIRS
static bool try_path(const char* filename, unsigned flags)
{
if (flags & IS_FILE)
@ -189,8 +195,6 @@ static const char* _get_user_file_path(const char *path,
return ret;
}
#elif !defined(paths_init)
void paths_init(void) { }
#endif
static const char* handle_special_dirs(const char* dir, unsigned flags,
@ -261,7 +265,14 @@ int app_rename(const char *old, const char *new)
* get_dir_info() */
struct __dir {
DIR *dir;
IF_MD(int volumes_returned);
#ifdef HAVE_MULTIDRIVE
int volumes_returned;
/* A crc of rbhome is used to speed op the common case where
* readdir()/get_dir_info() is called on non-rbhome paths, because
* each call needs to check against rbhome for the virtual
* mount point of the external storage */
uint32_t path_hash;
#endif
char path[];
};
@ -278,7 +289,9 @@ struct dirinfo dir_get_info(DIR* _parent, struct dirent *dir)
#ifdef HAVE_MULTIDRIVE
char vol_string[VOL_ENUM_POS + 8];
sprintf(vol_string, VOL_NAMES, 1);
if (!strcmp(vol_string, dir->d_name))
if (UNLIKELY(rbhome_hash == parent->path_hash) &&
/* compare path anyway because of possible hash collision */
!strcmp(vol_string, dir->d_name))
{
ret.attribute = ATTR_LINK;
strcpy(path, MULTIDRIVE_DIR);
@ -314,9 +327,11 @@ struct dirinfo dir_get_info(DIR* _parent, struct dirent *dir)
DIR* app_opendir(const char *_name)
{
size_t name_len;
char realpath[MAX_PATH];
const char *name = handle_special_dirs(_name, 0, realpath, sizeof(realpath));
char *buf = malloc(sizeof(struct __dir) + strlen(name)+1);
name_len = strlen(name);
char *buf = malloc(sizeof(struct __dir) + name_len+1);
if (!buf)
return NULL;
@ -331,7 +346,11 @@ DIR* app_opendir(const char *_name)
free(buf);
return NULL;
}
IF_MD(this->volumes_returned = 0);
#ifdef HAVE_MULTIDRIVE
this->volumes_returned = 0;
this->path_hash = crc_32((const void *)this->path, name_len, 0xffffffff);
#endif
return (DIR*)this;
}
@ -350,9 +369,11 @@ struct dirent* app_readdir(DIR* dir)
#ifdef HAVE_MULTIDRIVE
/* this is not MT-safe but OK according to man readdir */
static struct dirent voldir;
if (d->volumes_returned < (NUM_VOLUMES-1)
if (UNLIKELY(rbhome_hash == d->path_hash)
&& d->volumes_returned < (NUM_VOLUMES-1)
&& volume_present(d->volumes_returned+1)
&& IS_HOME(d->path))
/* compare path anyway because of possible hash collision */
&& !strcmp(d->path, rbhome))
{
d->volumes_returned += 1;
sprintf(voldir.d_name, VOL_NAMES, d->volumes_returned);

View File

@ -55,8 +55,6 @@
#define PLUGIN_DIR ROCKBOX_DIR "/rocks"
#define CODECS_DIR ROCKBOX_DIR "/codecs"
#define paths_init()
#else /* APPLICATION */
#define HOME_DIR "<HOME>" /* replaced at runtime */
@ -68,8 +66,6 @@
#define CODECS_DIR ROCKBOX_LIBRARY_PATH "/rockbox/codecs"
#endif
extern void paths_init(void);
#endif /* !APPLICATION || SAMSUNG_YPR0 */
#define HOME_DIR_LEN (sizeof(HOME_DIR)-1)
@ -91,6 +87,8 @@ int app_mkdir(const char* name);
int app_rmdir(const char* name);
ssize_t app_readlink(const char *path, char *buf, size_t bufsiz);
extern void paths_init(void);
#endif
#define REC_BASE_DIR HOME_DIR