summaryrefslogtreecommitdiff
path: root/memory_replay/main.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'memory_replay/main.cpp')
-rw-r--r--memory_replay/main.cpp151
1 files changed, 83 insertions, 68 deletions
diff --git a/memory_replay/main.cpp b/memory_replay/main.cpp
index 9873ec70..42b52983 100644
--- a/memory_replay/main.cpp
+++ b/memory_replay/main.cpp
@@ -18,7 +18,6 @@
#include <errno.h>
#include <fcntl.h>
#include <inttypes.h>
-#include <malloc.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
@@ -27,67 +26,95 @@
#include <sys/types.h>
#include <unistd.h>
-#include "Alloc.h"
-#include "File.h"
+#include "Action.h"
+#include "LineBuffer.h"
#include "NativeInfo.h"
#include "Pointers.h"
#include "Thread.h"
#include "Threads.h"
-constexpr size_t kDefaultMaxThreads = 512;
+static char g_buffer[65535];
-static size_t GetMaxAllocs(const AllocEntry* entries, size_t num_entries) {
+size_t GetMaxAllocs(int fd) {
+ lseek(fd, 0, SEEK_SET);
+ LineBuffer line_buf(fd, g_buffer, sizeof(g_buffer));
+ char* line;
+ size_t line_len;
size_t num_allocs = 0;
- for (size_t i = 0; i < num_entries; i++) {
- switch (entries[i].type) {
- case THREAD_DONE:
- break;
- case MALLOC:
- case CALLOC:
- case MEMALIGN:
- case REALLOC:
- num_allocs++;
- break;
- case FREE:
+ while (line_buf.GetLine(&line, &line_len)) {
+ char* word = reinterpret_cast<char*>(memchr(line, ':', line_len));
+ if (word == nullptr) {
+ continue;
+ }
+
+ word++;
+ while (*word++ == ' ');
+ // This will treat a realloc as an allocation, even if it frees
+ // another allocation. Since reallocs are relatively rare, this
+ // shouldn't inflate the numbers that much.
+ if (*word == 'f') {
+ // Check if this is a free of zero.
+ uintptr_t pointer;
+ if (sscanf(word, "free %" SCNxPTR, &pointer) == 1 && pointer != 0) {
num_allocs--;
- break;
+ }
+ } else if (*word != 't') {
+ // Skip the thread_done message.
+ num_allocs++;
}
}
return num_allocs;
}
-static void ProcessDump(const AllocEntry* entries, size_t num_entries, size_t max_threads) {
- // Do a pass to get the maximum number of allocations used at one
- // time to allow a single mmap that can hold the maximum number of
- // pointers needed at once.
- size_t max_allocs = GetMaxAllocs(entries, num_entries);
+void ProcessDump(int fd, size_t max_allocs, size_t max_threads) {
+ lseek(fd, 0, SEEK_SET);
Pointers pointers(max_allocs);
Threads threads(&pointers, max_threads);
- NativePrintf("Maximum threads available: %zu\n", threads.max_threads());
- NativePrintf("Maximum allocations in dump: %zu\n", max_allocs);
- NativePrintf("Total pointers available: %zu\n\n", pointers.max_pointers());
-
- NativePrintInfo("Initial ");
-
- for (size_t i = 0; i < num_entries; i++) {
- if (((i + 1) % 100000) == 0) {
- NativePrintf(" At line %zu:\n", i + 1);
- NativePrintInfo(" ");
+ printf("Maximum threads available: %zu\n", threads.max_threads());
+ printf("Maximum allocations in dump: %zu\n", max_allocs);
+ printf("Total pointers available: %zu\n", pointers.max_pointers());
+ printf("\n");
+
+ PrintNativeInfo("Initial ");
+
+ LineBuffer line_buf(fd, g_buffer, sizeof(g_buffer));
+ char* line;
+ size_t line_len;
+ size_t line_number = 0;
+ while (line_buf.GetLine(&line, &line_len)) {
+ pid_t tid;
+ int line_pos = 0;
+ char type[128];
+ uintptr_t key_pointer;
+
+ // Every line is of this format:
+ // <tid>: <action_type> <pointer>
+ // Some actions have extra arguments which will be used and verified
+ // when creating the Action object.
+ if (sscanf(line, "%d: %s %" SCNxPTR " %n", &tid, type, &key_pointer, &line_pos) != 3) {
+ err(1, "Unparseable line found: %s\n", line);
}
- const AllocEntry& entry = entries[i];
- Thread* thread = threads.FindThread(entry.tid);
+ line_number++;
+ if ((line_number % 100000) == 0) {
+ printf(" At line %zu:\n", line_number);
+ PrintNativeInfo(" ");
+ }
+ Thread* thread = threads.FindThread(tid);
if (thread == nullptr) {
- thread = threads.CreateThread(entry.tid);
+ thread = threads.CreateThread(tid);
}
// Wait for the thread to complete any previous actions before handling
// the next action.
thread->WaitForReady();
- thread->SetAllocEntry(&entry);
+ Action* action = thread->CreateAction(key_pointer, type, line + line_pos);
+ if (action == nullptr) {
+ err(1, "Cannot create action from line: %s\n", line);
+ }
- bool does_free = AllocDoesFree(entry);
+ bool does_free = action->DoesFree();
if (does_free) {
// Make sure that any other threads doing allocations are complete
// before triggering the action. Otherwise, another thread could
@@ -98,7 +125,7 @@ static void ProcessDump(const AllocEntry* entries, size_t num_entries, size_t ma
// Tell the thread to execute the action.
thread->SetPending();
- if (entries[i].type == THREAD_DONE) {
+ if (action->EndThread()) {
// Wait for the thread to finish and clear the thread entry.
threads.Finish(thread);
}
@@ -113,7 +140,7 @@ static void ProcessDump(const AllocEntry* entries, size_t num_entries, size_t ma
// Wait for all threads to stop processing actions.
threads.WaitForAllToQuiesce();
- NativePrintInfo("Final ");
+ PrintNativeInfo("Final ");
// Free any outstanding pointers.
// This allows us to run a tool like valgrind to verify that no memory
@@ -122,12 +149,12 @@ static void ProcessDump(const AllocEntry* entries, size_t num_entries, size_t ma
pointers.FreeAll();
// Print out the total time making all allocation calls.
- char buffer[256];
- uint64_t total_nsecs = threads.total_time_nsecs();
- NativeFormatFloat(buffer, sizeof(buffer), total_nsecs, 1000000000);
- NativePrintf("Total Allocation/Free Time: %" PRIu64 "ns %ss\n", total_nsecs, buffer);
+ printf("Total Allocation/Free Time: %" PRIu64 "ns %0.2fs\n",
+ threads.total_time_nsecs(), threads.total_time_nsecs()/1000000000.0);
}
+constexpr size_t DEFAULT_MAX_THREADS = 512;
+
int main(int argc, char** argv) {
if (argc != 2 && argc != 3) {
if (argc > 3) {
@@ -136,41 +163,29 @@ int main(int argc, char** argv) {
fprintf(stderr, "Requires at least one argument.\n");
}
fprintf(stderr, "Usage: %s MEMORY_LOG_FILE [MAX_THREADS]\n", basename(argv[0]));
- fprintf(stderr, " MEMORY_LOG_FILE\n");
- fprintf(stderr, " This can either be a text file or a zipped text file.\n");
- fprintf(stderr, " MAX_THREADs\n");
- fprintf(stderr, " The maximum number of threads in the trace. The default is %zu.\n",
- kDefaultMaxThreads);
- fprintf(stderr, " This pre-allocates the memory for thread data to avoid allocating\n");
- fprintf(stderr, " while the trace is being replayed.\n");
return 1;
}
-#if defined(__LP64__)
- NativePrintf("64 bit environment.\n");
-#else
- NativePrintf("32 bit environment.\n");
-#endif
-
-#if defined(__BIONIC__)
- NativePrintf("Setting decay time to 1\n");
- mallopt(M_DECAY_TIME, 1);
-#endif
-
- size_t max_threads = kDefaultMaxThreads;
+ size_t max_threads = DEFAULT_MAX_THREADS;
if (argc == 3) {
max_threads = atoi(argv[2]);
}
- AllocEntry* entries;
- size_t num_entries;
- GetUnwindInfo(argv[1], &entries, &num_entries);
+ int dump_fd = open(argv[1], O_RDONLY);
+ if (dump_fd == -1) {
+ fprintf(stderr, "Failed to open %s: %s\n", argv[1], strerror(errno));
+ return 1;
+ }
- NativePrintf("Processing: %s\n", argv[1]);
+ printf("Processing: %s\n", argv[1]);
- ProcessDump(entries, num_entries, max_threads);
+ // Do a first pass to get the total number of allocations used at one
+ // time to allow a single mmap that can hold the maximum number of
+ // pointers needed at once.
+ size_t max_allocs = GetMaxAllocs(dump_fd);
+ ProcessDump(dump_fd, max_allocs, max_threads);
- FreeEntries(entries, num_entries);
+ close(dump_fd);
return 0;
}