[f2fs-dev] [PATCH 1/2] libf2fs_io: Add user-space cache

2019-11-22 Thread Jaegeuk Kim
From: Robin Hsu 

Implemented cache options in F2FS configuration 'c' (i.e. user
options):
* use c.cache_config.num_cache_entry to set the number of
  cache entries (in block), minimum 1024, or 0 to disable cache.
* use c.cache_config.max_hash_collision to set maximum hash
  collision (max 16).
* use c.cavhe_config.dbg_en to enable printing of debug messages.

Cache properties:
* Per block save based (block size = f2fs block size = 4K Bytes)
* Device block indices are used to hash (simple modular hash
  function) to cache indices.
* A hash collision (when a block is hashed to an already occupied
  cache block) will trigger offset-based relocation to max 16
  other places, at first empty slot found policy.
* A hash collision with all 17 possible relocating places occupied
  will evict the oldest used one (replaced by the new read block).
  A global 'use' tick is kept ticking-up per block read for this
  purpose.
* On write cache hit, it will update the corresponding cached
  block.
* On write cache miss, the data won't be cached.
* Write-through policy only: never delayed write.
* On read cache hit, it returns the cached block.
* On read cache miss, it issues an I/O read to the kernel, and
  then caches and returns the block.
* Currently read ahead is not implemented.  Yet, the read ahead
  logic is kept as before, i.e. using kernel's read ahead
  mechanism.

Signed-off-by: Robin Hsu 
Signed-off-by: Jaegeuk Kim 
---
 include/f2fs_fs.h |  18 +++
 lib/libf2fs_io.c  | 331 +-
 2 files changed, 348 insertions(+), 1 deletion(-)

diff --git a/include/f2fs_fs.h b/include/f2fs_fs.h
index 84f3f3e..cb67c7e 100644
--- a/include/f2fs_fs.h
+++ b/include/f2fs_fs.h
@@ -3,6 +3,8 @@
  *
  * Copyright (c) 2012 Samsung Electronics Co., Ltd.
  * http://www.samsung.com/
+ * Copyright (c) 2019 Google Inc.
+ * http://www.google.com/
  *
  * Dual licensed under the GPL or LGPL version 2 licenses.
  *
@@ -329,6 +331,16 @@ struct device_info {
size_t zone_blocks;
 };
 
+typedef struct {
+   /* Value 0 means no cache, minimum 1024 */
+   long num_cache_entry;
+
+   /* Value 0 means always overwrite (no collision allowed). maximum 16 */
+   unsigned max_hash_collision;
+
+   bool dbg_en;
+} dev_cache_config_t;
+
 struct f2fs_configuration {
u_int32_t reserved_segments;
u_int32_t new_reserved_segments;
@@ -419,6 +431,9 @@ struct f2fs_configuration {
 
/* precomputed fs UUID checksum for seeding other checksums */
u_int32_t chksum_seed;
+
+   /* cache parameters */
+   dev_cache_config_t cache_config;
 };
 
 #ifdef CONFIG_64BIT
@@ -1185,6 +1200,9 @@ extern int f2fs_init_sparse_file(void);
 extern int f2fs_finalize_device(void);
 extern int f2fs_fsync_device(void);
 
+extern void dcache_init(void);
+extern void dcache_release(void);
+
 extern int dev_read(void *, __u64, size_t);
 #ifdef POSIX_FADV_WILLNEED
 extern int dev_readahead(__u64, size_t);
diff --git a/lib/libf2fs_io.c b/lib/libf2fs_io.c
index 4d0ea0d..971ae37 100644
--- a/lib/libf2fs_io.c
+++ b/lib/libf2fs_io.c
@@ -3,6 +3,8 @@
  *
  * Copyright (c) 2013 Samsung Electronics Co., Ltd.
  * http://www.samsung.com/
+ * Copyright (c) 2019 Google Inc.
+ * http://www.google.com/
  *
  * Dual licensed under the GPL or LGPL version 2 licenses.
  */
@@ -27,7 +29,10 @@
 #include 
 #endif
 
-#include 
+#include 
+#include 
+#include 
+#include "f2fs_fs.h"
 
 struct f2fs_configuration c;
 
@@ -64,6 +69,318 @@ static inline off64_t lseek64(int fd, __u64 offset, int set)
 }
 #endif
 
