From f470f3a166b3d471e2a3282864af35fa9d83c859 Mon Sep 17 00:00:00 2001 From: Andreas Dilger Date: Thu, 9 Mar 2017 16:21:44 -0700 Subject: [PATCH] LU-9201 libcfs: reduce libcfs checksum speed test time 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 Change-Id: I4b4ea109633585f61201a661c54ce4229c3ebbe5 Reviewed-on: https://review.whamcloud.com/25923 Tested-by: Jenkins Tested-by: Maloo Reviewed-by: Alex Zhuravlev Reviewed-by: Jinshan Xiong Reviewed-by: Oleg Drokin --- libcfs/include/libcfs/libcfs_crypto.h | 4 ++- libcfs/libcfs/linux/linux-crypto-crc32pclmul.c | 3 +- libcfs/libcfs/linux/linux-crypto.c | 38 ++++++++++++++++++-------- lustre/include/lustre/lustre_idl.h | 2 +- lustre/include/obd_cksum.h | 6 ++-- lustre/ofd/ofd_dev.c | 2 ++ lustre/ofd/ofd_internal.h | 10 ++++--- lustre/ofd/ofd_obd.c | 2 +- 8 files changed, 44 insertions(+), 23 deletions(-) diff --git a/libcfs/include/libcfs/libcfs_crypto.h b/libcfs/include/libcfs/libcfs_crypto.h index 929ad6f..ea9234a 100644 --- a/libcfs/include/libcfs/libcfs_crypto.h +++ b/libcfs/include/libcfs/libcfs_crypto.h @@ -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 }; diff --git a/libcfs/libcfs/linux/linux-crypto-crc32pclmul.c b/libcfs/libcfs/linux/linux-crypto-crc32pclmul.c index 0b3abaf..a238e4e 100644 --- a/libcfs/libcfs/linux/linux-crypto-crc32pclmul.c +++ b/libcfs/libcfs/linux/linux-crypto-crc32pclmul.c @@ -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); diff --git a/libcfs/libcfs/linux/linux-crypto.c b/libcfs/libcfs/linux/linux-crypto.c index 1a0a105..1991a86 100644 --- a/libcfs/libcfs/linux/linux-crypto.c +++ b/libcfs/libcfs/linux/linux-crypto.c @@ -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; diff --git a/lustre/include/lustre/lustre_idl.h b/lustre/include/lustre/lustre_idl.h index 99d5e3a..ab14d6d 100644 --- a/lustre/include/lustre/lustre_idl.h +++ b/lustre/include/lustre/lustre_idl.h @@ -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, diff --git a/lustre/include/obd_cksum.h b/lustre/include/obd_cksum.h index 549e446..6a0cfe8 100644 --- a/lustre/include/obd_cksum.h +++ b/lustre/include/obd_cksum.h @@ -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)), diff --git a/lustre/ofd/ofd_dev.c b/lustre/ofd/ofd_dev.c index 4bd5029..716e602 100644 --- a/lustre/ofd/ofd_dev.c +++ b/lustre/ofd/ofd_dev.c @@ -69,6 +69,7 @@ #define DEBUG_SUBSYSTEM S_FILTER #include +#include #include #include #include @@ -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; diff --git a/lustre/ofd/ofd_internal.h b/lustre/ofd/ofd_internal.h index 8846786..1e8dd7f 100644 --- a/lustre/ofd/ofd_internal.h +++ b/lustre/ofd/ofd_internal.h @@ -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 */ diff --git a/lustre/ofd/ofd_obd.c b/lustre/ofd/ofd_obd.c index a0d1787..4b6034b 100644 --- a/lustre/ofd/ofd_obd.c +++ b/lustre/ofd/ofd_obd.c @@ -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 " -- 1.8.3.1