aboutsummaryrefslogtreecommitdiffstats
path: root/framework/src/onos/utils/misc/src/main/java/org/onlab/util/Counter.java
blob: bde287836952b82e765e26422714da165bb97d84 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
/*
 * Copyright 2014 Open Networking Laboratory
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.onlab.util;

import java.util.Objects;

import static com.google.common.base.MoreObjects.toStringHelper;
import static com.google.common.base.Preconditions.checkArgument;

/**
 * Counting mechanism capable of tracking occurrences and rates.
 */
public class Counter {

    private long total = 0;
    private long start = System.currentTimeMillis();
    private long end = 0;

    /**
     * Creates a new counter.
     */
    public Counter() {
    }

    /**
     * Creates a new counter in a specific state. If non-zero end time is
     * specified, the counter will be frozen.
     *
     * @param start start time
     * @param total total number of items to start with
     * @param end   end time; if non-ze
     */
    public Counter(long start, long total, long end) {
        checkArgument(start <= end, "Malformed interval: start > end");
        checkArgument(total >= 0, "Total must be non-negative");
        this.start = start;
        this.total = total;
        this.end = end;
    }

    /**
     * Resets the counter, by zeroing out the count and restarting the timer.
     */
    public synchronized void reset() {
        end = 0;
        total = 0;
        start = System.currentTimeMillis();
    }

    /**
     * Freezes the counter in the current state including the counts and times.
     */
    public synchronized void freeze() {
        end = System.currentTimeMillis();
    }

    /**
     * Adds the specified number of occurrences to the counter.  No-op if the
     * counter has been frozen.
     *
     * @param count number of occurrences
     */
    public synchronized void add(long count) {
        checkArgument(count >= 0, "Count must be non-negative");
        if (end == 0L) {
            total += count;
        }
    }

    /**
     * Returns the number of occurrences per second.
     *
     * @return throughput in occurrences per second
     */
    public synchronized double throughput() {
        return total / duration();
    }

    /**
     * Returns the total number of occurrences counted.
     *
     * @return number of counted occurrences
     */
    public synchronized long total() {
        return total;
    }

    /**
     * Returns the duration expressed in fractional number of seconds.
     *
     * @return fractional number of seconds since the last reset
     */
    public synchronized double duration() {
        //  Protect against 0 return by artificially setting duration to 1ms
        long duration = (end == 0L ? System.currentTimeMillis() : end) - start;
        return (duration == 0 ? 1 : duration) / 1000.0;
    }

    @Override
    public int hashCode() {
        return Objects.hash(total, start, end);
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }
        if (obj instanceof Counter) {
            final Counter other = (Counter) obj;
            return Objects.equals(this.total, other.total) &&
                    Objects.equals(this.start, other.start) &&
                    Objects.equals(this.end, other.end);
        }
        return false;
    }

    @Override
    public String toString() {
        return toStringHelper(this)
                .add("total", total)
                .add("start", start)
                .add("end", end)
                .toString();
    }
}