Tcl Source Code

Artifact [53581e29da]
Login

Artifact 53581e29da4858b5383dffd5599370ca20e2ce14:

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