Re: [PATCH v3 2/2] erofs-utils: mkfs: introduce inter-file multi-threaded compression

2024-03-23 Thread Yifan Zhao



On 2024/3/23 11:46, Huang Jianan wrote:

Yifan Zhao  于2024年3月22日周五 18:25写道:

This patch allows parallelizing the compression process of different
files in mkfs. Specifically, a traverser thread traverses the files and
issues the compression task, which is handled by the workers. Then, the
main thread consumes them and writes the compressed data to the device.

To this end, the logic of erofs_write_compressed_file() has been
modified to split the creation and completion logic of the compression
task.

Signed-off-by: Yifan Zhao 
Co-authored-by: Tong Xin 
---
  include/erofs/compress.h |  16 ++
  include/erofs/inode.h|  17 ++
  include/erofs/internal.h |   3 +
  lib/compress.c   | 336 +--
  lib/inode.c  | 258 --
  5 files changed, 503 insertions(+), 127 deletions(-)

diff --git a/include/erofs/compress.h b/include/erofs/compress.h
index 871db54..8d5a54b 100644
--- a/include/erofs/compress.h
+++ b/include/erofs/compress.h
@@ -17,6 +17,22 @@ extern "C"
  #define EROFS_CONFIG_COMPR_MAX_SZ  (4000 * 1024)
  #define Z_EROFS_COMPR_QUEUE_SZ (EROFS_CONFIG_COMPR_MAX_SZ * 2)

+#ifdef EROFS_MT_ENABLED
+struct z_erofs_mt_file {
+   pthread_mutex_t mutex;
+   pthread_cond_t cond;
+   int total;
+   int nfini;
+
+   int fd;
+   struct erofs_compress_work *head;
+
+   struct z_erofs_mt_file *next;
+};
+
+int z_erofs_mt_reap(struct z_erofs_mt_file *desc);
+#endif
+
  void z_erofs_drop_inline_pcluster(struct erofs_inode *inode);
  int erofs_write_compressed_file(struct erofs_inode *inode, int fd, u64 fpos);

diff --git a/include/erofs/inode.h b/include/erofs/inode.h
index d5a732a..101ff59 100644
--- a/include/erofs/inode.h
+++ b/include/erofs/inode.h
@@ -41,6 +41,23 @@ struct erofs_inode *erofs_new_inode(void);
  struct erofs_inode *erofs_mkfs_build_tree_from_path(const char *path);
  struct erofs_inode *erofs_mkfs_build_special_from_fd(int fd, const char 
*name);

+#ifdef EROFS_MT_ENABLED
+struct erofs_inode_fifo {
+   pthread_mutex_t lock;
+   pthread_cond_t full, empty;
+
+   void *buf;
+
+   size_t size, elem_size;
+   size_t head, tail;
+};
+
+struct erofs_inode_fifo *erofs_alloc_inode_fifo(size_t size, size_t elem_size);
+void erofs_push_inode_fifo(struct erofs_inode_fifo *q, void *elem);
+void *erofs_pop_inode_fifo(struct erofs_inode_fifo *q);
+void erofs_destroy_inode_fifo(struct erofs_inode_fifo *q);
+#endif
+
  #ifdef __cplusplus
  }
  #endif
diff --git a/include/erofs/internal.h b/include/erofs/internal.h
index 4cd2059..2580588 100644
--- a/include/erofs/internal.h
+++ b/include/erofs/internal.h
@@ -250,6 +250,9 @@ struct erofs_inode {
  #ifdef WITH_ANDROID
 uint64_t capabilities;
  #endif
+#ifdef EROFS_MT_ENABLED
+   struct z_erofs_mt_file *mt_desc;
+#endif
  };

  static inline erofs_off_t erofs_iloc(struct erofs_inode *inode)
