diff options
Diffstat (limited to 'daemon/Child.cpp')
-rw-r--r-- | daemon/Child.cpp | 174 |
1 files changed, 55 insertions, 119 deletions
diff --git a/daemon/Child.cpp b/daemon/Child.cpp index 9ee2ef8..ca33561 100644 --- a/daemon/Child.cpp +++ b/daemon/Child.cpp | |||
@@ -1,38 +1,39 @@ | |||
1 | /** | 1 | /** |
2 | * Copyright (C) ARM Limited 2010-2013. All rights reserved. | 2 | * Copyright (C) ARM Limited 2010-2014. All rights reserved. |
3 | * | 3 | * |
4 | * This program is free software; you can redistribute it and/or modify | 4 | * This program is free software; you can redistribute it and/or modify |
5 | * it under the terms of the GNU General Public License version 2 as | 5 | * it under the terms of the GNU General Public License version 2 as |
6 | * published by the Free Software Foundation. | 6 | * published by the Free Software Foundation. |
7 | */ | 7 | */ |
8 | 8 | ||
9 | #include "Child.h" | ||
10 | |||
9 | #include <stdlib.h> | 11 | #include <stdlib.h> |
10 | #include <string.h> | 12 | #include <string.h> |
11 | #include <signal.h> | 13 | #include <signal.h> |
12 | #include <unistd.h> | 14 | #include <unistd.h> |
13 | #include <sys/prctl.h> | 15 | #include <sys/prctl.h> |
16 | |||
14 | #include "Logging.h" | 17 | #include "Logging.h" |
15 | #include "CapturedXML.h" | 18 | #include "CapturedXML.h" |
16 | #include "SessionData.h" | 19 | #include "SessionData.h" |
17 | #include "Child.h" | ||
18 | #include "LocalCapture.h" | 20 | #include "LocalCapture.h" |
19 | #include "Collector.h" | ||
20 | #include "Sender.h" | 21 | #include "Sender.h" |
21 | #include "OlyUtility.h" | 22 | #include "OlyUtility.h" |
23 | #include "OlySocket.h" | ||
22 | #include "StreamlineSetup.h" | 24 | #include "StreamlineSetup.h" |
23 | #include "ConfigurationXML.h" | 25 | #include "ConfigurationXML.h" |
24 | #include "Driver.h" | 26 | #include "Driver.h" |
25 | #include "Fifo.h" | 27 | #include "PerfSource.h" |
26 | #include "Buffer.h" | 28 | #include "DriverSource.h" |
27 | 29 | #include "UserSpaceSource.h" | |
28 | #define NS_PER_S ((uint64_t)1000000000) | 30 | #include "ExternalSource.h" |
29 | #define NS_PER_US 1000 | ||
30 | 31 | ||
31 | static sem_t haltPipeline, senderThreadStarted, startProfile, senderSem; // Shared by Child and spawned threads | 32 | static sem_t haltPipeline, senderThreadStarted, startProfile, senderSem; // Shared by Child and spawned threads |
32 | static Fifo* collectorFifo = NULL; // Shared by Child.cpp and spawned threads | 33 | static Source *primarySource = NULL; |
33 | static Buffer* buffer = NULL; | 34 | static Source *userSpaceSource = NULL; |
35 | static Source *externalSource = NULL; | ||
34 | static Sender* sender = NULL; // Shared by Child.cpp and spawned threads | 36 | static Sender* sender = NULL; // Shared by Child.cpp and spawned threads |
35 | static Collector* collector = NULL; | ||
36 | Child* child = NULL; // shared by Child.cpp and main.cpp | 37 | Child* child = NULL; // shared by Child.cpp and main.cpp |
37 | 38 | ||
38 | extern void cleanUp(); | 39 | extern void cleanUp(); |
@@ -78,7 +79,7 @@ static void child_handler(int signum) { | |||
78 | } | 79 | } |
79 | beenHere = true; | 80 | beenHere = true; |
80 | logg->logMessage("Gator is shutting down."); | 81 | logg->logMessage("Gator is shutting down."); |
81 | if (signum == SIGALRM || !collector) { | 82 | if (signum == SIGALRM || !primarySource) { |
82 | exit(1); | 83 | exit(1); |
83 | } else { | 84 | } else { |
84 | child->endSession(); | 85 | child->endSession(); |
@@ -139,77 +140,22 @@ static void *stopThread(void *) { | |||
139 | return 0; | 140 | return 0; |
140 | } | 141 | } |
141 | 142 | ||
142 | static void *countersThread(void *) { | ||
143 | prctl(PR_SET_NAME, (unsigned long)&"gatord-counters", 0, 0, 0); | ||
144 | |||
145 | gSessionData->hwmon.start(); | ||
146 | |||
147 | int64_t monotonic_started = 0; | ||
148 | while (monotonic_started <= 0) { | ||
149 | usleep(10); | ||
150 | |||
151 | if (Collector::readInt64Driver("/dev/gator/started", &monotonic_started) == -1) { | ||
152 | logg->logError(__FILE__, __LINE__, "Error reading gator driver start time"); | ||
153 | handleException(); | ||
154 | } | ||
155 | } | ||
156 | |||
157 | uint64_t next_time = 0; | ||
158 | while (gSessionData->mSessionIsActive) { | ||
159 | struct timespec ts; | ||
160 | #ifndef CLOCK_MONOTONIC_RAW | ||
161 | // Android doesn't have this defined but it was added in Linux 2.6.28 | ||
162 | #define CLOCK_MONOTONIC_RAW 4 | ||
163 | #endif | ||
164 | if (clock_gettime(CLOCK_MONOTONIC_RAW, &ts) != 0) { | ||
165 | logg->logError(__FILE__, __LINE__, "Failed to get uptime"); | ||
166 | handleException(); | ||
167 | } | ||
168 | const uint64_t curr_time = (NS_PER_S*ts.tv_sec + ts.tv_nsec) - monotonic_started; | ||
169 | // Sample ten times a second ignoring gSessionData->mSampleRate | ||
170 | next_time += NS_PER_S/10;//gSessionData->mSampleRate; | ||
171 | if (next_time < curr_time) { | ||
172 | logg->logMessage("Too slow, curr_time: %lli next_time: %lli", curr_time, next_time); | ||
173 | next_time = curr_time; | ||
174 | } | ||
175 | |||
176 | if (buffer->eventHeader(curr_time)) { | ||
177 | gSessionData->hwmon.read(buffer); | ||
178 | // Only check after writing all counters so that time and corresponding counters appear in the same frame | ||
179 | buffer->check(curr_time); | ||
180 | } | ||
181 | |||
182 | if (buffer->bytesAvailable() <= 0) { | ||
183 | logg->logMessage("One shot (counters)"); | ||
184 | child->endSession(); | ||
185 | } | ||
186 | |||
187 | usleep((next_time - curr_time)/NS_PER_US); | ||
188 | } | ||
189 | |||
190 | buffer->setDone(); | ||
191 | |||
192 | return NULL; | ||
193 | } | ||
194 | |||
195 | static void *senderThread(void *) { | 143 | static void *senderThread(void *) { |
196 | int length = 1; | ||
197 | char* data; | ||
198 | char end_sequence[] = {RESPONSE_APC_DATA, 0, 0, 0, 0}; | 144 | char end_sequence[] = {RESPONSE_APC_DATA, 0, 0, 0, 0}; |
199 | 145 | ||
200 | sem_post(&senderThreadStarted); | 146 | sem_post(&senderThreadStarted); |
201 | prctl(PR_SET_NAME, (unsigned long)&"gatord-sender", 0, 0, 0); | 147 | prctl(PR_SET_NAME, (unsigned long)&"gatord-sender", 0, 0, 0); |
202 | sem_wait(&haltPipeline); | 148 | sem_wait(&haltPipeline); |
203 | 149 | ||
204 | while (length > 0 || !buffer->isDone()) { | 150 | while (!primarySource->isDone() || (userSpaceSource != NULL && !userSpaceSource->isDone()) || (externalSource != NULL && !externalSource->isDone())) { |
205 | sem_wait(&senderSem); | 151 | sem_wait(&senderSem); |
206 | data = collectorFifo->read(&length); | 152 | |
207 | if (data != NULL) { | 153 | primarySource->write(sender); |
208 | sender->writeData(data, length, RESPONSE_APC_DATA); | 154 | if (userSpaceSource != NULL) { |
209 | collectorFifo->release(); | 155 | userSpaceSource->write(sender); |
210 | } | 156 | } |
211 | if (!buffer->isDone()) { | 157 | if (externalSource != NULL) { |
212 | buffer->write(sender); | 158 | externalSource->write(sender); |
213 | } | 159 | } |
214 | } | 160 | } |
215 | 161 | ||
@@ -255,15 +201,13 @@ void Child::initialization() { | |||
255 | 201 | ||
256 | void Child::endSession() { | 202 | void Child::endSession() { |
257 | gSessionData->mSessionIsActive = false; | 203 | gSessionData->mSessionIsActive = false; |
258 | collector->stop(); | 204 | primarySource->interrupt(); |
259 | sem_post(&haltPipeline); | 205 | sem_post(&haltPipeline); |
260 | } | 206 | } |
261 | 207 | ||
262 | void Child::run() { | 208 | void Child::run() { |
263 | char* collectBuffer; | ||
264 | int bytesCollected = 0; | ||
265 | LocalCapture* localCapture = NULL; | 209 | LocalCapture* localCapture = NULL; |
266 | pthread_t durationThreadID, stopThreadID, senderThreadID, countersThreadID; | 210 | pthread_t durationThreadID, stopThreadID, senderThreadID; |
267 | 211 | ||
268 | prctl(PR_SET_NAME, (unsigned long)&"gatord-child", 0, 0, 0); | 212 | prctl(PR_SET_NAME, (unsigned long)&"gatord-child", 0, 0, 0); |
269 | 213 | ||
@@ -282,7 +226,11 @@ void Child::run() { | |||
282 | { ConfigurationXML configuration; } | 226 | { ConfigurationXML configuration; } |
283 | 227 | ||
284 | // Set up the driver; must be done after gSessionData->mPerfCounterType[] is populated | 228 | // Set up the driver; must be done after gSessionData->mPerfCounterType[] is populated |
285 | collector = new Collector(); | 229 | if (!gSessionData->perf.isSetup()) { |
230 | primarySource = new DriverSource(&senderSem, &startProfile); | ||
231 | } else { | ||
232 | primarySource = new PerfSource(&senderSem, &startProfile); | ||
233 | } | ||
286 | 234 | ||
287 | // Initialize all drivers | 235 | // Initialize all drivers |
288 | for (Driver *driver = Driver::getHead(); driver != NULL; driver = driver->getNext()) { | 236 | for (Driver *driver = Driver::getHead(); driver != NULL; driver = driver->getNext()) { |
@@ -317,15 +265,11 @@ void Child::run() { | |||
317 | free(xmlString); | 265 | free(xmlString); |
318 | } | 266 | } |
319 | 267 | ||
320 | // Create user-space buffers, add 5 to the size to account for the 1-byte type and 4-byte length | 268 | // Must be after session XML is parsed |
321 | logg->logMessage("Created %d MB collector buffer with a %d-byte ragged end", gSessionData->mTotalBufferSize, collector->getBufferSize()); | 269 | if (!primarySource->prepare()) { |
322 | collectorFifo = new Fifo(collector->getBufferSize() + 5, gSessionData->mTotalBufferSize*1024*1024, &senderSem); | 270 | logg->logError(__FILE__, __LINE__, "Unable to prepare for capture"); |
323 | 271 | handleException(); | |
324 | // Get the initial pointer to the collect buffer | 272 | } |
325 | collectBuffer = collectorFifo->start(); | ||
326 | |||
327 | // Create a new Block Counter Buffer | ||
328 | buffer = new Buffer(0, 5, gSessionData->mTotalBufferSize*1024*1024, &senderSem); | ||
329 | 273 | ||
330 | // Sender thread shall be halted until it is signaled for one shot mode | 274 | // Sender thread shall be halted until it is signaled for one shot mode |
331 | sem_init(&haltPipeline, 0, gSessionData->mOneShot ? 0 : 2); | 275 | sem_init(&haltPipeline, 0, gSessionData->mOneShot ? 0 : 2); |
@@ -340,14 +284,21 @@ void Child::run() { | |||
340 | thread_creation_success = false; | 284 | thread_creation_success = false; |
341 | } | 285 | } |
342 | 286 | ||
343 | bool startcountersThread = gSessionData->hwmon.countersEnabled(); | 287 | if (gSessionData->hwmon.countersEnabled()) { |
344 | if (startcountersThread) { | 288 | userSpaceSource = new UserSpaceSource(&senderSem); |
345 | if (pthread_create(&countersThreadID, NULL, countersThread, this)) { | 289 | if (!userSpaceSource->prepare()) { |
346 | thread_creation_success = false; | 290 | logg->logError(__FILE__, __LINE__, "Unable to prepare for capture"); |
291 | handleException(); | ||
347 | } | 292 | } |
348 | } else { | 293 | userSpaceSource->start(); |
349 | // Let senderThread know there is no buffer data to send | 294 | } |
350 | buffer->setDone(); | 295 | if (access("/tmp/gator", F_OK) == 0) { |
296 | externalSource = new ExternalSource(&senderSem); | ||
297 | if (!externalSource->prepare()) { | ||
298 | logg->logError(__FILE__, __LINE__, "Unable to prepare for capture"); | ||
299 | handleException(); | ||
300 | } | ||
301 | externalSource->start(); | ||
351 | } | 302 | } |
352 | 303 | ||
353 | if (!thread_creation_success) { | 304 | if (!thread_creation_success) { |
@@ -359,28 +310,13 @@ void Child::run() { | |||
359 | sem_wait(&senderThreadStarted); | 310 | sem_wait(&senderThreadStarted); |
360 | 311 | ||
361 | // Start profiling | 312 | // Start profiling |
362 | logg->logMessage("********** Profiling started **********"); | 313 | primarySource->run(); |
363 | collector->start(); | ||
364 | sem_post(&startProfile); | ||
365 | |||
366 | // Collect Data | ||
367 | do { | ||
368 | // This command will stall until data is received from the driver | ||
369 | bytesCollected = collector->collect(collectBuffer); | ||
370 | |||
371 | // In one shot mode, stop collection once all the buffers are filled | ||
372 | if (gSessionData->mOneShot && gSessionData->mSessionIsActive) { | ||
373 | if (bytesCollected == -1 || collectorFifo->willFill(bytesCollected)) { | ||
374 | logg->logMessage("One shot"); | ||
375 | endSession(); | ||
376 | } | ||
377 | } | ||
378 | collectBuffer = collectorFifo->write(bytesCollected); | ||
379 | } while (bytesCollected > 0); | ||
380 | logg->logMessage("Exit collect data loop"); | ||
381 | 314 | ||
382 | if (startcountersThread) { | 315 | if (externalSource != NULL) { |
383 | pthread_join(countersThreadID, NULL); | 316 | externalSource->join(); |
317 | } | ||
318 | if (userSpaceSource != NULL) { | ||
319 | userSpaceSource->join(); | ||
384 | } | 320 | } |
385 | 321 | ||
386 | // Wait for the other threads to exit | 322 | // Wait for the other threads to exit |
@@ -401,9 +337,9 @@ void Child::run() { | |||
401 | 337 | ||
402 | logg->logMessage("Profiling ended."); | 338 | logg->logMessage("Profiling ended."); |
403 | 339 | ||
404 | delete buffer; | 340 | delete externalSource; |
405 | delete collectorFifo; | 341 | delete userSpaceSource; |
342 | delete primarySource; | ||
406 | delete sender; | 343 | delete sender; |
407 | delete collector; | ||
408 | delete localCapture; | 344 | delete localCapture; |
409 | } | 345 | } |