1// Copyright 2014 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4//
5// Tool to log the execution of the process (Chrome). Writes logs containing
6// time and address of the callback being called for the first time.
7//
8// For performance reasons logs are buffered. Every thread has its own buffer
9// and log file so the contention between threads is minimal. As a side-effect,
10// functions called might be mentioned in many thread logs.
11//
12// A special thread is created in the process to periodically flush logs for all
13// threads in case the thread had stopped before flushing its logs.
14//
15// Also note that the instrumentation code is self-activated. It begins to
16// record the log data when it is called first, including the run-time startup.
17// Have it in mind when modifying it, in particular do not use global objects
18// with constructors as they are called during startup (too late for us).
19
20#ifndef TOOLS_CYGPROFILE_CYGPROFILE_H_
21#define TOOLS_CYGPROFILE_CYGPROFILE_H_
22
23#include <vector>
24
25#include <sys/time.h>
26#include <sys/types.h>
27
28#include "base/callback.h"
29#include "base/containers/hash_tables.h"
30#include "base/macros.h"
31#include "base/memory/scoped_ptr.h"
32#include "base/synchronization/lock.h"
33#include "build/build_config.h"
34
35#if !defined(OS_ANDROID)
36// This is only supported on Android thanks to the fact that on Android
37// processes (other than the system's zygote) don't fork.
38//
39// To make cygprofile truly work (i.e. without any deadlock) on Chrome
40// platforms that use fork(), cygprofile.cc should be written in a way that
41// guarantees that:
42// - No lock is acquired by a foreign thread during fork(). In particular this
43// means that cygprofile.cc should not perform any heap allocation (since heap
44// allocators, including TCMalloc generally use locks).
45// - Only cygprofile.cc uses pthread_atfork() in the whole process. Unlike POSIX
46// signals, pthread_atfork() doesn't provide a way to install multiple handlers.
47// Calling pthread_atfork() in cygprofile.cc would override any handler that
48// could have been installed previously.
49//
50// Chrome happens to violate the first requirement at least once by having its
51// process launcher thread fork. However the child process in that case, when
52// it's not instrumented with cygprofile, directly calls exec(). This is safe
53// since the child process doesn't try to release a lock acquired by another
54// thread in the parent process which would lead to a deadlock. This problem was
55// actually observed by trying to port the current version of cygprofile.cc to
56// Linux.
57#error This is only supported on Android.
58#endif
59
60// The following is only exposed for testing.
61namespace cygprofile {
62
63class Thread;
64
65// Single log entry recorded for each function call.
66struct LogEntry {
67  LogEntry(const void* address);
68
69  const timespec time;
70  const pid_t pid;
71  const pid_t tid;
72  const void* const address;
73};
74
75// Per-thread function calls log.
76class ThreadLog {
77 public:
78  // Callback invoked for flushing that can be provided for testing.
79  typedef base::Callback<void (std::vector<LogEntry>*)> FlushCallback;
80
81  ThreadLog();
82
83  // Used for testing.
84  ThreadLog(const FlushCallback& flush_callback);
85
86  ~ThreadLog();
87
88  // Must only be called from the thread this ThreadLog instance is watching.
89  void AddEntry(void* address);
90
91  // Can be called from any thread.
92  void TakeEntries(std::vector<LogEntry>* output);
93
94  // Flushes the provided vector of entries to a file and clears it. Note that
95  // this can be called from any thread.
96  void Flush(std::vector<LogEntry>* entries) const;
97
98 private:
99  // Default implementation (that can be overridden for testing) of the method
100  // above.
101  void FlushInternal(std::vector<LogEntry>* entries) const;
102
103  // Thread identifier as Linux kernel shows it.  LWP (light-weight process) is
104  // a unique ID of the thread in the system, unlike pthread_self() which is the
105  // same for fork()-ed threads.
106  const pid_t tid_;
107
108  // Current thread is inside the instrumentation routine.
109  bool in_use_;
110
111  // Callback used to flush entries.
112  const FlushCallback flush_callback_;
113
114  // Keeps track of all functions that have been logged on this thread so we do
115  // not record duplicates.
116  std::hash_set<void*> called_functions_;
117
118  // A lock that guards |entries_| usage between per-thread instrumentation
119  // routine and timer flush callback. So the contention could happen only
120  // during the flush, every 15 secs.
121  base::Lock lock_;
122
123  std::vector<LogEntry> entries_;
124
125  DISALLOW_COPY_AND_ASSIGN(ThreadLog);
126};
127
128// Manages a list of per-thread logs.
129class ThreadLogsManager {
130 public:
131  ThreadLogsManager();
132
133  // Used for testing. The provided callbacks are used for testing to
134  // synchronize the internal thread with the unit test running on the main
135  // thread.
136  ThreadLogsManager(const base::Closure& wait_callback,
137                    const base::Closure& notify_callback);
138
139  ~ThreadLogsManager();
140
141  // Can be called from any thread.
142  void AddLog(scoped_ptr<ThreadLog> new_log);
143
144 private:
145  void StartInternalFlushThread_Locked();
146
147  // Flush thread's entry point.
148  void FlushAllLogsOnFlushThread();
149
150  // Used to make the internal thread sleep before each flush iteration.
151  const base::Closure wait_callback_;
152  // Used to trigger a notification when a flush happened on the internal
153  // thread.
154  const base::Closure notify_callback_;
155
156  // Protects the state below.
157  base::Lock lock_;
158  scoped_ptr<Thread> flush_thread_;
159  std::vector<ThreadLog*> logs_;
160
161  DISALLOW_COPY_AND_ASSIGN(ThreadLogsManager);
162};
163
164}  // namespace cygprofile
165
166#endif  // TOOLS_CYGPROFILE_CYGPROFILE_H_
167