Skip to content

Commit 18d8a82

Browse files
authored
[CORE] Enable and improve buffered IO in LocalFile to reduce its cost by up to 90% (#1299)
1 parent e6339f0 commit 18d8a82

File tree

3 files changed

+67
-72
lines changed

3 files changed

+67
-72
lines changed

Core/GameEngine/Include/Common/GameDefines.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,3 +47,9 @@
4747
#ifndef ENABLE_CONFIGURABLE_SHROUD
4848
#define ENABLE_CONFIGURABLE_SHROUD (1) // When enabled, the GlobalData contains a field to turn on/off the shroud, otherwise shroud is always enabled
4949
#endif
50+
51+
// Enable buffered IO in File System. Was disabled in retail game.
52+
// Buffered IO generally is much faster than unbuffered for small reads and writes.
53+
#ifndef USE_BUFFERED_IO
54+
#define USE_BUFFERED_IO (1)
55+
#endif

Core/GameEngine/Include/Common/LocalFile.h

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -54,12 +54,7 @@
5454

5555
#include "Common/file.h"
5656

57-
// srj sez: this was purely an experiment in optimization.
58-
// at the present time, it doesn't appear to be a good one.
59-
// but I am leaving the code in for now.
60-
// if still present in 2003, please nuke.
61-
#define NO_USE_BUFFERED_IO
62-
#ifdef USE_BUFFERED_IO
57+
#if USE_BUFFERED_IO
6358
#include <stdio.h>
6459
#endif
6560

@@ -85,11 +80,12 @@ class LocalFile : public File
8580
MEMORY_POOL_GLUE_ABC(LocalFile)
8681
private:
8782

88-
#ifdef USE_BUFFERED_IO
83+
#if USE_BUFFERED_IO
84+
// srj sez: this was purely an experiment in optimization.
85+
// at the present time, it doesn't appear to be a good one.
86+
// TheSuperHackers @info It is a good optimization and will be
87+
// significantly faster than unbuffered IO with small reads and writes.
8988
FILE* m_file;
90-
91-
enum { BUF_SIZE = 32768 };
92-
char m_vbuf[BUF_SIZE];
9389
#else
9490
int m_handle; ///< Local C file handle
9591
#endif

Core/GameEngine/Source/Common/System/LocalFile.cpp

Lines changed: 55 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ static Int s_totalOpen = 0;
107107
//=================================================================
108108

109109
LocalFile::LocalFile()
110-
#ifdef USE_BUFFERED_IO
110+
#if USE_BUFFERED_IO
111111
: m_file(NULL)
112112
#else
113113
: m_handle(-1)
@@ -127,7 +127,7 @@ LocalFile::LocalFile()
127127

128128
LocalFile::~LocalFile()
129129
{
130-
#ifdef USE_BUFFERED_IO
130+
#if USE_BUFFERED_IO
131131
if (m_file)
132132
{
133133
fclose(m_file);
@@ -167,61 +167,54 @@ Bool LocalFile::open( const Char *filename, Int access )
167167
}
168168

169169
/* here we translate WSYS file access to the std C equivalent */
170-
#ifdef USE_BUFFERED_IO
171-
char mode[32];
172-
char* m = mode;
173-
174-
if (m_access & APPEND)
170+
#if USE_BUFFERED_IO
171+
172+
// r open for reading (The file must exist)
173+
// w open for writing (creates file if it doesn't exist). Deletes content and overwrites the file.
174+
// a open for appending (creates file if it doesn't exist).
175+
// r+ open for reading and writing (The file must exist).
176+
// w+ open for reading and writing.
177+
// If file exists deletes content and overwrites the file, otherwise creates an empty new file.
178+
// a+ open for reading and writing (append if file exists).
179+
180+
const Bool write = (m_access & WRITE) != 0;
181+
const Bool readwrite = (m_access & READWRITE) == READWRITE;
182+
const Bool append = (m_access & APPEND) != 0;
183+
const Bool create = (m_access & CREATE) != 0;
184+
const Bool truncate = (m_access & TRUNCATE) != 0;
185+
const Bool binary = (m_access & BINARY) != 0;
186+
187+
const Char *mode = NULL;
188+
189+
// Mode string selection (mimics _open flag combinations)
190+
// TEXT is implicit for fopen if 'b' is not present
191+
// READ is implicit here if not READWRITE or WRITE
192+
if (readwrite)
175193
{
176-
DEBUG_CRASH(("not yet supported by buffered mode"));
177-
}
178-
179-
if (m_access & TRUNCATE)
180-
{
181-
DEBUG_CRASH(("not yet supported by buffered mode"));
182-
}
183-
184-
if((m_access & READWRITE ) == READWRITE )
185-
{
186-
if (m_access & CREATE)
187-
{
188-
*m++ = 'w';
189-
*m++ = '+';
190-
}
194+
if (append)
195+
mode = binary ? "a+b" : "a+";
196+
else if (truncate || create)
197+
mode = binary ? "w+b" : "w+";
191198
else
192-
{
193-
*m++ = 'r';
194-
*m++ = '+';
195-
}
199+
mode = binary ? "r+b" : "r+";
196200
}
197-
else if(m_access & WRITE)
198-
{
199-
*m++ = 'w';
200-
}
201-
else
202-
{
203-
*m++ = 'r';
204-
DEBUG_ASSERTCRASH(!(m_access & TRUNCATE), ("cannot truncate with read-only"));
205-
}
206-
207-
if (m_access & TEXT)
201+
else if (write)
208202
{
209-
*m++ = 't';
203+
if (append)
204+
mode = binary ? "ab" : "a";
205+
else
206+
mode = binary ? "wb" : "w";
210207
}
211-
if (m_access & BINARY)
208+
else // implicitly read-only
212209
{
213-
*m++ = 'b';
210+
mode = binary ? "rb" : "r";
214211
}
215212

216-
*m++ = 0;
217-
218213
m_file = fopen(filename, mode);
219214
if (m_file == NULL)
220215
{
221216
goto error;
222217
}
223-
224-
//setvbuf(m_file, m_vbuf, _IOFBF, sizeof(BUF_SIZE));
225218

226219
#else
227220

@@ -257,7 +250,7 @@ Bool LocalFile::open( const Char *filename, Int access )
257250
flags |= _O_WRONLY;
258251
flags |= _O_CREAT;
259252
}
260-
else
253+
else // implicitly read-only
261254
{
262255
flags |= _O_RDONLY;
263256
}
@@ -318,15 +311,15 @@ Int LocalFile::read( void *buffer, Int bytes )
318311

319312
if (buffer == NULL)
320313
{
321-
#ifdef USE_BUFFERED_IO
314+
#if USE_BUFFERED_IO
322315
fseek(m_file, bytes, SEEK_CUR);
323316
#else
324317
_lseek(m_handle, bytes, SEEK_CUR);
325318
#endif
326319
return bytes;
327320
}
328321

329-
#ifdef USE_BUFFERED_IO
322+
#if USE_BUFFERED_IO
330323
Int ret = fread(buffer, 1, bytes, m_file);
331324
#else
332325
Int ret = _read( m_handle, buffer, bytes );
@@ -347,7 +340,7 @@ Int LocalFile::write( const void *buffer, Int bytes )
347340
return -1;
348341
}
349342

