1 /* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /*
3  *     Copyright 2015 Couchbase, Inc
4  *
5  *   Licensed under the Apache License, Version 2.0 (the "License");
6  *   you may not use this file except in compliance with the License.
7  *   You may obtain a copy of the License at
8  *
9  *       http://www.apache.org/licenses/LICENSE-2.0
10  *
11  *   Unless required by applicable law or agreed to in writing, software
12  *   distributed under the License is distributed on an "AS IS" BASIS,
13  *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  *   See the License for the specific language governing permissions and
15  *   limitations under the License.
16  */
17 #include "timings.h"
18 #include <memcached/protocol_binary.h>
19 #include <platform/platform.h>
20 #include "timing_histogram.h"
21 
Timings()22 Timings::Timings() {
23     reset();
24 }
25 
operator =(const Timings& other)26 Timings& Timings::operator=(const Timings& other) {
27     timings = other.timings;
28     interval_latency_lookups = other.interval_latency_lookups;
29     interval_latency_mutations = other.interval_latency_mutations;
30     return *this;
31 }
32 
reset(void)33 void Timings::reset(void) {
34     for (int ii = 0; ii < MAX_NUM_OPCODES; ++ii) {
35         timings[ii].reset();
36     }
37 
38     {
39         std::lock_guard<std::mutex> lg(lock);
40         interval_latency_lookups.reset();
41         interval_latency_mutations.reset();
42     }
43 }
44 
collect(const uint8_t opcode, const std::chrono::nanoseconds nsec)45 void Timings::collect(const uint8_t opcode,
46                       const std::chrono::nanoseconds nsec) {
47     timings[opcode].add(nsec);
48     auto& interval = interval_counters[opcode];
49     interval.count++;
50     interval.duration_ns += nsec.count();
51 }
52 
generate(const uint8_t opcode)53 std::string Timings::generate(const uint8_t opcode) {
54     return timings[opcode].to_string();
55 }
56 
57 static const uint8_t timings_mutations[] = {
58     PROTOCOL_BINARY_CMD_ADD,
59     PROTOCOL_BINARY_CMD_ADDQ,
60     PROTOCOL_BINARY_CMD_APPEND,
61     PROTOCOL_BINARY_CMD_APPENDQ,
62     PROTOCOL_BINARY_CMD_DECREMENT,
63     PROTOCOL_BINARY_CMD_DECREMENTQ,
64     PROTOCOL_BINARY_CMD_DELETE,
65     PROTOCOL_BINARY_CMD_DELETEQ,
66     PROTOCOL_BINARY_CMD_GAT,
67     PROTOCOL_BINARY_CMD_GATQ,
68     PROTOCOL_BINARY_CMD_INCREMENT,
69     PROTOCOL_BINARY_CMD_INCREMENTQ,
70     PROTOCOL_BINARY_CMD_PREPEND,
71     PROTOCOL_BINARY_CMD_PREPENDQ,
72     PROTOCOL_BINARY_CMD_REPLACE,
73     PROTOCOL_BINARY_CMD_REPLACEQ,
74     PROTOCOL_BINARY_CMD_SET,
75     PROTOCOL_BINARY_CMD_SETQ,
76     PROTOCOL_BINARY_CMD_TOUCH,
77     PROTOCOL_BINARY_CMD_SUBDOC_ARRAY_ADD_UNIQUE,
78     PROTOCOL_BINARY_CMD_SUBDOC_ARRAY_INSERT,
79     PROTOCOL_BINARY_CMD_SUBDOC_ARRAY_PUSH_FIRST,
80     PROTOCOL_BINARY_CMD_SUBDOC_ARRAY_PUSH_LAST,
81     PROTOCOL_BINARY_CMD_SUBDOC_ARRAY_ADD_UNIQUE,
82     PROTOCOL_BINARY_CMD_SUBDOC_COUNTER,
83     PROTOCOL_BINARY_CMD_SUBDOC_DELETE,
84     PROTOCOL_BINARY_CMD_SUBDOC_DICT_UPSERT,
85     PROTOCOL_BINARY_CMD_SUBDOC_REPLACE,
86     PROTOCOL_BINARY_CMD_SUBDOC_DICT_ADD,
87     PROTOCOL_BINARY_CMD_SUBDOC_MULTI_MUTATION};
88 
89 static const uint8_t timings_retrievals[] = {
90     PROTOCOL_BINARY_CMD_GAT,
91     PROTOCOL_BINARY_CMD_GATQ,
92     PROTOCOL_BINARY_CMD_GET,
93     PROTOCOL_BINARY_CMD_GETK,
94     PROTOCOL_BINARY_CMD_GETKQ,
95     PROTOCOL_BINARY_CMD_GETQ,
96     PROTOCOL_BINARY_CMD_GET_LOCKED,
97     PROTOCOL_BINARY_CMD_GET_RANDOM_KEY,
98     PROTOCOL_BINARY_CMD_GET_REPLICA,
99     PROTOCOL_BINARY_CMD_SUBDOC_MULTI_LOOKUP,
100     PROTOCOL_BINARY_CMD_SUBDOC_GET,
101     PROTOCOL_BINARY_CMD_SUBDOC_EXISTS};
102 
103 
get_aggregated_mutation_stats()104 uint64_t Timings::get_aggregated_mutation_stats() {
105 
106     uint64_t ret = 0;
107     for (auto cmd : timings_mutations) {
108         ret += timings[cmd].get_total();
109     }
110     return ret;
111 }
112 
get_aggregated_retrival_stats()113 uint64_t Timings::get_aggregated_retrival_stats() {
114 
115     uint64_t ret = 0;
116     for (auto cmd : timings_retrievals) {
117         ret += timings[cmd].get_total();
118     }
119     return ret;
120 }
121 
get_interval_mutation_latency()122 cb::sampling::Interval Timings::get_interval_mutation_latency() {
123     std::lock_guard<std::mutex> lg(lock);
124     return interval_latency_mutations.getAggregate();
125 }
126 
get_interval_lookup_latency()127 cb::sampling::Interval Timings::get_interval_lookup_latency() {
128     std::lock_guard<std::mutex> lg(lock);
129     return interval_latency_lookups.getAggregate();
130 }
131 
sample(std::chrono::seconds sample_interval)132 void Timings::sample(std::chrono::seconds sample_interval) {
133     cb::sampling::Interval interval_lookup, interval_mutation;
134 
135     for (auto op : timings_mutations) {
136         interval_mutation += interval_counters[op];
137         interval_counters[op].reset();
138     }
139 
140     for (auto op : timings_retrievals) {
141         interval_lookup += interval_counters[op];
142         interval_counters[op].reset();
143     }
144 
145     {
146         std::lock_guard<std::mutex> lg(lock);
147         interval_latency_lookups.sample(interval_lookup);
148         interval_latency_mutations.sample(interval_mutation);
149     }
150 }
151