From d60249a561b8d3079ab9cf94b80921063fa6d9d1 Mon Sep 17 00:00:00 2001 From: Justus Winter <4winter@informatik.uni-hamburg.de> Date: Wed, 30 Apr 2014 02:12:11 +0200 Subject: refresh libpager-singlethreaded.patch, add related patches --- .../fatfs-improve-diskfs_node_iterate.patch | 75 +++++++ debian/patches/fatfs-simplify-expr.patch | 22 ++ debian/patches/fatfs-two-pagers.patch | 238 +++++++++++++++++++++ debian/patches/libpager-singlethreaded.patch | 67 +++++- debian/patches/series | 4 + .../tmpfs-improve-diskfs_node_iterate.patch | 53 +++++ 6 files changed, 448 insertions(+), 11 deletions(-) create mode 100644 debian/patches/fatfs-improve-diskfs_node_iterate.patch create mode 100644 debian/patches/fatfs-simplify-expr.patch create mode 100644 debian/patches/fatfs-two-pagers.patch create mode 100644 debian/patches/tmpfs-improve-diskfs_node_iterate.patch (limited to 'debian') diff --git a/debian/patches/fatfs-improve-diskfs_node_iterate.patch b/debian/patches/fatfs-improve-diskfs_node_iterate.patch new file mode 100644 index 00000000..da39f92d --- /dev/null +++ b/debian/patches/fatfs-improve-diskfs_node_iterate.patch @@ -0,0 +1,75 @@ +commit d54ad18d9783729ffd7a54458bb0b941f3f14f75 +Author: Justus Winter <4winter@informatik.uni-hamburg.de> +Date: Wed Apr 30 02:04:31 2014 +0200 + + fatfs: improve diskfs_node_iterate + + Currently, diskfs_node_iterate iterates twice over all nodes in the + cache. The first time only to determine the number of nodes currently + in the cache. Simply count them instead. + + * fatfs/inode.c (nodehash_nr_items): New variable. + (diskfs_cached_lookup): Increment nodehash_nr_items. + (diskfs_cached_lookup_in_dirbuf): Likewise. + (diskfs_node_norefs): Decrement nodehash_nr_items. + (diskfs_node_iterate): Fix the type of num_nodes, use nodehash_nr_items. + +diff --git a/fatfs/inode.c b/fatfs/inode.c +index 4229806..ed6f3f0 100644 +--- a/fatfs/inode.c ++++ b/fatfs/inode.c +@@ -45,6 +45,7 @@ + #endif + + static struct node *nodehash[INOHSZ]; ++static size_t nodehash_nr_items; + + static error_t read_node (struct node *np, vm_address_t buf); + +@@ -106,6 +107,7 @@ diskfs_cached_lookup (ino64_t inum, struct node **npp) + dn->hnext->dn->hprevp = &dn->hnext; + dn->hprevp = &nodehash[INOHASH(inum)]; + nodehash[INOHASH(inum)] = np; ++ nodehash_nr_items += 1; + + pthread_spin_unlock (&diskfs_node_refcnt_lock); + +@@ -171,6 +173,7 @@ diskfs_cached_lookup_in_dirbuf (int inum, struct node **npp, vm_address_t buf) + dn->hnext->dn->hprevp = &dn->hnext; + dn->hprevp = &nodehash[INOHASH(inum)]; + nodehash[INOHASH(inum)] = np; ++ nodehash_nr_items += 1; + + pthread_spin_unlock (&diskfs_node_refcnt_lock); + +@@ -216,7 +219,8 @@ diskfs_node_norefs (struct node *np) + *np->dn->hprevp = np->dn->hnext; + if (np->dn->hnext) + np->dn->hnext->dn->hprevp = np->dn->hprevp; +- ++ nodehash_nr_items -= 1; ++ + while (last) + { + struct cluster_chain *next = last->next; +@@ -546,7 +550,8 @@ error_t + diskfs_node_iterate (error_t (*fun)(struct node *)) + { + error_t err = 0; +- int n, num_nodes = 0; ++ int n; ++ size_t num_nodes; + struct node *node, **node_list, **p; + + pthread_spin_lock (&diskfs_node_refcnt_lock); +@@ -557,9 +562,7 @@ diskfs_node_iterate (error_t (*fun)(struct node *)) + diskfs_node_refcnt_lock, but we can't hold this while locking the + individual node locks). */ + +- for (n = 0; n < INOHSZ; n++) +- for (node = nodehash[n]; node; node = node->dn->hnext) +- num_nodes++; ++ num_nodes = nodehash_nr_items; + + node_list = alloca (num_nodes * sizeof (struct node *)); + p = node_list; diff --git a/debian/patches/fatfs-simplify-expr.patch b/debian/patches/fatfs-simplify-expr.patch new file mode 100644 index 00000000..e0325db5 --- /dev/null +++ b/debian/patches/fatfs-simplify-expr.patch @@ -0,0 +1,22 @@ +commit 2dfdb4737f65a4e969f445f4b19008cf2c17895e +Author: Justus Winter <4winter@informatik.uni-hamburg.de> +Date: Wed Apr 30 01:13:47 2014 +0200 + + fatfs: simplify expression + + * fatfs/pager.c (add_pager_max_prot): Simplify expression. + +diff --git a/fatfs/pager.c b/fatfs/pager.c +index 8146e64..6180aac 100644 +--- a/fatfs/pager.c ++++ b/fatfs/pager.c +@@ -1008,8 +1008,7 @@ diskfs_max_user_pager_prot () + max_prot |= upi->max_prot; + /* Stop iterating if MAX_PROT is as filled as it is going to + get. */ +- return (max_prot +- == (VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE)) ? 1 : 0; ++ return max_prot == (VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE); + } + + disable_caching (); /* Make any silly pagers go away. */ diff --git a/debian/patches/fatfs-two-pagers.patch b/debian/patches/fatfs-two-pagers.patch new file mode 100644 index 00000000..4a9d0b9b --- /dev/null +++ b/debian/patches/fatfs-two-pagers.patch @@ -0,0 +1,238 @@ +commit c32e4ca99fc266f2fe87a84ecdb604c83d1fe0cb +Author: Justus Winter <4winter@informatik.uni-hamburg.de> +Date: Wed Apr 30 01:10:05 2014 +0200 + + fatfs: use two distinct pager buckets for the disk and file pager + + fatfs has two kinds of pagers. One for the files, one for the disk. + Previously, both were in the same port bucket. + + If a request for a file pager arrives, it most likely touches some + metadata (like the superblock). This is in turn backed by the disk + pager, so another request is generated for the disk pager. + + Seperate all pagers clearly by using two port buckets. This will + enable us to use a single thread per port bucket in the future. + + * fatfs/pager.c (pager_bucket): Rename to... + (disk_pager_bucket): ... this to make the change explicit at every + occurrence. + (file_pager_bucket): New variable. + (service_paging_requests): New function. + (create_fat_pager): Also create the file pager. + (diskfs_get_filemap): Handout pagers from the file_pager_bucket. + (diskfs_shutdown_pager): This is only concerned with the file pager. + Simplify code accordingly. + (diskfs_sync_everything): Likewise. + (diskfs_pager_users): Likewise. + (diskfs_max_user_pager_prot): Likewise. + (disable_caching): Iterate over both buckets. + (enable_caching): Likewise. + +diff --git a/fatfs/pager.c b/fatfs/pager.c +index 6180aac..f855ecf 100644 +--- a/fatfs/pager.c ++++ b/fatfs/pager.c +@@ -18,12 +18,16 @@ + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */ + ++#include + #include + #include + #include "fatfs.h" + +-/* A ports bucket to hold pager ports. */ +-struct port_bucket *pager_bucket; ++/* A ports bucket to hold disk pager ports. */ ++struct port_bucket *disk_pager_bucket; ++ ++/* A ports bucket to hold file pager ports. */ ++struct port_bucket *file_pager_bucket; + + /* Mapped image of the FAT. */ + void *fat_image; +@@ -752,16 +756,51 @@ pager_dropweak (struct user_pager_info *p __attribute__ ((unused))) + { + } + ++/* A top-level function for the paging thread that just services paging ++ requests. */ ++static void * ++service_paging_requests (void *arg) ++{ ++ struct port_bucket *pager_bucket = arg; ++ ports_manage_port_operations_multithread (pager_bucket, ++ pager_demuxer, ++ 1000, ++ 0, ++ NULL); ++ /* Not reached. */ ++ return NULL; ++} ++ + /* Create the disk pager. */ + void + create_fat_pager (void) + { ++ pthread_t thread; ++ pthread_attr_t attr; ++ error_t err; ++ ++ /* The disk pager. */ + struct user_pager_info *upi = malloc (sizeof (struct user_pager_info)); + upi->type = FAT; +- pager_bucket = ports_create_bucket (); +- diskfs_start_disk_pager (upi, pager_bucket, MAY_CACHE, 0, ++ disk_pager_bucket = ports_create_bucket (); ++ diskfs_start_disk_pager (upi, disk_pager_bucket, MAY_CACHE, 0, + bytes_per_sector * sectors_per_fat, + &fat_image); ++ ++ /* The file pager. */ ++ file_pager_bucket = ports_create_bucket (); ++ ++#define STACK_SIZE (64 * 1024) ++ pthread_attr_init (&attr); ++ pthread_attr_setstacksize (&attr, STACK_SIZE); ++#undef STACK_SIZE ++ ++ /* Make a thread to service file paging requests. */ ++ err = pthread_create (&thread, &attr, ++ service_paging_requests, file_pager_bucket); ++ if (err) ++ error (2, err, "pthread_create"); ++ pthread_detach (thread); + } + + /* Call this to create a FILE_DATA pager and return a send right. +@@ -800,7 +839,7 @@ diskfs_get_filemap (struct node *node, vm_prot_t prot) + upi->max_prot = prot; + diskfs_nref_light (node); + node->dn->pager = +- pager_create (upi, pager_bucket, MAY_CACHE, ++ pager_create (upi, file_pager_bucket, MAY_CACHE, + MEMORY_OBJECT_COPY_DELAY, 0); + if (node->dn->pager == 0) + { +@@ -881,14 +920,13 @@ diskfs_shutdown_pager () + error_t shutdown_one (void *v_p) + { + struct pager *p = v_p; +- if (p != diskfs_disk_pager) +- pager_shutdown (p); ++ pager_shutdown (p); + return 0; + } + + write_all_disknodes (); + +- ports_bucket_iterate (pager_bucket, shutdown_one); ++ ports_bucket_iterate (file_pager_bucket, shutdown_one); + + pager_sync (diskfs_disk_pager, 1); + +@@ -903,13 +941,12 @@ diskfs_sync_everything (int wait) + error_t sync_one (void *v_p) + { + struct pager *p = v_p; +- if (p != diskfs_disk_pager) +- pager_sync (p, wait); ++ pager_sync (p, wait); + return 0; + } + + write_all_disknodes (); +- ports_bucket_iterate (pager_bucket, sync_one); ++ ports_bucket_iterate (file_pager_bucket, sync_one); + pager_sync (diskfs_disk_pager, wait); + } + +@@ -926,7 +963,8 @@ disable_caching () + + /* Loop through the pagers and turn off caching one by one, + synchronously. That should cause termination of each pager. */ +- ports_bucket_iterate (pager_bucket, block_cache); ++ ports_bucket_iterate (disk_pager_bucket, block_cache); ++ ports_bucket_iterate (file_pager_bucket, block_cache); + } + + static void +@@ -954,7 +992,8 @@ enable_caching () + return 0; + } + +- ports_bucket_iterate (pager_bucket, enable_cache); ++ ports_bucket_iterate (disk_pager_bucket, enable_cache); ++ ports_bucket_iterate (file_pager_bucket, enable_cache); + } + + /* Tell diskfs if there are pagers exported, and if none, then +@@ -962,9 +1001,9 @@ enable_caching () + int + diskfs_pager_users () + { +- int npagers = ports_count_bucket (pager_bucket); ++ int npagers = ports_count_bucket (file_pager_bucket); + +- if (npagers <= 1) ++ if (npagers == 0) + return 0; + + if (MAY_CACHE) +@@ -975,8 +1014,8 @@ diskfs_pager_users () + immediately. XXX */ + sleep (1); + +- npagers = ports_count_bucket (pager_bucket); +- if (npagers <= 1) ++ npagers = ports_count_bucket (file_pager_bucket); ++ if (npagers == 0) + return 0; + + /* Darn, there are actual honest users. Turn caching back on, +@@ -984,7 +1023,7 @@ diskfs_pager_users () + enable_caching (); + } + +- ports_enable_bucket (pager_bucket); ++ ports_enable_bucket (file_pager_bucket); + + return 1; + } +@@ -995,17 +1034,15 @@ vm_prot_t + diskfs_max_user_pager_prot () + { + vm_prot_t max_prot = 0; +- int npagers = ports_count_bucket (pager_bucket); ++ int npagers = ports_count_bucket (file_pager_bucket); + +- if (npagers > 1) +- /* More than just the disk pager. */ ++ if (npagers > 0) + { + error_t add_pager_max_prot (void *v_p) + { + struct pager *p = v_p; + struct user_pager_info *upi = pager_get_upi (p); +- if (upi->type == FILE_DATA) +- max_prot |= upi->max_prot; ++ max_prot |= upi->max_prot; + /* Stop iterating if MAX_PROT is as filled as it is going to + get. */ + return max_prot == (VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE); +@@ -1017,12 +1054,12 @@ diskfs_max_user_pager_prot () + immediately. XXX */ + sleep (1); + +- ports_bucket_iterate (pager_bucket, add_pager_max_prot); ++ ports_bucket_iterate (file_pager_bucket, add_pager_max_prot); + + enable_caching (); + } + +- ports_enable_bucket (pager_bucket); ++ ports_enable_bucket (file_pager_bucket); + + return max_prot; + } diff --git a/debian/patches/libpager-singlethreaded.patch b/debian/patches/libpager-singlethreaded.patch index b515dc51..f03ba024 100644 --- a/debian/patches/libpager-singlethreaded.patch +++ b/debian/patches/libpager-singlethreaded.patch @@ -1,16 +1,42 @@ -commit 840c3b15ddf9d58cff1ce458cc3fddab3e368254 +commit 18fa27d294185abc9db774f02008f484280ddb33 Author: Justus Winter <4winter@informatik.uni-hamburg.de> Date: Sun Apr 27 09:16:40 2014 +0200 - libpager: make libpager single-threaded + XXX libpager: make libpager single-threaded - * console/pager.c ( - * ext2fs/pager.c - * libdiskfs/disk-pager.c - * storeio/pager.c + Previously, libpager used multiple threads to service requests to + memory objects. This has proven to be problematic, as paging requests + often arrive in batches, resulting in the creation of many hundred + threads. - * libpager/Makefile: Likewise. - * libpager/chg-compl.c: Likewise. + Furthermore, the semantic of paging requests requires that the + requests to an object processed in the order the messages were + delivered. This was implemented using sequence barriers in + _pager_wait_for_seqno, _pager_release_seqno, and + _pager_update_seqno{,_p}. + + Unfortunately, this means that not only do we create too many threads, + but worse, all but one thread processing requests to an object are + asleep most of the time. + + Previous attempts to introduce a fixed upper bound on the number of + threads failed because ext2fs (fatfs) used two kinds of pagers managed + by the same thread pool. This has been fixed in XXX (YYY). + + Use a single thread to service paging requests. This removes the need + for the sequence barriers, remove that code. + + This prevents paging-related thread-storms. It also seems to actually + increase the performance of the whole system, as indicated by slightly + faster Hurd package builds. + + * console/pager.c (service_paging_requests): Use a single thread. + * ext2fs/pager.c (service_paging_requests): Likewise. + * fatfs/pager.c (service_paging_requests): Likewise. + * libdiskfs/disk-pager.c (service_paging_requests): Likewise. + * storeio/pager.c (service_paging_requests): Likewise. + * libpager/chg-compl.c: Remove calls to _pager_wait_for_seqno, + _pager_release_seqno, _pager_update_seqno, and _pager_update_seqno_p. * libpager/data-request.c: Likewise. * libpager/data-return.c: Likewise. * libpager/data-unlock.c: Likewise. @@ -21,10 +47,10 @@ Date: Sun Apr 27 09:16:40 2014 +0200 * libpager/object-init.c: Likewise. * libpager/object-terminate.c: Likewise. * libpager/pager-create.c: Likewise. - * libpager/priv.h: Likewise. - * libpager/seqnos.c: Likewise. * libpager/stubs.c: Likewise. + * libpager/priv.h (struct pager): Drop fields seqno and waitingforseqno. * libpager/seqnos.c: Remove unused file. + * libpager/Makefile (SRCS): Drop seqnos.c. diff --git a/console/pager.c b/console/pager.c index 87c36f0..e40ae45 100644 @@ -47,7 +73,7 @@ index 87c36f0..e40ae45 100644 } diff --git a/ext2fs/pager.c b/ext2fs/pager.c -index f3e9489..febde8f 100644 +index 017efcc..92e9178 100644 --- a/ext2fs/pager.c +++ b/ext2fs/pager.c @@ -1198,11 +1198,9 @@ static void * @@ -61,6 +87,25 @@ index f3e9489..febde8f 100644 - NULL); + ports_manage_port_operations_one_thread (pager_bucket, + pager_demuxer, ++ 0); + /* Not reached. */ + return NULL; + } +diff --git a/fatfs/pager.c b/fatfs/pager.c +index f855ecf..623b8d4 100644 +--- a/fatfs/pager.c ++++ b/fatfs/pager.c +@@ -762,11 +762,9 @@ static void * + service_paging_requests (void *arg) + { + struct port_bucket *pager_bucket = arg; +- ports_manage_port_operations_multithread (pager_bucket, +- pager_demuxer, +- 1000, +- 0, +- NULL); ++ ports_manage_port_operations_one_thread (pager_bucket, ++ pager_demuxer, + 0); /* Not reached. */ return NULL; diff --git a/debian/patches/series b/debian/patches/series index 8662284c..d984ad4e 100644 --- a/debian/patches/series +++ b/debian/patches/series @@ -42,8 +42,12 @@ xkb-compat.patch mach-defpager-protected-payload.patch ext2fs-two-pagers.patch +fatfs-simplify-expr.patch +fatfs-two-pagers.patch #ext2fs-cache-superblock.patch libpager-singlethreaded.patch libpager-drop-seqnos.patch ext2fs-improve-diskfs_node_iterate.patch +fatfs-improve-diskfs_node_iterate.patch +tmpfs-improve-diskfs_node_iterate.patch xxx-fix-build-paper-over-gnumach-bug.patch diff --git a/debian/patches/tmpfs-improve-diskfs_node_iterate.patch b/debian/patches/tmpfs-improve-diskfs_node_iterate.patch new file mode 100644 index 00000000..fbb013bd --- /dev/null +++ b/debian/patches/tmpfs-improve-diskfs_node_iterate.patch @@ -0,0 +1,53 @@ +commit 328d69406ec81b4b8248f46fafa205c6745ef083 +Author: Justus Winter <4winter@informatik.uni-hamburg.de> +Date: Wed Apr 30 02:08:41 2014 +0200 + + tmpfs: improve diskfs_node_iterate + + Currently, diskfs_node_iterate iterates twice over all nodes. The + first time only to determine the number of nodes currently in the + cache. Simply count them instead. + + * tmpfs/node.c (all_nodes_nr_items): New variable. + (diskfs_node_norefs): Decrement all_nodes_nr_items. + (diskfs_cached_lookup): Increment all_nodes_nr_items. + (diskfs_node_iterate): Fix the type of num_nodes, use all_nodes_nr_items. + +diff --git a/tmpfs/node.c b/tmpfs/node.c +index bc0ad64..3925d00 100644 +--- a/tmpfs/node.c ++++ b/tmpfs/node.c +@@ -30,6 +30,7 @@ unsigned int num_files; + static unsigned int gen; + + struct node *all_nodes; ++static size_t all_nodes_nr_items; + + error_t + diskfs_alloc_node (struct node *dp, mode_t mode, struct node **npp) +@@ -122,6 +123,7 @@ diskfs_node_norefs (struct node *np) + np->dn->hnext->dn->hprevp = np->dn->hprevp; + np->dn->hnext = 0; + np->dn->hprevp = 0; ++ all_nodes_nr_items -= 1; + } + + free (np); +@@ -186,6 +188,7 @@ diskfs_cached_lookup (ino_t inum, struct node **npp) + dn->hnext->dn->hprevp = &dn->hnext; + dn->hprevp = &all_nodes; + all_nodes = np; ++ all_nodes_nr_items += 1; + pthread_spin_unlock (&diskfs_node_refcnt_lock); + + st = &np->dn_stat; +@@ -233,8 +236,7 @@ diskfs_node_iterate (error_t (*fun) (struct node *)) + diskfs_node_refcnt_lock, but we can't hold this while locking the + individual node locks). */ + +- for (node = all_nodes; node != 0; node = node->dn->hnext) +- num_nodes++; ++ num_nodes = all_nodes_nr_items; + + p = node_list = alloca (num_nodes * sizeof (struct node *)); + for (node = all_nodes; node != 0; node = node->dn->hnext) -- cgit v1.2.3