Attachment "219148.patch" to
ticket [219148ffff]
added by
andreas_kupries
2001-09-07 06:46:25.
Index: ChangeLog
===================================================================
RCS file: /cvsroot/tcl/tcl/ChangeLog,v
retrieving revision 1.538
diff -u -r1.538 ChangeLog
--- ChangeLog 2001/08/23 21:15:59 1.538
+++ ChangeLog 2001/09/06 23:43:19
@@ -1,3 +1,44 @@
+2001-09-06 Andreas Kupries <[email protected]>
+
+ * All the changes below serve to fix bug [219148] which reports a
+ 80x performance hit for file I/O on Win* systems. On my system
+ it was closer to a 120x hit. Problem report by Uwe Traum <no
+ email address available>.
+
+ The fix goes like this: The obstacle is 'FlushFileBuffers',
+ executed whenever Tcl writes data to the OS, as Tcl has to wait
+ for the disk to complete I/O, and disks are slow. We remove that
+ obstacle. This opens another problem, [file size] reports back
+ wrong numbers. So for [file size] we add the call back in. As
+ optimization we keep track of the channels which were written to
+ and flush only these.
+
+ * win/tclWinFile.c (TclpObjStat): Added a call to
+ 'TclWinFlushDirtyChannels'. This ensures that [file size] and
+ related commands report the correct size of a file even if Tcl
+ has recently written to it. Unixoid OS's always report the
+ correct size even for files with pending data, but Win*
+ syssystem don't. They only report what is actually on disk.
+
+ * win/tclWinInt.h: Added declaration of
+ 'TclWinFlushDirtyChannels', making it available to other parts
+ of the tcl core.
+
+ * win/tclWinChan.c (TclWinFlushDirtyChannels): New, internal,
+ procedure. Goes through the list of open file channels and
+ forces the OS to flush its file buffers for all which were
+ written to since the last call of this function. This is an
+ expensive operation as Tcl has to wait for the OS to complete
+ actual writes to the disk.
+
+ (FileInfo): Added dirty flag required by the procedure above.
+
+ (FileOutputProc): Removed flushing of file buffers, setting the
+ dirty flag instead. This means that the previously incurred
+ delays do not happen anymore.
+
+ (TclWinOpenFileChannel): Added initialization of 'dirty' flag.
+
2001-08-23 Andreas Kupries <[email protected]>
* win/tclWinPipe.c (BuildCommandLine): Fixed tcl Bug
Index: win/tclWinChan.c
===================================================================
RCS file: /cvsroot/tcl/tcl/win/tclWinChan.c,v
retrieving revision 1.13
diff -u -r1.13 tclWinChan.c
--- win/tclWinChan.c 2000/10/06 23:46:06 1.13
+++ win/tclWinChan.c 2001/09/06 23:44:51
@@ -40,6 +40,8 @@
int flags; /* State flags, see above for a list. */
HANDLE handle; /* Input/output file. */
struct FileInfo *nextPtr; /* Pointer to next registered file. */
+ int dirty; /* Boolean flag. Set if the OS may have data
+ * pending on the channel */
} FileInfo;
typedef struct ThreadSpecificData {
@@ -557,7 +559,7 @@
*errorCode = errno;
return -1;
}
- FlushFileBuffers(infoPtr->handle);
+ infoPtr->dirty = 1;
return bytesWritten;
}
@@ -1126,7 +1128,7 @@
infoPtr->watchMask = 0;
infoPtr->flags = appendMode;
infoPtr->handle = handle;
-
+ infoPtr->dirty = 0;
wsprintfA(channelName, "file%lx", (int) infoPtr);
infoPtr->channel = Tcl_CreateChannel(&fileChannelType, channelName,
@@ -1143,3 +1145,45 @@
return infoPtr->channel;
}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * TclWinOpenFileChannel --
+ *
+ * Constructs a File channel for the specified standard OS handle.
+ * This is a helper function to break up the construction of
+ * channels into File, Console, or Serial.
+ *
+ * Results:
+ * Returns the new channel, or NULL.
+ *
+ * Side effects:
+ * May open the channel and may cause creation of a file on the
+ * file system.
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+TclWinFlushDirtyChannels ()
+{
+ FileInfo *infoPtr;
+ ThreadSpecificData *tsdPtr;
+
+ tsdPtr = FileInit();
+
+ /*
+ * Flush all channels which are dirty, i.e. may have data pending
+ * in the OS
+ */
+
+ for (infoPtr = tsdPtr->firstFilePtr;
+ infoPtr != NULL;
+ infoPtr = infoPtr->nextPtr) {
+ if (infoPtr->dirty) {
+ FlushFileBuffers(infoPtr->handle);
+ infoPtr->dirty = 0;
+ }
+ }
+}
Index: win/tclWinFile.c
===================================================================
RCS file: /cvsroot/tcl/tcl/win/tclWinFile.c,v
retrieving revision 1.12
diff -u -r1.12 tclWinFile.c
--- win/tclWinFile.c 2001/08/23 17:37:08 1.12
+++ win/tclWinFile.c 2001/09/06 23:44:52
@@ -846,6 +846,14 @@
return -1;
}
+ /*
+ * Ensure correct file sizes by forcing the OS to write any
+ * pending data to disk. This is done only for channels which are
+ * dirty, i.e. have been written to since the last flush here.
+ */
+
+ TclWinFlushDirtyChannels ();
+
nativePath = (TCHAR *) Tcl_FSGetNativePath(pathPtr);
handle = (*tclWinProcs->findFirstFileProc)(nativePath, &data);
if (handle == INVALID_HANDLE_VALUE) {
Index: win/tclWinInt.h
===================================================================
RCS file: /cvsroot/tcl/tcl/win/tclWinInt.h,v
retrieving revision 1.9
diff -u -r1.9 tclWinInt.h
--- win/tclWinInt.h 2001/03/26 11:08:16 1.9
+++ win/tclWinInt.h 2001/09/06 23:44:52
@@ -100,6 +100,8 @@
EXTERN void TclWinInit(HINSTANCE hInst);
+EXTERN void TclWinFlushDirtyChannels _ANSI_ARGS_((void));
+
# undef TCL_STORAGE_CLASS
# define TCL_STORAGE_CLASS DLLIMPORT