Whamcloud - gitweb
LU-9201 libcfs: reduce libcfs checksum speed test time 23/25923/2
authorAndreas Dilger <andreas.dilger@intel.com>
Thu, 9 Mar 2017 23:21:44 +0000 (16:21 -0700)
committerOleg Drokin <oleg.drokin@intel.com>
Thu, 16 Mar 2017 21:39:24 +0000 (21:39 +0000)
Loading the libcfs module is getting increasingly slow due to
multiple checksum types being speed tested at startup (8 different
checksums * 1s per checksum).

Reduce the number of checksum algorithms checked at module load
time to the ones that are actually need the speed (i.e. the bulk
data checksums), and reduce the amount of time taken to compute the
checksum.  The other checksum types typically do not need the speed,
but rather are selected by the configuration.

Precompute the checksum speeds and supported types for the OST so
they are not recomputed for each new client that connects.

This reduces the module load time from 8.0s to 0.76s in my testing.

Signed-off-by: Andreas Dilger <andreas.dilger@intel.com>
Change-Id: I4b4ea109633585f61201a661c54ce4229c3ebbe5
Reviewed-on: https://review.whamcloud.com/25923
Tested-by: Jenkins
Tested-by: Maloo <hpdd-maloo@intel.com>
Reviewed-by: Alex Zhuravlev <alexey.zhuravlev@intel.com>
Reviewed-by: Jinshan Xiong <jinshan.xiong@intel.com>
Reviewed-by: Oleg Drokin <oleg.drokin@intel.com>
libcfs/include/libcfs/libcfs_crypto.h
libcfs/libcfs/linux/linux-crypto-crc32pclmul.c
libcfs/libcfs/linux/linux-crypto.c
lustre/include/lustre/lustre_idl.h
lustre/include/obd_cksum.h
lustre/ofd/ofd_dev.c
lustre/ofd/ofd_internal.h
lustre/ofd/ofd_obd.c

index 929ad6f..ea9234a 100644 (file)
@@ -42,13 +42,15 @@ enum cfs_crypto_hash_alg {
        CFS_HASH_ALG_NULL       = 0,
        CFS_HASH_ALG_ADLER32,
        CFS_HASH_ALG_CRC32,
+       CFS_HASH_ALG_CRC32C,
+       /* hashes before here will be speed-tested at module load */
        CFS_HASH_ALG_MD5,
        CFS_HASH_ALG_SHA1,
        CFS_HASH_ALG_SHA256,
        CFS_HASH_ALG_SHA384,
        CFS_HASH_ALG_SHA512,
-       CFS_HASH_ALG_CRC32C,
        CFS_HASH_ALG_MAX,
+       CFS_HASH_ALG_SPEED_MAX = CFS_HASH_ALG_MD5,
        CFS_HASH_ALG_UNKNOWN    = 0xff
 };
 
