Skip to content

vosst/lttng

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

6 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

lttng

This library provides C++(11) classes and functions for interacting with lttng. On the one hand, the library enables developers to control and configure lttng trace generation from within C++(11) programs. On the other hand, the library provides support for reading and iterating traces in the Common Trace Format, enabling easy processing of trace files.

The library is primarily used as a convenience tool to support integration- and acceptance-testing infrastructure, specifically for setups that span across multiple processes and additionally require capturing kernel behavior.

Dependencies

  • Boost

    • coroutine/context: For an easy async pattern.
    • filesystem: For handling anything filesystem.
    • system: Required by filesystem.
    • thread: Required by coroutine/context.
  • babeltrace/babeltrace-ctf: For accessing CTF traces.

  • process-cpp: For interaction with the lttng control application.

    On Ubuntu, you can install all required build- and run-time dependencies with:

    sudo apt-get install \
        libboost-dev libboost-filesystem-dev libboost-system-dev libboost-test-dev \
        libbabeltrace-dev libbabeltrace-ctf-dev \
        libprocess-cpp-dev

Example

The following snippet illustrates analyzing multiple processes carrying out a task (memory allocation for demonstration purposes), capturing relevant trace points in a trace, and finally iterating the trace for calculating required statistics:

namespace acc = boost::accumulators;

// Typedef our accumulator type.
typedef acc::accumulator_set<
  double,
  acc::stats<
    acc::tag::count, // The total count of events.
    acc::tag::min,   // Minimum value seen over all events.
    acc::tag::max,   // Maximum value seen over all events.
    acc::tag::mean,  // The mean value seen over all events.
    acc::tag::variance, // The variance in values seen over all events.
    acc::tag::density // Histogram over all values.
  >
> Statistics;

// Call like: LD_PRELOAD=liblttng-ust-libc-wrapper.so ./lttng-example
int main()
{
  // We instruct lttng to write traces to /tmp, more precisely: To a subdirectory
  // in /tmp of its own choice.
  auto consumer = std::make_shared<lttng::FileSystemConsumer>("/tmp/lttng-example");
  // We want to trace userspace events.
  auto ust_tracer = lttng::Tracer::create(lttng::Domain::userspace);
  // Create a tracing session.
  auto ust_session = ust_tracer->create_session("JustATestingSession", consumer);
  
  // Every event of the trace will carry this information.
  ust_session->add_context(lttng::Context::ip);
  ust_session->add_context(lttng::Context::proc_name);
  ust_session->add_context(lttng::Context::vpid);
  ust_session->add_context(lttng::Context::vtid);

  // Enable all libc and pthread events for recording purposes.
  ust_session->enable_event(lttng::events::userspace::libc::all);
  ust_session->enable_event(lttng::events::userspace::pthread::all);
  
  // Finally start the session.
  ust_session->start();

  std::vector<core::posix::ChildProcess> children;
  for (unsigned int i = 0; i < 5; i++)
    children.push_back(core::posix::fork([]() {
          std::default_random_engine rng;
          // We do allocations of size [1, 500].
          std::uniform_int_distribution<int> dist(1, 500);
                                           
          // Allocate memory a hundred times.
          for (unsigned i = 0; i < 100; i++)
            free(malloc(dist(rng)));
    
          return core::posix::exit::Status::success;
        }, core::posix::StandardStream::stderr));

  for(auto& child : children)
    child.wait_for(core::posix::wait::Flags::untraced);

  // Done, stopping the session.
  ust_session->stop();

  // We want to calcute the average size of malloc calls.
  Statistics malloc_size_stats(acc::tag::density::num_bins = 20, acc::tag::density::cache_size = 10);
  // Open the previously recorded trace.
  ctf::Trace trace(consumer->path());

  // Spec out the fields we are interested in:
  ctf::FieldSpec<ctf::Field::Type::integer> size{ctf::Scope::event_fields, "size"};
  ctf::FieldSpec<ctf::Field::Type::integer> vpid{ctf::Scope::stream_event_context, "vpid"};

  // Iterate over the trace.
  trace.for_each_event([&](const ctf::Event& event)
  {
    if (event.name == lttng::events::userspace::libc::malloc)
    {
      if (size.available_in(event))
        malloc_size_stats(size.interpret(event)->as_uint64());
    }

    return ctf::Trace::EventEnumeratorReply::ok;
  });

  // Statistics have been calculated, printing summary now:
  std::cout << acc::count(malloc_size_stats) << " " 
            << acc::mean(malloc_size_stats) << " " 
            << std::sqrt(acc::variance(malloc_size_stats)) << " "
            << acc::min(malloc_size_stats) << " "
            << acc::max(malloc_size_stats) << std::endl;

  // And print the histogram.
  auto hist = acc::density(malloc_size_stats);
  for (auto pair : hist)
    std::cout << pair.first << " " << pair.second << "\n";
  
  return 0;

About

A simple lttng/ctf wrapper for C++11

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published