350-
#ifdef USE_BUFFERED_IO
343+
#if USE_BUFFERED_IO
351344
Int ret = fwrite(buffer, 1, bytes, m_file);
352345
#else
353346
Int ret = _write( m_handle, buffer, bytes );
@@ -366,21 +359,21 @@ Int LocalFile::seek( Int pos, seekMode mode)
366359
switch( mode )
367360
{
368361
case START:
362+
DEBUG_ASSERTCRASH(pos >= 0, ("LocalFile::seek - pos must be >= 0 when seeking from the beginning of the file"));
369363
lmode = SEEK_SET;
370364
break;
371365
case CURRENT:
372366
lmode = SEEK_CUR;
373367
break;
374368
case END:
375-
DEBUG_ASSERTCRASH(pos <= 0, ("LocalFile::seek - pos should be <= 0 for a seek starting at the end of the file"));
376369
lmode = SEEK_END;
377370
break;
378371
default:
379-
// bad seek mode
372+
DEBUG_CRASH(("LocalFile::seek - bad seek mode"));
380373
return -1;
381374
}
382375

383-
#ifdef USE_BUFFERED_IO
376+
#if USE_BUFFERED_IO
384377
Int ret = fseek(m_file, pos, lmode);
385378
if (ret == 0)
386379
return ftell(m_file);
@@ -406,7 +399,7 @@ Bool LocalFile::scanInt(Int &newInt)
406399

