1 : // Copyright 2014 Google Inc. All Rights Reserved.
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 : #include "syzygy/agent/memprof/function_call_logger.h"
16 :
17 : #include "syzygy/agent/common/stack_capture.h"
18 :
19 : namespace agent {
20 : namespace memprof {
21 :
22 : FunctionCallLogger::FunctionCallLogger(
23 : trace::client::RpcSession* session)
24 : : session_(session),
25 : stack_trace_tracking_(kTrackingNone),
26 : serialize_timestamps_(false),
27 : call_counter_(0),
28 E : serial_(0) {
29 E : DCHECK_NE(static_cast<trace::client::RpcSession*>(nullptr), session);
30 :
31 : // Generate a unique 'serial number' for this instance. This is so that we
32 : // can tell one logger from the next in unittests, where they often end up
33 : // having the same address.
34 E : uint64 t = ::trace::common::GetTsc();
35 : serial_ = static_cast<uint32>(t & 0xFFFFFFFF) ^
36 : static_cast<uint32>((t >> 32) & 0xFFFFFFFF) ^
37 E : reinterpret_cast<uint32>(this);
38 E : }
39 :
40 : // Given a function name returns it's ID. If this is the first time seeing
41 : // a given function name then emits a record to the call-trace buffer.
42 : uint32 FunctionCallLogger::GetFunctionId(TraceFileSegment* segment,
43 E : const std::string& function_name) {
44 E : DCHECK_NE(static_cast<TraceFileSegment*>(nullptr), segment);
45 E : size_t id = 0;
46 :
47 : {
48 E : base::AutoLock lock(lock_);
49 E : auto it = function_id_map_.find(function_name);
50 E : if (it != function_id_map_.end())
51 E : return it->second;
52 E : id = function_id_map_.size();
53 E : function_id_map_.insert(std::make_pair(function_name, id));
54 E : }
55 :
56 : size_t data_size = FIELD_OFFSET(TraceFunctionNameTableEntry, name) +
57 E : function_name.size() + 1;
58 :
59 E : if (!segment->CanAllocate(data_size) && !FlushSegment(segment))
60 i : return id;
61 E : DCHECK(segment->CanAllocate(data_size));
62 :
63 : TraceFunctionNameTableEntry* data =
64 E : segment->AllocateTraceRecord<TraceFunctionNameTableEntry>(data_size);
65 E : DCHECK_NE(static_cast<TraceFunctionNameTableEntry*>(nullptr), data);
66 E : data->function_id = id;
67 E : data->name_length = function_name.size() + 1;
68 E : ::memcpy(data->name, function_name.data(), data->name_length);
69 :
70 E : return id;
71 E : }
72 :
73 E : uint32 FunctionCallLogger::GetStackTraceId(TraceFileSegment* segment) {
74 E : DCHECK_NE(static_cast<TraceFileSegment*>(nullptr), segment);
75 E : if (stack_trace_tracking_ == kTrackingNone)
76 E : return 0;
77 :
78 E : agent::common::StackCapture stack;
79 E : stack.InitFromStack();
80 E : if (stack_trace_tracking_ == kTrackingTrack)
81 E : return stack.absolute_stack_id();
82 :
83 : // Insert the stack ID. If it already exists it doesn't need to be emitted
84 : // so return early.
85 E : bool inserted = false;
86 : {
87 E : base::AutoLock lock(lock_);
88 E : inserted = emitted_stack_ids_.insert(stack.absolute_stack_id()).second;
89 E : }
90 E : if (!inserted)
91 i : return stack.absolute_stack_id();
92 :
93 E : size_t frame_size = sizeof(void*) * stack.num_frames();
94 E : size_t data_size = FIELD_OFFSET(TraceStackTrace, frames) + frame_size;
95 E : if (!segment->CanAllocate(data_size) && !FlushSegment(segment))
96 i : return stack.absolute_stack_id();
97 E : DCHECK(segment->CanAllocate(data_size));
98 :
99 : TraceStackTrace* data = segment->AllocateTraceRecord<TraceStackTrace>(
100 E : data_size);
101 E : DCHECK_NE(static_cast<TraceStackTrace*>(nullptr), data);
102 E : data->num_frames = stack.num_frames();
103 E : data->stack_trace_id = stack.absolute_stack_id();
104 E : ::memcpy(data->frames, stack.frames(), frame_size);
105 :
106 E : return stack.absolute_stack_id();
107 E : }
108 :
109 i : bool FunctionCallLogger::FlushSegment(TraceFileSegment* segment) {
110 i : DCHECK_NE(static_cast<TraceFileSegment*>(nullptr), segment);
111 i : return session_->ExchangeBuffer(segment);
112 i : }
113 :
114 : } // namespace memprof
115 : } // namespace agent
|