xref: /aosp_15_r20/external/deqp/framework/qphelper/qpWatchDog.c (revision 35238bce31c2a825756842865a792f8cf7f89930)
1 /*-------------------------------------------------------------------------
2  * drawElements Quality Program Helper Library
3  * -------------------------------------------
4  *
5  * Copyright 2014 The Android Open Source Project
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  *
19  *//*!
20  * \file
21  * \brief Watch dog for detecting timeouts
22  *//*--------------------------------------------------------------------*/
23 
24 #include "qpWatchDog.h"
25 
26 #include "deThread.h"
27 #include "deClock.h"
28 #include "deMemory.h"
29 
30 #include <stdio.h>
31 
32 #if 0
33 #define DBGPRINT(X) qpPrintf X
34 #else
35 #define DBGPRINT(X)
36 #endif
37 
38 typedef enum Status_e
39 {
40     STATUS_THREAD_RUNNING = 0,
41     STATUS_STOP_THREAD,
42 
43     STATUS_LAST
44 } Status;
45 
46 struct qpWatchDog_s
47 {
48     qpWatchDogFunc timeOutFunc;
49     void *timeOutUserPtr;
50     int totalTimeLimit;    /* Total test case time limit in seconds    */
51     int intervalTimeLimit; /* Iteration length limit in seconds        */
52     /*
53         Iteration time limit in seconds specified to the constructor. This is stored so that
54         intervalTimeLimit can be restored after qpWatchDog_touchAndDisableIntervalTimeLimit
55         is called.
56     */
57     int defaultIntervalTimeLimit;
58 
59     volatile uint64_t resetTime;
60     volatile uint64_t lastTouchTime;
61 
62     deThread watchDogThread;
63     volatile Status status;
64 };
65 
watchDogThreadFunc(void * arg)66 static void watchDogThreadFunc(void *arg)
67 {
68     qpWatchDog *dog = (qpWatchDog *)arg;
69     DE_ASSERT(dog);
70 
71     DBGPRINT(("watchDogThreadFunc(): start\n"));
72 
73     while (dog->status == STATUS_THREAD_RUNNING)
74     {
75         uint64_t curTime          = deGetMicroseconds();
76         int totalSecondsPassed    = (int)((curTime - dog->resetTime) / 1000000ull);
77         int secondsSinceLastTouch = (int)((curTime - dog->lastTouchTime) / 1000000ull);
78         bool overIntervalLimit    = secondsSinceLastTouch > dog->intervalTimeLimit;
79         bool overTotalLimit       = totalSecondsPassed > dog->totalTimeLimit;
80 
81         if (overIntervalLimit || overTotalLimit)
82         {
83             qpTimeoutReason reason = overTotalLimit ? QP_TIMEOUT_REASON_TOTAL_LIMIT : QP_TIMEOUT_REASON_INTERVAL_LIMIT;
84             DBGPRINT(("watchDogThreadFunc(): call timeout func\n"));
85             dog->timeOutFunc(dog, dog->timeOutUserPtr, reason);
86             break;
87         }
88 
89         deSleep(100);
90     }
91 
92     DBGPRINT(("watchDogThreadFunc(): stop\n"));
93 }
94 
qpWatchDog_create(qpWatchDogFunc timeOutFunc,void * userPtr,int totalTimeLimitSecs,int intervalTimeLimitSecs)95 qpWatchDog *qpWatchDog_create(qpWatchDogFunc timeOutFunc, void *userPtr, int totalTimeLimitSecs,
96                               int intervalTimeLimitSecs)
97 {
98     /* Allocate & initialize. */
99     qpWatchDog *dog = (qpWatchDog *)deCalloc(sizeof(qpWatchDog));
100     if (!dog)
101         return dog;
102 
103     DE_ASSERT(timeOutFunc);
104     DE_ASSERT((totalTimeLimitSecs > 0) && (intervalTimeLimitSecs > 0));
105 
106     DBGPRINT(("qpWatchDog::create(%ds, %ds)\n", totalTimeLimitSecs, intervalTimeLimitSecs));
107 
108     dog->timeOutFunc              = timeOutFunc;
109     dog->timeOutUserPtr           = userPtr;
110     dog->totalTimeLimit           = totalTimeLimitSecs;
111     dog->intervalTimeLimit        = intervalTimeLimitSecs;
112     dog->defaultIntervalTimeLimit = intervalTimeLimitSecs;
113 
114     /* Reset (sets time values). */
115     qpWatchDog_reset(dog);
116 
117     /* Initialize watchdog thread. */
118     dog->status         = STATUS_THREAD_RUNNING;
119     dog->watchDogThread = deThread_create(watchDogThreadFunc, dog, DE_NULL);
120     if (!dog->watchDogThread)
121     {
122         deFree(dog);
123         return DE_NULL;
124     }
125 
126     return dog;
127 }
128 
qpWatchDog_reset(qpWatchDog * dog)129 void qpWatchDog_reset(qpWatchDog *dog)
130 {
131     uint64_t curTime = deGetMicroseconds();
132 
133     DE_ASSERT(dog);
134     DBGPRINT(("qpWatchDog::reset()\n"));
135 
136     dog->resetTime     = curTime;
137     dog->lastTouchTime = curTime;
138 }
139 
qpWatchDog_destroy(qpWatchDog * dog)140 void qpWatchDog_destroy(qpWatchDog *dog)
141 {
142     DE_ASSERT(dog);
143     DBGPRINT(("qpWatchDog::destroy()\n"));
144 
145     /* Finish the watchdog thread. */
146     dog->status = STATUS_STOP_THREAD;
147     deThread_join(dog->watchDogThread);
148     deThread_destroy(dog->watchDogThread);
149 
150     DBGPRINT(("qpWatchDog::destroy() finished\n"));
151     deFree(dog);
152 }
153 
qpWatchDog_touch(qpWatchDog * dog)154 void qpWatchDog_touch(qpWatchDog *dog)
155 {
156     DE_ASSERT(dog);
157     DBGPRINT(("qpWatchDog::touch()\n"));
158     dog->lastTouchTime = deGetMicroseconds();
159 }
160 
161 /*
162     These function exists to allow the interval timer to be disabled for special cases
163     like very long shader compilations. Heavy code can be put between calls
164     to qpWatchDog_touchAndDisableIntervalTimeLimit and qpWatchDog_touchAndEnableIntervalTimeLimit
165     and during that period the interval time limit will become the same as the total
166     time limit. Afterwards, the interval timer is set back to its default.
167 */
qpWatchDog_touchAndDisableIntervalTimeLimit(qpWatchDog * dog)168 void qpWatchDog_touchAndDisableIntervalTimeLimit(qpWatchDog *dog)
169 {
170     dog->intervalTimeLimit = dog->totalTimeLimit;
171     qpWatchDog_touch(dog);
172 }
173 
qpWatchDog_touchAndEnableIntervalTimeLimit(qpWatchDog * dog)174 void qpWatchDog_touchAndEnableIntervalTimeLimit(qpWatchDog *dog)
175 {
176     dog->intervalTimeLimit = dog->defaultIntervalTimeLimit;
177     qpWatchDog_touch(dog);
178 }
179