@@ -92,6 +92,14 @@ std::string getTempOnDiskCachePath() {
92
92
}
93
93
#endif
94
94
95
+ struct PrewarmData {
96
+ GrpcReplayService* prewarm_service = nullptr ;
97
+ Context* prewarm_context = nullptr ;
98
+ std::string prewarm_id;
99
+ std::string cleanup_id;
100
+ std::string current_state;
101
+ };
102
+
95
103
// Setup creates and starts a replay server at the given URI port. Returns the
96
104
// created and started server.
97
105
// Note the given memory manager and the crash handler, they may be used for
@@ -101,15 +109,14 @@ std::string getTempOnDiskCachePath() {
101
109
std::unique_ptr<Server> Setup (const char * uri, const char * authToken,
102
110
ResourceCache* cache, int idleTimeoutSec,
103
111
core::CrashHandler* crashHandler,
104
- MemoryManager* memMgr, std::mutex* lock) {
112
+ MemoryManager* memMgr, PrewarmData* prewarm,
113
+ std::mutex* lock) {
105
114
// Return a replay server with the following replay ID handler. The first
106
115
// package for a replay must be the ID of the replay.
107
116
return Server::createAndStart (
108
117
uri, authToken, idleTimeoutSec,
109
- [cache, memMgr, crashHandler, lock](GrpcReplayService* replayConn,
110
- const std::string& replayId) {
111
- std::lock_guard<std::mutex> mem_mgr_crash_hdl_lock_guard (*lock);
112
-
118
+ [cache, memMgr, crashHandler, lock,
119
+ prewarm](GrpcReplayService* replayConn) {
113
120
std::unique_ptr<ResourceLoader> resLoader;
114
121
if (cache == nullptr ) {
115
122
resLoader = PassThroughResourceLoader::create (replayConn);
@@ -126,16 +133,134 @@ std::unique_ptr<Server> Setup(const char* uri, const char* authToken,
126
133
Context::create (replayConn, *crashHandler, resLoader.get (), memMgr);
127
134
128
135
if (context == nullptr ) {
129
- GAPID_WARNING (" Loading Context failed!" );
136
+ GAPID_ERROR (" Loading Context failed!" );
130
137
return ;
131
138
}
132
- if (cache != nullptr ) {
133
- context->prefetch (cache);
134
- }
135
139
136
- GAPID_INFO (" Replay started" );
137
- bool ok = context->interpret ();
138
- GAPID_INFO (" Replay %s" , ok ? " finished successfully" : " failed" );
140
+ auto cleanup_state = [&]() {
141
+ if (!prewarm->prewarm_context ->initialize (prewarm->cleanup_id )) {
142
+ return false ;
143
+ }
144
+ if (cache != nullptr ) {
145
+ prewarm->prewarm_context ->prefetch (cache);
146
+ }
147
+ bool ok = prewarm->prewarm_context ->interpret ();
148
+ if (!ok) {
149
+ return false ;
150
+ }
151
+ if (!prewarm->prewarm_context ->cleanup ()) {
152
+ return false ;
153
+ }
154
+ prewarm->prewarm_id = " " ;
155
+ prewarm->cleanup_id = " " ;
156
+ prewarm->current_state = " " ;
157
+ prewarm->prewarm_context = nullptr ;
158
+ prewarm->prewarm_service = nullptr ;
159
+ return true ;
160
+ };
161
+
162
+ auto prime_state = [&](std::string state, std::string cleanup) {
163
+ GAPID_INFO (" Priming %s" , state.c_str ());
164
+ if (context->initialize (state)) {
165
+ GAPID_INFO (" Replay context initialized successfully" );
166
+ } else {
167
+ GAPID_ERROR (" Replay context initialization failed" );
168
+ return false ;
169
+ }
170
+ if (cache != nullptr ) {
171
+ context->prefetch (cache);
172
+ }
173
+ GAPID_INFO (" Replay started" );
174
+ bool ok = context->interpret (false );
175
+ GAPID_INFO (" Priming %s" , ok ? " finished successfully" : " failed" );
176
+ if (!ok) {
177
+ return false ;
178
+ }
179
+
180
+ if (!cleanup.empty ()) {
181
+ prewarm->current_state = state;
182
+ prewarm->cleanup_id = cleanup;
183
+ prewarm->prewarm_id = state;
184
+ prewarm->prewarm_service = replayConn;
185
+ prewarm->prewarm_context = context.get ();
186
+ }
187
+ return true ;
188
+ };
189
+
190
+ do {
191
+ auto req = replayConn->getReplayRequest ();
192
+ if (!req) {
193
+ GAPID_INFO (" No more requests!" );
194
+ break ;
195
+ }
196
+ GAPID_INFO (" Got request %d" , req->req_case ());
197
+ switch (req->req_case ()) {
198
+ case replay_service::ReplayRequest::kReplay : {
199
+ std::lock_guard<std::mutex> mem_mgr_crash_hdl_lock_guard (*lock);
200
+
201
+ if (prewarm->current_state != req->replay ().dependent_id ()) {
202
+ GAPID_INFO (" Trying to get into the correct state" );
203
+ cleanup_state ();
204
+ if (req->replay ().dependent_id () != " " ) {
205
+ prime_state (req->replay ().dependent_id (), " " );
206
+ }
207
+ } else {
208
+ GAPID_INFO (" Already in the correct state" );
209
+ }
210
+ GAPID_INFO (" Running %s" , req->replay ().replay_id ().c_str ());
211
+ if (context->initialize (req->replay ().replay_id ())) {
212
+ GAPID_INFO (" Replay context initialized successfully" );
213
+ } else {
214
+ GAPID_ERROR (" Replay context initialization failed" );
215
+ continue ;
216
+ }
217
+ if (cache != nullptr ) {
218
+ context->prefetch (cache);
219
+ }
220
+
221
+ GAPID_INFO (" Replay started" );
222
+ bool ok = context->interpret ();
223
+ GAPID_INFO (" Replay %s" , ok ? " finished successfully" : " failed" );
224
+ replayConn->sendReplayFinished ();
225
+ if (!context->cleanup ()) {
226
+ return ;
227
+ }
228
+ prewarm->current_state = " " ;
229
+ if (prewarm->prewarm_service && !prewarm->prewarm_id .empty () &&
230
+ !prewarm->cleanup_id .empty ()) {
231
+ prewarm->prewarm_service ->primeState (prewarm->prewarm_id ,
232
+ prewarm->cleanup_id );
233
+ }
234
+ break ;
235
+ }
236
+ case replay_service::ReplayRequest::kPrewarm : {
237
+ std::lock_guard<std::mutex> mem_mgr_crash_hdl_lock_guard (*lock);
238
+ // We want to pre-warm into the existing state, good deal.
239
+ if (prewarm->current_state == req->prewarm ().prerun_id ()) {
240
+ GAPID_INFO (
241
+ " Already primed in the correct state, no more work is "
242
+ " needed" );
243
+ prewarm->cleanup_id = req->prewarm ().cleanup_id ();
244
+ break ;
245
+ }
246
+ if (prewarm->current_state != " " ) {
247
+ if (!cleanup_state ()) {
248
+ GAPID_ERROR (
249
+ " Could not clean up after previous replay, in a bad "
250
+ " state now" );
251
+ return ;
252
+ }
253
+ }
254
+ if (!prime_state (std::move (req->prewarm ().prerun_id ()),
255
+ std::move (req->prewarm ().cleanup_id ()))) {
256
+ GAPID_ERROR (" Could not prime state: in a bad state now" );
257
+ return ;
258
+ }
259
+ break ;
260
+ }
261
+ default : { break ; }
262
+ }
263
+ } while (true );
139
264
});
140
265
}
141
266
@@ -234,9 +359,10 @@ void android_main(struct android_app* app) {
234
359
auto opts = Options::Parse (app);
235
360
auto cache = InMemoryResourceCache::create (memoryManager.getTopAddress ());
236
361
std::mutex lock;
362
+ PrewarmData data;
237
363
std::unique_ptr<Server> server =
238
364
Setup (uri.c_str (), opts.authToken .c_str (), cache.get (),
239
- opts.idleTimeoutSec , &crashHandler, &memoryManager, &lock);
365
+ opts.idleTimeoutSec , &crashHandler, &memoryManager, &data, & lock);
240
366
std::atomic<bool > serverIsDone (false );
241
367
std::thread waiting_thread ([&]() {
242
368
server.get ()->wait ();
@@ -498,11 +624,24 @@ static int replayArchive(Options opts) {
498
624
auto onDiskCache = OnDiskResourceCache::create (opts.replayArchive , false );
499
625
std::unique_ptr<ResourceLoader> resLoader =
500
626
CachedResourceLoader::create (onDiskCache.get (), nullptr );
627
+
501
628
std::unique_ptr<Context> context = Context::create (
502
629
&replayArchive, crashHandler, resLoader.get (), &memoryManager);
503
630
631
+ if (context->initialize (" payload" )) {
632
+ GAPID_DEBUG (" Replay context initialized successfully" );
633
+ } else {
634
+ GAPID_ERROR (" Replay context initialization failed" );
635
+ return EXIT_FAILURE;
636
+ }
637
+
504
638
GAPID_INFO (" Replay started" );
505
639
bool ok = context->interpret ();
640
+ replayArchive.sendReplayFinished ();
641
+ if (!context->cleanup ()) {
642
+ GAPID_ERROR (" Replay cleanup failed" );
643
+ return EXIT_FAILURE;
644
+ }
506
645
GAPID_INFO (" Replay %s" , ok ? " finished successfully" : " failed" );
507
646
508
647
return ok ? EXIT_SUCCESS : EXIT_FAILURE;
@@ -554,9 +693,11 @@ static int startServer(Options opts) {
554
693
auto cache = createCache (opts.onDiskCacheOptions , &memoryManager);
555
694
556
695
std::mutex lock;
557
- std::unique_ptr<Server> server = Setup (
558
- uri.c_str (), (authToken.size () > 0 ) ? authToken.data () : nullptr ,
559
- cache.get (), opts.idleTimeoutSec , &crashHandler, &memoryManager, &lock);
696
+ PrewarmData data;
697
+ std::unique_ptr<Server> server =
698
+ Setup (uri.c_str (), (authToken.size () > 0 ) ? authToken.data () : nullptr ,
699
+ cache.get (), opts.idleTimeoutSec , &crashHandler, &memoryManager,
700
+ &data, &lock);
560
701
// The following message is parsed by launchers to detect the selected port.
561
702
// DO NOT CHANGE!
562
703
printf (" Bound on port '%s'\n " , portStr.c_str ());
0 commit comments