• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2016 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "PerfTest.h"
18 #include <fstream>
19 #include <iomanip>
20 #include <iostream>
21 #include <string>
22 
23 #ifdef ASSERT
24 #undef ASSERT
25 #endif
26 #define ASSERT(cond)                                                                              \
27     do {                                                                                          \
28         if (!(cond)) {                                                                            \
29             cerr << __func__ << ":" << __LINE__ << " condition:" << #cond << " failed\n" << endl; \
30             exit(EXIT_FAILURE);                                                                   \
31         }                                                                                         \
32     } while (0)
33 
34 // the ratio that the service is synced on the same cpu beyond
35 // GOOD_SYNC_MIN is considered as good
36 #define GOOD_SYNC_MIN (0.6)
37 
38 // the precision used for cout to dump float
39 #define DUMP_PRICISION 2
40 
41 using std::cerr;
42 using std::cout;
43 using std::endl;
44 using std::left;
45 using std::ios;
46 using std::min;
47 using std::max;
48 using std::to_string;
49 using std::setprecision;
50 using std::setw;
51 using std::ofstream;
52 using std::make_tuple;
53 
createPipePair()54 tuple<Pipe, Pipe> Pipe::createPipePair() {
55     int a[2];
56     int b[2];
57 
58     int error1 = pipe(a);
59     int error2 = pipe(b);
60     ASSERT(error1 >= 0);
61     ASSERT(error2 >= 0);
62 
63     return make_tuple(Pipe(a[0], b[1]), Pipe(b[0], a[1]));
64 }
65 
Pipe(Pipe && rval)66 Pipe::Pipe(Pipe&& rval) noexcept {
67     fd_read_ = rval.fd_read_;
68     fd_write_ = rval.fd_write_;
69     rval.fd_read_ = 0;
70     rval.fd_write_ = 0;
71 }
72 
~Pipe()73 Pipe::~Pipe() {
74     if (fd_read_) {
75         close(fd_read_);
76     }
77     if (fd_write_) {
78         close(fd_write_);
79     }
80 }
81 
combine(const Results & a,const Results & b)82 Results Results::combine(const Results& a, const Results& b) {
83     Results ret;
84     for (uint32_t i = 0; i < kNumBuckets; i++) {
85         ret.buckets_[i] = a.buckets_[i] + b.buckets_[i];
86     }
87     ret.worst_ = max(a.worst_, b.worst_);
88     ret.best_ = min(a.best_, b.best_);
89     ret.transactions_ = a.transactions_ + b.transactions_;
90     ret.miss_ = a.miss_ + b.miss_;
91     ret.total_time_ = a.total_time_ + b.total_time_;
92     return ret;
93 }
94 
traceStop()95 static void traceStop() {
96     ofstream file;
97     file.open(TRACE_PATH "/tracing_on", ios::out | ios::trunc);
98     file << '0' << endl;
99     file.close();
100 }
101 
addTime(uint64_t nano)102 void Results::addTime(uint64_t nano) {
103     buckets_[min(nano, kMaxTimeBucket - 1) / kTimePerBucket] += 1;
104     best_ = min(nano, best_);
105     worst_ = max(nano, worst_);
106     if (raw_dump_) {
107         raw_data_->push_back(nano);
108     }
109     transactions_ += 1;
110     total_time_ += nano;
111     if (missDeadline(nano)) {
112         miss_++;
113         if (tracing_) {
114             // There might be multiple process pair running the test concurrently
115             // each may execute following statements and only the first one actually
116             // stop the trace and any traceStop() after then has no effect.
117             traceStop();
118             cerr << endl;
119             cerr << "deadline triggered: halt & stop trace" << endl;
120             cerr << "log:" TRACE_PATH "/trace" << endl;
121             cerr << endl;
122             exit(EXIT_FAILURE);
123         }
124     }
125 }
126 
setupRawData()127 void Results::setupRawData() {
128     raw_dump_ = true;
129     if (raw_data_ == nullptr) {
130         raw_data_ = new list<uint64_t>;
131     } else {
132         raw_data_->clear();
133     }
134 }
135 
flushRawData()136 void Results::flushRawData() {
137     if (raw_dump_) {
138         bool first = true;
139         cout << "[";
140         for (auto nano : *raw_data_) {
141             cout << (first ? "" : ",") << to_string(nano);
142             first = false;
143         }
144         cout << "]," << endl;
145         delete raw_data_;
146         raw_data_ = nullptr;
147     }
148 }
149 
dump() const150 void Results::dump() const {
151     double best = (double)best_ / 1.0E6;
152     double worst = (double)worst_ / 1.0E6;
153     double average = (double)total_time_ / transactions_ / 1.0E6;
154     int W = DUMP_PRICISION + 2;
155     cout << std::setprecision(DUMP_PRICISION) << "{ \"avg\":" << setw(W) << left << average
156          << ", \"wst\":" << setw(W) << left << worst << ", \"bst\":" << setw(W) << left << best
157          << ", \"miss\":" << left << miss_ << ", \"meetR\":" << setprecision(DUMP_PRICISION + 3)
158          << left << (1.0 - (double)miss_ / transactions_) << "}";
159 }
160 
dumpDistribution() const161 void Results::dumpDistribution() const {
162     uint64_t cur_total = 0;
163     cout << "{ ";
164     cout << std::setprecision(DUMP_PRICISION + 3);
165     for (uint32_t i = 0; i < kNumBuckets; i++) {
166         float cur_time = kTimePerBucketMS * i + 0.5f * kTimePerBucketMS;
167         float accumulation = cur_total + buckets_[i];
168         if ((cur_total < 0.5f * transactions_) && (accumulation >= 0.5f * transactions_)) {
169             cout << "\"p50\":" << cur_time << ", ";
170         }
171         if ((cur_total < 0.9f * transactions_) && (accumulation >= 0.9f * transactions_)) {
172             cout << "\"p90\":" << cur_time << ", ";
173         }
174         if ((cur_total < 0.95f * transactions_) && (accumulation >= 0.95f * transactions_)) {
175             cout << "\"p95\":" << cur_time << ", ";
176         }
177         if ((cur_total < 0.99f * transactions_) && (accumulation >= 0.99f * transactions_)) {
178             cout << "\"p99\": " << cur_time;
179         }
180         cur_total += buckets_[i];
181     }
182     cout << "}";
183 }
184 
combine(const PResults & a,const PResults & b)185 PResults PResults::combine(const PResults& a, const PResults& b) {
186     PResults ret;
187     ret.nNotInherent = a.nNotInherent + b.nNotInherent;
188     ret.nNotSync = a.nNotSync + b.nNotSync;
189     ret.other = Results::combine(a.other, b.other);
190     ret.fifo = Results::combine(a.fifo, b.fifo);
191     return ret;
192 }
193 
dump() const194 void PResults::dump() const {
195     int no_trans = other.getTransactions() + fifo.getTransactions();
196     double sync_ratio = (1.0 - (double)nNotSync / no_trans);
197     cout << "{\"SYNC\":\"" << ((sync_ratio > GOOD_SYNC_MIN) ? "GOOD" : "POOR") << "\","
198          << "\"S\":" << (no_trans - nNotSync) << ",\"I\":" << no_trans << ","
199          << "\"R\":" << sync_ratio << "," << endl;
200     cout << "  \"other_ms\":";
201     other.dump();
202     cout << "," << endl;
203     cout << "  \"fifo_ms\": ";
204     fifo.dump();
205     cout << "," << endl;
206     cout << "  \"otherdis\":";
207     other.dumpDistribution();
208     cout << "," << endl;
209     cout << "  \"fifodis\": ";
210     fifo.dumpDistribution();
211     cout << endl;
212     cout << "}," << endl;
213 }
214