]>
Commit | Line | Data |
---|---|---|
8d318d62 | 1 | // SPDX-License-Identifier: GPL-2.0-or-later |
d11cc69e | 2 | /* |
52520522 | 3 | * Copyright (C) 2018-2024 Oracle. All Rights Reserved. |
8d318d62 | 4 | * Author: Darrick J. Wong <djwong@kernel.org> |
d11cc69e | 5 | */ |
a440f877 | 6 | #include "xfs.h" |
d11cc69e DW |
7 | #include <stdint.h> |
8 | #include <stdlib.h> | |
d11cc69e DW |
9 | #include <string.h> |
10 | #include <assert.h> | |
11 | #include <pthread.h> | |
14051909 | 12 | #include "libfrog/ptvar.h" |
d11cc69e DW |
13 | #include "counter.h" |
14 | ||
15 | /* | |
16 | * Per-Thread Counters | |
17 | * | |
18 | * This is a global counter object that uses per-thread counters to | |
19 | * count things without having to content for a single shared lock. | |
20 | * Provided we know the number of threads that will be accessing the | |
21 | * counter, each thread gets its own thread-specific counter variable. | |
22 | * Changing the value is fast, though retrieving the value is expensive | |
23 | * and approximate. | |
24 | */ | |
25 | struct ptcounter { | |
26 | struct ptvar *var; | |
27 | }; | |
28 | ||
da3dd6c0 DW |
29 | /* Allocate per-thread counter. */ |
30 | int | |
31 | ptcounter_alloc( | |
32 | size_t nr, | |
33 | struct ptcounter **pp) | |
d11cc69e DW |
34 | { |
35 | struct ptcounter *p; | |
cb321a39 | 36 | int ret; |
d11cc69e DW |
37 | |
38 | p = malloc(sizeof(struct ptcounter)); | |
39 | if (!p) | |
da3dd6c0 | 40 | return errno; |
2f4422f4 | 41 | ret = -ptvar_alloc(nr, sizeof(uint64_t), &p->var); |
cb321a39 | 42 | if (ret) { |
d11cc69e | 43 | free(p); |
da3dd6c0 | 44 | return ret; |
d11cc69e | 45 | } |
da3dd6c0 DW |
46 | *pp = p; |
47 | return 0; | |
d11cc69e DW |
48 | } |
49 | ||
50 | /* Free per-thread counter. */ | |
51 | void | |
52 | ptcounter_free( | |
53 | struct ptcounter *ptc) | |
54 | { | |
55 | ptvar_free(ptc->var); | |
56 | free(ptc); | |
57 | } | |
58 | ||
59 | /* Add a quantity to the counter. */ | |
da3dd6c0 | 60 | int |
d11cc69e DW |
61 | ptcounter_add( |
62 | struct ptcounter *ptc, | |
63 | int64_t nr) | |
64 | { | |
65 | uint64_t *p; | |
cb321a39 | 66 | int ret; |
d11cc69e | 67 | |
cb321a39 | 68 | p = ptvar_get(ptc->var, &ret); |
da3dd6c0 | 69 | if (ret) |
2f4422f4 | 70 | return -ret; |
d11cc69e | 71 | *p += nr; |
da3dd6c0 | 72 | return 0; |
d11cc69e DW |
73 | } |
74 | ||
cb321a39 | 75 | static int |
d11cc69e DW |
76 | ptcounter_val_helper( |
77 | struct ptvar *ptv, | |
78 | void *data, | |
79 | void *foreach_arg) | |
80 | { | |
81 | uint64_t *sum = foreach_arg; | |
82 | uint64_t *count = data; | |
83 | ||
84 | *sum += *count; | |
cb321a39 | 85 | return 0; |
d11cc69e DW |
86 | } |
87 | ||
88 | /* Return the approximate value of this counter. */ | |
da3dd6c0 | 89 | int |
d11cc69e | 90 | ptcounter_value( |
da3dd6c0 DW |
91 | struct ptcounter *ptc, |
92 | uint64_t *sum) | |
d11cc69e | 93 | { |
da3dd6c0 | 94 | *sum = 0; |
2f4422f4 | 95 | return -ptvar_foreach(ptc->var, ptcounter_val_helper, sum); |
d11cc69e | 96 | } |