Cygwin Filesystem Performance degradation 1.7.5 vs 1.7.7, and methods for improving performance

Yoni Londner yonihola2@gmail.com
Wed Oct 13 15:39:00 GMT 2010


Hi,

Patch for caching fs info.

Yoni.

Index: mount.cc
===================================================================
RCS file: /cvs/src/src/winsup/cygwin/mount.cc,v
retrieving revision 1.72
diff -u -p -r1.72 mount.cc
--- mount.cc	28 Sep 2010 14:49:31 -0000	1.72
+++ mount.cc	13 Oct 2010 15:20:42 -0000
@@ -48,6 +48,7 @@ details. */
  bool NO_COPY mount_info::got_usr_bin;
  bool NO_COPY mount_info::got_usr_lib;
  int NO_COPY mount_info::root_idx = -1;
+bool use_fs_info_cache = true;

  /* is_unc_share: Return non-zero if PATH begins with //server/share
  		 or with one of the native prefixes //./ or //?/
@@ -163,6 +164,99 @@ fs_info_cache::add (uint32_t hashval, fs
    fsi_lock.release ();
  }

+typedef struct fs_info_list_t {
+    struct fs_info_list_t *next;
+    fs_info fsi;
+    wchar_t path[MAX_PATH];
+    int path_len;
+} fs_info_list_t;
+
+static fs_info_list_t *fs_info_list;
+static int in_fs_info_update;
+
+int fs_info_lookup(fs_info *fsi, PUNICODE_STRING upath)
+{
+    int shortest = 0;
+    fs_info_list_t *f, *found = NULL;
+    if (in_fs_info_update)
+	return 0;
+    /* find first (longest match) */
+    for (f = fs_info_list; f != NULL; f=f->next)
+    {
+	if (!wcsncmp(f->path, upath->Buffer, f->path_len))
+	{
+	    if (!shortest || shortest > f->path_len)
+	    {
+		shortest = f->path_len;
+		found = f;
+	    }
+	}
+    }
+    if (!found)
+	return 0;
+    memcpy(fsi, &found->fsi, sizeof(fsi));
+    return 1;
+}
+
+static inline int fs_info_eq(fs_info *a, fs_info *b)
+{
+    return a->serial_number()==b->serial_number() &&
+	!memcmp(&a->status, &b->status, sizeof(a->status));
+}
+
+static void fs_info_update(fs_info *fsi, PUNICODE_STRING upath)
+{
+    wchar_t scan_path[MAX_PATH], save, *p;
+    fs_info *_fsi, *scan = NULL;
+    fs_info_list_t *f;
+    UNICODE_STRING  ustr;
+    if (in_fs_info_update)
+	return;
+    in_fs_info_update++;
+    _fsi = new fs_info();
+    _fsi->update(upath, NULL);
+    /* sanity check */
+    if (!fs_info_eq(_fsi, fsi))
+    {
+	debug_printf("fs_info_update: strange: got different volume");
+	delete _fsi;
+	goto Exit;
+    }
+    /* scan up the path to find the base directory of the mount */
+    wcscpy(scan_path, upath->Buffer);
+    while ((p=wcsrchr(scan_path, '\\')))
+    {
+	save = *p;
+	*p = 0;
+	if (p==scan_path)
+	{
+	    *p = save;
+	    break;
+	}
+	if (scan)
+	    delete scan;
+	scan = new fs_info();
+	ustr.Buffer = scan_path;
+	ustr.Length = wcslen(scan_path);
+	ustr.MaximumLength = sizeof(scan_path);
+	if (!scan->update(&ustr, NULL) || !fs_info_eq(scan, fsi))
+	{
+	    *p = save;
+	    break;
+	}
+    }
+    if (scan)
+	delete scan;
+    f = (fs_info_list_t*)calloc(sizeof(*f), 1);
+    memcpy(&f->fsi, _fsi, sizeof(_fsi));
+    f->path_len = wcslen(scan_path);
+    wcscpy(f->path, scan_path);
+    f->next = fs_info_list;
+    fs_info_list = f;
+Exit:
+    in_fs_info_update--;
+}
+
  bool
  fs_info::update (PUNICODE_STRING upath, HANDLE in_vol)
  {
@@ -183,6 +277,8 @@ fs_info::update (PUNICODE_STRING upath,
    } ffvi_buf;
    UNICODE_STRING fsname;

+  if (use_fs_info_cache && fs_info_lookup(this, upath))
+       return true;
    clear ();
    if (in_vol)
      vol = in_vol;
@@ -431,6 +527,8 @@ fs_info::update (PUNICODE_STRING upath,
    if (!in_vol)
      NtClose (vol);
    fsi_cache.add (hash, this);
+  if (use_fs_info_cache)
+       fs_info_update(this, upath);
    return true;
  }

Index: mount.h
===================================================================
RCS file: /cvs/src/src/winsup/cygwin/mount.h,v
retrieving revision 1.15
diff -u -p -r1.15 mount.h
--- mount.h	21 Sep 2010 16:32:22 -0000	1.15
+++ mount.h	13 Oct 2010 15:20:42 -0000
@@ -43,6 +43,11 @@ extern struct fs_names_t {

  class fs_info
  {
+  ULONG sernum;			/* Volume Serial Number */
+  char fsn[80];			/* Windows filesystem name */
+  unsigned long got_fs () const { return status.fs_type != none; }
+
+ public:
    struct status_flags
    {
      ULONG flags;		/* Volume flags */
@@ -59,11 +64,7 @@ class fs_info
      unsigned has_buggy_basic_info	: 1;
      unsigned has_dos_filenames_only	: 1;
    } status;
-  ULONG sernum;			/* Volume Serial Number */
-  char fsn[80];			/* Windows filesystem name */
-  unsigned long got_fs () const { return status.fs_type != none; }

- public:
    void clear ()
    {
      memset (&status, 0 , sizeof status);



More information about the Cygwin-developers mailing list