Skip to content

File trace.h

File List > include > simtix > trace.h

Go to the documentation of this file

#pragma once

#include <fmt/format.h>
#include <fmt/ostream.h>
#include <fmt/printf.h>
#include <simtix/clocked.h>
#include <simtix/macro.h>

#include <cstdio>
#include <iostream>
#include <string>

#ifndef MAX_FLAG_LENGTH
#define MAX_FLAG_LENGTH 10
#endif

#define FLAG_FMT(length) "{:<" STRINGIFY(length) "}"

inline const char *TRACE_FMT = "[{:d}\t" FLAG_FMT(MAX_FLAG_LENGTH) "] {}";

namespace simtix {

namespace trace {

class OstreamTracer {
 public:
  // Cannot be copied.
  OstreamTracer(const OstreamTracer &) = delete;
  OstreamTracer &operator=(const OstreamTracer &) = delete;

  void DumpTrace(std::string_view msg) { fmt::print(os_, msg); }
  void DumpTraceFlag(const char *flag, const std::string &msg) {
    fmt::print(os_, TRACE_FMT, sim::CurTick(), flag, msg);
  }

  static void Init(std::ostream &os) { OstreamTracer::GetInstanceImpl(&os); }

  static OstreamTracer &GetInstance() {
    return OstreamTracer::GetInstanceImpl();
  }

 private:
  explicit OstreamTracer(std::ostream &os) : os_(os) {
    if (DEFINED_MACRO(NDEBUG) && &os == &std::cout) {
      std::ios_base::sync_with_stdio(false);
      std::cin.tie(0);
    }
  }

  static OstreamTracer &GetInstanceImpl(std::ostream *os = &std::cout) {
    static OstreamTracer instance(*os);
    return instance;
  }

  std::ostream &os_;
};

class KonataTracer {
 public:
  // Cannot be copied.
  KonataTracer(const KonataTracer &) = delete;
  KonataTracer &operator=(const KonataTracer &) = delete;

  inline void Dump(char cmd, uint64_t a) {
    fmt::print(os_, "{}\t{}\n", cmd, a);
  }

  inline void Dump(char cmd, uint64_t a, uint32_t b, uint32_t c) {
    fmt::print(os_, "{}\t{}\t{}\t{}\n", cmd, a, b, c);
  }

  inline void Dump(char cmd, uint64_t a, uint32_t b, std::string_view c) {
    fmt::print(os_, "{}\t{}\t{}\t{}\n", cmd, a, b, c);
  }

  static void Init(std::ostream &os) { KonataTracer::GetInstanceImpl(&os); }

  static KonataTracer &GetInstance() { return KonataTracer::GetInstanceImpl(); }

 private:
  explicit KonataTracer(std::ostream &os) : os_(os) {
    os << "Kanata\t0004\n";
    os << "C=\t-1\n";
  }

  static KonataTracer &GetInstanceImpl(std::ostream *os = &std::cout) {
    static KonataTracer instance(*os);
    return instance;
  }

  std::ostream &os_;
};

}  // namespace trace

}  // namespace simtix

// Section: Tracing APIs

#define TRACE_ENABLED(flag) DEFINED_MACRO(flag##_TRACE_ENABLED)

#define DDUMP(flag, ...)                                     \
  do {                                                       \
    if constexpr (TRACE_ENABLED(flag)) {                     \
      simtix::trace::OstreamTracer::GetInstance().DumpTrace( \
          fmt::sprintf(__VA_ARGS__));                        \
    }                                                        \
  } while (0)

#define DPRINTF(flag, ...)                                       \
  do {                                                           \
    if constexpr (TRACE_ENABLED(flag)) {                         \
      simtix::trace::OstreamTracer::GetInstance().DumpTraceFlag( \
          #flag, fmt::sprintf(__VA_ARGS__));                     \
    }                                                            \
  } while (0)

#define DPRINT(flag, ...)                                        \
  do {                                                           \
    if constexpr (TRACE_ENABLED(flag)) {                         \
      simtix::trace::OstreamTracer::GetInstance().DumpTraceFlag( \
          #flag, fmt::format(__VA_ARGS__));                      \
    }                                                            \
  } while (0)

#define KONATA(cmd, ...)                                               \
  do {                                                                 \
    if constexpr (TRACE_ENABLED(Konata)) {                             \
      constexpr char c = #cmd[0];                                      \
      simtix::trace::KonataTracer::GetInstance().Dump(c, __VA_ARGS__); \
    }                                                                  \
  } while (0)