forums.ps2dev.org Forum Index forums.ps2dev.org
Homebrew PS2, PSP & PS3 Development Discussions
 
 FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

Better I/O performances with a different BUFSIZ

 
Post new topic   Reply to topic    forums.ps2dev.org Forum Index -> PSP Development
View previous topic :: View next topic  
Author Message
Beuc



Joined: 26 Mar 2009
Posts: 33
Location: holland

PostPosted: Tue Jul 07, 2009 12:57 am    Post subject: Better I/O performances with a different BUFSIZ Reply with quote

Hi,

I saw that the memory stick access is pretty unefficient when using fread(3).

From what I can see this is because BUFSIZ is set to 1024 in the psptoolchain, and it could be improved to up to 8x.

How about using a BUFSIZ value like 65k to (dramatically) improve Memory Stick perfs?


I did the following tests with read(2):
Code:

test_bufsiz=     512 - read(2): 31493ms (22048501B, 700.11B/s)
test_bufsiz=    1024 - read(2): 16443ms (22048501B, 1340.91B/s)
test_bufsiz=    2048 - read(2):  8964ms (22048501B, 2459.67B/s)
test_bufsiz=    4096 - read(2):  5457ms (22048501B, 4040.41B/s)
test_bufsiz=    8192 - read(2):  3703ms (22048501B, 5954.23B/s)
test_bufsiz=   16384 - read(2):  2842ms (22048501B, 7758.09B/s)
test_bufsiz=   32768 - read(2):  2391ms (22048501B, 9221.46B/s)
test_bufsiz=   65536 - read(2):  2162ms (22048501B, 10198.20B/s)
test_bufsiz=  131072 - read(2):  2126ms (22048501B, 10370.88B/s)
test_bufsiz=  262144 - read(2):  2113ms (22048501B, 10434.69B/s)
test_bufsiz=  524288 - read(2):  2104ms (22048501B, 10479.33B/s)
test_bufsiz= 1048576 - read(2):  2099ms (22048501B, 10504.29B/s)
test_bufsiz= 2097152 - read(2):  2097ms (22048501B, 10514.31B/s)
test_bufsiz= 4194304 - read(2):  2096ms (22048501B, 10519.32B/s)
test_bufsiz= 8388608 - read(2):  2094ms (22048501B, 10529.37B/s)
test_bufsiz=16777216 - read(2):  2095ms (22048501B, 10524.34B/s)


Source code:
Code:

#include <stdio.h>
#include <stdlib.h>

#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

#include <SDL/SDL.h>

#include <pspmoduleinfo.h>
PSP_HEAP_SIZE_MAX();

int main()
{
  SDL_Init(SDL_INIT_EVERYTHING);
  Uint32 start;
  printf("I/O perf test\n");

  int i;
  for (i = 9; i <= 24; i++)
    {
      int test_bufsiz = 1<<i;
      char* buf = malloc(test_bufsiz);
      if (buf == NULL) printf("out of memory\n"), exit(0);
      printf("test_bufsiz=%8d -", test_bufsiz);

      start = SDL_GetTicks();
      int nb_read = 0;
      int total = 0;
      int din = open("ms0:/340.PBP", 0);
      while ((nb_read = read(din, buf, test_bufsiz)) > 0) total += nb_read;
      int t = SDL_GetTicks() - start;
      printf(" read(2): %5dms (%8dB, %.2fB/s)", t, total, 1.0*total/t);
      close(din);

      printf("\n");
      free(buf);
    }

  SDL_Quit();
  return 0;
}


We can compare with fread, which internally uses 1024:
Code:

test_bufsiz=     512 - fread(3): 28748ms (22048256B, 766.95B/s)
test_bufsiz=    1024 - fread(3): 28704ms (22047744B, 768.11B/s)
test_bufsiz=    2048 - fread(3): 28348ms (22046720B, 777.72B/s)
test_bufsiz=    4096 - fread(3): 28681ms (22044672B, 768.62B/s)
test_bufsiz=    8192 - fread(3): 28712ms (22044672B, 767.79B/s)
test_bufsiz=   16384 - fread(3): 28376ms (22036480B, 776.59B/s)
test_bufsiz=   32768 - fread(3): 28742ms (22020096B, 766.13B/s)
test_bufsiz=   65536 - fread(3): 28725ms (22020096B, 766.58B/s)
test_bufsiz=  131072 - fread(3): 28379ms (22020096B, 775.93B/s)
test_bufsiz=  262144 - fread(3): 28741ms (22020096B, 766.16B/s)
test_bufsiz=  524288 - fread(3): 28722ms (22020096B, 766.66B/s)
test_bufsiz= 1048576 - fread(3): 28372ms (22020096B, 776.12B/s)
test_bufsiz= 2097152 - fread(3): 28735ms (20971520B, 729.82B/s)
test_bufsiz= 4194304 - fread(3): 28726ms (20971520B, 730.05B/s)
test_bufsiz= 8388608 - fread(3): 28367ms (16777216B, 591.43B/s)
test_bufsiz=16777216 - fread(3): 28725ms (16777216B, 584.06B/s)


