text: #ifndef QUIET
  
  #include "internal.hpp"
  
  namespace CaDiCaL {
  
  // Initialize all profile counters with constant name and profiling level.
  
  Profiles::Profiles (Internal * s)
  :
    internal (s)
  #define PROFILE(NAME, LEVEL) \
    , NAME (#NAME, LEVEL)
    PROFILES
  #undef PROFILE
  {
  }
  
  void Internal::start_profiling (Profile & profile, double s) {
    assert (profile.level <= opts.profile);
    assert (!profile.active);
    profile.started = s;
    profile.active = true;
  }
  
  void Internal::stop_profiling (Profile & profile, double s) {
    assert (profile.level <= opts.profile);
    assert (profile.active);
    profile.value += s - profile.started;
    profile.active = false;
  }
  
  double Internal::update_profiles () {
    double now = time ();
  # define PROFILE(NAME,LEVEL) \
  do { \
    Profile & profile = profiles.NAME; \
    if (profile.active) { \
      assert (profile.level <= opts.profile); \
      profile.value += now - profile.started; \
      profile.started = now; \
    } \
  } while (0);
    PROFILES
  # undef PROFILE
    return now;
  }
  
  double Internal::solve_time () {
    (void) update_profiles ();
    return profiles.solve.value;
  }
  
  #define PRT(S,T) \
    MSG ("%s" S "%s", tout.magenta_code (), T, tout.normal_code ())
  
  void Internal::print_profile () {
    double now = update_profiles ();
    const char * time_type = opts.realtime ? "real" : "process";
    SECTION ("run-time profiling");
    PRT ("%s time taken by individual solving procedures", time_type);
    PRT ("(percentage relative to %s time for solving)", time_type);
    MSG ("");
    const size_t size = sizeof profiles / sizeof (Profile);
    struct Profile * profs[size];
    size_t n = 0;
  #define PROFILE(NAME,LEVEL) \
  do { \
    if (LEVEL > opts.profile) break; \
    Profile * p = &profiles.NAME; \
    if (p == &profiles.solve) break; \
    if (!profiles.NAME.value && \
        p != &profiles.parse && \
        p != &profiles.search && \
        p != &profiles.simplify) break; \
    profs[n++] = p; \
  } while (0);
    PROFILES
  #undef PROFILE
  
    assert (n <= size);
  
    // Explicit bubble sort to avoid heap allocation since 'print_profile'
    // is also called during catching a signal after out of heap memory.
    // This only makes sense if 'profs' is allocated on the stack, and
    // not the heap, which should be the case.
  
    double solve = profiles.solve.value;
  
    for (size_t i = 0; i < n; i++) {
      for (size_t j = i + 1; j < n; j++)
        if (profs[j]->value > profs[i]->value)
          swap (profs[i], profs[j]);
      MSG ("%12.2f %7.2f%% %s",
        profs[i]->value, percent (profs[i]->value, solve), profs[i]->name);
    }
  
    MSG ("  =================================");
    MSG ("%12.2f %7.2f%% solve", solve, percent (solve, now));
  
    MSG ("");
    PRT ("last line shows %s time for solving", time_type);
    PRT ("(percentage relative to total %s time)", time_type);
  }
  
  }
  
  #endif // ifndef QUIET
  