+/* -- dev_cache, Least Used First (LUF) policy  --- */
+/*
+ * Least used block will be the first victim to be replaced when max hash
+ * collision exceeds
+ */
+static bool *dcache_valid; /* is the cached block valid? */
+static off64_t  *dcache_blk; /* which block it cached */
+static uint64_t *dcache_lastused; /* last used ticks for cache entries */
+static char *dcache_buf; /* cached block data */
+static uint64_t dcache_usetick; /* current use tick */
+
+static uint64_t dcache_raccess;
+static uint64_t dcache_rhit;
+static uint64_t dcache_rmiss;
+static uint64_t dcache_rreplace;
+
+static bool dcache_exit_registered = false;
+
+/*
+ *  Shadow config:
+ *
+ *  Active set of the configurations.
+ *  Global configuration 'dcache_config' will be transferred here when
+ *  when dcache_init() is called
+ */
+static dev_cache_config_t dcache_config = {0, 16, 1};
+static bool dcache_initialized = false;
+
+#define MIN_NUM_CACHE_ENTRY  1024L
+#define MAX_MAX_HASH_COLLISION  16
+
+static long dcache_relocate_offset0[] = {
+   20, -20, 40, -40, 80, -80, 160, -160,
+   320, -320, 640, -640, 1280, -1280, 2560, -2560,
+};
+static int dcache_relocate_offset[16];
+
+static void dcache_print_statistics(void)
+{
+   long i;
+   long 

Re: [f2fs-dev] [PATCH 1/2] libf2fs_io: Add user-space cache

2019-10-30 Thread Jaegeuk Kim
Hi Robin,

Could you please address this build errors for mac build?

libf2fs_io.c:85:38: error: use of undeclared identifier 'false'
static bool dcache_exit_registered = false;
 ^
libf2fs_io.c:95:34: error: use of undeclared identifier 'false'
static bool dcache_initialized = false;
 ^
libf2fs_io.c:127:4: warning: format specifies type 'unsigned long' but the 
argument has type 'off64_t' (aka 'long long') [-Wformat]
dcache_config.num_cache_entry,
^
libf2fs_io.c:128:4: warning: format specifies type 'unsigned long' but the 
argument has type 'off64_t' (aka 'long long') [-Wformat]
useCnt,
^~
libf2fs_io.c:129:4: warning: format specifies type 'long' but the argument has 
type 'int64_t' (aka 'long long') [-Wformat]
dcache_raccess,
^~
libf2fs_io.c:130:4: warning: format specifies type 'long' but the argument has 
type 'int64_t' (aka 'long long') [-Wformat]
dcache_rhit,
^~~
libf2fs_io.c:131:4: warning: format specifies type 'long' but the argument has 
type 'int64_t' (aka 'long long') [-Wformat]
dcache_rmiss,
^~~~
libf2fs_io.c:132:4: warning: format specifies type 'long' but the argument has 
type 'int64_t' (aka 'long long') [-Wformat]
dcache_rreplace);
^~~
libf2fs_io.c:140:23: error: use of undeclared identifier 'false'
dcache_initialized = false;
 ^
libf2fs_io.c:222:23: error: use of undeclared identifier 'true'
dcache_initialized = true;
 ^
libf2fs_io.c:225:28: error: use of undeclared identifier 'true'
dcache_exit_registered = true;
 ^
libf2fs_io.c:273:24: error: use of undeclared identifier 'true'
dcache_valid[entry] = true;
  ^
libf2fs_io.c:363:50: error: use of undeclared identifier 'true'
return dcache_update_rw(fd, buf, offset, count, true);
^
libf2fs_io.c:369:50: error: use of undeclared identifier 'false'
return dcache_update_rw(fd, buf, offset, count, false);