diff --git a/lib/compress.c b/lib/compress.c
index e064293..d89e404 100644
--- a/lib/compress.c
+++ b/lib/compress.c
@@ -85,6 +85,7 @@ struct erofs_compress_work {
 struct erofs_work work;
 struct z_erofs_compress_sctx ctx;
 struct erofs_compress_work *next;
+   struct z_erofs_mt_file *mtfile_desc;

 unsigned int alg_id;
 char *alg_name;
@@ -96,14 +97,14 @@ struct erofs_compress_work {

  static struct {
 struct erofs_workqueue wq;
-   struct erofs_compress_work *idle;
-   pthread_mutex_t mutex;
-   pthread_cond_t cond;
-   int nfini;
+   struct erofs_compress_work *work_idle;
+   pthread_mutex_t work_mutex;
+   struct z_erofs_mt_file *file_idle;
+   pthread_mutex_t file_mutex;
  } z_erofs_mt_ctrl;
  #endif

-static bool z_erofs_mt_enabled;
+bool z_erofs_mt_enabled;

  #define Z_EROFS_LEGACY_MAP_HEADER_SIZE Z_EROFS_FULL_INDEX_ALIGN(0)

@@ -1025,6 +1026,90 @@ int z_erofs_compress_segment(struct 
z_erofs_compress_sctx *ctx,
 return 0;
  }

+int z_erofs_finalize_compression(struct z_erofs_compress_ictx *ictx,
+struct erofs_buffer_head *bh,
+erofs_blk_t blkaddr,
+erofs_blk_t compressed_blocks)
+{
+   struct erofs_inode *inode = ictx->inode;
+   struct erofs_sb_info *sbi = inode->sbi;
+   u8 *compressmeta = ictx->metacur - Z_EROFS_LEGACY_MAP_HEADER_SIZE;
+   unsigned int legacymetasize;
+   int ret = 0;
+
+   /* fall back to no compression mode */
+   DBG_BUGON(compressed_blocks < !!inode->idata_size);
+   compressed_blocks -= !!inode->idata_size;
+
+   z_erofs_write_indexes(ictx);
+   legacymetasize = ictx->metacur - compressmeta;
+   /* estimate if data compression saves space or not */
+   if (!inode->fragment_size &&
+   compressed_blocks * erofs_blksiz(sbi) + inode->idata_size +
+   legacymetasize >= inode->i_size) {
+   z_erofs_dedupe_commit(true);
+
+   if 

Re: [PATCH v3 2/2] erofs-utils: mkfs: introduce inter-file multi-threaded compression

2024-03-22 Thread Huang Jianan
Huang Jianan  于2024年3月23日周六 11:46写道:
>
> Yifan Zhao  于2024年3月22日周五 18:25写道:
> >
> > This patch allows parallelizing the compression process of different
> > files in mkfs. Specifically, a traverser thread traverses the files and
> > issues the compression task, which is handled by the workers. Then, the
> > main thread consumes them and writes the compressed data to the device.
> >
> > To this end, the logic of erofs_write_compressed_file() has been
> > modified to split the creation and completion logic of the compression
> > task.
> >
> > Signed-off-by: Yifan Zhao 
> > Co-authored-by: Tong Xin 
> > ---
> >  include/erofs/compress.h |  16 ++
> >  include/erofs/inode.h|  17 ++
> >  include/erofs/internal.h |   3 +
> >  lib/compress.c   | 336 +--
> >  lib/inode.c  | 258 --
> >  5 files changed, 503 insertions(+), 127 deletions(-)
> >
> > diff --git a/include/erofs/compress.h b/include/erofs/compress.h
> > index 871db54..8d5a54b 100644
> > --- a/include/erofs/compress.h
> > +++ b/include/erofs/compress.h
> > @@ -17,6 +17,22 @@ extern "C"
> >  #define EROFS_CONFIG_COMPR_MAX_SZ  (4000 * 1024)
> >  #define Z_EROFS_COMPR_QUEUE_SZ (EROFS_CONFIG_COMPR_MAX_SZ * 2)
> >
> > +#ifdef EROFS_MT_ENABLED
> > +struct z_erofs_mt_file {
> > +   pthread_mutex_t mutex;
> > +   pthread_cond_t cond;
> > +   int total;
> > +   int nfini;
> > +
> > +   int fd;
> > +   struct erofs_compress_work *head;
> > +
> > +   struct z_erofs_mt_file *next;
> > +};
> > +
> > +int z_erofs_mt_reap(struct z_erofs_mt_file *desc);
> > +#endif
> > +
> >  void z_erofs_drop_inline_pcluster(struct erofs_inode *inode);
> >  int erofs_write_compressed_file(struct erofs_inode *inode, int fd, u64 
> > fpos);
> >
> > diff --git a/include/erofs/inode.h b/include/erofs/inode.h
> > index d5a732a..101ff59 100644
> > --- a/include/erofs/inode.h
> > +++ b/include/erofs/inode.h
> > @@ -41,6 +41,23 @@ struct erofs_inode *erofs_new_inode(void);
> >  struct erofs_inode *erofs_mkfs_build_tree_from_path(const char *path);
> >  struct erofs_inode *erofs_mkfs_build_special_from_fd(int fd, const char 
> > *name);
> >
> > +#ifdef EROFS_MT_ENABLED
> > +struct erofs_inode_fifo {
> > +   pthread_mutex_t lock;
> > +   pthread_cond_t full, empty;
> > +
> > +   void *buf;
> > +
> > +   size_t size, elem_size;
> > +   size_t head, tail;
> > +};
> > +
> > +struct erofs_inode_fifo *erofs_alloc_inode_fifo(size_t size, size_t 
> > elem_size);
> > +void erofs_push_inode_fifo(struct erofs_inode_fifo *q, void *elem);
> > +void *erofs_pop_inode_fifo(struct erofs_inode_fifo *q);
> > +void erofs_destroy_inode_fifo(struct erofs_inode_fifo *q);
> > +#endif
> > +
> >  #ifdef __cplusplus
> >  }
> >  #endif
> > diff --git a/include/erofs/internal.h b/include/erofs/internal.h
> > index 4cd2059..2580588 100644
> > --- a/include/erofs/internal.h
> > +++ b/include/erofs/internal.h
> > @@ -250,6 +250,9 @@ struct erofs_inode {
> >  #ifdef WITH_ANDROID
> > uint64_t capabilities;
> >  #endif
> > +#ifdef EROFS_MT_ENABLED
> > +   struct z_erofs_mt_file *mt_desc;
> > +#endif
> >  };
> >
> >  static inline erofs_off_t erofs_iloc(struct erofs_inode *inode)
> > diff --git a/lib/compress.c b/lib/compress.c
> > index e064293..d89e404 100644
> > --- a/lib/compress.c
> > +++ b/lib/compress.c
> > @@ -85,6 +85,7 @@ struct erofs_compress_work {
> > struct erofs_work work;
> > struct z_erofs_compress_sctx ctx;
> > struct erofs_compress_work *next;
> > +   struct z_erofs_mt_file *mtfile_desc;
> >
> > unsigned int alg_id;
> > char *alg_name;
> > @@ -96,14 +97,14 @@ struct erofs_compress_work {
> >
> >  static struct {
> > struct erofs_workqueue wq;
> > -   struct erofs_compress_work *idle;
> > -   pthread_mutex_t mutex;
> > -   pthread_cond_t cond;
> > -   int nfini;
> > +   struct erofs_compress_work *work_idle;
> > +   pthread_mutex_t work_mutex;
> > +   struct z_erofs_mt_file *file_idle;
> > +   pthread_mutex_t file_mutex;
> >  } z_erofs_mt_ctrl;
> >  #endif
> >
> > -static bool z_erofs_mt_enabled;
> > +bool z_erofs_mt_enabled;
> >
> >  #define Z_EROFS_LEGACY_MAP_HEADER_SIZE Z_EROFS_FULL_INDEX_ALIGN(0)
> >
> > @@ -1025,6 +1026,90 @@ int z_erofs_compress_segment(struct 
> > z_erofs_compress_sctx *ctx,
> > return 0;
> >  }
> >
> > +int z_erofs_finalize_compression(struct z_erofs_compress_ictx *ictx,
> > +struct erofs_buffer_head *bh,
> > +erofs_blk_t blkaddr,
> > +erofs_blk_t compressed_blocks)
> > +{
> > +   struct erofs_inode *inode = ictx->inode;
> > +   struct erofs_sb_info *sbi = inode->sbi;
> > +   u8 *compressmeta = ictx->metacur - Z_EROFS_LEGACY_MAP_HEADER_SIZE;
> > +   unsigned int legacymetasize;
> > +   int ret = 0;
> > +
> > +   /* fall 

Re: [PATCH v3 2/2] erofs-utils: mkfs: introduce inter-file multi-threaded compression

2024-03-22 Thread Huang Jianan
Yifan Zhao  于2024年3月22日周五 18:25写道:
>
> This patch allows parallelizing the compression process of different
> files in mkfs. Specifically, a traverser thread traverses the files and
> issues the compression task, which is handled by the workers. Then, the
> main thread consumes them and writes the compressed data to the device.
>
> To this end, the logic of erofs_write_compressed_file() has been
> modified to split the creation and completion logic of the compression
> task.
>
> Signed-off-by: Yifan Zhao 
> Co-authored-by: Tong Xin 
> ---
>  include/erofs/compress.h |  16 ++
>  include/erofs/inode.h|  17 ++
>  include/erofs/internal.h |   3 +
>  lib/compress.c   | 336 +--
>  lib/inode.c  | 258 --
>  5 files changed, 503 insertions(+), 127 deletions(-)
>
> diff --git a/include/erofs/compress.h b/include/erofs/compress.h
> index 871db54..8d5a54b 100644
> --- a/include/erofs/compress.h
> +++ b/include/erofs/compress.h
> @@ -17,6 +17,22 @@ extern "C"
>  #define EROFS_CONFIG_COMPR_MAX_SZ  (4000 * 1024)
>  #define Z_EROFS_COMPR_QUEUE_SZ (EROFS_CONFIG_COMPR_MAX_SZ * 2)
>
> +#ifdef EROFS_MT_ENABLED
> +struct z_erofs_mt_file {
> +   pthread_mutex_t mutex;
> +   pthread_cond_t cond;
> +   int total;
> +   int nfini;
> +
> +   int fd;
> +   struct erofs_compress_work *head;
> +
> +   struct z_erofs_mt_file *next;
> +};
> +
> +int z_erofs_mt_reap(struct z_erofs_mt_file *desc);
> +#endif
> +
>  void z_erofs_drop_inline_pcluster(struct erofs_inode *inode);
>  int erofs_write_compressed_file(struct erofs_inode *inode, int fd, u64 fpos);
>
> diff --git a/include/erofs/inode.h b/include/erofs/inode.h
> index d5a732a..101ff59 100644
> --- a/include/erofs/inode.h
> +++ b/include/erofs/inode.h
> @@ -41,6 +41,23 @@ struct erofs_inode *erofs_new_inode(void);
>  struct erofs_inode *erofs_mkfs_build_tree_from_path(const char *path);
>  struct erofs_inode *erofs_mkfs_build_special_from_fd(int fd, const char 
> *name);
>
> +#ifdef EROFS_MT_ENABLED
> +struct erofs_inode_fifo {
> +   pthread_mutex_t lock;
> +   pthread_cond_t full, empty;
> +
> +   void *buf;
> +
> +   size_t size, elem_size;
> +   size_t head, tail;
> +};
> +
> +struct erofs_inode_fifo *erofs_alloc_inode_fifo(size_t size, size_t 
> elem_size);
> +void erofs_push_inode_fifo(struct erofs_inode_fifo *q, void *elem);
> +void *erofs_pop_inode_fifo(struct erofs_inode_fifo *q);
> +void erofs_destroy_inode_fifo(struct erofs_inode_fifo *q);
> +#endif
> +
>  #ifdef __cplusplus
>  }
>  #endif
> diff --git a/include/erofs/internal.h b/include/erofs/internal.h
> index 4cd2059..2580588 100644
> --- a/include/erofs/internal.h
> +++ b/include/erofs/internal.h
> @@ -250,6 +250,9 @@ struct erofs_inode {
>  #ifdef WITH_ANDROID
> uint64_t capabilities;
>  #endif
> +#ifdef EROFS_MT_ENABLED
> +   struct z_erofs_mt_file *mt_desc;
> +#endif
>  };
>
>  static inline erofs_off_t erofs_iloc(struct erofs_inode *inode)
> diff --git a/lib/compress.c b/lib/compress.c
> index e064293..d89e404 100644
> --- a/lib/compress.c
> +++ b/lib/compress.c
> @@ -85,6 +85,7 @@ struct erofs_compress_work {
> struct erofs_work work;
> struct z_erofs_compress_sctx ctx;
> struct erofs_compress_work *next;
> +   struct z_erofs_mt_file *mtfile_desc;
>
> unsigned int alg_id;
> char *alg_name;
> @@ -96,14 +97,14 @@ struct erofs_compress_work {
>
>  static struct {
> struct erofs_workqueue wq;
> -   struct erofs_compress_work *idle;
> -   pthread_mutex_t mutex;
> -   pthread_cond_t cond;
> -   int nfini;
> +   struct erofs_compress_work *work_idle;
> +   pthread_mutex_t work_mutex;
> +   struct z_erofs_mt_file *file_idle;
> +   pthread_mutex_t file_mutex;
>  } z_erofs_mt_ctrl;
>  #endif
>
> -static bool z_erofs_mt_enabled;
> +bool z_erofs_mt_enabled;
>
>  #define Z_EROFS_LEGACY_MAP_HEADER_SIZE Z_EROFS_FULL_INDEX_ALIGN(0)
>
> @@ -1025,6 +1026,90 @@ int z_erofs_compress_segment(struct 
> z_erofs_compress_sctx *ctx,
> return 0;
>  }
>
> +int z_erofs_finalize_compression(struct z_erofs_compress_ictx *ictx,
> +struct erofs_buffer_head *bh,
> +erofs_blk_t blkaddr,
> +erofs_blk_t compressed_blocks)
> +{
> +   struct erofs_inode *inode = ictx->inode;
> +   struct erofs_sb_info *sbi = inode->sbi;
> +   u8 *compressmeta = ictx->metacur - Z_EROFS_LEGACY_MAP_HEADER_SIZE;
> +   unsigned int legacymetasize;
> +   int ret = 0;
> +
> +   /* fall back to no compression mode */
> +   DBG_BUGON(compressed_blocks < !!inode->idata_size);
> +   compressed_blocks -= !!inode->idata_size;
> +
> +   z_erofs_write_indexes(ictx);
> +   legacymetasize = ictx->metacur - compressmeta;
> +   /* estimate if data compression saves space or not */
> +   if 

[PATCH v3 2/2] erofs-utils: mkfs: introduce inter-file multi-threaded compression

2024-03-22 Thread Yifan Zhao
This patch allows parallelizing the compression process of different
files in mkfs. Specifically, a traverser thread traverses the files and
issues the compression task, which is handled by the workers. Then, the
main thread consumes them and writes the compressed data to the device.

To this end, the logic of erofs_write_compressed_file() has been
modified to split the creation and completion logic of the compression
task.

Signed-off-by: Yifan Zhao 
Co-authored-by: Tong Xin 
---
 include/erofs/compress.h |  16 ++
 include/erofs/inode.h|  17 ++
 include/erofs/internal.h |   3 +
 lib/compress.c   | 336 +--
 lib/inode.c  | 258 --
 5 files changed, 503 insertions(+), 127 deletions(-)

diff --git a/include/erofs/compress.h b/include/erofs/compress.h
index 871db54..8d5a54b 100644
--- a/include/erofs/compress.h
+++ b/include/erofs/compress.h
@@ -17,6 +17,22 @@ extern "C"
 #define EROFS_CONFIG_COMPR_MAX_SZ  (4000 * 1024)
 #define Z_EROFS_COMPR_QUEUE_SZ (EROFS_CONFIG_COMPR_MAX_SZ * 2)
 
+#ifdef EROFS_MT_ENABLED
+struct z_erofs_mt_file {
+   pthread_mutex_t mutex;
+   pthread_cond_t cond;
+   int total;
+   int nfini;
+
+   int fd;
+   struct erofs_compress_work *head;
+
+   struct z_erofs_mt_file *next;
+};
+
+int z_erofs_mt_reap(struct z_erofs_mt_file *desc);
+#endif
+
 void z_erofs_drop_inline_pcluster(struct erofs_inode *inode);
 int erofs_write_compressed_file(struct erofs_inode *inode, int fd, u64 fpos);
 
diff --git a/include/erofs/inode.h b/include/erofs/inode.h
index d5a732a..101ff59 100644
--- a/include/erofs/inode.h
+++ b/include/erofs/inode.h
@@ -41,6 +41,23 @@ struct erofs_inode *erofs_new_inode(void);
 struct erofs_inode *erofs_mkfs_build_tree_from_path(const char *path);
 struct erofs_inode *erofs_mkfs_build_special_from_fd(int fd, const char *name);
 
+#ifdef EROFS_MT_ENABLED
+struct erofs_inode_fifo {
+   pthread_mutex_t lock;
+   pthread_cond_t full, empty;
+
+   void *buf;
+
+   size_t size, elem_size;
+   size_t head, tail;
+};
+
+struct erofs_inode_fifo *erofs_alloc_inode_fifo(size_t size, size_t elem_size);
+void erofs_push_inode_fifo(struct erofs_inode_fifo *q, void *elem);
+void *erofs_pop_inode_fifo(struct erofs_inode_fifo *q);
+void erofs_destroy_inode_fifo(struct erofs_inode_fifo *q);
+#endif
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/include/erofs/internal.h b/include/erofs/internal.h
index 4cd2059..2580588 100644
--- a/include/erofs/internal.h
+++ b/include/erofs/internal.h
@@ -250,6 +250,9 @@ struct erofs_inode {
 #ifdef WITH_ANDROID
uint64_t capabilities;
 #endif
+#ifdef EROFS_MT_ENABLED
+   struct z_erofs_mt_file *mt_desc;
+#endif
 };
 
 static inline erofs_off_t erofs_iloc(struct erofs_inode *inode)
diff --git a/lib/compress.c b/lib/compress.c
index e064293..d89e404 100644
--- a/lib/compress.c
+++ b/lib/compress.c
@@ -85,6 +85,7 @@ struct erofs_compress_work {
struct erofs_work work;
struct z_erofs_compress_sctx ctx;
struct erofs_compress_work *next;
+   struct z_erofs_mt_file *mtfile_desc;
 
unsigned int alg_id;
char *alg_name;
@@ -96,14 +97,14 @@ struct erofs_compress_work {
 
 static struct {
struct erofs_workqueue wq;
-   struct erofs_compress_work *idle;
-   pthread_mutex_t mutex;
-   pthread_cond_t cond;
-   int nfini;
+   struct erofs_compress_work *work_idle;
+   pthread_mutex_t work_mutex;
+   struct z_erofs_mt_file *file_idle;
+   pthread_mutex_t file_mutex;
 } z_erofs_mt_ctrl;
 #endif
 
-static bool z_erofs_mt_enabled;
+bool z_erofs_mt_enabled;
 
 #define Z_EROFS_LEGACY_MAP_HEADER_SIZE Z_EROFS_FULL_INDEX_ALIGN(0)
 
@@ -1025,6 +1026,90 @@ int z_erofs_compress_segment(struct 
z_erofs_compress_sctx *ctx,
return 0;
 }
 
+int z_erofs_finalize_compression(struct z_erofs_compress_ictx *ictx,
+struct erofs_buffer_head *bh,
+erofs_blk_t blkaddr,
+erofs_blk_t compressed_blocks)
+{
+   struct erofs_inode *inode = ictx->inode;
+   struct erofs_sb_info *sbi = inode->sbi;
+   u8 *compressmeta = ictx->metacur - Z_EROFS_LEGACY_MAP_HEADER_SIZE;
+   unsigned int legacymetasize;
+   int ret = 0;
+
+   /* fall back to no compression mode */
+   DBG_BUGON(compressed_blocks < !!inode->idata_size);
+   compressed_blocks -= !!inode->idata_size;
+
+   z_erofs_write_indexes(ictx);
+   legacymetasize = ictx->metacur - compressmeta;
+   /* estimate if data compression saves space or not */
+   if (!inode->fragment_size &&
+   compressed_blocks * erofs_blksiz(sbi) + inode->idata_size +
+   legacymetasize >= inode->i_size) {
+   z_erofs_dedupe_commit(true);
+
+   if (inode->idata) {
+   free(inode->idata);
+   inode->idata =