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