001/*
002 * Written by Doug Lea with assistance from members of JCP JSR-166
003 * Expert Group and released to the public domain, as explained at
004 * http://creativecommons.org/publicdomain/zero/1.0/
005 *
006 * Source: http://gee.cs.oswego.edu/cgi-bin/viewcvs.cgi/jsr166/src/jsr166e/DoubleAdder.java?revision=1.12
007 */
008
009package io.prometheus.client;
010
011import java.io.IOException;
012import java.io.ObjectInputStream;
013import java.io.ObjectOutputStream;
014import java.io.Serializable;
015
016/**
017 * One or more variables that together maintain an initially zero
018 * {@code double} sum.  When updates (method {@link #add}) are
019 * contended across threads, the set of variables may grow dynamically
020 * to reduce contention.  Method {@link #sum} (or, equivalently {@link
021 * #doubleValue}) returns the current total combined across the
022 * variables maintaining the sum.
023 *
024 * <p>This class extends {@link Number}, but does <em>not</em> define
025 * methods such as {@code equals}, {@code hashCode} and {@code
026 * compareTo} because instances are expected to be mutated, and so are
027 * not useful as collection keys.
028 *
029 * <p><em>jsr166e note: This class is targeted to be placed in
030 * java.util.concurrent.atomic.</em>
031 *
032 * @since 1.8
033 * @author Doug Lea
034 */
035public class DoubleAdder extends Striped64 implements Serializable {
036    private static final long serialVersionUID = 7249069246863182397L;
037
038    /**
039     * Update function. Note that we must use "long" for underlying
040     * representations, because there is no compareAndSet for double,
041     * due to the fact that the bitwise equals used in any CAS
042     * implementation is not the same as double-precision equals.
043     * However, we use CAS only to detect and alleviate contention,
044     * for which bitwise equals works best anyway. In principle, the
045     * long/double conversions used here should be essentially free on
046     * most platforms since they just re-interpret bits.
047     *
048     * Similar conversions are used in other methods.
049     */
050    final long fn(long v, long x) {
051        return Double.doubleToRawLongBits
052                (Double.longBitsToDouble(v) +
053                        Double.longBitsToDouble(x));
054    }
055
056    /**
057     * Creates a new adder with initial sum of zero.
058     */
059    public DoubleAdder() {
060    }
061
062    /**
063     * Adds the given value.
064     *
065     * @param x the value to add
066     */
067    public void add(double x) {
068        Cell[] as; long b, v; int[] hc; Cell a; int n;
069        if ((as = cells) != null ||
070                !casBase(b = base,
071                        Double.doubleToRawLongBits
072                                (Double.longBitsToDouble(b) + x))) {
073            boolean uncontended = true;
074            if ((hc = threadHashCode.get()) == null ||
075                    as == null || (n = as.length) < 1 ||
076                    (a = as[(n - 1) & hc[0]]) == null ||
077                    !(uncontended = a.cas(v = a.value,
078                            Double.doubleToRawLongBits
079                                    (Double.longBitsToDouble(v) + x))))
080                retryUpdate(Double.doubleToRawLongBits(x), hc, uncontended);
081        }
082    }
083
084    /**
085     * Returns the current sum.  The returned value is <em>NOT</em> an
086     * atomic snapshot; invocation in the absence of concurrent
087     * updates returns an accurate result, but concurrent updates that
088     * occur while the sum is being calculated might not be
089     * incorporated.  Also, because floating-point arithmetic is not
090     * strictly associative, the returned result need not be identical
091     * to the value that would be obtained in a sequential series of
092     * updates to a single variable.
093     *
094     * @return the sum
095     */
096    public double sum() {
097        // On concurrent `sum` and `set`, it is acceptable to `get` an outdated `value`.
098        // On concurrent `sum` and `add`, it is acceptable to `get` an outdated `value`.
099        // On concurrent `sum` and `set` and `add`, it is possible to `get` an outdated `value`.
100
101        // Correctness is guaranteed by `volatile` memory access ordering and visibility semantics.
102        // Program order:
103        //  - writes in `set` - `busy` (CAS), `cells` (Wc), `base` (Wb), `busy`
104        //  - reads in `sum` - `cells` (Rc), `base` (Rb), `busy`, `cells` (Cc), `base` (Cb)
105        // Note that:
106        //  - `busy` is written after `cells` and `base`
107        //  - `busy` is read after `cells` and `base`, then `cells` and `base` is re-read after `busy`
108        // In other words:
109        //  - if we see the write to `busy`, then we must see the write to `cells` and `busy` on re-read
110        //  - if we don't see the write to `busy`, then we must retry as we have no guarantees
111        // Execution order (in the former case):
112        //  - serial
113        //    - old result - Rc, Rb, Cc, Cb, Wc, Wb
114        //    - new result - Wc, Wb, Rc, Rb, Cc, Cb
115        //  - concurrent
116        //    - old result - Rc, Wc, Rb, Wb, Cc, Cb - retry (superfluous)
117        //    - new result - Wc, Rc, Wb, Rb, Cc, Cb
118        //    - invalid result - Rc, Wc, Wb, Rb, Cc, Cb - retry
119        //    - invalid result - Wc, Rc, Rb, Wb, Cc, Cb - retry
120        Cell[] as = cells; long b = base;
121        while (as != null && !(busy == 0 && cells == as && base == b)) {
122            // busy waiting, retry loop
123            Thread.yield();
124            as = cells; b = base;
125        }
126
127        double sum = Double.longBitsToDouble(b);
128        if (as != null) {
129            int n = as.length;
130            for (int i = 0; i < n; ++i) {
131                Cell a = as[i];
132                if (a != null)
133                    sum += Double.longBitsToDouble(a.value);
134            }
135        }
136        return sum;
137    }
138
139    /**
140     * Resets variables maintaining the sum to zero.  This method may
141     * be a useful alternative to creating a new adder, but is only
142     * effective if there are no concurrent updates.  Because this
143     * method is intrinsically racy, it should only be used when it is
144     * known that no threads are concurrently updating.
145     */
146    public void reset() {
147        internalReset(0L);
148    }
149
150    public void set(double x) {
151        // On concurrent `set` and `set`, it should be acceptable to lose one `set` measurement.
152        // On concurrent `set` and `add`, it should be acceptable to lose the `add` measurement.
153
154        // Correctness is ensured by different techniques:
155        //  - `set` waits on contention (blocking)
156        //  - `add` avoids contention (non-blocking)
157        //  - `sum` retries on conflicts (non-blocking)
158        // Performance characteristics by use cases:
159        //  - only `set` - `cells` is always `null` - no allocations
160        //  - only `add` - `cells` allocated on contention
161        //  - mixed `set` and `add` - `cells` allocated on contention, `cells` deallocated on `set`
162        for (;;) {
163            Cell[] as;
164            if ((as = cells) != null) { // have cells
165                if (busy == 0 && casBusy()) {
166                    try {
167                        if (cells == as) { // recheck under lock
168                            // update cells and base (not atomic)
169                            cells = null;
170                            base = Double.doubleToLongBits(x);
171                            break;
172                        }
173                    } finally {
174                        busy = 0;
175                    }
176                }
177            } else { // no cells
178                // update base (atomic)
179                base = Double.doubleToLongBits(x);
180                break;
181            }
182        }
183    }
184
185    /**
186     * Equivalent in effect to {@link #sum} followed by {@link
187     * #reset}. This method may apply for example during quiescent
188     * points between multithreaded computations.  If there are
189     * updates concurrent with this method, the returned value is
190     * <em>not</em> guaranteed to be the final value occurring before
191     * the reset.
192     *
193     * @return the sum
194     */
195    public double sumThenReset() {
196        Cell[] as = cells;
197        double sum = Double.longBitsToDouble(base);
198        base = 0L;
199        if (as != null) {
200            int n = as.length;
201            for (int i = 0; i < n; ++i) {
202                Cell a = as[i];
203                if (a != null) {
204                    long v = a.value;
205                    a.value = 0L;
206                    sum += Double.longBitsToDouble(v);
207                }
208            }
209        }
210        return sum;
211    }
212
213    /**
214     * Returns the String representation of the {@link #sum}.
215     * @return the String representation of the {@link #sum}
216     */
217    public String toString() {
218        return Double.toString(sum());
219    }
220
221    /**
222     * Equivalent to {@link #sum}.
223     *
224     * @return the sum
225     */
226    public double doubleValue() {
227        return sum();
228    }
229
230    /**
231     * Returns the {@link #sum} as a {@code long} after a
232     * narrowing primitive conversion.
233     */
234    public long longValue() {
235        return (long)sum();
236    }
237
238    /**
239     * Returns the {@link #sum} as an {@code int} after a
240     * narrowing primitive conversion.
241     */
242    public int intValue() {
243        return (int)sum();
244    }
245
246    /**
247     * Returns the {@link #sum} as a {@code float}
248     * after a narrowing primitive conversion.
249     */
250    public float floatValue() {
251        return (float)sum();
252    }
253
254    private void writeObject(ObjectOutputStream s) throws IOException {
255        s.defaultWriteObject();
256        s.writeDouble(sum());
257    }
258
259    private void readObject(ObjectInputStream s)
260            throws IOException, ClassNotFoundException {
261        s.defaultReadObject();
262        busy = 0;
263        cells = null;
264        base = Double.doubleToRawLongBits(s.readDouble());
265    }
266
267}