From 6f5d22c9207cc58e5647a5afc576f739727edb2e Mon Sep 17 00:00:00 2001 From: Alex Zhuravlev Date: Mon, 15 Jun 2020 11:47:44 +0300 Subject: [PATCH] LU-13827 utils: ofd_access_batch to print top hot files with -F option one can specify fraction (in %%) of hot files to be printed. Signed-off-by: Alex Zhuravlev Change-Id: I131c47bb2252da88c9afce757c5264b8d2011d1a Reviewed-on: https://review.whamcloud.com/39529 Reviewed-by: John L. Hammond Tested-by: jenkins Tested-by: Maloo Reviewed-by: Andreas Dilger Reviewed-by: Gu Zheng Reviewed-by: Oleg Drokin --- lustre/utils/Makefile.am | 1 + lustre/utils/ofd_access_batch.c | 223 ++++++++++++++++++++++++----------- lustre/utils/ofd_access_batch.h | 2 +- lustre/utils/ofd_access_log_reader.c | 11 +- 4 files changed, 162 insertions(+), 75 deletions(-) diff --git a/lustre/utils/Makefile.am b/lustre/utils/Makefile.am index 1f769b8..22cc532 100644 --- a/lustre/utils/Makefile.am +++ b/lustre/utils/Makefile.am @@ -140,6 +140,7 @@ ofd_access_log_reader_SOURCES = \ ofd_access_batch.c \ ofd_access_batch.h \ ofd_access_log_reader.c +ofd_access_log_reader_LDADD := -lpthread if UTILS diff --git a/lustre/utils/ofd_access_batch.c b/lustre/utils/ofd_access_batch.c index aebc940..f02932b 100644 --- a/lustre/utils/ofd_access_batch.c +++ b/lustre/utils/ofd_access_batch.c @@ -29,10 +29,13 @@ * * Access log entry batching for ofd_access_log_reader. */ +#include #include #include #include #include +#include +#include #include #include #include @@ -42,15 +45,15 @@ #include "ofd_access_batch.h" /* XXX Weird param order to be consistent with list_replace_init(). */ -static inline void hlist_replace_init(struct hlist_node *old_node, - struct hlist_node *new_node) +static inline void list_replace_init(struct list_head *old_node, + struct list_head *new_node) { - hlist_add_before(new_node, old_node); - hlist_del_init(old_node); + list_add(new_node, old_node); + list_del_init(old_node); } struct fid_hash_node { - struct hlist_node fhn_node; + struct list_head fhn_node; struct lu_fid fhn_fid; }; @@ -118,45 +121,44 @@ static unsigned long fid_hash(const struct lu_fid *f, unsigned int shift) static void fhn_init(struct fid_hash_node *fhn, const struct lu_fid *fid) { - INIT_HLIST_NODE(&fhn->fhn_node); + INIT_LIST_HEAD(&fhn->fhn_node); fhn->fhn_fid = *fid; } -static bool fhn_is_hashed(const struct fid_hash_node *fhn) +static bool fhn_is_hashed(struct fid_hash_node *fhn) { - return !hlist_unhashed(&fhn->fhn_node); + return !list_empty(&fhn->fhn_node); } static void fhn_del_init(struct fid_hash_node *fhn) { if (fhn_is_hashed(fhn)) - hlist_del_init(&fhn->fhn_node); + list_del_init(&fhn->fhn_node); } static inline void fhn_replace_init(struct fid_hash_node *old_fhn, struct fid_hash_node *new_fhn) { - hlist_add_before(&new_fhn->fhn_node, &old_fhn->fhn_node); - hlist_del_init(&old_fhn->fhn_node); + list_add(&new_fhn->fhn_node, &old_fhn->fhn_node); + list_del_init(&old_fhn->fhn_node); } -void fid_hash_add(struct hlist_head *head, unsigned int shift, +void fid_hash_add(struct list_head *head, unsigned int shift, struct fid_hash_node *fhn) { assert(!fhn_is_hashed(fhn)); - hlist_add_head(&fhn->fhn_node, &head[fid_hash(&fhn->fhn_fid, shift)]); + list_add(&fhn->fhn_node, &head[fid_hash(&fhn->fhn_fid, shift)]); } struct fid_hash_node * -fid_hash_find(struct hlist_head *head, unsigned int shift, const struct lu_fid *fid) +fid_hash_find(struct list_head *head, unsigned int shift, const struct lu_fid *fid) { - struct hlist_head *hash_list; - struct hlist_node *node, *next; - struct fid_hash_node *fhn; + struct list_head *hash_list; + struct fid_hash_node *fhn, *next; hash_list = &head[fid_hash(fid, shift)]; - hlist_for_each_entry_safe(fhn, node, next, hash_list, fhn_node) { + list_for_each_entry_safe(fhn, next, hash_list, fhn_node) { assert(fhn_is_hashed(fhn)); if (fid_eq(fid, &fhn->fhn_fid)) @@ -167,28 +169,27 @@ fid_hash_find(struct hlist_head *head, unsigned int shift, const struct lu_fid * } struct fid_hash_node * -fid_hash_insert(struct hlist_head *head, unsigned int shift, struct fid_hash_node *new_fhn) +fid_hash_insert(struct list_head *head, unsigned int shift, struct fid_hash_node *new_fhn) { - struct hlist_head *list; - struct hlist_node *node, *next; - struct fid_hash_node *old_fhn; + struct list_head *list; + struct fid_hash_node *old_fhn, *next; list = &head[fid_hash(&new_fhn->fhn_fid, shift)]; - hlist_for_each_entry_safe(old_fhn, node, next, list, fhn_node) { + list_for_each_entry_safe(old_fhn, next, list, fhn_node) { assert(fhn_is_hashed(old_fhn)); if (fid_eq(&old_fhn->fhn_fid, &new_fhn->fhn_fid)) return old_fhn; } - hlist_add_head(&new_fhn->fhn_node, list); + list_add(&new_fhn->fhn_node, list); return new_fhn; } -int fid_hash_init(struct hlist_head **phead, unsigned int *pshift, unsigned int shift) +int fid_hash_init(struct list_head **phead, unsigned int *pshift, unsigned int shift) { - struct hlist_head *new_head; + struct list_head *new_head; unsigned int i; new_head = malloc(sizeof(*new_head) << shift); @@ -196,7 +197,7 @@ int fid_hash_init(struct hlist_head **phead, unsigned int *pshift, unsigned int return -1; for (i = 0; i < (1 << shift); i++) - INIT_HLIST_HEAD(&new_head[i]); + INIT_LIST_HEAD(&new_head[i]); *phead = new_head; *pshift = shift; @@ -204,9 +205,9 @@ int fid_hash_init(struct hlist_head **phead, unsigned int *pshift, unsigned int return 0; } -int fid_hash_resize(struct hlist_head **phead, unsigned int *pshift, unsigned int new_shift) +int fid_hash_resize(struct list_head **phead, unsigned int *pshift, unsigned int new_shift) { - struct hlist_head *new_head; + struct list_head *new_head; unsigned int i; int rc; @@ -218,11 +219,10 @@ int fid_hash_resize(struct hlist_head **phead, unsigned int *pshift, unsigned in return rc; for (i = 0; i < (1 << *pshift); i++) { - struct hlist_head *list = &(*phead)[i]; - struct hlist_node *node, *next; - struct fid_hash_node *fhn; + struct list_head *list = &(*phead)[i]; + struct fid_hash_node *fhn, *next; - hlist_for_each_entry_safe(fhn, node, next, list, fhn_node) { + list_for_each_entry_safe(fhn, next, list, fhn_node) { fhn_del_init(fhn); fid_hash_add(new_head, new_shift, fhn); } @@ -258,7 +258,7 @@ enum { }; struct alr_batch { - struct hlist_head *alrb_hash; + struct list_head *alrb_hash; unsigned int alrb_hash_shift; unsigned int alrb_count; }; @@ -323,52 +323,132 @@ out: return rc; } -/* Print, clear, and resize the batch. */ -int alr_batch_print(struct alr_batch *alrb, FILE *file) +int sort_compare(const void *a1, const void *a2) { - unsigned int i; - unsigned int new_hash_shift; - int rc = 0; - - if (alrb == NULL) - return 0; + int l = *(const int*)a1; + int r = *(const int *)a2; + if (l > r) return -1; + if (l < r) return 1; + return 0; +} - for (i = 0; i < (1 << alrb->alrb_hash_shift); i++) { - struct hlist_head *list = &alrb->alrb_hash[i]; - struct hlist_node *node, *next; - struct alr_entry *alre; +static void alre_printf(FILE *f, struct alr_entry *alre, int d) +{ + fprintf(f, "%s "DFID" %lld %llu %llu %llu %llu %llu %c\n", + alre->alre_obd_name, + PFID(&alre->alre_fid_hash_node.fhn_fid), + (long long)alre->alre_time[d], + (unsigned long long)alre->alre_begin[d], + (unsigned long long)alre->alre_end[d], + (unsigned long long)alre->alre_size[d], + (unsigned long long)alre->alre_segment_count[d], + (unsigned long long)alre->alre_count[d], + (d == ALR_READ) ? 'r' : 'w'); +} - hlist_for_each_entry_safe(alre, node, next, list, - alre_fid_hash_node.fhn_node) { - unsigned int d; +struct alr_thread_arg { + struct list_head list; + int fraction; + FILE *file; +}; +void *alr_sort_and_print_thread(void *arg) +{ + struct alr_entry *alre, *next; + struct alr_thread_arg *aa = arg; + struct list_head *tmp = &aa->list; + int *sa, d, i, nr = 0; + unsigned long cut; + + list_for_each_entry(alre, tmp, alre_fid_hash_node.fhn_node) { + if (alre->alre_count[0] > 0) + nr++; + if (alre->alre_count[1] > 0) + nr++; + } + if (nr) { + sa = calloc(sizeof(int), nr); + if (!sa) { + fprintf(stderr, "cannot allocate memory for sorting\n"); + exit(1); + } + i = 0; + list_for_each_entry(alre, tmp, alre_fid_hash_node.fhn_node) { + if (alre->alre_count[0] > 0) + sa[i++] = alre->alre_count[0]; + if (alre->alre_count[1] > 0) + sa[i++] = alre->alre_count[1]; + } + qsort(sa, nr, sizeof(int), sort_compare); + i = nr * aa->fraction / 100; + if (i > 0) + i--; + cut = sa[i]; + if (cut < 1) + cut = 1; + free(sa); + + /* there might be lots of items at @cut, but we want to limit total + * output. so the first loop dumps all items > @cut and the second + * loop dumps items=@cut so that total number (@i) is not exceeeded. + * XXX: possible optimization - move items=@cut to another list, so + * that 2nd pass takes < O(n) */ + list_for_each_entry_safe(alre, next, tmp, alre_fid_hash_node.fhn_node) { for (d = 0; d < 2; d++) { - int rc2; - - if (alre->alre_count[d] == 0) + if (alre->alre_count[d] <= cut) continue; - - /* stdio stream error state is sticky. */ - rc2 = fprintf(file, - "%s "DFID" %lld %llu %llu %llu %llu %llu %c\n", - alre->alre_obd_name, - PFID(&alre->alre_fid_hash_node.fhn_fid), - (long long)alre->alre_time[d], - (unsigned long long)alre->alre_begin[d], - (unsigned long long)alre->alre_end[d], - (unsigned long long)alre->alre_size[d], - (unsigned long long)alre->alre_segment_count[d], - (unsigned long long)alre->alre_count[d], - (d == ALR_READ) ? 'r' : 'w'); - if (rc2 < 0) - rc = rc2; + alre_printf(aa->file, alre, d); + i--; + } + } + list_for_each_entry_safe(alre, next, tmp, alre_fid_hash_node.fhn_node) { + for (d = 0; d < 2 && i > 0; d++) { + if (alre->alre_count[d] != cut) + continue; + alre_printf(aa->file, alre, d); + i--; } - alre_del_init(alre); free(alre); } } + free(aa); + pthread_exit((void *)0); + + return 0; +} + +/* Print, clear, and resize the batch. */ +int alr_batch_print(struct alr_batch *alrb, FILE *file, int fraction) +{ + unsigned int new_hash_shift; + struct alr_thread_arg *aa; + pthread_t pid; + int i, rc; + + if (alrb == NULL) + return 0; + + aa = malloc(sizeof(*aa)); + if (!aa) + return -ENOMEM; + + /* move all collected items to the temp list */ + INIT_LIST_HEAD(&aa->list); + for (i = 0; i < (1 << alrb->alrb_hash_shift); i++) { + if (list_empty(&alrb->alrb_hash[i])) + continue; + list_splice(&alrb->alrb_hash[i], &aa->list); + INIT_LIST_HEAD(&alrb->alrb_hash[i]); + } + aa->file = file; + aa->fraction = fraction; + + /* as sorting may take time and we don't want to lose access + * records we better do sorting and printing in a different thread */ + rc = pthread_create(&pid, NULL, alr_sort_and_print_thread, aa); + /* Resize hash based on previous count. */ new_hash_shift = alrb->alrb_hash_shift; @@ -413,11 +493,10 @@ void alr_batch_destroy(struct alr_batch *alrb) return; for (i = 0; i < (1 << alrb->alrb_hash_shift); i++) { - struct hlist_head *list = &alrb->alrb_hash[i]; - struct hlist_node *node, *next; - struct alr_entry *alre; + struct list_head *list = &alrb->alrb_hash[i]; + struct alr_entry *alre, *next; - hlist_for_each_entry_safe(alre, node, next, list, alre_fid_hash_node.fhn_node) { + list_for_each_entry_safe(alre, next, list, alre_fid_hash_node.fhn_node) { alre_del_init(alre); free(alre); } diff --git a/lustre/utils/ofd_access_batch.h b/lustre/utils/ofd_access_batch.h index e06278f..7b874ee0 100644 --- a/lustre/utils/ofd_access_batch.h +++ b/lustre/utils/ofd_access_batch.h @@ -11,6 +11,6 @@ void alr_batch_destroy(struct alr_batch *alrb); int alr_batch_add(struct alr_batch *alrb, const char *obd_name, const struct lu_fid *pfid, time_t time, __u64 begin, __u64 end, __u32 size, __u32 segment_count, __u32 flags); -int alr_batch_print(struct alr_batch *alrb, FILE *file); +int alr_batch_print(struct alr_batch *alrb, FILE *file, int fraction); #endif /* _OFD_ACCESS_BATCH_H_ */ diff --git a/lustre/utils/ofd_access_log_reader.c b/lustre/utils/ofd_access_log_reader.c index 35d4a1c..75d5a59 100644 --- a/lustre/utils/ofd_access_log_reader.c +++ b/lustre/utils/ofd_access_log_reader.c @@ -128,6 +128,7 @@ static unsigned int oal_log_minor_max; static struct alr_batch *alr_batch; static FILE *alr_batch_file; static const char *alr_batch_file_path; +static int alr_print_fraction = 100; #define D_ALR_DEV "%s %d" #define P_ALR_DEV(ad) \ @@ -498,7 +499,7 @@ static int alr_batch_timer_io(int epoll_fd, struct alr_dev *td, unsigned int mas DEBUG_U(expire_count); - rc = alr_batch_print(alr_batch, alr_batch_file); + rc = alr_batch_print(alr_batch, alr_batch_file, alr_print_fraction); if (rc < 0) { ERROR("cannot write to '%s': %s\n", alr_batch_file_path, strerror(errno)); @@ -629,12 +630,13 @@ int main(int argc, char *argv[]) { .name = "batch-offset", .has_arg = required_argument, .val = 'o', }, { .name = "debug", .has_arg = optional_argument, .val = 'd', }, { .name = "help", .has_arg = no_argument, .val = 'h', }, + { .name = "fraction", .has_arg = required_argument, .val = 'F', }, { .name = "list", .has_arg = no_argument, .val = 'l', }, { .name = "trace", .has_arg = optional_argument, .val = 't', }, { .name = NULL, }, }; - while ((c = getopt_long(argc, argv, "d::f:hi:lt::", options, NULL)) != -1) { + while ((c = getopt_long(argc, argv, "d::f:F:hi:lt::", options, NULL)) != -1) { switch (c) { case 'f': alr_batch_file_path = optarg; @@ -669,6 +671,11 @@ int main(int argc, char *argv[]) case 'h': usage(); exit(EXIT_SUCCESS); + case 'F': + alr_print_fraction = strtoll(optarg, NULL, 0); + if (alr_print_fraction < 1 || alr_print_fraction > 100) + FATAL("invalid batch offset '%s'\n", optarg); + break; case 'l': list_info = 1; break; -- 1.8.3.1