407400
// skip preceding non-numeric characters
408401
do {
409-
#ifdef USE_BUFFERED_IO
402+
#if USE_BUFFERED_IO
410403
val = fread(&c, 1, 1, m_file);
411404
#else
412405
val = _read( m_handle, &c, 1);
@@ -419,7 +412,7 @@ Bool LocalFile::scanInt(Int &newInt)
419412

420413
do {
421414
tempstr.concat(c);
422-
#ifdef USE_BUFFERED_IO
415+
#if USE_BUFFERED_IO
423416
val = fread(&c, 1, 1, m_file);
424417
#else
425418
val = _read( m_handle, &c, 1);
@@ -428,7 +421,7 @@ Bool LocalFile::scanInt(Int &newInt)
428421

429422
// put the last read char back, since we didn't use it.
430423
if (val != 0) {
431-
#ifdef USE_BUFFERED_IO
424+
#if USE_BUFFERED_IO
432425
fseek(m_file, -1, SEEK_CUR);
433426
#else
434427
_lseek(m_handle, -1, SEEK_CUR);
@@ -454,7 +447,7 @@ Bool LocalFile::scanReal(Real &newReal)
454447

455448
// skip the preceding white space
456449
do {
457-
#ifdef USE_BUFFERED_IO
450+
#if USE_BUFFERED_IO
458451
val = fread(&c, 1, 1, m_file);
459452
#else
460453
val = _read( m_handle, &c, 1);
@@ -470,15 +463,15 @@ Bool LocalFile::scanReal(Real &newReal)
470463
if (c == '.') {
471464
sawDec = TRUE;
472465
}
473-
#ifdef USE_BUFFERED_IO
466+
#if USE_BUFFERED_IO
474467
val = fread(&c, 1, 1, m_file);
475468
#else
476469
val = _read(m_handle, &c, 1);
477470
#endif
478471
} while ((val != 0) && (((c >= '0') && (c <= '9')) || ((c == '.') && !sawDec)));
479472

480473
if (val != 0) {
481-
#ifdef USE_BUFFERED_IO
474+
#if USE_BUFFERED_IO
482475
fseek(m_file, -1, SEEK_CUR);
483476
#else
484477
_lseek(m_handle, -1, SEEK_CUR);
@@ -503,7 +496,7 @@ Bool LocalFile::scanString(AsciiString &newString)
503496

504497
// skip the preceding whitespace
505498
do {
506-
#ifdef USE_BUFFERED_IO
499+
#if USE_BUFFERED_IO
507500
val = fread(&c, 1, 1, m_file);
508501
#else
509502
val = _read(m_handle, &c, 1);
@@ -516,15 +509,15 @@ Bool LocalFile::scanString(AsciiString &newString)
516509

517510
do {
518511
newString.concat(c);
519-
#ifdef USE_BUFFERED_IO
512+
#if USE_BUFFERED_IO
520513
val = fread(&c, 1, 1, m_file);
521514
#else
522515
val = _read(m_handle, &c, 1);
523516
#endif
524517
} while ((val != 0) && (!isspace(c)));
525518

526519
if (val != 0) {
527-
#ifdef USE_BUFFERED_IO
520+
#if USE_BUFFERED_IO
528521
fseek(m_file, -1, SEEK_CUR);
529522
#else
530523
_lseek(m_handle, -1, SEEK_CUR);
@@ -547,13 +540,13 @@ void LocalFile::nextLine(Char *buf, Int bufSize)
547540
// seek to the next new-line.
548541
do {
549542
if ((buf == NULL) || (i >= (bufSize-1))) {
550-
#ifdef USE_BUFFERED_IO
543+
#if USE_BUFFERED_IO
551544
val = fread(&c, 1, 1, m_file);
552545
#else
553546
val = _read(m_handle, &c, 1);
554547
#endif
555548
} else {
556-
#ifdef USE_BUFFERED_IO
549+
#if USE_BUFFERED_IO
557550
val = fread(buf + i, 1, 1, m_file);
558551
#else
559552
val = _read(m_handle, buf + i, 1);

0 commit comments

Comments
 (0)