(The byte counts is not accurate because fread(3) only returns "I got it all" or "I didn't got it all", without details on how much data was read in a partial read, but the timing data remains right.)

Source code:
Code:

#include <stdio.h>
#include <stdlib.h>

#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

#include <SDL/SDL.h>

#include <pspmoduleinfo.h>
PSP_HEAP_SIZE_MAX();

int main()
{
  SDL_Init(SDL_INIT_EVERYTHING);
  Uint32 start;
  printf("I/O perf test\n");

  int i;
  for (i = 9; i <= 24; i++)
    {
      int test_bufsiz = 1<<i;
      char* buf = malloc(test_bufsiz);
      if (buf == NULL) printf("out of memory\n"), exit(0);
      printf("test_bufsiz=%8d -", test_bufsiz);

      start = SDL_GetTicks();
      int total2 = 0;
      FILE* fin = fopen("ms0:/340.PBP", "rb");
      while (fread(buf, test_bufsiz, 1, fin)) total2 += test_bufsiz;
      int t = SDL_GetTicks() - start;
      printf(" fread(3): %5dms (%8dB, %.2fB/s)", t, total2, 1.0*total2/t);
      fclose(fin);

      printf("\n");
      free(buf);
    }

  SDL_Quit();
  return 0;
}
Back to top
View user's profile Send private message
jimparis



Joined: 10 Jun 2005
Posts: 1179
Location: Boston

PostPosted: Tue Jul 07, 2009 3:03 am    Post subject: Reply with quote

sure, if you could write a patch I'll apply it.
Back to top
View user's profile Send private message
TyRaNiD



Joined: 18 Jan 2004
Posts: 918

PostPosted: Tue Jul 07, 2009 3:07 am    Post subject: Reply with quote

Urm be careful though (I haven't checked where the buffer is defined) but there is always the risk that increasing the size could make existing code fail due to higher memory requirements (well when recompiled against a new libc).

If it is a static buffer (I guess likely) then you could blow away almost an extra meg of ram if someone opened as many MS files as they can. If it is stack based there is the risk of stack overflow which are really bastards to track down on the PSP.

As I have always tried to point out, libc is there more for glue code to make porting easier than something which you should rely on in a memory limited embedded system.
Back to top
View user's profile Send private message
Beuc



Joined: 26 Mar 2009
Posts: 33
Location: holland

PostPosted: Tue Jul 07, 2009 3:59 am    Post subject: Reply with quote

jimparis wrote:
sure, if you could write a patch I'll apply it.


I'll give this a try!

TyRaNiD wrote:
Urm be careful though (I haven't checked where the buffer is defined) but there is always the risk that increasing the size could make existing code fail due to higher memory requirements (well when recompiled against a new libc).

If it is a static buffer (I guess likely) then you could blow away almost an extra meg of ram if someone opened as many MS files as they can. If it is stack based there is the risk of stack overflow which are really bastards to track down on the PSP.

As I have always tried to point out, libc is there more for glue code to make porting easier than something which you should rely on in a memory limited embedded system.


Yes, a too big buffer sound like a bad idea. Plus it's only 8192k in GNU/Linux (though that's an efficient value there) - better remain on the same order of magnitude.

Still, fread(3) is used by lots of games, if only through SDL (and SDL_rwops.c), so it's worth the trouble :)
Back to top
View user's profile Send private message
J.F.



Joined: 22 Feb 2004
Posts: 2906

PostPosted: Tue Jul 07, 2009 4:05 am    Post subject: Reply with quote

I'd suggest something like the PSP_HEAP_SIZE_XXX defines... make a weak variable called something like "_fread_bufsize" that defaults to 1024 when not defined, but otherwise takes the defined value. That way, someone who's aware of the memory constraint and wants the fastest speed can add "PSP_FREAD_BUFSIZE(65536);" to the application to set the buffer size explicitly.

Look at the sbrk code in newlib to see how the heap size is handled.
Back to top
View user's profile Send private message AIM Address
coolkehon



Joined: 20 Oct 2008
Posts: 355

PostPosted: Tue Jul 07, 2009 4:30 am    Post subject: Reply with quote

this sound like a good idea
note: just posting so that i will get notified by email because i dont know how to watch this topic =)
Back to top
View user's profile Send private message MSN Messenger
Beuc



