Coverage for /Syzygy/agent/memprof/function_call_logger.h

CoverageLines executed / instrumented / missingexe / inst / missLanguageGroup
92.9%91980.C++source

Line-by-line coverage:

   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    :  // Declares a FunctionCallLogger class. This contains functionality for
  16    :  // logging detailed function call records via the call-trace service.
  17    :  
  18    :  #ifndef SYZYGY_AGENT_MEMPROF_FUNCTION_CALL_LOGGER_H_
  19    :  #define SYZYGY_AGENT_MEMPROF_FUNCTION_CALL_LOGGER_H_
  20    :  
  21    :  #include <set>
  22    :  
  23    :  #include "syzygy/agent/memprof/parameters.h"
  24    :  #include "syzygy/trace/client/rpc_session.h"
  25    :  
  26    :  namespace agent {
  27    :  namespace memprof {
  28    :  
  29    :  class FunctionCallLogger {
  30    :   public:
  31    :    // Forward declarations.
  32    :    struct NoArgument;
  33    :    template<typename ArgType> struct ArgumentSerializer;
  34    :  
  35    :    typedef trace::client::TraceFileSegment TraceFileSegment;
  36    :  
  37    :    // Consructor.
  38    :    // @param session The call-trace session to log to.
  39    :    // @param segment The segment to write to.
  40    :    explicit FunctionCallLogger(trace::client::RpcSession* session);
  41    :  
  42    :    // Given a function name returns it's ID. If this is the first time seeing
  43    :    // a given function name then emits a record to the call-trace buffer.
  44    :    // @param function_name The name of the function.
  45    :    // @returns the ID of the function.
  46    :    uint32 GetFunctionId(TraceFileSegment* segment,
  47    :                         const std::string& function_name);
  48    :  
  49    :    // Gets a stack ID for the current stack. The behaviour of this function
  50    :    // depends on the stack_trace_tracking mode. If disabled, this always
  51    :    // returns 0. If enabled, this returns the actual ID of the current stack.
  52    :    // If 'emit' mode is enabled, this will also keep track of already emitted
  53    :    // stack IDs and emit the stack the first time it's encountered.
  54    :    // @returns the ID of the current stack trace.
  55    :    uint32 GetStackTraceId(TraceFileSegment* segment);
  56    :  
  57    :    // Emits a detailed function call event with a variable number of arguments.
  58    :    // @tparam ArgTypeN The type of the optional Nth argument.
  59    :    // @param function_id The ID of the function that was called.
  60    :    // @param stack_trace_id The ID of the stack trace where the function was
  61    :    //     called.
  62    :    // @param argN The value of the optional Nth argument.
  63    :    template<typename ArgType0 = NoArgument,
  64    :             typename ArgType1 = NoArgument,
  65    :             typename ArgType2 = NoArgument,
  66    :             typename ArgType3 = NoArgument,
  67    :             typename ArgType4 = NoArgument,
  68    :             typename ArgType5 = NoArgument>
  69    :    void EmitDetailedFunctionCall(TraceFileSegment* segment,
  70    :                                  uint32 function_id,
  71    :                                  uint32 stack_trace_id,
  72    :                                  ArgType0 arg0 = NoArgument(),
  73    :                                  ArgType1 arg1 = NoArgument(),
  74    :                                  ArgType2 arg2 = NoArgument(),
  75    :                                  ArgType3 arg3 = NoArgument(),
  76    :                                  ArgType4 arg4 = NoArgument(),
  77    :                                  ArgType5 arg5 = NoArgument());
  78    :  
  79    :    // @name Accessors and mutators.
  80    :    // @{
  81    :    StackTraceTracking stack_trace_tracking() const {
  82    :      return stack_trace_tracking_;
  83    :    }
  84  E :    void set_stack_trace_tracking(StackTraceTracking tracking) {
  85  E :      stack_trace_tracking_ = tracking;
  86  E :    }
  87    :    bool serialize_timestamps() const {
  88    :      return serialize_timestamps_;
  89    :    }
  90  E :    void set_serialize_timestamps(bool serialize_timestamps) {
  91  E :      serialize_timestamps_ = serialize_timestamps;
  92  E :    }
  93    :    // @}
  94    :  
  95    :    // @returns a unique serial number for this function call logger.
  96    :    // @note This is for unittesting purposes.
  97  E :    uint32 serial() const { return serial_; }
  98    :  
  99    :   protected:
 100    :    // Flushes the provided segment, and gets a new one.
 101    :    bool FlushSegment(TraceFileSegment* segment);
 102    :  
 103    :    // The stack-trace tracking mode. Default to kTrackingNone.
 104    :    StackTraceTracking stack_trace_tracking_;
 105    :  
 106    :    // Whether or not timestamps are being serialized.
 107    :    bool serialize_timestamps_;
 108    :  
 109    :    // The RPC session events are being written to.
 110    :    trace::client::RpcSession* session_;
 111    :  
 112    :    // A lock that is used for synchronizing access to internals.
 113    :    base::Lock lock_;
 114    :  
 115    :    // The counter to use for serialized timestamps. Only used if
 116    :    // |serialized_timestamps_| is true.
 117    :    uint64 call_counter_;  // Under lock_.
 118    :  
 119    :    // A map of known function names and their IDs. This is used for making the
 120    :    // call-trace format more compact.
 121    :    typedef std::map<std::string, uint32> FunctionIdMap;
 122    :    FunctionIdMap function_id_map_;  // Under lock_.
 123    :  
 124    :    // A set of stack traces whose IDs have already been emitted. This is only
 125    :    // maintained if stack_trace_tracking_ is set to 'kTrackingEmit'.
 126    :    typedef std::set<uint32> StackIdSet;
 127    :    StackIdSet emitted_stack_ids_;  // Under lock_.
 128    :  
 129    :    // A unique serial number generated at construction time. For unittesting.
 130    :    uint32 serial_;
 131    :  
 132    :   private:
 133    :    DISALLOW_COPY_AND_ASSIGN(FunctionCallLogger);
 134    :  };
 135    :  
 136    :  // Used to indicate the lack of an argument in the detailed
 137    :  // function call reporting helper.
 138    :  struct FunctionCallLogger::NoArgument {};
 139    :  
 140    :  // Helper for serializing argument contents.
 141    :  template<typename ArgType>
 142    :  struct FunctionCallLogger::ArgumentSerializer {
 143  E :    size_t size() const {
 144  E :      return sizeof(ArgType);
 145  E :    }
 146  E :    void serialize(ArgType argument, uint8* buffer) {
 147  E :      ::memcpy(buffer, &argument, sizeof(ArgType));
 148  E :    }
 149    :  };
 150    :  
 151    :  // A no-op serializer for unused arguments.
 152    :  template<> struct FunctionCallLogger::ArgumentSerializer<
 153    :      FunctionCallLogger::NoArgument> {
 154  E :    size_t size() const {
 155  E :      return 0;
 156  E :    }
 157  E :    void serialize(NoArgument argument, uint8* buffer) {
 158    :      return;
 159  E :    }
 160    :  };
 161    :  
 162    :  // Implementation off the detailed function call logger. Populates a
 163    :  // TraceDetailedFunctionCall buffer with variable length encodings of
 164    :  // the arguments. Arguments are serialized using the ArgumentSerializer
 165    :  // helper.
 166    :  template<typename ArgType0,
 167    :           typename ArgType1,
 168    :           typename ArgType2,
 169    :           typename ArgType3,
 170    :           typename ArgType4,
 171    :           typename ArgType5>
 172    :  void FunctionCallLogger::EmitDetailedFunctionCall(TraceFileSegment* segment,
 173    :                                                    uint32 function_id,
 174    :                                                    uint32 stack_trace_id,
 175    :                                                    ArgType0 arg0,
 176    :                                                    ArgType1 arg1,
 177    :                                                    ArgType2 arg2,
 178    :                                                    ArgType3 arg3,
 179    :                                                    ArgType4 arg4,
 180  E :                                                    ArgType5 arg5) {
 181  E :    DCHECK_NE(static_cast<TraceFileSegment*>(nullptr), segment);
 182  E :    size_t args_count = 0;
 183  E :    size_t args_size = 0;
 184    :  
 185  E :    size_t arg_size0 = ArgumentSerializer<ArgType0>().size();
 186  E :    args_count += arg_size0 > 0 ? 1 : 0;
 187  E :    args_size += arg_size0;
 188    :  
 189  E :    size_t arg_size1 = ArgumentSerializer<ArgType1>().size();
 190  E :    args_count += arg_size1 > 0 ? 1 : 0;
 191  E :    args_size += arg_size1;
 192    :  
 193  E :    size_t arg_size2 = ArgumentSerializer<ArgType2>().size();
 194  E :    args_count += arg_size2 > 0 ? 1 : 0;
 195  E :    args_size += arg_size2;
 196    :  
 197  E :    size_t arg_size3 = ArgumentSerializer<ArgType3>().size();
 198  E :    args_count += arg_size3 > 0 ? 1 : 0;
 199  E :    args_size += arg_size3;
 200    :  
 201  E :    size_t arg_size4 = ArgumentSerializer<ArgType4>().size();
 202  E :    args_count += arg_size4 > 0 ? 1 : 0;
 203  E :    args_size += arg_size4;
 204    :  
 205  E :    size_t arg_size5 = ArgumentSerializer<ArgType5>().size();
 206  E :    args_count += arg_size5 > 0 ? 1 : 0;
 207  E :    args_size += arg_size5;
 208    :  
 209  E :    if (args_size > 0)
 210  E :      args_size += (args_count + 1) * sizeof(uint32);
 211    :    size_t data_size = FIELD_OFFSET(TraceDetailedFunctionCall, argument_data) +
 212  E :        args_size;
 213    :  
 214  E :    if (!segment->CanAllocate(data_size) && !FlushSegment(segment))
 215  i :      return;
 216  E :    DCHECK(segment->CanAllocate(data_size));
 217    :  
 218    :    TraceDetailedFunctionCall* data =
 219  E :        segment->AllocateTraceRecord<TraceDetailedFunctionCall>(data_size);
 220  E :    data->function_id = function_id;
 221  E :    data->stack_trace_id = stack_trace_id;
 222  E :    data->argument_data_size = args_size;
 223    :  
 224  E :    if (serialize_timestamps_) {
 225  E :      base::AutoLock lock(lock_);
 226  E :      data->timestamp = call_counter_;
 227  E :      ++call_counter_;
 228  E :    } else {
 229  E :      data->timestamp = ::trace::common::GetTsc();
 230    :    }
 231    :  
 232  E :    if (args_size == 0)
 233  i :      return;
 234    :  
 235    :    // Output the number of arguments.
 236  E :    uint32* arg_sizes = reinterpret_cast<uint32*>(data->argument_data);
 237  E :    *(arg_sizes++) = args_count;
 238    :  
 239    :    // Output argument sizes.
 240  E :    if (arg_size0 > 0)
 241  E :      *(arg_sizes++) = arg_size0;
 242  E :    if (arg_size1 > 0)
 243  i :      *(arg_sizes++) = arg_size1;
 244  E :    if (arg_size2 > 0)
 245  i :      *(arg_sizes++) = arg_size2;
 246  E :    if (arg_size3 > 0)
 247  i :      *(arg_sizes++) = arg_size3;
 248  E :    if (arg_size4 > 0)
 249  i :      *(arg_sizes++) = arg_size4;
 250  E :    if (arg_size5 > 0)
 251  i :      *(arg_sizes++) = arg_size5;
 252    :  
 253    :    // Output argument data.
 254  E :    uint8* arg_data = reinterpret_cast<uint8*>(arg_sizes);
 255  E :    ArgumentSerializer<ArgType0>().serialize(arg0, arg_data);
 256  E :    arg_data += arg_size0;
 257  E :    ArgumentSerializer<ArgType1>().serialize(arg1, arg_data);
 258  E :    arg_data += arg_size1;
 259  E :    ArgumentSerializer<ArgType2>().serialize(arg2, arg_data);
 260  E :    arg_data += arg_size2;
 261  E :    ArgumentSerializer<ArgType3>().serialize(arg3, arg_data);
 262  E :    arg_data += arg_size3;
 263  E :    ArgumentSerializer<ArgType4>().serialize(arg4, arg_data);
 264  E :    arg_data += arg_size4;
 265  E :    ArgumentSerializer<ArgType5>().serialize(arg5, arg_data);
 266  E :    arg_data += arg_size5;
 267  E :  }
 268    :  
 269    :  // A templated helper for emitting a detailed function call record.
 270    :  // @param function_call_logger A pointer to the function call logger
 271    :  //     instance to use.
 272    :  // @param segment A pointer to the TraceFileSegment to write to.
 273    :  // @param logger_serial A pointer to where the serial number of the previous
 274    :  //     function call logger can be stored. Must be statically initialized to
 275    :  //     -1.
 276    :  // @param function_id A pointer where the function ID can be saved. Must
 277    :  //     be statically initialized to -1.
 278    :  // @param function_name The name of the function being traced.
 279    :  // @param arguments The arguments to the function being traced.
 280    :  template<typename... Arguments>
 281    :  inline void EmitDetailedFunctionCallHelper(
 282    :      FunctionCallLogger* function_call_logger,
 283    :      trace::client::TraceFileSegment* segment,
 284    :      uint32* logger_serial,
 285    :      uint32* function_id,
 286    :      const char* function_name,
 287  E :      const Arguments&... arguments) {
 288  E :    DCHECK_NE(static_cast<FunctionCallLogger*>(nullptr), function_call_logger);
 289  E :    DCHECK_NE(static_cast<trace::client::TraceFileSegment*>(nullptr), segment);
 290  E :    DCHECK_NE(static_cast<uint32*>(nullptr), logger_serial);
 291  E :    DCHECK_NE(static_cast<uint32*>(nullptr), function_id);
 292  E :    DCHECK_NE(static_cast<char*>(nullptr), function_name);
 293    :  
 294    :    // This is racy but safe because of the way GetFunctionId works and because
 295    :    // 32-bit writes are atomic.
 296    :    if (*logger_serial != function_call_logger->serial() ||
 297  E :        *function_id == -1) {
 298  E :      *logger_serial = function_call_logger->serial();
 299  E :      *function_id = function_call_logger->GetFunctionId(segment, function_name);
 300    :    }
 301    :    uint32 stack_trace_id =
 302  E :        function_call_logger->GetStackTraceId(segment);
 303    :    function_call_logger->EmitDetailedFunctionCall(
 304  E :        segment, *function_id, stack_trace_id, arguments...);
 305  E :  }
 306    :  
 307    :  // A macro for emitting a detailed function call record. Automatically
 308    :  // emits a function name record the first time it is invoked for a given
 309    :  // function. This is a macro because it needs to use some function scope
 310    :  // static storage.
 311    :  // @param function_call_logger A pointer to the function call logger
 312    :  //     instance to use.
 313    :  // @param segment A pointer to the TraceFileSegment to write to.
 314    :  #define EMIT_DETAILED_FUNCTION_CALL(function_call_logger, segment, ...)        \
 315    :    {                                                                            \
 316    :      static uint32 logger_serial = UINT32_MAX;                                  \
 317    :      static uint32 function_id = UINT32_MAX;                                    \
 318    :      EmitDetailedFunctionCallHelper((function_call_logger), (segment),          \
 319    :                                     &logger_serial, &function_id, __FUNCTION__, \
 320    :                                     __VA_ARGS__);                               \
 321    :    }
 322    :  
 323    :  }  // namespace memprof
 324    :  }  // namespace agent
 325    :  
 326    :  #endif  // SYZYGY_AGENT_MEMPROF_FUNCTION_CALL_LOGGER_H_

Coverage information generated Thu Jan 14 17:40:38 2016.