On 10/29, Robin Hsu wrote:
> Implemented cache options in F2FS configuration 'c':
>   * use c.cache_config.num_cache_entry to set the number of
> cache entries (in block), minimum 1024, or 0 to disable cache.
>   * use c.cache_config.max_hash_collision to set maximum hash
> collision (max 16).
>   * use c.cache_config.dbg_en to enable printing of debug messages.
> 
> Signed-off-by: Robin Hsu 
> ---
>  include/f2fs_fs.h |  20 +++
>  lib/libf2fs_io.c  | 317 ++
>  2 files changed, 337 insertions(+)
> 
> diff --git a/include/f2fs_fs.h b/include/f2fs_fs.h
> index 84f3f3e..a386e61 100644
> --- a/include/f2fs_fs.h
> +++ b/include/f2fs_fs.h
> @@ -3,6 +3,8 @@
>   *
>   * Copyright (c) 2012 Samsung Electronics Co., Ltd.
>   * http://www.samsung.com/
> + * Copyright (c) 2019 Google Inc.
> + * http://www.google.com/
>   *
>   * Dual licensed under the GPL or LGPL version 2 licenses.
>   *
> @@ -329,6 +331,18 @@ struct device_info {
>   size_t zone_blocks;
>  };
>  
> +typedef off_toff64_t;
> +
> +typedef struct {
> + /* Value 0 means no cache, minimum 1024 */
> + off64_t num_cache_entry;
> +
> + /* Value 0 means always overwrite (no collision allowed). maximum 16 */
> + unsigned max_hash_collision;
> +
> + bool dbg_en;
> +} dev_cache_config_t;
> +
>  struct f2fs_configuration {
>   u_int32_t reserved_segments;
>   u_int32_t new_reserved_segments;
> @@ -419,6 +433,9 @@ struct f2fs_configuration {
>  
>   /* precomputed fs UUID checksum for seeding other checksums */
>   u_int32_t chksum_seed;
> +
> + /* cache parameters */
> + dev_cache_config_t cache_config;
>  };
>  
>  #ifdef CONFIG_64BIT
> @@ -1185,6 +1202,9 @@ extern int f2fs_init_sparse_file(void);
>  extern int f2fs_finalize_device(void);
>  extern int f2fs_fsync_device(void);
>  
> +extern void dcache_init(void);
> +extern void dcache_release(void);
> +
>  extern int dev_read(void *, __u64, size_t);
>  #ifdef POSIX_FADV_WILLNEED
>  extern int dev_readahead(__u64, size_t);
> diff --git a/lib/libf2fs_io.c b/lib/libf2fs_io.c
> index 4d0ea0d..4888b6e 100644
> --- a/lib/libf2fs_io.c
> +++ b/lib/libf2fs_io.c
> @@ -3,6 +3,8 @@
>   *
>   * Copyright (c) 2013 Samsung Electronics Co., Ltd.
>   * http://www.samsung.com/
> + * Copyright (c) 2019 Google Inc.
> + * http://www.google.com/
>   *
>   * Dual licensed under the GPL or LGPL version 2 licenses.
>   */
> @@ -64,6 +66,309 @@ 

[f2fs-dev] [PATCH 1/2] libf2fs_io: Add user-space cache

2019-10-29 Thread Robin Hsu via Linux-f2fs-devel
Implemented cache options in F2FS configuration 'c':
* use c.cache_config.num_cache_entry to set the number of
  cache entries (in block), minimum 1024, or 0 to disable cache.
* use c.cache_config.max_hash_collision to set maximum hash
  collision (max 16).
* use c.cache_config.dbg_en to enable printing of debug messages.

Signed-off-by: Robin Hsu 
---
 include/f2fs_fs.h |  20 +++
 lib/libf2fs_io.c  | 317 ++
 2 files changed, 337 insertions(+)

diff --git a/include/f2fs_fs.h b/include/f2fs_fs.h
index 84f3f3e..a386e61 100644
--- a/include/f2fs_fs.h
+++ b/include/f2fs_fs.h
@@ -3,6 +3,8 @@
  *
  * Copyright (c) 2012 Samsung Electronics Co., Ltd.
  * http://www.samsung.com/
+ * Copyright (c) 2019 Google Inc.
+ * http://www.google.com/
  *
  * Dual licensed under the GPL or LGPL version 2 licenses.
  *
@@ -329,6 +331,18 @@ struct device_info {
size_t zone_blocks;
 };
 
+typedef off_t  off64_t;
+
+typedef struct {
+   /* Value 0 means no cache, minimum 1024 */
+   off64_t num_cache_entry;
+
+   /* Value 0 means always overwrite (no collision allowed). maximum 16 */
+   unsigned max_hash_collision;
+
+   bool dbg_en;
+} dev_cache_config_t;
+
 struct f2fs_configuration {
u_int32_t reserved_segments;
u_int32_t new_reserved_segments;
@@ -419,6 +433,9 @@ struct f2fs_configuration {
 
/* precomputed fs UUID checksum for seeding other checksums */
u_int32_t chksum_seed;
+
+   /* cache parameters */
+   dev_cache_config_t cache_config;
 };
 
 #ifdef CONFIG_64BIT
@@ -1185,6 +1202,9 @@ extern int f2fs_init_sparse_file(void);
 extern int f2fs_finalize_device(void);
 extern int f2fs_fsync_device(void);
 
+extern void dcache_init(void);
+extern void dcache_release(void);
+
 extern int dev_read(void *, __u64, size_t);
 #ifdef POSIX_FADV_WILLNEED
 extern int dev_readahead(__u64, size_t);
diff --git a/lib/libf2fs_io.c b/lib/libf2fs_io.c
index 4d0ea0d..4888b6e 100644
--- a/lib/libf2fs_io.c
+++ b/lib/libf2fs_io.c
@@ -3,6 +3,8 @@
  *
  * Copyright (c) 2013 Samsung Electronics Co., Ltd.
  * http://www.samsung.com/
+ * Copyright (c) 2019 Google Inc.
+ * http://www.google.com/
  *
  * Dual licensed under the GPL or LGPL version 2 licenses.
  */
@@ -64,6 +66,309 @@ static inline off64_t lseek64(int fd, __u64 offset, int set)
 }
 #endif
 
+/* -- dev_cache, Least Used First (LUF) policy  --- */
+/*
+ * Least used block will be the first victim to be replaced when max hash
+ * collision exceeds
+ */
+static bool *dcache_valid; /* is the cached block valid? */
+static off64_t  *dcache_blk; /* which block it cached */
+static uint64_t *dcache_lastused; /* last used ticks for cache entries */
+static char *dcache_buf; /* cached block data */
+static uint64_t dcache_usetick; /* current use tick */
+
+static int64_t dcache_raccess;
+static int64_t dcache_rhit;
+static int64_t dcache_rmiss;
+static int64_t dcache_rreplace;
+
+static bool dcache_exit_registered = false;
+
+/*
+ *  Shadow config:
+ *
+ *  Active set of the configurations.
+ *  Global configuration 'dcache_config' will be transferred here when
+ *  when dcache_init() is called
+ */
+static dev_cache_config_t dcache_config = {0, 16, 1};
+static bool dcache_initialized = false;
+
+#define MIN_NUM_CACHE_ENTRY  ((off64_t)1024)
+#define MAX_MAX_HASH_COLLISION  16
+
+static int dcache_relocate_offset0[] = {
+   20, -20, 40, -40, 80, -80, 160, -160,
+   320, -320, 640, -640, 1280, -1280, 2560, -2560,
+};
+static int dcache_relocate_offset[16];
+
+static void dcache_print_statistics(void)
+{
+   off64_t i;
+   off64_t useCnt;
+
+   /* Number of used cache entries */
+   useCnt = 0;
+   for (i = 0; i < dcache_config.num_cache_entry; i++)
+   if (dcache_valid[i])
+   ++useCnt;
+
+   /*
+*  c: number of cache entries
+*  u: used entries
+*  RA: number of read access blocks
+*  CH: cache hit
+*  CM: cache miss
+*  Repl: read cache replaced
+*/
+   printf ("\nc, u, RA, CH, CM, Repl=\n");
+   printf ("%lu %lu %ld %ld %ld %ld\n",
+   dcache_config.num_cache_entry,
+   useCnt,
+   dcache_raccess,
+   dcache_rhit,
+   dcache_rmiss,
+   dcache_rreplace);
+}
+
+void dcache_release(void)
+{
+   if (!dcache_initialized)
+   return;
+
+   dcache_initialized = false;
+
+   if (c.cache_config.dbg_en)
+   dcache_print_statistics();
+
+   if (dcache_blk != NULL)
+   free(dcache_blk);
+   if (dcache_lastused != NULL)
+   free(dcache_lastused);
+   if (dcache_buf != NULL)
+   free(dcache_buf);
+   if (dcache_valid != NULL)
+