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.
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.
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.
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.
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).
20 #ifndef TOOLS_CYGPROFILE_CYGPROFILE_H_
21 #define TOOLS_CYGPROFILE_CYGPROFILE_H_
26 #include <sys/types.h>
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"
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.
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
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.
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
57 #error This is only supported on Android.
60 // The following is only exposed for testing.
61 namespace cygprofile
{
65 // Single log entry recorded for each function call.
67 LogEntry(const void* address
);
72 const void* const address
;
75 // Per-thread function calls log.
78 // Callback invoked for flushing that can be provided for testing.
79 typedef base::Callback
<void (std::vector
<LogEntry
>*)> FlushCallback
;
84 ThreadLog(const FlushCallback
& flush_callback
);
88 // Must only be called from the thread this ThreadLog instance is watching.
89 void AddEntry(void* address
);
91 // Can be called from any thread.
92 void TakeEntries(std::vector
<LogEntry
>* output
);
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;
99 // Default implementation (that can be overridden for testing) of the method
101 void FlushInternal(std::vector
<LogEntry
>* entries
) const;
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.
108 // Current thread is inside the instrumentation routine.
111 // Callback used to flush entries.
112 const FlushCallback flush_callback_
;
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_
;
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.
123 std::vector
<LogEntry
> entries_
;
125 DISALLOW_COPY_AND_ASSIGN(ThreadLog
);
128 // Manages a list of per-thread logs.
129 class ThreadLogsManager
{
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
136 ThreadLogsManager(const base::Closure
& wait_callback
,
137 const base::Closure
& notify_callback
);
139 ~ThreadLogsManager();
141 // Can be called from any thread.
142 void AddLog(scoped_ptr
<ThreadLog
> new_log
);
145 void StartInternalFlushThread_Locked();
147 // Flush thread's entry point.
148 void FlushAllLogsOnFlushThread();
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
154 const base::Closure notify_callback_
;
156 // Protects the state below.
158 scoped_ptr
<Thread
> flush_thread_
;
159 std::vector
<ThreadLog
*> logs_
;
161 DISALLOW_COPY_AND_ASSIGN(ThreadLogsManager
);
164 } // namespace cygprofile
166 #endif // TOOLS_CYGPROFILE_CYGPROFILE_H_