1 : // Copyright 2012 Google Inc.
2 : //
3 : // Licensed under the Apache License, Version 2.0 (the "License");
4 : // you may not use this file except in compliance with the License.
5 : // You may obtain a copy of the License at
6 : //
7 : // http://www.apache.org/licenses/LICENSE-2.0
8 : //
9 : // Unless required by applicable law or agreed to in writing, software
10 : // distributed under the License is distributed on an "AS IS" BASIS,
11 : // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 : // See the License for the specific language governing permissions and
13 : // limitations under the License.
14 : //
15 : // A hierarchical profiler, indended for use with the Syzygy function level
16 : // instrumenter. The Syzygy instrumented provides a function entry hook, and
17 : // this implementation uses a shadow stack with return address swizzling to
18 : // get an exit hook.
19 : // The profiler uses RDTSC as wall clock, which makes it unsuitable for
20 : // profiling on systems with CPUs prior to AMD Barcelona/Phenom, or older
21 : // Intel processors, see e.g. http://en.wikipedia.org/wiki/Time_Stamp_Counter
22 : // for the low down details.
23 :
24 : #ifndef SYZYGY_AGENT_PROFILER_PROFILER_H_
25 : #define SYZYGY_AGENT_PROFILER_PROFILER_H_
26 :
27 : #include <windows.h>
28 : #include <winnt.h>
29 : #include <vector>
30 :
31 : #include "base/hash_tables.h"
32 : #include "base/lazy_instance.h"
33 : #include "base/synchronization/lock.h"
34 : #include "base/threading/thread_local.h"
35 : #include "syzygy/agent/common/entry_frame.h"
36 : #include "syzygy/agent/common/thread_state.h"
37 : #include "syzygy/trace/client/rpc_session.h"
38 :
39 : // Assembly instrumentation stubs to handle function entry and exit.
40 m : extern "C" void _cdecl _indirect_penter();
41 m : extern "C" void _cdecl _indirect_penter_dllmain();
42 m : extern "C" void _cdecl _indirect_penter_inside_function();
43 m : extern void pexit();
44 :
45 m : namespace agent {
46 m : namespace profiler {
47 :
48 : // There's a single instance of this class.
49 m : class Profiler {
50 m : public:
51 m : static void WINAPI DllMainEntryHook(EntryFrame* entry_frame,
52 m : FuncAddr function,
53 m : uint64 cycles);
54 :
55 m : static void WINAPI FunctionEntryHook(EntryFrame* entry_frame,
56 m : FuncAddr function,
57 m : uint64 cycles);
58 :
59 : // Resolves a return address location to a thunk's stashed original
60 : // location if a thunk is involved.
61 : // @param pc_location an address on stack where a return address is stored.
62 : // @returns the address where the profiler stashed the original return address
63 : // if *(@p pc_location) refers to a thunk, otherwise @p pc_location.
64 : // @note this function must be able to resolve through thunks that belong
65 : // to other threads, as e.g. V8 will traverse all stacks that are using
66 : // V8 during garbage collection.
67 m : RetAddr* ResolveReturnAddressLocation(RetAddr* pc_location);
68 :
69 : // Retrieves the profiler singleton instance.
70 m : static Profiler* Instance();
71 :
72 : // Called when a thread is terminating.
73 m : void OnThreadDetach();
74 :
75 m : private:
76 : // Make sure the LazyInstance can be created.
77 m : friend struct base::DefaultLazyInstanceTraits<Profiler>;
78 :
79 m : Profiler();
80 m : ~Profiler();
81 :
82 : // Called form DllMainEntryHook.
83 m : void OnModuleEntry(EntryFrame* entry_frame,
84 m : FuncAddr function,
85 m : uint64 cycles);
86 :
87 : // Callbacks from ThreadState.
88 m : void OnPageAdded(const void* page);
89 m : void OnPageRemoved(const void* page);
90 :
91 : // Called on a first chance exception declaring thread name.
92 m : void OnThreadName(const base::StringPiece& thread_name);
93 :
94 : // Our vectored exception handler that takes care
95 : // of capturing thread name debug exceptions.
96 m : static LONG CALLBACK ExceptionHandler(EXCEPTION_POINTERS* ex_info);
97 :
98 m : class ThreadState;
99 :
100 m : ThreadState* CreateFirstThreadStateAndSession();
101 m : ThreadState* GetOrAllocateThreadState();
102 m : ThreadState* GetOrAllocateThreadStateImpl();
103 m : ThreadState* GetThreadState() const;
104 m : void FreeThreadState();
105 :
106 : // The RPC session we're logging to/through.
107 m : trace::client::RpcSession session_;
108 :
109 : // Protects pages_ and logged_modules_.
110 m : base::Lock lock_;
111 :
112 : // Contains the thunk pages in lexical order.
113 m : typedef std::vector<const void*> PageVector;
114 m : PageVector pages_; // Under lock_.
115 :
116 : // Contains the set of modules we've seen and logged.
117 m : typedef base::hash_set<HMODULE> ModuleSet;
118 m : ModuleSet logged_modules_; // Under lock_.
119 :
120 : // A helper to manage the life-cycle of the ThreadState instances allocated
121 : // by this agent.
122 m : agent::common::ThreadStateManager thread_state_manager_;
123 :
124 : // Stores our vectored exception handler registration handle.
125 m : void* handler_registration_;
126 :
127 : // This points to our per-thread state.
128 m : mutable base::ThreadLocalPointer<ThreadState> tls_;
129 m : };
130 :
131 m : } // namespace profiler
132 m : } // namespace agent
133 :
134 : #endif // SYZYGY_AGENT_PROFILER_PROFILER_H_
|