diff options
author | Thomas Martitz <kugel@rockbox.org> | 2014-02-24 23:07:37 +0100 |
---|---|---|
committer | Thomas Martitz <kugel@rockbox.org> | 2014-02-24 23:07:37 +0100 |
commit | c27c3f10fd8c32e837c1f11176dc7223542bda6d (patch) | |
tree | 5c5cf1900071c8dac231409364f9948d4f6bc48f /firmware/common | |
parent | 3a3d26eee223f5d7307b9ab31d0dee93c82a41f5 (diff) | |
download | rockbox-c27c3f10fd8c32e837c1f11176dc7223542bda6d.tar.gz rockbox-c27c3f10fd8c32e837c1f11176dc7223542bda6d.zip |
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
Diffstat (limited to 'firmware/common')
-rw-r--r-- | firmware/common/rbpaths.c | 49 |
1 files changed, 35 insertions, 14 deletions
diff --git a/firmware/common/rbpaths.c b/firmware/common/rbpaths.c index dba39476fc..c59ef7cf65 100644 --- a/firmware/common/rbpaths.c +++ b/firmware/common/rbpaths.c | |||
@@ -28,6 +28,7 @@ | |||
28 | #include <unistd.h> | 28 | #include <unistd.h> |
29 | #include "config.h" | 29 | #include "config.h" |
30 | #include "rbpaths.h" | 30 | #include "rbpaths.h" |
31 | #include "crc32.h" | ||
31 | #include "file.h" /* MAX_PATH */ | 32 | #include "file.h" /* MAX_PATH */ |
32 | #include "logf.h" | 33 | #include "logf.h" |
33 | #include "gcc_extensions.h" | 34 | #include "gcc_extensions.h" |
@@ -52,9 +53,11 @@ | |||
52 | 53 | ||
53 | #if (CONFIG_PLATFORM & PLATFORM_ANDROID) | 54 | #if (CONFIG_PLATFORM & PLATFORM_ANDROID) |
54 | static const char rbhome[] = "/sdcard"; | 55 | static const char rbhome[] = "/sdcard"; |
55 | #endif | 56 | #elif (CONFIG_PLATFORM & (PLATFORM_SDL|PLATFORM_MAEMO|PLATFORM_PANDORA)) && !defined(__PCTOOL__) |
56 | #if (CONFIG_PLATFORM & (PLATFORM_SDL|PLATFORM_MAEMO|PLATFORM_PANDORA)) && !defined(__PCTOOL__) | ||
57 | const char *rbhome; | 57 | const char *rbhome; |
58 | #else | ||
59 | /* YPR0, YPR1 */ | ||
60 | static const char rbhome[] = HOME_DIR; | ||
58 | #endif | 61 | #endif |
59 | 62 | ||
60 | #if !(defined(SAMSUNG_YPR0) || defined(SAMSUNG_YPR1)) && !defined(__PCTOOL__) | 63 | #if !(defined(SAMSUNG_YPR0) || defined(SAMSUNG_YPR1)) && !defined(__PCTOOL__) |
@@ -62,9 +65,6 @@ const char *rbhome; | |||
62 | * over the ones where Rockbox is installed to. Classic example would be | 65 | * over the ones where Rockbox is installed to. Classic example would be |
63 | * $HOME/.config/rockbox.org vs /usr/share/rockbox */ | 66 | * $HOME/.config/rockbox.org vs /usr/share/rockbox */ |
64 | #define HAVE_SPECIAL_DIRS | 67 | #define HAVE_SPECIAL_DIRS |
65 | #define IS_HOME(p) (!strcmp(p, rbhome)) | ||
66 | #else | ||
67 | #define IS_HOME(p) (!strcmp(p, HOME_DIR)) | ||
68 | #endif | 68 | #endif |
69 | 69 | ||
70 | /* flags for get_user_file_path() */ | 70 | /* flags for get_user_file_path() */ |
@@ -75,6 +75,7 @@ const char *rbhome; | |||
75 | #define IS_FILE (1<<1) | 75 | #define IS_FILE (1<<1) |
76 | 76 | ||
77 | #ifdef HAVE_MULTIDRIVE | 77 | #ifdef HAVE_MULTIDRIVE |
78 | static uint32_t rbhome_hash; | ||
78 | /* A special link is created under e.g. HOME_DIR/<microSD1>, e.g. to access | 79 | /* A special link is created under e.g. HOME_DIR/<microSD1>, e.g. to access |
79 | * external storage in a convinient location, much similar to the mount | 80 | * external storage in a convinient location, much similar to the mount |
80 | * point on our native targets. Here they are treated as symlink (one which | 81 | * 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, | |||
103 | } | 104 | } |
104 | #endif | 105 | #endif |
105 | 106 | ||
106 | #ifdef HAVE_SPECIAL_DIRS | ||
107 | void paths_init(void) | 107 | void paths_init(void) |
108 | { | 108 | { |
109 | #ifdef HAVE_SPECIAL_DIRS | ||
109 | /* make sure $HOME/.config/rockbox.org exists, it's needed for config.cfg */ | 110 | /* make sure $HOME/.config/rockbox.org exists, it's needed for config.cfg */ |
110 | #if (CONFIG_PLATFORM & PLATFORM_ANDROID) | 111 | #if (CONFIG_PLATFORM & PLATFORM_ANDROID) |
111 | mkdir("/sdcard/rockbox", 0777); | 112 | mkdir("/sdcard/rockbox", 0777); |
@@ -133,9 +134,14 @@ void paths_init(void) | |||
133 | snprintf(config_dir, sizeof(config_dir), "%s/.config/rockbox.org/rocks.data", home); | 134 | snprintf(config_dir, sizeof(config_dir), "%s/.config/rockbox.org/rocks.data", home); |
134 | mkdir(config_dir, 0777); | 135 | mkdir(config_dir, 0777); |
135 | #endif | 136 | #endif |
137 | #endif /* HAVE_SPECIAL_DIRS */ | ||
136 | 138 | ||
139 | #ifdef HAVE_MULTIDRIVE | ||
140 | rbhome_hash = crc_32((const void *) rbhome, strlen(rbhome), 0xffffffff); | ||
141 | #endif /* HAVE_MULTIDRIVE */ | ||
137 | } | 142 | } |
138 | 143 | ||
144 | #ifdef HAVE_SPECIAL_DIRS | ||
139 | static bool try_path(const char* filename, unsigned flags) | 145 | static bool try_path(const char* filename, unsigned flags) |
140 | { | 146 | { |
141 | if (flags & IS_FILE) | 147 | if (flags & IS_FILE) |
@@ -189,8 +195,6 @@ static const char* _get_user_file_path(const char *path, | |||
189 | return ret; | 195 | return ret; |
190 | } | 196 | } |
191 | 197 | ||
192 | #elif !defined(paths_init) | ||
193 | void paths_init(void) { } | ||
194 | #endif | 198 | #endif |
195 | 199 | ||
196 | static const char* handle_special_dirs(const char* dir, unsigned flags, | 200 | static const char* handle_special_dirs(const char* dir, unsigned flags, |
@@ -261,7 +265,14 @@ int app_rename(const char *old, const char *new) | |||
261 | * get_dir_info() */ | 265 | * get_dir_info() */ |
262 | struct __dir { | 266 | struct __dir { |
263 | DIR *dir; | 267 | DIR *dir; |
264 | IF_MD(int volumes_returned); | 268 | #ifdef HAVE_MULTIDRIVE |
269 | int volumes_returned; | ||
270 | /* A crc of rbhome is used to speed op the common case where | ||
271 | * readdir()/get_dir_info() is called on non-rbhome paths, because | ||
272 | * each call needs to check against rbhome for the virtual | ||
273 | * mount point of the external storage */ | ||
274 | uint32_t path_hash; | ||
275 | #endif | ||
265 | char path[]; | 276 | char path[]; |
266 | }; | 277 | }; |
267 | 278 | ||
@@ -278,7 +289,9 @@ struct dirinfo dir_get_info(DIR* _parent, struct dirent *dir) | |||
278 | #ifdef HAVE_MULTIDRIVE | 289 | #ifdef HAVE_MULTIDRIVE |
279 | char vol_string[VOL_ENUM_POS + 8]; | 290 | char vol_string[VOL_ENUM_POS + 8]; |
280 | sprintf(vol_string, VOL_NAMES, 1); | 291 | sprintf(vol_string, VOL_NAMES, 1); |
281 | if (!strcmp(vol_string, dir->d_name)) | 292 | if (UNLIKELY(rbhome_hash == parent->path_hash) && |
293 | /* compare path anyway because of possible hash collision */ | ||
294 | !strcmp(vol_string, dir->d_name)) | ||
282 | { | 295 | { |
283 | ret.attribute = ATTR_LINK; | 296 | ret.attribute = ATTR_LINK; |
284 | strcpy(path, MULTIDRIVE_DIR); | 297 | strcpy(path, MULTIDRIVE_DIR); |
@@ -314,9 +327,11 @@ struct dirinfo dir_get_info(DIR* _parent, struct dirent *dir) | |||
314 | 327 | ||
315 | DIR* app_opendir(const char *_name) | 328 | DIR* app_opendir(const char *_name) |
316 | { | 329 | { |
330 | size_t name_len; | ||
317 | char realpath[MAX_PATH]; | 331 | char realpath[MAX_PATH]; |
318 | const char *name = handle_special_dirs(_name, 0, realpath, sizeof(realpath)); | 332 | const char *name = handle_special_dirs(_name, 0, realpath, sizeof(realpath)); |
319 | char *buf = malloc(sizeof(struct __dir) + strlen(name)+1); | 333 | name_len = strlen(name); |
334 | char *buf = malloc(sizeof(struct __dir) + name_len+1); | ||
320 | if (!buf) | 335 | if (!buf) |
321 | return NULL; | 336 | return NULL; |
322 | 337 | ||
@@ -331,7 +346,11 @@ DIR* app_opendir(const char *_name) | |||
331 | free(buf); | 346 | free(buf); |
332 | return NULL; | 347 | return NULL; |
333 | } | 348 | } |
334 | IF_MD(this->volumes_returned = 0); | 349 | #ifdef HAVE_MULTIDRIVE |
350 | this->volumes_returned = 0; | ||
351 | this->path_hash = crc_32((const void *)this->path, name_len, 0xffffffff); | ||
352 | #endif | ||
353 | |||
335 | return (DIR*)this; | 354 | return (DIR*)this; |
336 | } | 355 | } |
337 | 356 | ||
@@ -350,9 +369,11 @@ struct dirent* app_readdir(DIR* dir) | |||
350 | #ifdef HAVE_MULTIDRIVE | 369 | #ifdef HAVE_MULTIDRIVE |
351 | /* this is not MT-safe but OK according to man readdir */ | 370 | /* this is not MT-safe but OK according to man readdir */ |
352 | static struct dirent voldir; | 371 | static struct dirent voldir; |
353 | if (d->volumes_returned < (NUM_VOLUMES-1) | 372 | if (UNLIKELY(rbhome_hash == d->path_hash) |
373 | && d->volumes_returned < (NUM_VOLUMES-1) | ||
354 | && volume_present(d->volumes_returned+1) | 374 | && volume_present(d->volumes_returned+1) |
355 | && IS_HOME(d->path)) | 375 | /* compare path anyway because of possible hash collision */ |
376 | && !strcmp(d->path, rbhome)) | ||
356 | { | 377 | { |
357 | d->volumes_returned += 1; | 378 | d->volumes_returned += 1; |
358 | sprintf(voldir.d_name, VOL_NAMES, d->volumes_returned); | 379 | sprintf(voldir.d_name, VOL_NAMES, d->volumes_returned); |