From patchwork Sat Jan 6 01:52:54 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 10147535 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 67F0A60155 for ; Sat, 6 Jan 2018 02:08:02 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id ED9E228A5E for ; Sat, 6 Jan 2018 02:08:01 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id E260328A62; Sat, 6 Jan 2018 02:08:01 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.8 required=2.0 tests=BAYES_00,DKIM_SIGNED, RCVD_IN_DNSWL_HI, T_DKIM_INVALID, UNPARSEABLE_RELAY autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id C644B28A5E for ; Sat, 6 Jan 2018 02:08:00 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753523AbeAFCIA (ORCPT ); Fri, 5 Jan 2018 21:08:00 -0500 Received: from aserp2120.oracle.com ([141.146.126.78]:46182 "EHLO aserp2120.oracle.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753494AbeAFCH7 (ORCPT ); Fri, 5 Jan 2018 21:07:59 -0500 Received: from pps.filterd (aserp2120.oracle.com [127.0.0.1]) by aserp2120.oracle.com (8.16.0.21/8.16.0.21) with SMTP id w06273I2057983; Sat, 6 Jan 2018 02:07:57 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=oracle.com; h=subject : from : to : cc : date : message-id : in-reply-to : references : mime-version : content-type : content-transfer-encoding; s=corp-2017-10-26; bh=1HQ1S4E25/+qxhrmL8IqCPiXGdhvHmln+3Cilc8c7Rs=; b=WRpTTVL60r0CJ9OpFrtu+JeG3sfKSqygmhjLSG60KzWHx0kHWSonYksTe3iuCv2fQEqx 8RMK14wfccszcuXYwhNmHL3J2qON71Hwb/eTsGJRhJ+4QdiZ1EUVpwTzHGxL6UdyHlTB oiYhBA2aNqdoryIiBKp2XYTwvoKO8sRIwtZCsX6/UIfck1gqkRRbsw1/xJmUq2pqIs+m ZW8nQ4faFBjZWRRb8R6l+Lyp7ONmu6xfW4Ky134tKx5qJWJobb+uzDqWF6CpYo1XJbPd WVpUa+aD0Nl1luzzcuZ2RjPgtf59Z4y1oo7pnPOvimo73M0A7zvURUjgLKlr+xrHrjhD zw== Received: from userv0021.oracle.com (userv0021.oracle.com [156.151.31.71]) by aserp2120.oracle.com with ESMTP id 2fan7900y1-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Sat, 06 Jan 2018 02:07:56 +0000 Received: from userv0121.oracle.com (userv0121.oracle.com [156.151.31.72]) by userv0021.oracle.com (8.14.4/8.14.4) with ESMTP id w061qtVt026072 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=FAIL); Sat, 6 Jan 2018 01:52:55 GMT Received: from abhmp0003.oracle.com (abhmp0003.oracle.com [141.146.116.9]) by userv0121.oracle.com (8.14.4/8.13.8) with ESMTP id w061qtJk013020; Sat, 6 Jan 2018 01:52:55 GMT Received: from localhost (/65.154.186.210) by default (Oracle Beehive Gateway v4.0) with ESMTP ; Fri, 05 Jan 2018 17:52:54 -0800 Subject: [PATCH 14/27] xfs_scrub: thread-safe stats counter From: "Darrick J. Wong" To: sandeen@redhat.com, darrick.wong@oracle.com Cc: linux-xfs@vger.kernel.org Date: Fri, 05 Jan 2018 17:52:54 -0800 Message-ID: <151520357409.2027.12469635382334280334.stgit@magnolia> In-Reply-To: <151520348769.2027.9860697266310422360.stgit@magnolia> References: <151520348769.2027.9860697266310422360.stgit@magnolia> User-Agent: StGit/0.17.1-dirty MIME-Version: 1.0 X-Proofpoint-Virus-Version: vendor=nai engine=5900 definitions=8765 signatures=668651 X-Proofpoint-Spam-Details: rule=notspam policy=default score=0 suspectscore=2 malwarescore=0 phishscore=0 bulkscore=0 spamscore=0 mlxscore=0 mlxlogscore=999 adultscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.0.1-1711220000 definitions=main-1801060023 Sender: linux-xfs-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-xfs@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: Darrick J. Wong Create a threaded stats counter that we'll use to track scan progress. This includes things like how much of the disk blocks we've scanned, or later how much progress we've made in each phase. Signed-off-by: Darrick J. Wong --- include/ptvar.h | 32 +++++++++++++ libfrog/Makefile | 1 libfrog/ptvar.c | 133 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ scrub/Makefile | 2 + scrub/counter.c | 104 ++++++++++++++++++++++++++++++++++++++++++ scrub/counter.h | 29 ++++++++++++ 6 files changed, 301 insertions(+) create mode 100644 include/ptvar.h create mode 100644 libfrog/ptvar.c create mode 100644 scrub/counter.c create mode 100644 scrub/counter.h -- To unsubscribe from this list: send the line "unsubscribe linux-xfs" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html diff --git a/include/ptvar.h b/include/ptvar.h new file mode 100644 index 0000000..6308228 --- /dev/null +++ b/include/ptvar.h @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2018 Oracle. All Rights Reserved. + * + * Author: Darrick J. Wong + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it would be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef LIBFROG_PERCPU_H_ +#define LIBFROG_PERCPU_H_ + +struct ptvar; + +typedef bool (*ptvar_iter_fn)(struct ptvar *ptv, void *data, void *foreach_arg); + +struct ptvar *ptvar_init(size_t nr, size_t size); +void ptvar_free(struct ptvar *ptv); +void *ptvar_get(struct ptvar *ptv); +bool ptvar_foreach(struct ptvar *ptv, ptvar_iter_fn fn, void *foreach_arg); + +#endif /* LIBFROG_PERCPU_H_ */ diff --git a/libfrog/Makefile b/libfrog/Makefile index 4c15605..230b08f 100644 --- a/libfrog/Makefile +++ b/libfrog/Makefile @@ -16,6 +16,7 @@ convert.c \ list_sort.c \ paths.c \ projects.c \ +ptvar.c \ radix-tree.c \ topology.c \ util.c \ diff --git a/libfrog/ptvar.c b/libfrog/ptvar.c new file mode 100644 index 0000000..3654706 --- /dev/null +++ b/libfrog/ptvar.c @@ -0,0 +1,133 @@ +/* + * Copyright (C) 2018 Oracle. All Rights Reserved. + * + * Author: Darrick J. Wong + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it would be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include +#include +#include +#include +#include +#include +#include +#include "platform_defs.h" +#include "ptvar.h" + +/* + * Per-thread Variables + * + * This data structure manages a lockless per-thread variable. We + * implement this by allocating an array of memory regions, and as each + * thread tries to acquire its own region, we hand out the array + * elements to each thread. This way, each thread gets its own + * cacheline and (after the first access) doesn't have to contend for a + * lock for each access. + */ +struct ptvar { + pthread_key_t key; + pthread_mutex_t lock; + size_t nr_used; + size_t nr_counters; + size_t data_size; + unsigned char data[0]; +}; +#define PTVAR_SIZE(nr, sz) (sizeof(struct ptvar) + ((nr) * (size))) + +/* Initialize per-thread counter. */ +struct ptvar * +ptvar_init( + size_t nr, + size_t size) +{ + struct ptvar *ptv; + int ret; + +#ifdef _SC_LEVEL1_DCACHE_LINESIZE + /* Try to prevent cache pingpong by aligning to cacheline size. */ + size = max(size, sysconf(_SC_LEVEL1_DCACHE_LINESIZE)); +#endif + + ptv = malloc(PTVAR_SIZE(nr, size)); + if (!ptv) + return NULL; + ptv->data_size = size; + ptv->nr_counters = nr; + ptv->nr_used = 0; + memset(ptv->data, 0, nr * size); + ret = pthread_mutex_init(&ptv->lock, NULL); + if (ret) + goto out; + ret = pthread_key_create(&ptv->key, NULL); + if (ret) + goto out_mutex; + return ptv; + +out_mutex: + pthread_mutex_destroy(&ptv->lock); +out: + free(ptv); + return NULL; +} + +/* Free per-thread counter. */ +void +ptvar_free( + struct ptvar *ptv) +{ + pthread_key_delete(ptv->key); + pthread_mutex_destroy(&ptv->lock); + free(ptv); +} + +/* Get a reference to this thread's variable. */ +void * +ptvar_get( + struct ptvar *ptv) +{ + void *p; + + p = pthread_getspecific(ptv->key); + if (!p) { + pthread_mutex_lock(&ptv->lock); + assert(ptv->nr_used < ptv->nr_counters); + p = &ptv->data[(ptv->nr_used++) * ptv->data_size]; + pthread_setspecific(ptv->key, p); + pthread_mutex_unlock(&ptv->lock); + } + return p; +} + +/* Iterate all of the per-thread variables. */ +bool +ptvar_foreach( + struct ptvar *ptv, + ptvar_iter_fn fn, + void *foreach_arg) +{ + size_t i; + bool ret = true; + + pthread_mutex_lock(&ptv->lock); + for (i = 0; i < ptv->nr_used; i++) { + ret = fn(ptv, &ptv->data[i * ptv->data_size], foreach_arg); + if (!ret) + break; + } + pthread_mutex_unlock(&ptv->lock); + + return ret; +} diff --git a/scrub/Makefile b/scrub/Makefile index 9edc933..30dbe54 100644 --- a/scrub/Makefile +++ b/scrub/Makefile @@ -17,6 +17,7 @@ endif # scrub_prereqs HFILES = \ common.h \ +counter.h \ disk.h \ filemap.h \ fscounters.h \ @@ -27,6 +28,7 @@ xfs_scrub.h CFILES = \ common.c \ +counter.c \ disk.c \ filemap.c \ fscounters.c \ diff --git a/scrub/counter.c b/scrub/counter.c new file mode 100644 index 0000000..ced3cf3 --- /dev/null +++ b/scrub/counter.c @@ -0,0 +1,104 @@ +/* + * Copyright (C) 2018 Oracle. All Rights Reserved. + * + * Author: Darrick J. Wong + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it would be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include +#include +#include +#include +#include +#include +#include "ptvar.h" +#include "counter.h" + +/* + * Per-Thread Counters + * + * This is a global counter object that uses per-thread counters to + * count things without having to content for a single shared lock. + * Provided we know the number of threads that will be accessing the + * counter, each thread gets its own thread-specific counter variable. + * Changing the value is fast, though retrieving the value is expensive + * and approximate. + */ +struct ptcounter { + struct ptvar *var; +}; + +/* Initialize per-thread counter. */ +struct ptcounter * +ptcounter_init( + size_t nr) +{ + struct ptcounter *p; + + p = malloc(sizeof(struct ptcounter)); + if (!p) + return NULL; + p->var = ptvar_init(nr, sizeof(uint64_t)); + if (!p->var) { + free(p); + return NULL; + } + return p; +} + +/* Free per-thread counter. */ +void +ptcounter_free( + struct ptcounter *ptc) +{ + ptvar_free(ptc->var); + free(ptc); +} + +/* Add a quantity to the counter. */ +void +ptcounter_add( + struct ptcounter *ptc, + int64_t nr) +{ + uint64_t *p; + + p = ptvar_get(ptc->var); + *p += nr; +} + +static bool +ptcounter_val_helper( + struct ptvar *ptv, + void *data, + void *foreach_arg) +{ + uint64_t *sum = foreach_arg; + uint64_t *count = data; + + *sum += *count; + return true; +} + +/* Return the approximate value of this counter. */ +uint64_t +ptcounter_value( + struct ptcounter *ptc) +{ + uint64_t sum = 0; + + ptvar_foreach(ptc->var, ptcounter_val_helper, &sum); + return sum; +} diff --git a/scrub/counter.h b/scrub/counter.h new file mode 100644 index 0000000..2aac795 --- /dev/null +++ b/scrub/counter.h @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2018 Oracle. All Rights Reserved. + * + * Author: Darrick J. Wong + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it would be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef XFS_SCRUB_COUNTER_H_ +#define XFS_SCRUB_COUNTER_H_ + +struct ptcounter; +struct ptcounter *ptcounter_init(size_t nr); +void ptcounter_free(struct ptcounter *ptc); +void ptcounter_add(struct ptcounter *ptc, int64_t nr); +uint64_t ptcounter_value(struct ptcounter *ptc); + +#endif /* XFS_SCRUB_COUNTER_H_ */