xref: /aosp_15_r20/external/stressapptest/src/finelock_queue.cc (revision 424fb153c814cbcb3e8904974796228774b3229a)
1*424fb153SAndroid Build Coastguard Worker // Copyright 2007 Google Inc. All Rights Reserved.
2*424fb153SAndroid Build Coastguard Worker 
3*424fb153SAndroid Build Coastguard Worker // Licensed under the Apache License, Version 2.0 (the "License");
4*424fb153SAndroid Build Coastguard Worker // you may not use this file except in compliance with the License.
5*424fb153SAndroid Build Coastguard Worker // You may obtain a copy of the License at
6*424fb153SAndroid Build Coastguard Worker 
7*424fb153SAndroid Build Coastguard Worker //      http://www.apache.org/licenses/LICENSE-2.0
8*424fb153SAndroid Build Coastguard Worker 
9*424fb153SAndroid Build Coastguard Worker // Unless required by applicable law or agreed to in writing, software
10*424fb153SAndroid Build Coastguard Worker // distributed under the License is distributed on an "AS IS" BASIS,
11*424fb153SAndroid Build Coastguard Worker // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*424fb153SAndroid Build Coastguard Worker // See the License for the specific language governing permissions and
13*424fb153SAndroid Build Coastguard Worker // limitations under the License.
14*424fb153SAndroid Build Coastguard Worker 
15*424fb153SAndroid Build Coastguard Worker // This is an interface to a simple thread safe container with fine-grain locks,
16*424fb153SAndroid Build Coastguard Worker // used to hold data blocks and patterns.
17*424fb153SAndroid Build Coastguard Worker 
18*424fb153SAndroid Build Coastguard Worker // This file must work with autoconf on its public version,
19*424fb153SAndroid Build Coastguard Worker // so these includes are correct.
20*424fb153SAndroid Build Coastguard Worker #include "finelock_queue.h"
21*424fb153SAndroid Build Coastguard Worker #include "os.h"
22*424fb153SAndroid Build Coastguard Worker 
23*424fb153SAndroid Build Coastguard Worker // Page entry queue implementation follows.
24*424fb153SAndroid Build Coastguard Worker // Push and Get functions are analogous to lock and unlock operations on a given
25*424fb153SAndroid Build Coastguard Worker // page entry, while preserving queue semantics.
26*424fb153SAndroid Build Coastguard Worker //
27*424fb153SAndroid Build Coastguard Worker // The actual 'queue' implementation is actually just an array. The entries are
28*424fb153SAndroid Build Coastguard Worker // never shuffled or re-ordered like that of a real queue. Instead, Get
29*424fb153SAndroid Build Coastguard Worker // functions return a random page entry of a given type and lock that particular
30*424fb153SAndroid Build Coastguard Worker // page entry until it is unlocked by corresponding Put functions.
31*424fb153SAndroid Build Coastguard Worker //
32*424fb153SAndroid Build Coastguard Worker // In this implementation, a free page is those page entries where pattern is
33*424fb153SAndroid Build Coastguard Worker // null (pe->pattern == 0)
34*424fb153SAndroid Build Coastguard Worker 
35*424fb153SAndroid Build Coastguard Worker 
36*424fb153SAndroid Build Coastguard Worker // Constructor: Allocates memory and initialize locks.
FineLockPEQueue(uint64 queuesize,int64 pagesize)37*424fb153SAndroid Build Coastguard Worker FineLockPEQueue::FineLockPEQueue(
38*424fb153SAndroid Build Coastguard Worker                  uint64 queuesize, int64 pagesize) {
39*424fb153SAndroid Build Coastguard Worker   q_size_ = queuesize;
40*424fb153SAndroid Build Coastguard Worker   pages_ = new struct page_entry[q_size_];
41*424fb153SAndroid Build Coastguard Worker   pagelocks_ = new pthread_mutex_t[q_size_];
42*424fb153SAndroid Build Coastguard Worker   page_size_ = pagesize;
43*424fb153SAndroid Build Coastguard Worker 
44*424fb153SAndroid Build Coastguard Worker   // What metric should we measure this run.
45*424fb153SAndroid Build Coastguard Worker   queue_metric_ = kTouch;
46*424fb153SAndroid Build Coastguard Worker 
47*424fb153SAndroid Build Coastguard Worker   {  // Init all the page locks.
48*424fb153SAndroid Build Coastguard Worker     for (uint64 i = 0; i < q_size_; i++) {
49*424fb153SAndroid Build Coastguard Worker         pthread_mutex_init(&(pagelocks_[i]), NULL);
50*424fb153SAndroid Build Coastguard Worker         // Pages start out owned (locked) by Sat::InitializePages.
51*424fb153SAndroid Build Coastguard Worker         // A locked state indicates that the page state is unknown,
52*424fb153SAndroid Build Coastguard Worker         // and the lock should not be aquired. As InitializePages creates
53*424fb153SAndroid Build Coastguard Worker         // the page records, they will be inserted and unlocked, at which point
54*424fb153SAndroid Build Coastguard Worker         // they are ready to be aquired and filled by worker threads.
55*424fb153SAndroid Build Coastguard Worker         sat_assert(pthread_mutex_lock(&(pagelocks_[i])) == 0);
56*424fb153SAndroid Build Coastguard Worker     }
57*424fb153SAndroid Build Coastguard Worker   }
58*424fb153SAndroid Build Coastguard Worker 
59*424fb153SAndroid Build Coastguard Worker   {  // Init the random number generator.
60*424fb153SAndroid Build Coastguard Worker     for (int i = 0; i < 4; i++) {
61*424fb153SAndroid Build Coastguard Worker       rand_seed_[i] = i + 0xbeef;
62*424fb153SAndroid Build Coastguard Worker       pthread_mutex_init(&(randlocks_[i]), NULL);
63*424fb153SAndroid Build Coastguard Worker     }
64*424fb153SAndroid Build Coastguard Worker   }
65*424fb153SAndroid Build Coastguard Worker 
66*424fb153SAndroid Build Coastguard Worker   // Try to make a linear congruential generator with our queue size.
67*424fb153SAndroid Build Coastguard Worker   // We need this to deterministically search all the queue (being able to find
68*424fb153SAndroid Build Coastguard Worker   // a single available element is a design requirement), but we don't want to
69*424fb153SAndroid Build Coastguard Worker   // cause any page to be more likley chosen than another. The previous
70*424fb153SAndroid Build Coastguard Worker   // sequential retry heavily biased pages at the beginning of a bunch, or
71*424fb153SAndroid Build Coastguard Worker   // isolated pages surrounded by unqualified ones.
72*424fb153SAndroid Build Coastguard Worker   int64 length = queuesize;
73*424fb153SAndroid Build Coastguard Worker   int64 modlength = length;
74*424fb153SAndroid Build Coastguard Worker   int64 a;
75*424fb153SAndroid Build Coastguard Worker   int64 c;
76*424fb153SAndroid Build Coastguard Worker 
77*424fb153SAndroid Build Coastguard Worker   if (length < 3) {
78*424fb153SAndroid Build Coastguard Worker     a = 1;
79*424fb153SAndroid Build Coastguard Worker     c = 1;
80*424fb153SAndroid Build Coastguard Worker   } else {
81*424fb153SAndroid Build Coastguard Worker     // Search for a nontrivial generator.
82*424fb153SAndroid Build Coastguard Worker     a = getA(length) % length;
83*424fb153SAndroid Build Coastguard Worker     // If this queue size doesn't have a nontrivial generator (where the
84*424fb153SAndroid Build Coastguard Worker     // multiplier is greater then one) we'll check increasing queue sizes,
85*424fb153SAndroid Build Coastguard Worker     // and discard out of bounds results.
86*424fb153SAndroid Build Coastguard Worker     while (a == 1) {
87*424fb153SAndroid Build Coastguard Worker       modlength++;
88*424fb153SAndroid Build Coastguard Worker       a = getA(modlength) % modlength;
89*424fb153SAndroid Build Coastguard Worker     }
90*424fb153SAndroid Build Coastguard Worker     c = getC(modlength);
91*424fb153SAndroid Build Coastguard Worker   }
92*424fb153SAndroid Build Coastguard Worker 
93*424fb153SAndroid Build Coastguard Worker   // This is our final generator.
94*424fb153SAndroid Build Coastguard Worker   a_ = a;
95*424fb153SAndroid Build Coastguard Worker   c_ = c;
96*424fb153SAndroid Build Coastguard Worker   modlength_ = modlength;
97*424fb153SAndroid Build Coastguard Worker }
98*424fb153SAndroid Build Coastguard Worker 
99*424fb153SAndroid Build Coastguard Worker // Part of building a linear congruential generator n1 = (a * n0 + c) % m
100*424fb153SAndroid Build Coastguard Worker // Get 'a', where a - 1 must be divisible by all prime
101*424fb153SAndroid Build Coastguard Worker // factors of 'm', our queue size.
getA(int64 m)102*424fb153SAndroid Build Coastguard Worker int64 FineLockPEQueue::getA(int64 m) {
103*424fb153SAndroid Build Coastguard Worker   int64 remaining = m;
104*424fb153SAndroid Build Coastguard Worker   int64 a = 1;
105*424fb153SAndroid Build Coastguard Worker   if ((((remaining / 4) * 4) == remaining)) {
106*424fb153SAndroid Build Coastguard Worker     a = 2;
107*424fb153SAndroid Build Coastguard Worker   }
108*424fb153SAndroid Build Coastguard Worker   // For each number, let's see if it's divisible,
109*424fb153SAndroid Build Coastguard Worker   // then divide it out.
110*424fb153SAndroid Build Coastguard Worker   for (int64 i = 2; i <= m; i++) {
111*424fb153SAndroid Build Coastguard Worker     if (((remaining / i) * i) == remaining) {
112*424fb153SAndroid Build Coastguard Worker       remaining /= i;
113*424fb153SAndroid Build Coastguard Worker       // Keep dividing it out until there's no more.
114*424fb153SAndroid Build Coastguard Worker       while (((remaining / i) * i) == remaining)
115*424fb153SAndroid Build Coastguard Worker         remaining /= i;
116*424fb153SAndroid Build Coastguard Worker       a *= i;
117*424fb153SAndroid Build Coastguard Worker     }
118*424fb153SAndroid Build Coastguard Worker   }
119*424fb153SAndroid Build Coastguard Worker 
120*424fb153SAndroid Build Coastguard Worker   // Return 'a' as specified.
121*424fb153SAndroid Build Coastguard Worker   return (a + 1) % m;
122*424fb153SAndroid Build Coastguard Worker }
123*424fb153SAndroid Build Coastguard Worker 
124*424fb153SAndroid Build Coastguard Worker 
125*424fb153SAndroid Build Coastguard Worker // Part of building a linear congruential generator n1 = (a * n0 + c) % m
126*424fb153SAndroid Build Coastguard Worker // Get a prime number approx 3/4 the size of our queue.
getC(int64 m)127*424fb153SAndroid Build Coastguard Worker int64 FineLockPEQueue::getC(int64 m) {
128*424fb153SAndroid Build Coastguard Worker   // Start here at 3/4.
129*424fb153SAndroid Build Coastguard Worker   int64 start = (3 * m) / 4 + 1;
130*424fb153SAndroid Build Coastguard Worker   int64 possible_prime = start;
131*424fb153SAndroid Build Coastguard Worker   // Keep trying until we find a prime.
132*424fb153SAndroid Build Coastguard Worker   for (possible_prime = start; possible_prime > 1; possible_prime--) {
133*424fb153SAndroid Build Coastguard Worker     bool failed = false;
134*424fb153SAndroid Build Coastguard Worker     for (int64 i = 2; i < possible_prime; i++) {
135*424fb153SAndroid Build Coastguard Worker       if (((possible_prime / i) * i) == possible_prime) {
136*424fb153SAndroid Build Coastguard Worker         failed = true;
137*424fb153SAndroid Build Coastguard Worker         break;
138*424fb153SAndroid Build Coastguard Worker       }
139*424fb153SAndroid Build Coastguard Worker     }
140*424fb153SAndroid Build Coastguard Worker     if (!failed) {
141*424fb153SAndroid Build Coastguard Worker       return possible_prime;
142*424fb153SAndroid Build Coastguard Worker     }
143*424fb153SAndroid Build Coastguard Worker   }
144*424fb153SAndroid Build Coastguard Worker   // One is prime enough.
145*424fb153SAndroid Build Coastguard Worker   return 1;
146*424fb153SAndroid Build Coastguard Worker }
147*424fb153SAndroid Build Coastguard Worker 
148*424fb153SAndroid Build Coastguard Worker // Destructor: Clean-up allocated memory and destroy pthread locks.
~FineLockPEQueue()149*424fb153SAndroid Build Coastguard Worker FineLockPEQueue::~FineLockPEQueue() {
150*424fb153SAndroid Build Coastguard Worker   uint64 i;
151*424fb153SAndroid Build Coastguard Worker   for (i = 0; i < q_size_; i++)
152*424fb153SAndroid Build Coastguard Worker     pthread_mutex_destroy(&(pagelocks_[i]));
153*424fb153SAndroid Build Coastguard Worker   delete[] pagelocks_;
154*424fb153SAndroid Build Coastguard Worker   delete[] pages_;
155*424fb153SAndroid Build Coastguard Worker   for (i = 0; i < 4; i++) {
156*424fb153SAndroid Build Coastguard Worker     pthread_mutex_destroy(&(randlocks_[i]));
157*424fb153SAndroid Build Coastguard Worker   }
158*424fb153SAndroid Build Coastguard Worker }
159*424fb153SAndroid Build Coastguard Worker 
160*424fb153SAndroid Build Coastguard Worker 
QueueAnalysis()161*424fb153SAndroid Build Coastguard Worker bool FineLockPEQueue::QueueAnalysis() {
162*424fb153SAndroid Build Coastguard Worker   const char *measurement = "Error";
163*424fb153SAndroid Build Coastguard Worker   uint64 buckets[32];
164*424fb153SAndroid Build Coastguard Worker 
165*424fb153SAndroid Build Coastguard Worker   if (queue_metric_ == kTries)
166*424fb153SAndroid Build Coastguard Worker     measurement = "Failed retrievals";
167*424fb153SAndroid Build Coastguard Worker   else if (queue_metric_ == kTouch)
168*424fb153SAndroid Build Coastguard Worker     measurement = "Reads per page";
169*424fb153SAndroid Build Coastguard Worker 
170*424fb153SAndroid Build Coastguard Worker   // Buckets for each log2 access counts.
171*424fb153SAndroid Build Coastguard Worker   for (int b = 0; b < 32; b++) {
172*424fb153SAndroid Build Coastguard Worker     buckets[b] = 0;
173*424fb153SAndroid Build Coastguard Worker   }
174*424fb153SAndroid Build Coastguard Worker 
175*424fb153SAndroid Build Coastguard Worker   // Bucketize the page counts by highest bit set.
176*424fb153SAndroid Build Coastguard Worker   for (uint64 i = 0; i < q_size_; i++) {
177*424fb153SAndroid Build Coastguard Worker     uint32 readcount = pages_[i].touch;
178*424fb153SAndroid Build Coastguard Worker     int b = 0;
179*424fb153SAndroid Build Coastguard Worker     for (b = 0; b < 31; b++) {
180*424fb153SAndroid Build Coastguard Worker       if (readcount < (1u << b))
181*424fb153SAndroid Build Coastguard Worker         break;
182*424fb153SAndroid Build Coastguard Worker     }
183*424fb153SAndroid Build Coastguard Worker 
184*424fb153SAndroid Build Coastguard Worker     buckets[b]++;
185*424fb153SAndroid Build Coastguard Worker   }
186*424fb153SAndroid Build Coastguard Worker 
187*424fb153SAndroid Build Coastguard Worker   logprintf(12, "Log:  %s histogram\n", measurement);
188*424fb153SAndroid Build Coastguard Worker   for (int b = 0; b < 32; b++) {
189*424fb153SAndroid Build Coastguard Worker     if (buckets[b])
190*424fb153SAndroid Build Coastguard Worker       logprintf(12, "Log:  %12d - %12d: %12d\n",
191*424fb153SAndroid Build Coastguard Worker           ((1 << b) >> 1), 1 << b, buckets[b]);
192*424fb153SAndroid Build Coastguard Worker   }
193*424fb153SAndroid Build Coastguard Worker 
194*424fb153SAndroid Build Coastguard Worker   return true;
195*424fb153SAndroid Build Coastguard Worker }
196*424fb153SAndroid Build Coastguard Worker 
197*424fb153SAndroid Build Coastguard Worker namespace {
198*424fb153SAndroid Build Coastguard Worker // Callback mechanism for exporting last action.
199*424fb153SAndroid Build Coastguard Worker OsLayer *g_os;
200*424fb153SAndroid Build Coastguard Worker FineLockPEQueue *g_fpqueue = 0;
201*424fb153SAndroid Build Coastguard Worker 
202*424fb153SAndroid Build Coastguard Worker // Global callback to hook into Os object.
err_log_callback(uint64 paddr,string * buf)203*424fb153SAndroid Build Coastguard Worker bool err_log_callback(uint64 paddr, string *buf) {
204*424fb153SAndroid Build Coastguard Worker   if (g_fpqueue) {
205*424fb153SAndroid Build Coastguard Worker     return g_fpqueue->ErrorLogCallback(paddr, buf);
206*424fb153SAndroid Build Coastguard Worker   }
207*424fb153SAndroid Build Coastguard Worker   return false;
208*424fb153SAndroid Build Coastguard Worker }
209*424fb153SAndroid Build Coastguard Worker }
210*424fb153SAndroid Build Coastguard Worker 
211*424fb153SAndroid Build Coastguard Worker // Setup global state for exporting callback.
set_os(OsLayer * os)212*424fb153SAndroid Build Coastguard Worker void FineLockPEQueue::set_os(OsLayer *os) {
213*424fb153SAndroid Build Coastguard Worker   g_os = os;
214*424fb153SAndroid Build Coastguard Worker   g_fpqueue = this;
215*424fb153SAndroid Build Coastguard Worker }
216*424fb153SAndroid Build Coastguard Worker 
get_err_log_callback()217*424fb153SAndroid Build Coastguard Worker OsLayer::ErrCallback FineLockPEQueue::get_err_log_callback() {
218*424fb153SAndroid Build Coastguard Worker   return err_log_callback;
219*424fb153SAndroid Build Coastguard Worker }
220*424fb153SAndroid Build Coastguard Worker 
221*424fb153SAndroid Build Coastguard Worker // This call is used to export last transaction info on a particular physical
222*424fb153SAndroid Build Coastguard Worker // address.
ErrorLogCallback(uint64 paddr,string * message)223*424fb153SAndroid Build Coastguard Worker bool FineLockPEQueue::ErrorLogCallback(uint64 paddr, string *message) {
224*424fb153SAndroid Build Coastguard Worker   struct page_entry pe;
225*424fb153SAndroid Build Coastguard Worker   OsLayer *os = g_os;
226*424fb153SAndroid Build Coastguard Worker   sat_assert(g_os);
227*424fb153SAndroid Build Coastguard Worker   char buf[256];
228*424fb153SAndroid Build Coastguard Worker 
229*424fb153SAndroid Build Coastguard Worker   // Find the page of this paddr.
230*424fb153SAndroid Build Coastguard Worker   int gotpage = GetPageFromPhysical(paddr, &pe);
231*424fb153SAndroid Build Coastguard Worker   if (!gotpage) {
232*424fb153SAndroid Build Coastguard Worker     return false;
233*424fb153SAndroid Build Coastguard Worker   }
234*424fb153SAndroid Build Coastguard Worker 
235*424fb153SAndroid Build Coastguard Worker   // Find offset into the page.
236*424fb153SAndroid Build Coastguard Worker   uint64 addr_diff = paddr - pe.paddr;
237*424fb153SAndroid Build Coastguard Worker 
238*424fb153SAndroid Build Coastguard Worker   // Find vaddr of this paddr. Make sure it matches,
239*424fb153SAndroid Build Coastguard Worker   // as sometimes virtual memory is not contiguous.
240*424fb153SAndroid Build Coastguard Worker   char *vaddr =
241*424fb153SAndroid Build Coastguard Worker     reinterpret_cast<char*>(os->PrepareTestMem(pe.offset, page_size_));
242*424fb153SAndroid Build Coastguard Worker   uint64 new_paddr = os->VirtualToPhysical(vaddr + addr_diff);
243*424fb153SAndroid Build Coastguard Worker   os->ReleaseTestMem(vaddr, pe.offset, page_size_);
244*424fb153SAndroid Build Coastguard Worker 
245*424fb153SAndroid Build Coastguard Worker   // Is the physical address at this page offset the same as
246*424fb153SAndroid Build Coastguard Worker   // the physical address we were given?
247*424fb153SAndroid Build Coastguard Worker   if (new_paddr != paddr) {
248*424fb153SAndroid Build Coastguard Worker     return false;
249*424fb153SAndroid Build Coastguard Worker   }
250*424fb153SAndroid Build Coastguard Worker 
251*424fb153SAndroid Build Coastguard Worker   // Print all the info associated with this page.
252*424fb153SAndroid Build Coastguard Worker   message->assign(" (Last Transaction:");
253*424fb153SAndroid Build Coastguard Worker 
254*424fb153SAndroid Build Coastguard Worker   if (pe.lastpattern) {
255*424fb153SAndroid Build Coastguard Worker     int offset = addr_diff / 8;
256*424fb153SAndroid Build Coastguard Worker     datacast_t data;
257*424fb153SAndroid Build Coastguard Worker 
258*424fb153SAndroid Build Coastguard Worker     data.l32.l = pe.lastpattern->pattern(offset << 1);
259*424fb153SAndroid Build Coastguard Worker     data.l32.h = pe.lastpattern->pattern((offset << 1) + 1);
260*424fb153SAndroid Build Coastguard Worker 
261*424fb153SAndroid Build Coastguard Worker     snprintf(buf, sizeof(buf), " %s data=%#016llx",
262*424fb153SAndroid Build Coastguard Worker                   pe.lastpattern->name(), data.l64);
263*424fb153SAndroid Build Coastguard Worker     message->append(buf);
264*424fb153SAndroid Build Coastguard Worker   }
265*424fb153SAndroid Build Coastguard Worker   snprintf(buf, sizeof(buf), " tsc=%#llx)", pe.ts);
266*424fb153SAndroid Build Coastguard Worker   message->append(buf);
267*424fb153SAndroid Build Coastguard Worker   return true;
268*424fb153SAndroid Build Coastguard Worker }
269*424fb153SAndroid Build Coastguard Worker 
GetPageFromPhysical(uint64 paddr,struct page_entry * pe)270*424fb153SAndroid Build Coastguard Worker bool FineLockPEQueue::GetPageFromPhysical(uint64 paddr,
271*424fb153SAndroid Build Coastguard Worker                                           struct page_entry *pe) {
272*424fb153SAndroid Build Coastguard Worker   // Traverse through array until finding a page
273*424fb153SAndroid Build Coastguard Worker   // that contains the address we want..
274*424fb153SAndroid Build Coastguard Worker   for (uint64 i = 0; i < q_size_; i++) {
275*424fb153SAndroid Build Coastguard Worker     uint64 page_addr = pages_[i].paddr;
276*424fb153SAndroid Build Coastguard Worker     // This assumes linear vaddr.
277*424fb153SAndroid Build Coastguard Worker     if ((page_addr <= paddr) && (page_addr + page_size_ > paddr)) {
278*424fb153SAndroid Build Coastguard Worker       *pe = pages_[i];
279*424fb153SAndroid Build Coastguard Worker       return true;
280*424fb153SAndroid Build Coastguard Worker     }
281*424fb153SAndroid Build Coastguard Worker   }
282*424fb153SAndroid Build Coastguard Worker   return false;
283*424fb153SAndroid Build Coastguard Worker }
284*424fb153SAndroid Build Coastguard Worker 
285*424fb153SAndroid Build Coastguard Worker 
286*424fb153SAndroid Build Coastguard Worker // Get a random number from the slot we locked.
GetRandom64FromSlot(int slot)287*424fb153SAndroid Build Coastguard Worker uint64 FineLockPEQueue::GetRandom64FromSlot(int slot) {
288*424fb153SAndroid Build Coastguard Worker   // 64 bit LCG numbers suggested on the internets by
289*424fb153SAndroid Build Coastguard Worker   // http://nuclear.llnl.gov/CNP/rng/rngman/node4.html and others.
290*424fb153SAndroid Build Coastguard Worker   uint64 result = 2862933555777941757ULL * rand_seed_[slot] + 3037000493ULL;
291*424fb153SAndroid Build Coastguard Worker   rand_seed_[slot] = result;
292*424fb153SAndroid Build Coastguard Worker   return result;
293*424fb153SAndroid Build Coastguard Worker }
294*424fb153SAndroid Build Coastguard Worker 
295*424fb153SAndroid Build Coastguard Worker // Get a random number, we have 4 generators to choose from so hopefully we
296*424fb153SAndroid Build Coastguard Worker // won't be blocking on this.
GetRandom64()297*424fb153SAndroid Build Coastguard Worker uint64 FineLockPEQueue::GetRandom64() {
298*424fb153SAndroid Build Coastguard Worker   // Try each available slot.
299*424fb153SAndroid Build Coastguard Worker   for (int i = 0; i < 4; i++) {
300*424fb153SAndroid Build Coastguard Worker     if (pthread_mutex_trylock(&(randlocks_[i])) == 0) {
301*424fb153SAndroid Build Coastguard Worker       uint64 result = GetRandom64FromSlot(i);
302*424fb153SAndroid Build Coastguard Worker       pthread_mutex_unlock(&(randlocks_[i]));
303*424fb153SAndroid Build Coastguard Worker       return result;
304*424fb153SAndroid Build Coastguard Worker     }
305*424fb153SAndroid Build Coastguard Worker   }
306*424fb153SAndroid Build Coastguard Worker   // Forget it, just wait.
307*424fb153SAndroid Build Coastguard Worker   int i = 0;
308*424fb153SAndroid Build Coastguard Worker   if (pthread_mutex_lock(&(randlocks_[i])) == 0) {
309*424fb153SAndroid Build Coastguard Worker     uint64 result = GetRandom64FromSlot(i);
310*424fb153SAndroid Build Coastguard Worker     pthread_mutex_unlock(&(randlocks_[i]));
311*424fb153SAndroid Build Coastguard Worker     return result;
312*424fb153SAndroid Build Coastguard Worker   }
313*424fb153SAndroid Build Coastguard Worker 
314*424fb153SAndroid Build Coastguard Worker   logprintf(0, "Process Error: Could not acquire random lock.\n");
315*424fb153SAndroid Build Coastguard Worker   sat_assert(0);
316*424fb153SAndroid Build Coastguard Worker   return 0;
317*424fb153SAndroid Build Coastguard Worker }
318*424fb153SAndroid Build Coastguard Worker 
319*424fb153SAndroid Build Coastguard Worker 
320*424fb153SAndroid Build Coastguard Worker // Helper function to get a random page entry with given predicate,
321*424fb153SAndroid Build Coastguard Worker // ie, page_is_valid() or page_is_empty() as defined in finelock_queue.h.
322*424fb153SAndroid Build Coastguard Worker //
323*424fb153SAndroid Build Coastguard Worker // Setting tag to a value other than kDontCareTag (-1)
324*424fb153SAndroid Build Coastguard Worker // indicates that we need a tag match, otherwise any tag will do.
325*424fb153SAndroid Build Coastguard Worker //
326*424fb153SAndroid Build Coastguard Worker // Returns true on success, false on failure.
GetRandomWithPredicateTag(struct page_entry * pe,bool (* pred_func)(struct page_entry *),int32 tag)327*424fb153SAndroid Build Coastguard Worker bool FineLockPEQueue::GetRandomWithPredicateTag(struct page_entry *pe,
328*424fb153SAndroid Build Coastguard Worker                       bool (*pred_func)(struct page_entry*),
329*424fb153SAndroid Build Coastguard Worker                       int32 tag) {
330*424fb153SAndroid Build Coastguard Worker   if (!pe || !q_size_)
331*424fb153SAndroid Build Coastguard Worker     return false;
332*424fb153SAndroid Build Coastguard Worker 
333*424fb153SAndroid Build Coastguard Worker   // Randomly index into page entry array.
334*424fb153SAndroid Build Coastguard Worker   uint64 first_try = GetRandom64() % q_size_;
335*424fb153SAndroid Build Coastguard Worker   uint64 next_try = 1;
336*424fb153SAndroid Build Coastguard Worker 
337*424fb153SAndroid Build Coastguard Worker   // Traverse through array until finding a page meeting given predicate.
338*424fb153SAndroid Build Coastguard Worker   for (uint64 i = 0; i < q_size_; i++) {
339*424fb153SAndroid Build Coastguard Worker     uint64 index = (next_try + first_try) % q_size_;
340*424fb153SAndroid Build Coastguard Worker     // Go through the loop linear conguentially. We are offsetting by
341*424fb153SAndroid Build Coastguard Worker     // 'first_try' so this path will be a different sequence for every
342*424fb153SAndroid Build Coastguard Worker     // initioal value chosen.
343*424fb153SAndroid Build Coastguard Worker     next_try = (a_ * next_try + c_) % (modlength_);
344*424fb153SAndroid Build Coastguard Worker     while (next_try >= q_size_) {
345*424fb153SAndroid Build Coastguard Worker       // If we have chosen a modlength greater than the queue size,
346*424fb153SAndroid Build Coastguard Worker       // discard out of bounds results.
347*424fb153SAndroid Build Coastguard Worker       next_try = (a_ * next_try + c_) % (modlength_);
348*424fb153SAndroid Build Coastguard Worker     }
349*424fb153SAndroid Build Coastguard Worker 
350*424fb153SAndroid Build Coastguard Worker     // If page does not meet predicate, don't trylock (expensive).
351*424fb153SAndroid Build Coastguard Worker     if (!(pred_func)(&pages_[index]))
352*424fb153SAndroid Build Coastguard Worker       continue;
353*424fb153SAndroid Build Coastguard Worker 
354*424fb153SAndroid Build Coastguard Worker     // If page does not meet tag predicate, don't trylock (expensive).
355*424fb153SAndroid Build Coastguard Worker     if ((tag != kDontCareTag) && !(pages_[index].tag & tag))
356*424fb153SAndroid Build Coastguard Worker       continue;
357*424fb153SAndroid Build Coastguard Worker 
358*424fb153SAndroid Build Coastguard Worker     if (pthread_mutex_trylock(&(pagelocks_[index])) == 0) {
359*424fb153SAndroid Build Coastguard Worker       // If page property (valid/empty) changes before successfully locking,
360*424fb153SAndroid Build Coastguard Worker       // release page and move on.
361*424fb153SAndroid Build Coastguard Worker       if (!(pred_func)(&pages_[index])) {
362*424fb153SAndroid Build Coastguard Worker         pthread_mutex_unlock(&(pagelocks_[index]));
363*424fb153SAndroid Build Coastguard Worker         continue;
364*424fb153SAndroid Build Coastguard Worker       } else {
365*424fb153SAndroid Build Coastguard Worker         // A page entry with given predicate is locked, returns success.
366*424fb153SAndroid Build Coastguard Worker         *pe = pages_[index];
367*424fb153SAndroid Build Coastguard Worker 
368*424fb153SAndroid Build Coastguard Worker         // Add metrics as necessary.
369*424fb153SAndroid Build Coastguard Worker         if (pred_func == page_is_valid) {
370*424fb153SAndroid Build Coastguard Worker           // Measure time to fetch valid page.
371*424fb153SAndroid Build Coastguard Worker           if (queue_metric_ == kTries)
372*424fb153SAndroid Build Coastguard Worker             pe->touch = i;
373*424fb153SAndroid Build Coastguard Worker           // Measure number of times each page is read.
374*424fb153SAndroid Build Coastguard Worker           if (queue_metric_ == kTouch)
375*424fb153SAndroid Build Coastguard Worker             pe->touch++;
376*424fb153SAndroid Build Coastguard Worker         }
377*424fb153SAndroid Build Coastguard Worker 
378*424fb153SAndroid Build Coastguard Worker         return true;
379*424fb153SAndroid Build Coastguard Worker       }
380*424fb153SAndroid Build Coastguard Worker     }
381*424fb153SAndroid Build Coastguard Worker   }
382*424fb153SAndroid Build Coastguard Worker 
383*424fb153SAndroid Build Coastguard Worker   return false;
384*424fb153SAndroid Build Coastguard Worker }
385*424fb153SAndroid Build Coastguard Worker 
386*424fb153SAndroid Build Coastguard Worker // Without tag hint.
GetRandomWithPredicate(struct page_entry * pe,bool (* pred_func)(struct page_entry *))387*424fb153SAndroid Build Coastguard Worker bool FineLockPEQueue::GetRandomWithPredicate(struct page_entry *pe,
388*424fb153SAndroid Build Coastguard Worker                       bool (*pred_func)(struct page_entry*)) {
389*424fb153SAndroid Build Coastguard Worker   return GetRandomWithPredicateTag(pe, pred_func, kDontCareTag);
390*424fb153SAndroid Build Coastguard Worker }
391*424fb153SAndroid Build Coastguard Worker 
392*424fb153SAndroid Build Coastguard Worker 
393*424fb153SAndroid Build Coastguard Worker // GetValid() randomly finds a valid page, locks it and returns page entry by
394*424fb153SAndroid Build Coastguard Worker // pointer.
395*424fb153SAndroid Build Coastguard Worker //
396*424fb153SAndroid Build Coastguard Worker // Returns true on success, false on failure.
GetValid(struct page_entry * pe)397*424fb153SAndroid Build Coastguard Worker bool FineLockPEQueue::GetValid(struct page_entry *pe) {
398*424fb153SAndroid Build Coastguard Worker   return GetRandomWithPredicate(pe, page_is_valid);
399*424fb153SAndroid Build Coastguard Worker }
400*424fb153SAndroid Build Coastguard Worker 
GetValid(struct page_entry * pe,int32 mask)401*424fb153SAndroid Build Coastguard Worker bool FineLockPEQueue::GetValid(struct page_entry *pe, int32 mask) {
402*424fb153SAndroid Build Coastguard Worker   return GetRandomWithPredicateTag(pe, page_is_valid, mask);
403*424fb153SAndroid Build Coastguard Worker }
404*424fb153SAndroid Build Coastguard Worker 
405*424fb153SAndroid Build Coastguard Worker // GetEmpty() randomly finds an empty page, locks it and returns page entry by
406*424fb153SAndroid Build Coastguard Worker // pointer.
407*424fb153SAndroid Build Coastguard Worker //
408*424fb153SAndroid Build Coastguard Worker // Returns true on success, false on failure.
GetEmpty(struct page_entry * pe,int32 mask)409*424fb153SAndroid Build Coastguard Worker bool FineLockPEQueue::GetEmpty(struct page_entry *pe, int32 mask) {
410*424fb153SAndroid Build Coastguard Worker   return GetRandomWithPredicateTag(pe, page_is_empty, mask);
411*424fb153SAndroid Build Coastguard Worker }
GetEmpty(struct page_entry * pe)412*424fb153SAndroid Build Coastguard Worker bool FineLockPEQueue::GetEmpty(struct page_entry *pe) {
413*424fb153SAndroid Build Coastguard Worker   return GetRandomWithPredicate(pe, page_is_empty);
414*424fb153SAndroid Build Coastguard Worker }
415*424fb153SAndroid Build Coastguard Worker 
416*424fb153SAndroid Build Coastguard Worker // PutEmpty puts an empty page back into the queue, making it available by
417*424fb153SAndroid Build Coastguard Worker // releasing the per-page-entry lock.
418*424fb153SAndroid Build Coastguard Worker //
419*424fb153SAndroid Build Coastguard Worker // Returns true on success, false on failure.
PutEmpty(struct page_entry * pe)420*424fb153SAndroid Build Coastguard Worker bool FineLockPEQueue::PutEmpty(struct page_entry *pe) {
421*424fb153SAndroid Build Coastguard Worker   if (!pe || !q_size_)
422*424fb153SAndroid Build Coastguard Worker     return false;
423*424fb153SAndroid Build Coastguard Worker 
424*424fb153SAndroid Build Coastguard Worker   int64 index = pe->offset / page_size_;
425*424fb153SAndroid Build Coastguard Worker   if (!valid_index(index))
426*424fb153SAndroid Build Coastguard Worker     return false;
427*424fb153SAndroid Build Coastguard Worker 
428*424fb153SAndroid Build Coastguard Worker   pages_[index] = *pe;
429*424fb153SAndroid Build Coastguard Worker   // Enforce that page entry is indeed empty.
430*424fb153SAndroid Build Coastguard Worker   pages_[index].pattern = 0;
431*424fb153SAndroid Build Coastguard Worker   return (pthread_mutex_unlock(&(pagelocks_[index])) == 0);
432*424fb153SAndroid Build Coastguard Worker }
433*424fb153SAndroid Build Coastguard Worker 
434*424fb153SAndroid Build Coastguard Worker // PutValid puts a valid page back into the queue, making it available by
435*424fb153SAndroid Build Coastguard Worker // releasing the per-page-entry lock.
436*424fb153SAndroid Build Coastguard Worker //
437*424fb153SAndroid Build Coastguard Worker // Returns true on success, false on failure.
PutValid(struct page_entry * pe)438*424fb153SAndroid Build Coastguard Worker bool FineLockPEQueue::PutValid(struct page_entry *pe) {
439*424fb153SAndroid Build Coastguard Worker   if (!pe || !page_is_valid(pe) || !q_size_)
440*424fb153SAndroid Build Coastguard Worker     return false;
441*424fb153SAndroid Build Coastguard Worker 
442*424fb153SAndroid Build Coastguard Worker   int64 index = pe->offset / page_size_;
443*424fb153SAndroid Build Coastguard Worker   if (!valid_index(index))
444*424fb153SAndroid Build Coastguard Worker     return false;
445*424fb153SAndroid Build Coastguard Worker 
446*424fb153SAndroid Build Coastguard Worker   pages_[index] = *pe;
447*424fb153SAndroid Build Coastguard Worker   return (pthread_mutex_unlock(&(pagelocks_[index])) == 0);
448*424fb153SAndroid Build Coastguard Worker }
449