index 0b3abaf..a238e4e 100644 (file)
@@ -183,8 +183,7 @@ static struct shash_alg alg = {
 int cfs_crypto_crc32_pclmul_register(void)
 {
        if (!boot_cpu_has(X86_FEATURE_PCLMULQDQ)) {
-               CDEBUG(D_INFO, "PCLMULQDQ-NI instructions are not "
-                      "detected.\n");
+               CDEBUG(D_INFO, "PCLMULQDQ-NI instructions are not detected.\n");
                return -ENODEV;
        }
        return crypto_register_shash(&alg);
index 1a0a105..1991a86 100644 (file)
@@ -306,7 +306,10 @@ EXPORT_SYMBOL(cfs_crypto_hash_final);
 /**
  * Compute the speed of specified hash function
  *
- * Run a speed test on the given hash algorithm on buffer of the given size.
+ * Run a speed test on the given hash algorithm on buffer using a 1MB buffer
+ * size.  This is a reasonable buffer size for Lustre RPCs, even if the actual
+ * RPC size is larger or smaller.
+ *
  * The speed is stored internally in the cfs_crypto_hash_speeds[] array, and
  * is available through the cfs_crypto_hash_speed() function.
  *
@@ -335,9 +338,8 @@ static void cfs_crypto_performance_test(enum cfs_crypto_hash_alg hash_alg)
        memset(buf, 0xAD, PAGE_SIZE);
        kunmap(page);
 
-       for (start = jiffies, end = start + msecs_to_jiffies(MSEC_PER_SEC),
-            bcount = 0;
-            time_before(jiffies, end) && err == 0; bcount++) {
+       for (start = jiffies, end = start + msecs_to_jiffies(MSEC_PER_SEC / 4),
+            bcount = 0; time_before(jiffies, end) && err == 0; bcount++) {
                struct cfs_crypto_hash_desc *hdesc;
                int i;
 
@@ -380,8 +382,12 @@ out_err:
 /**
  * hash speed in Mbytes per second for valid hash algorithm
  *
- * Return the performance of the specified \a hash_alg that was previously
- * computed using cfs_crypto_performance_test().
+ * Return the performance of the specified \a hash_alg that was
+ * computed using cfs_crypto_performance_test().  If the performance
+ * has not yet been computed, do that when it is first requested.
+ * That avoids computing the speed when it is not actually needed.
+ * To avoid competing threads computing the checksum speed at the
+ * same time, only compute a single checksum speed at one time.
  *
  * \param[in] hash_alg hash algorithm id (CFS_HASH_ALG_*)
  *
@@ -391,8 +397,17 @@ out_err:
  */
 int cfs_crypto_hash_speed(enum cfs_crypto_hash_alg hash_alg)
 {
-       if (hash_alg < CFS_HASH_ALG_MAX)
+       if (hash_alg < CFS_HASH_ALG_MAX) {
+               if (unlikely(cfs_crypto_hash_speeds[hash_alg] == 0)) {
+                       static DEFINE_MUTEX(crypto_hash_speed_mutex);
+
+                       mutex_lock(&crypto_hash_speed_mutex);
+                       if (cfs_crypto_hash_speeds[hash_alg] == 0)
+                               cfs_crypto_performance_test(hash_alg);
+                       mutex_unlock(&crypto_hash_speed_mutex);
+               }
                return cfs_crypto_hash_speeds[hash_alg];
+       }
 
        return -ENOENT;
 }
@@ -401,9 +416,10 @@ EXPORT_SYMBOL(cfs_crypto_hash_speed);
 /**
  * Run the performance test for all hash algorithms.
  *
- * Run the cfs_crypto_performance_test() benchmark for all of the available
- * hash functions using a 1MB buffer size.  This is a reasonable buffer size
- * for Lustre RPCs, even if the actual RPC size is larger or smaller.
+ * Run the cfs_crypto_performance_test() benchmark for some of the available
+ * hash functions at module load time.  This can't be reliably done at runtime
+ * since the CPUs may be under load from thousands of connecting clients when
+ * the first client connects and the checksum speeds are needed.
  *
  * Since the setup cost and computation speed of various hash algorithms is
  * a function of the buffer size (and possibly internal contention of offload
@@ -420,7 +436,7 @@ static int cfs_crypto_test_hashes(void)
 {
        enum cfs_crypto_hash_alg hash_alg;
 
-       for (hash_alg = 0; hash_alg < CFS_HASH_ALG_MAX; hash_alg++)
+       for (hash_alg = 1; hash_alg < CFS_HASH_ALG_SPEED_MAX; hash_alg++)
                cfs_crypto_performance_test(hash_alg);
 
        return 0;
index 99d5e3a..ab14d6d 100644 (file)
@@ -861,7 +861,7 @@ struct obd_connect_data {
  * Please update DECLARE_CKSUM_NAME/OBD_CKSUM_ALL in obd.h when adding a new
  * algorithm and also the OBD_FL_CKSUM* flags.
  */
-typedef enum {
+typedef enum cksum_types {
         OBD_CKSUM_CRC32 = 0x00000001,
         OBD_CKSUM_ADLER = 0x00000002,
         OBD_CKSUM_CRC32C= 0x00000004,
index 549e446..6a0cfe8 100644 (file)
@@ -133,10 +133,10 @@ static inline cksum_type_t cksum_types_supported_client(void)
 }
 
 /* Server uses algos that perform at 50% or better of the Adler */
-static inline cksum_type_t cksum_types_supported_server(void)
+static inline enum cksum_types cksum_types_supported_server(void)
 {
-       int          base_speed;
-       cksum_type_t    ret = OBD_CKSUM_ADLER;
+       enum cksum_types ret = OBD_CKSUM_ADLER;
+       int base_speed;
 
        CDEBUG(D_INFO, "Crypto hash speed: crc %d, crc32c %d, adler %d\n",
               cfs_crypto_hash_speed(cksum_obd2cfs(OBD_CKSUM_CRC32)),
index 4bd5029..716e602 100644 (file)
@@ -69,6 +69,7 @@
 #define DEBUG_SUBSYSTEM S_FILTER
 
 #include <obd_class.h>
+#include <obd_cksum.h>
 #include <lustre_param.h>
 #include <lustre_fid.h>
 #include <lustre_lfsck.h>
@@ -2995,6 +2996,7 @@ static int ofd_init0(const struct lu_env *env, struct ofd_device *m,
        else
                m->ofd_brw_size = ONE_MB_BRW_SIZE;
 
+       m->ofd_cksum_types_supported = cksum_types_supported_server();
        m->ofd_precreate_batch = OFD_PRECREATE_BATCH_DEFAULT;
        if (osfs->os_bsize * osfs->os_blocks < OFD_PRECREATE_SMALL_FS)
                m->ofd_precreate_batch = OFD_PRECREATE_BATCH_SMALL;
index 8846786..1e8dd7f 100644 (file)
@@ -122,7 +122,6 @@ struct ofd_device {
        struct dt_object        *ofd_health_check_file;
        struct local_oid_storage *ofd_los;
 
-       int                      ofd_subdir_count;
        __u64                    ofd_inconsistency_self_detected;
        __u64                    ofd_inconsistency_self_repaired;
 
@@ -138,13 +137,14 @@ struct ofd_device {
        struct obd_statfs        ofd_osfs;
        __u64                    ofd_osfs_age;
        int                      ofd_blockbits;
+       /* counters used during statfs update, protected by ofd_osfs_lock.
+        * record when some statfs refresh are in progress */
+       int                      ofd_statfs_inflight;
+
        /* writes between prep & commit which might be accounted twice in
         * ofd_osfs.os_bavail */
        u64                      ofd_osfs_unstable;
 
-       /* counters used during statfs update, protected by ofd_osfs_lock.
-        * record when some statfs refresh are in progress */
-       int                      ofd_statfs_inflight;
        /* track writes completed while statfs refresh is underway.
         * tracking is only effective when ofd_statfs_inflight > 1 */
        u64                      ofd_osfs_inflight;
@@ -163,6 +163,8 @@ struct ofd_device {
 
        /* preferred BRW size, decided by storage type and capability */
        __u32                    ofd_brw_size;
+       /* checksum types supported on this node */
+       enum cksum_types         ofd_cksum_types_supported;
 
        /* ofd mod data: ofd_device wide values */
        int                      ofd_fmd_max_num; /* per ofd ofd_mod_data */
index a0d1787..4b6034b 100644 (file)
@@ -249,7 +249,7 @@ static int ofd_parse_connect_data(const struct lu_env *env,
                /* The client set in ocd_cksum_types the checksum types it
                 * supports. We have to mask off the algorithms that we don't
                 * support */
-               data->ocd_cksum_types &= cksum_types_supported_server();
+               data->ocd_cksum_types &= ofd->ofd_cksum_types_supported;
 
                if (unlikely(data->ocd_cksum_types == 0)) {
                        CERROR("%s: Connect with checksum support but no "