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

CoverageLines executed / instrumented / missingexe / inst / missLanguageGroup
92.8%90970.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_t 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_t 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_t function_id,
  71    :                                  uint32_t 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_t 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_t 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_t> 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_t> StackIdSet;
 127    :    StackIdSet emitted_stack_ids_;  // Under lock_.
 128    :  
 129    :    // A unique serial number generated at construction time. For unittesting.
 130    :    uint32_t 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_t* 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_t* buffer) { return; }
 158    :  };
 159    :  
 160    :  // Implementation off the detailed function call logger. Populates a
 161    :  // TraceDetailedFunctionCall buffer with variable length encodings of
 162    :  // the arguments. Arguments are serialized using the ArgumentSerializer
 163    :  // helper.
 164    :  template <typename ArgType0,
 165    :            typename ArgType1,
 166    :            typename ArgType2,
 167    :            typename ArgType3,
 168    :            typename ArgType4,
 169    :            typename ArgType5>
 170    :  void FunctionCallLogger::EmitDetailedFunctionCall(TraceFileSegment* segment,
 171    :                                                    uint32_t function_id,
 172    :                                                    uint32_t stack_trace_id,
 173    :                                                    ArgType0 arg0,
 174    :                                                    ArgType1 arg1,
 175    :                                                    ArgType2 arg2,
 176    :                                                    ArgType3 arg3,
 177    :                                                    ArgType4 arg4,
 178  E :                                                    ArgType5 arg5) {
 179  E :    DCHECK_NE(static_cast<TraceFileSegment*>(nullptr), segment);
 180  E :    size_t args_count = 0;
 181  E :    size_t args_size = 0;
 182    :  
 183  E :    size_t arg_size0 = ArgumentSerializer<ArgType0>().size();
 184  E :    args_count += arg_size0 > 0 ? 1 : 0;
 185  E :    args_size += arg_size0;
 186    :  
 187  E :    size_t arg_size1 = ArgumentSerializer<ArgType1>().size();
 188  E :    args_count += arg_size1 > 0 ? 1 : 0;
 189  E :    args_size += arg_size1;
 190    :  
 191  E :    size_t arg_size2 = ArgumentSerializer<ArgType2>().size();
 192  E :    args_count += arg_size2 > 0 ? 1 : 0;
 193  E :    args_size += arg_size2;
 194    :  
 195  E :    size_t arg_size3 = ArgumentSerializer<ArgType3>().size();
 196  E :    args_count += arg_size3 > 0 ? 1 : 0;
 197  E :    args_size += arg_size3;
 198    :  
 199  E :    size_t arg_size4 = ArgumentSerializer<ArgType4>().size();
 200  E :    args_count += arg_size4 > 0 ? 1 : 0;
 201  E :    args_size += arg_size4;
 202    :  
 203  E :    size_t arg_size5 = ArgumentSerializer<ArgType5>().size();
 204  E :    args_count += arg_size5 > 0 ? 1 : 0;
 205  E :    args_size += arg_size5;
 206    :  
 207  E :    if (args_size > 0)
 208  E :      args_size += (args_count + 1) * sizeof(uint32_t);
 209  E :    size_t data_size = FIELD_OFFSET(TraceDetailedFunctionCall, argument_data) +
 210    :        args_size;
 211    :  
 212  E :    if (!segment->CanAllocate(data_size) && !FlushSegment(segment))
 213  i :      return;
 214  E :    DCHECK(segment->CanAllocate(data_size));
 215    :  
 216    :    TraceDetailedFunctionCall* data =
 217  E :        segment->AllocateTraceRecord<TraceDetailedFunctionCall>(data_size);
 218  E :    data->function_id = function_id;
 219  E :    data->stack_trace_id = stack_trace_id;
 220  E :    data->argument_data_size = args_size;
 221    :  
 222  E :    if (serialize_timestamps_) {
 223  E :      base::AutoLock lock(lock_);
 224  E :      data->timestamp = call_counter_;
 225  E :      ++call_counter_;
 226  E :    } else {
 227  E :      data->timestamp = ::trace::common::GetTsc();
 228    :    }
 229    :  
 230  E :    if (args_size == 0)
 231  i :      return;
 232    :  
 233    :    // Output the number of arguments.
 234  E :    uint32_t* arg_sizes = reinterpret_cast<uint32_t*>(data->argument_data);
 235  E :    *(arg_sizes++) = args_count;
 236    :  
 237    :    // Output argument sizes.
 238  E :    if (arg_size0 > 0)
 239  E :      *(arg_sizes++) = arg_size0;
 240  E :    if (arg_size1 > 0)
 241  i :      *(arg_sizes++) = arg_size1;
 242  E :    if (arg_size2 > 0)
 243  i :      *(arg_sizes++) = arg_size2;
 244  E :    if (arg_size3 > 0)
 245  i :      *(arg_sizes++) = arg_size3;
 246  E :    if (arg_size4 > 0)
 247  i :      *(arg_sizes++) = arg_size4;
 248  E :    if (arg_size5 > 0)
 249  i :      *(arg_sizes++) = arg_size5;
 250    :  
 251    :    // Output argument data.
 252  E :    uint8_t* arg_data = reinterpret_cast<uint8_t*>(arg_sizes);
 253  E :    ArgumentSerializer<ArgType0>().serialize(arg0, arg_data);
 254  E :    arg_data += arg_size0;
 255  E :    ArgumentSerializer<ArgType1>().serialize(arg1, arg_data);
 256  E :    arg_data += arg_size1;
 257  E :    ArgumentSerializer<ArgType2>().serialize(arg2, arg_data);
 258  E :    arg_data += arg_size2;
 259  E :    ArgumentSerializer<ArgType3>().serialize(arg3, arg_data);
 260  E :    arg_data += arg_size3;
 261  E :    ArgumentSerializer<ArgType4>().serialize(arg4, arg_data);
 262  E :    arg_data += arg_size4;
 263  E :    ArgumentSerializer<ArgType5>().serialize(arg5, arg_data);
 264  E :    arg_data += arg_size5;
 265  E :  }
 266    :  
 267    :  // A templated helper for emitting a detailed function call record.
 268    :  // @param function_call_logger A pointer to the function call logger
 269    :  //     instance to use.
 270    :  // @param segment A pointer to the TraceFileSegment to write to.
 271    :  // @param logger_serial A pointer to where the serial number of the previous
 272    :  //     function call logger can be stored. Must be statically initialized to
 273    :  //     -1.
 274    :  // @param function_id A pointer where the function ID can be saved. Must
 275    :  //     be statically initialized to -1.
 276    :  // @param function_name The name of the function being traced.
 277    :  // @param arguments The arguments to the function being traced.
 278    :  template <typename... Arguments>
 279    :  inline void EmitDetailedFunctionCallHelper(
 280    :      FunctionCallLogger* function_call_logger,
 281    :      trace::client::TraceFileSegment* segment,
 282    :      uint32_t* logger_serial,
 283    :      uint32_t* function_id,
 284    :      const char* function_name,
 285  E :      const Arguments&... arguments) {
 286  E :    DCHECK_NE(static_cast<FunctionCallLogger*>(nullptr), function_call_logger);
 287  E :    DCHECK_NE(static_cast<trace::client::TraceFileSegment*>(nullptr), segment);
 288  E :    DCHECK_NE(static_cast<uint32_t*>(nullptr), logger_serial);
 289  E :    DCHECK_NE(static_cast<uint32_t*>(nullptr), function_id);
 290  E :    DCHECK_NE(static_cast<char*>(nullptr), function_name);
 291    :  
 292    :    // This is racy but safe because of the way GetFunctionId works and because
 293    :    // 32-bit writes are atomic.
 294  E :    if (*logger_serial != function_call_logger->serial() ||
 295    :        *function_id == -1) {
 296  E :      *logger_serial = function_call_logger->serial();
 297  E :      *function_id = function_call_logger->GetFunctionId(segment, function_name);
 298    :    }
 299  E :    uint32_t stack_trace_id = function_call_logger->GetStackTraceId(segment);
 300  E :    function_call_logger->EmitDetailedFunctionCall(
 301    :        segment, *function_id, stack_trace_id, arguments...);
 302  E :  }
 303    :  
 304    :  // A macro for emitting a detailed function call record. Automatically
 305    :  // emits a function name record the first time it is invoked for a given
 306    :  // function. This is a macro because it needs to use some function scope
 307    :  // static storage.
 308    :  // @param function_call_logger A pointer to the function call logger
 309    :  //     instance to use.
 310    :  // @param segment A pointer to the TraceFileSegment to write to.
 311    :  #define EMIT_DETAILED_FUNCTION_CALL(function_call_logger, segment, ...)        \
 312    :    {                                                                            \
 313    :      static uint32_t logger_serial = UINT32_MAX;                                \
 314    :      static uint32_t function_id = UINT32_MAX;                                  \
 315    :      EmitDetailedFunctionCallHelper((function_call_logger), (segment),          \
 316    :                                     &logger_serial, &function_id, __FUNCTION__, \
 317    :                                     __VA_ARGS__);                               \
 318    :    }
 319    :  
 320    :  }  // namespace memprof
 321    :  }  // namespace agent
 322    :  
 323    :  #endif  // SYZYGY_AGENT_MEMPROF_FUNCTION_CALL_LOGGER_H_

Coverage information generated Fri Jul 29 11:00:21 2016.