xref: /aosp_15_r20/system/chre/platform/shared/dram_vote_client.cc (revision 84e339476a462649f82315436d70fd732297a399)
1 /*
2  * Copyright (C) 2020 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 "chre/platform/shared/dram_vote_client.h"
18 
19 #include <cinttypes>
20 
21 #include "chre/core/event_loop_manager.h"
22 #include "chre/platform/assert.h"
23 #include "chre/platform/fatal_error.h"
24 #include "chre/platform/log.h"
25 #include "chre/platform/system_time.h"
26 
27 namespace chre {
28 
voteDramAccess(bool enabled)29 void DramVoteClient::voteDramAccess(bool enabled) {
30   LockGuard<Mutex> lock(mMutex);
31   mLastDramRequest = enabled;
32 
33   bool needDram = (enabled || mDramVoteCount > 0);
34   if (needDram != mLastDramVote) {
35     issueDramVote(needDram);
36     mLastDramVote = needDram;
37   }
38 }
39 
incrementDramVoteCount()40 void DramVoteClient::incrementDramVoteCount() {
41   LockGuard<Mutex> lock(mMutex);
42 
43   if (mDramVoteCount++ == 0) {
44     mVoteCountStart = Milliseconds(SystemTime::getMonotonicTime());
45     // TODO(b/181172259): Change back to LOGW once buffered logging path is
46     // refactored.
47     // LOGW("DRAM vote count begins");
48     printf("CHRE: DRAM vote count begins\n");
49 
50     if (!mLastDramVote) {
51       // Do not call voteDramAccess() directly as it will override
52       // mLastDramRequest.
53       issueDramVote(true /* enabled */);
54       mLastDramVote = true;
55     }
56   } else {
57     checkDramDuration();
58   }
59 }
60 
decrementDramVoteCount()61 void DramVoteClient::decrementDramVoteCount() {
62   LockGuard<Mutex> lock(mMutex);
63   CHRE_ASSERT_LOG(mDramVoteCount > 0,
64                   "Tried to decrement DRAM vote count when it's 0");
65 
66   if (--mDramVoteCount == 0) {
67     // TODO(b/181172259): Change back to LOGW once buffered logging path is
68     // refactored.
69     // LOGW("DRAM vote count ends: %" PRIu64 " ms", checkDramDuration());
70     printf("CHRE: DRAM vote count ends: %" PRIu64 " ms\n",
71            checkDramDuration().getMilliseconds());
72 
73     // There's no DRAM activity now, remove CHRE's DRAM access vote.
74     if (!mLastDramRequest) {
75       issueDramVote(false /* enabled */);
76       mLastDramVote = false;
77     }
78   }
79 }
80 
checkDramDuration()81 Milliseconds DramVoteClient::checkDramDuration() {
82   Milliseconds duration(0);
83   if (mDramVoteCount > 0) {
84     duration = Milliseconds(SystemTime::getMonotonicTime()) - mVoteCountStart;
85   }
86 
87   // DRAM memory fallback only intends to handle a surge of DRAM memory
88   // requests. If there's a prolonged period of memory fallback, this might
89   // indicate a memory leak or inadequate SRAM heap size.
90   if (duration > kMaxDramDuration) {
91     if (EventLoopManagerSingleton::isInitialized() &&
92         !EventLoopManagerSingleton::get()
93              ->getEventLoop()
94              .getPowerControlManager()
95              .hostIsAwake()) {
96       // AP is asleep
97       FATAL_ERROR("Forced into DRAM for %" PRIu64 " msec",
98                   duration.getMilliseconds());
99     } else {
100       // AP is awake, don't report error, just reset the starting time
101       mVoteCountStart = Milliseconds(SystemTime::getMonotonicTime());
102     }
103   }
104   return duration;
105 }
106 
107 //! Explicitly instantiate the DramVoteClient singleton to reduce code size.
108 template class Singleton<DramVoteClient>;
109 
110 }  // namespace chre
111