Joined: 26 Mar 2009
Posts: 33
Location: holland

PostPosted: Tue Jul 07, 2009 5:17 am    Post subject: Reply with quote

J.F. wrote:
I'd suggest something like the PSP_HEAP_SIZE_XXX defines... make a weak variable called something like "_fread_bufsize" that defaults to 1024 when not defined, but otherwise takes the defined value. That way, someone who's aware of the memory constraint and wants the fastest speed can add "PSP_FREAD_BUFSIZE(65536);" to the application to set the buffer size explicitly.

Look at the sbrk code in newlib to see how the heap size is handled.


Well, BUFSIZ is used in a lot of statically allocated variables, including outside of newlib, so I think it needs to stay constant.

Maybe we can use this technique to change the FILE* internal buffer size though.
(apparently this happens in newlib/libc/stdio/makebuf.c:109)
Back to top
View user's profile Send private message
Beuc



Joined: 26 Mar 2009
Posts: 33
Location: holland

PostPosted: Tue Jul 07, 2009 8:26 am    Post subject: Reply with quote

Beuc wrote:
Maybe we can use this technique to change the FILE* internal buffer size though.
(apparently this happens in newlib/libc/stdio/makebuf.c:109)


I tried the following patch:
Code:

--- newlib-1.16.0.bak/newlib/libc/stdio/makebuf.c   2007-05-02 01:03:36.000000000 +0200
+++ newlib-1.16.0-psp/newlib/libc/stdio/makebuf.c   2009-07-06 23:56:19.000000000 +0200
@@ -74,8 +74,12 @@
 #ifdef HAVE_BLKSIZE
       size = st.st_blksize <= 0 ? BUFSIZ : st.st_blksize;
 #else
+#if defined(__psp__)
+      size = 65536;
+#else
       size = BUFSIZ;
 #endif
