133c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris/* 233c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris * Copyright (C) 2015 The Android Open Source Project 333c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris * 433c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris * Licensed under the Apache License, Version 2.0 (the "License"); 533c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris * you may not use this file except in compliance with the License. 633c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris * You may obtain a copy of the License at 733c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris * 833c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris * http://www.apache.org/licenses/LICENSE-2.0 933c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris * 1033c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris * Unless required by applicable law or agreed to in writing, software 1133c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris * distributed under the License is distributed on an "AS IS" BASIS, 1233c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1333c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris * See the License for the specific language governing permissions and 1433c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris * limitations under the License. 1533c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris */ 1633c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris 1733c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris#include <err.h> 1833c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris#include <errno.h> 1933c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris#include <fcntl.h> 2033c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris#include <inttypes.h> 2133c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris#include <stdint.h> 2233c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris#include <stdio.h> 2333c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris#include <stdlib.h> 2433c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris#include <string.h> 2533c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris#include <sys/stat.h> 2633c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris#include <sys/types.h> 2733c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris#include <unistd.h> 2833c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris 2933c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris#include "Action.h" 3033c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris#include "LineBuffer.h" 3133c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris#include "NativeInfo.h" 3233c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris#include "Pointers.h" 3333c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris#include "Thread.h" 3433c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris#include "Threads.h" 3533c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris 3633c03d38298ff359d8829aea91bb02b26caab245Christopher Ferrisstatic char g_buffer[65535]; 3733c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris 3833c03d38298ff359d8829aea91bb02b26caab245Christopher Ferrissize_t GetMaxAllocs(int fd) { 3957b648ab50307e0de2750c864b5db2a83604338bElliott Hughes lseek(fd, 0, SEEK_SET); 4033c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris LineBuffer line_buf(fd, g_buffer, sizeof(g_buffer)); 4133c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris char* line; 4233c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris size_t line_len; 4333c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris size_t num_allocs = 0; 4433c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris while (line_buf.GetLine(&line, &line_len)) { 4533c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris char* word = reinterpret_cast<char*>(memchr(line, ':', line_len)); 4633c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris if (word == nullptr) { 4733c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris continue; 4833c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris } 4933c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris 5033c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris word++; 5133c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris while (*word++ == ' '); 5233c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris // This will treat a realloc as an allocation, even if it frees 5333c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris // another allocation. Since reallocs are relatively rare, this 5433c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris // shouldn't inflate the numbers that much. 5533c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris if (*word == 'f') { 5633c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris // Check if this is a free of zero. 5733c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris uintptr_t pointer; 5833c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris if (sscanf(word, "free %" SCNxPTR, &pointer) == 1 && pointer != 0) { 5933c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris num_allocs--; 6033c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris } 6133c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris } else if (*word != 't') { 6233c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris // Skip the thread_done message. 6333c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris num_allocs++; 6433c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris } 6533c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris } 6633c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris return num_allocs; 6733c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris} 6833c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris 6933c03d38298ff359d8829aea91bb02b26caab245Christopher Ferrisvoid ProcessDump(int fd, size_t max_allocs, size_t max_threads) { 7057b648ab50307e0de2750c864b5db2a83604338bElliott Hughes lseek(fd, 0, SEEK_SET); 7133c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris Pointers pointers(max_allocs); 7233c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris Threads threads(&pointers, max_threads); 7333c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris 7433c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris printf("Maximum threads available: %zu\n", threads.max_threads()); 7533c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris printf("Maximum allocations in dump: %zu\n", max_allocs); 7633c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris printf("Total pointers available: %zu\n", pointers.max_pointers()); 7733c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris printf("\n"); 7833c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris 7933c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris PrintNativeInfo("Initial "); 8033c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris 8133c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris LineBuffer line_buf(fd, g_buffer, sizeof(g_buffer)); 8233c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris char* line; 8333c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris size_t line_len; 8433c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris size_t line_number = 0; 8533c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris while (line_buf.GetLine(&line, &line_len)) { 8633c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris pid_t tid; 8733c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris int line_pos = 0; 8833c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris char type[128]; 8933c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris uintptr_t key_pointer; 9033c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris 9133c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris // Every line is of this format: 9233c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris // <tid>: <action_type> <pointer> 9333c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris // Some actions have extra arguments which will be used and verified 9433c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris // when creating the Action object. 9533c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris if (sscanf(line, "%d: %s %" SCNxPTR " %n", &tid, type, &key_pointer, &line_pos) != 3) { 9633c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris err(1, "Unparseable line found: %s\n", line); 9733c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris } 9833c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris line_number++; 9933c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris if ((line_number % 100000) == 0) { 10033c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris printf(" At line %zu:\n", line_number); 10133c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris PrintNativeInfo(" "); 10233c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris } 10333c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris Thread* thread = threads.FindThread(tid); 10433c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris if (thread == nullptr) { 10533c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris thread = threads.CreateThread(tid); 10633c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris } 10733c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris 10833c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris // Wait for the thread to complete any previous actions before handling 10933c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris // the next action. 11033c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris thread->WaitForReady(); 11133c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris 11233c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris Action* action = thread->CreateAction(key_pointer, type, line + line_pos); 11333c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris if (action == nullptr) { 11433c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris err(1, "Cannot create action from line: %s\n", line); 11533c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris } 11633c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris 11733c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris bool does_free = action->DoesFree(); 11833c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris if (does_free) { 11933c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris // Make sure that any other threads doing allocations are complete 12033c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris // before triggering the action. Otherwise, another thread could 12133c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris // be creating the allocation we are going to free. 12233c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris threads.WaitForAllToQuiesce(); 12333c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris } 12433c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris 12533c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris // Tell the thread to execute the action. 12633c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris thread->SetPending(); 12733c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris 12833c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris if (action->EndThread()) { 12933c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris // Wait for the thread to finish and clear the thread entry. 13033c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris threads.Finish(thread); 13133c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris } 13233c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris 13333c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris // Wait for this action to complete. This avoids a race where 13433c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris // another thread could be creating the same allocation where are 13533c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris // trying to free. 13633c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris if (does_free) { 13733c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris thread->WaitForReady(); 13833c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris } 13933c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris } 14033c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris // Wait for all threads to stop processing actions. 14133c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris threads.WaitForAllToQuiesce(); 14233c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris 14333c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris PrintNativeInfo("Final "); 14433c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris 14533c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris // Free any outstanding pointers. 14633c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris // This allows us to run a tool like valgrind to verify that no memory 14733c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris // is leaked and everything is accounted for during a run. 14833c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris threads.FinishAll(); 14933c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris pointers.FreeAll(); 150cd7d10869f87b15f072aaa4ccb118fc97a570c23Christopher Ferris 151cd7d10869f87b15f072aaa4ccb118fc97a570c23Christopher Ferris // Print out the total time making all allocation calls. 152cd7d10869f87b15f072aaa4ccb118fc97a570c23Christopher Ferris printf("Total Allocation/Free Time: %" PRIu64 "ns %0.2fs\n", 153cd7d10869f87b15f072aaa4ccb118fc97a570c23Christopher Ferris threads.total_time_nsecs(), threads.total_time_nsecs()/1000000000.0); 15433c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris} 15533c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris 15633c03d38298ff359d8829aea91bb02b26caab245Christopher Ferrisconstexpr size_t DEFAULT_MAX_THREADS = 512; 15733c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris 15833c03d38298ff359d8829aea91bb02b26caab245Christopher Ferrisint main(int argc, char** argv) { 15933c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris if (argc != 2 && argc != 3) { 16033c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris if (argc > 3) { 16133c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris fprintf(stderr, "Only two arguments are expected.\n"); 16233c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris } else { 16333c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris fprintf(stderr, "Requires at least one argument.\n"); 16433c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris } 16533c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris fprintf(stderr, "Usage: %s MEMORY_LOG_FILE [MAX_THREADS]\n", basename(argv[0])); 16633c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris return 1; 16733c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris } 16833c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris 16933c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris size_t max_threads = DEFAULT_MAX_THREADS; 17033c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris if (argc == 3) { 17133c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris max_threads = atoi(argv[2]); 17233c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris } 17333c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris 17433c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris int dump_fd = open(argv[1], O_RDONLY); 17533c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris if (dump_fd == -1) { 17633c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris fprintf(stderr, "Failed to open %s: %s\n", argv[1], strerror(errno)); 17733c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris return 1; 17833c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris } 17933c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris 18033c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris printf("Processing: %s\n", argv[1]); 18133c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris 18233c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris // Do a first pass to get the total number of allocations used at one 18333c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris // time to allow a single mmap that can hold the maximum number of 18433c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris // pointers needed at once. 18533c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris size_t max_allocs = GetMaxAllocs(dump_fd); 18633c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris ProcessDump(dump_fd, max_allocs, max_threads); 18733c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris 18833c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris close(dump_fd); 18933c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris 19033c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris return 0; 19133c03d38298ff359d8829aea91bb02b26caab245Christopher Ferris} 192