CompuServe Messages

Writing Disk Driver

    07-Mar-94 23:57:04
Sb: Writing Disk Driver
Fm: James Luther 75300,724
To: Susan G. Conger 76360,500
>>>By the way, I contacted Developer's Support on this issue any their response was, >>>we knew the file system was slow however we didn't realize it was that slow! Who told you that? I work in Apple's Developer Technical Support group and provide primary support for the Macintosh file system and I know I didn't give you that answer. If you need more help and are an Apple Partner, write to DevSupport again and put "Attn: Jim Luther" in the subject. There are several easy ways to speed up your file system I/O. I know because I'm scheduled to give a session on that subject at this year's Worldwide Developer Conference in May. Here's the top ways (going from biggest win to smallest): 1) increase the size of your I/O operations. 32K reads or writes will get you above the knee of the performance curve on most devices except for older floppy disks and 150K per second CD-ROM drives. 64K is about right for best CD-ROM performance. 2) Align your read and write operations to 512-byte boundaries and make your requests in multiples of 512-bytes. 3) Use the file system cache wisely. The Macintosh file system uses a simple block cache mechanism that seems to have been designed mostly to make writing the HFS file system easy. It handles random block reads and writes very nicely. However, most programs I've seen either read/write a file in one big I/O operation or somewhat sequentially in random sized chunks and rarely do they use the same data more than once in a short period of time (over longer periods, it's very likely that the data will be flushed out of the cache). So, if you don't need your data cached, set the noCacheBit in your I/O operations. You'll speed up the whole ssystem since youre reads and writes won't be flushing other cached data. Here's the functions you can use: pascal OSErr FSReadNoCache(short refNum, long *count, void *buffPtr) { ParamBlockRec pb; OSErr error; pb.ioParam.ioRefNum = refNum; pb.ioParam.ioBuffer = buffPtr; pb.ioParam.ioReqCount = *count; pb.ioParam.ioPosMode = fsAtMark + 0x0020; /* fsAtMark + noCacheBit */ pb.ioParam.ioPosOffset = 0; error = PBReadSync(&pb); *count = pb.ioParam.ioActCount; return (error); } pascal OSErr FSWriteNoCache(short refNum, long *count, const void *buffPtr) { ParamBlockRec pb; OSErr error; pb.ioParam.ioRefNum = refNum; pb.ioParam.ioBuffer = (Ptr)buffPtr; pb.ioParam.ioReqCount = *count; pb.ioParam.ioPosMode = fsAtMark + 0x0020; /* fsAtMark + noCacheBit */ pb.ioParam.ioPosOffset = 0; error = PBWriteSync(&pb); *count = pb.ioParam.ioActCount; return (error); } 4) Don't use FlushVol unless you've made a change to the volume you can see with PBGetCatInfo. Don't use FlushFile unless you've made a change you can see by reading the file. 5) Preallocate the space for your file in large chunks. You (more than the file system) probably have a prety good idea how big your file is going to be before you write it. If you preallocate the space for the file with SetEOF, the file blocks will be allocated in large contiguous chunks (probably in one big chunk) and each write can skip quickly over the code that allocates more space for the file. Use SetEOF instead of Allocate because it ensures the blocks are permanently claimed (unused blocks between the logical EOF and physical EOF are released with the file or volume is flushed). 6) Do your own buffered I/O. Read or write in large chunks and use the data in the buffer. Again, you *know* how you're going to use the data – the file system can only make a stupid guess. 7) Use overlapping asynchronous I/O. It doesn't do much now on most systems, but in the future it will. SCSI Manager 4.3 on the AV systems now lets you start an asynchronous operation and crunch on other data while the SCSI system gets the requested data.