+#endif
       /*
        * Optimize fseek() only if it is a regular file.
        * (The test for __sseek is mainly paranoia.)


Here's the results of the fread(3) loop with different values:
Code:

newlib size =    1024 - fread(3): 26929ms (current)
newlib size =    4096 - fread(3): 11260ms
newlib size =   32768 - fread(3):  3467ms
newlib size =   65536 - fread(3):  2885ms
newlib size =  131072 - fread(3):  2595ms
newlib size = 1048576 - fread(3):  2367ms

It doesn't matter what test_bufsiz you use, the perfs are the same with +/- 50ms.
(btw perfs are slightly better than in my first post because I rebooted from fw 1.50 to 5.00 during the afternoon - 65k perfs for fw 1.50 are around 2925ms).

This looks promising :)

Also:
TyRaNiD wrote:
If it is a static buffer (I guess likely) then you could blow away almost an extra meg of ram if someone opened as many MS files as they can. If it is stack based there is the risk of stack overflow which are really bastards to track down on the PSP.


AFAICS it's a malloc:
Code:

  if ((p = _malloc_r (ptr, size)) == NULL)


I also see that the PSP crash when open more than 10 files at once. So the increased memory usage is at most (65k-1k)*10 = 640k.


We need to perform some _write_ test now.
If write performances are not harmed I think this patch is enough. BUFSIZ is not changed, and still does not represent an efficient buffer size, but there may be less issues with only altering 'size'.

What do you think?
Back to top
View user's profile Send private message
Beuc



Joined: 26 Mar 2009
Posts: 33
Location: holland

PostPosted: Tue Jul 07, 2009 8:48 am    Post subject: Reply with quote

Hmmm, BAD news.

I tried recompiling the game port I'm working on (GNU FreeDink), and apparently this patch dramatically _harms_ the loading time.

I suppose that when accessing lots of small files or when doing a decent number of fseek()s, reading big chunks (with a 65k buffer) harm performances (like 4x slower) more than when reading small chunks (with a 1k buffer).

Ah well..
Back to top
View user's profile Send private message
J.F.



Joined: 22 Feb 2004
Posts: 2906

PostPosted: Tue Jul 07, 2009 9:05 am    Post subject: Reply with quote

Beuc wrote:
Hmmm, BAD news.

I tried recompiling the game port I'm working on (GNU FreeDink), and apparently this patch dramatically _harms_ the loading time.

I suppose that when accessing lots of small files or when doing a decent number of fseek()s, reading big chunks (with a 65k buffer) harm performances (like 4x slower) more than when reading small chunks (with a 1k buffer).

Ah well..


I suppose fread needs to be made smarter - only reading what is asked for on the first read, but reading larger amounts if the next (one or two or more) freads are all sequential. That way sequential reads are sped up, while small random reads aren't slowed by reading large amounts that won't be used.
Back to top
View user's profile Send private message AIM Address
TyRaNiD



Joined: 18 Jan 2004
Posts: 918

PostPosted: Wed Jul 08, 2009 2:56 am    Post subject: Reply with quote

640K is still quite a sizable increase :)
Back to top
View user's profile Send private message
Beuc



Joined: 26 Mar 2009
Posts: 33
Location: holland

PostPosted: Wed Jul 08, 2009 7:18 am    Post subject: Reply with quote

AFAICS access time for small files doesn't change, this only impacts smalls reads in larger files:
Code:

test_bufsiz=    1024 - read(2):   401ms - lseek(2):   467ms
test_bufsiz=    2048 - read(2):   397ms - lseek(2):   444ms
test_bufsiz=    4096 - read(2):   397ms - lseek(2):   803ms
test_bufsiz=    8192 - read(2):   398ms - lseek(2):   766ms
test_bufsiz=   16384 - read(2):   397ms - lseek(2):   846ms
test_bufsiz=   32768 - read(2):   398ms - lseek(2):   995ms
test_bufsiz=   65536 - read(2):   397ms - lseek(2):  1425ms
test_bufsiz=  131072 - read(2):   399ms - lseek(2):  2069ms
test_bufsiz=  262144 - read(2):   398ms - lseek(2):  3320ms
test_bufsiz=  524288 - read(2):   397ms - lseek(2):  5827ms
test_bufsiz= 1048576 - read(2):   397ms - lseek(2): 10873ms


Source code:
Code:

#include <stdio.h>
#include <stdlib.h>

#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

#include <SDL/SDL.h>

#include <pspmoduleinfo.h>
PSP_HEAP_SIZE_MAX();

int main()
{
  SDL_Init(SDL_INIT_EVERYTHING);
  Uint32 start;
  printf("I/O perf test\n");

  int i;
  for (i = 10; i <= 20; i++)
    {
      int n;
      int test_bufsiz = 1<<i;
      char* buf = malloc(test_bufsiz);
      if (buf == NULL) printf("out of memory\n"), exit(0);
      printf("test_bufsiz=%8d", test_bufsiz);

      start = SDL_GetTicks();
      for (n = 0; n < 100; n++)
   {
     int nb_read = 0;
     int total = 0;
     int din = open("ms0:/batser.bin", 0);
     if (din < 0) perror("open"), exit(0);
     while ((nb_read = read(din, buf, test_bufsiz)) > 0) total += nb_read;
     close(din);
   }
      printf(" - read(2): %5dms", SDL_GetTicks() - start);

      start = SDL_GetTicks();
      int din = open("ms0:/500.PBP", 0);
      if (din < 0) perror("open"), exit(0);
      for (n = 0; n < 100; n++)
   {
     int nb_read = 0;
     int total = 0;
     if (lseek(din, 3500000, SEEK_SET) < 0)
       perror("lseek"), exit(0);
     do {
       nb_read = read(din, buf, test_bufsiz);
       total += nb_read;
     } while (total < 5000);
   }
      close(din);
      printf(" - lseek(2): %5dms", SDL_GetTicks() - start);

      printf("\n");
      free(buf);
    }

  SDL_Quit();
  return 0;
}
Back to top
View user's profile Send private message
Torch



Joined: 28 May 2008
Posts: 842

PostPosted: Thu Jul 09, 2009 12:21 am    Post subject: Reply with quote

How do the sceIO* functions handle things? Does it have another buffer or does it DMA straight into your pointer?
Back to top
View user's profile Send private message
Beuc



Joined: 26 Mar 2009
Posts: 33
Location: holland

PostPosted: Fri Jul 10, 2009 7:21 am    Post subject: Reply with quote

Hi!

Torch wrote:
How do the sceIO* functions handle things? Does it have another buffer or does it DMA straight into your pointer?


AFAICS the only software buffer is in fread(3). fread(3) itself calls read(2) which calls sceIoRead, with some reentrant (*_r) steps in-between.

The tests suggests that the PSP kernel doesn't manage cache for MS access.
Back to top
View user's profile Send private message
Display posts from previous:   
Post new topic   Reply to topic    forums.ps2dev.org Forum Index -> PSP Development All times are GMT + 10 Hours
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group