InterruptLatency.hpp 4.11 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
/**
 *  @file	InterruptLatency.hpp
 *  @brief	Measures the software overhead, i.e., the roundtrip time that is
 *              added by the TPC software layers. This is done via the 'Counter'
 *              IP cores, which simply provide a cycle-accurate countdown timer.
 *              The default design should provide at least one instance of the
 *              timer, which accepts a cycle count as first argument. The design
 *              should run at 100 Mhz (assumption of timing calculations).
 *  @author	J. Korinth, TU Darmstadt (jk@esa.cs.tu-darmstadt.de)
 **/
Jens Korinth's avatar
Jens Korinth committed
11
12
#ifndef INTERRUPT_LATENCY_HPP__
#define INTERRUPT_LATENCY_HPP__
13
14
15
16
17
18
19
20
21
22

#include <atomic>
#include <thread>
#include <future>
#include <vector>
#include <sstream>
#include <chrono>
#include <cmath>
#include <unistd.h>
#include <ncurses.h>
23
#include <tapasco_api.hpp>
24
25
26

using namespace std;
using namespace std::chrono;
27
using namespace tapasco;
28
29
30
31
32
33

/**
 * Measures interrupt latency added by software layers in TPC.
 **/
class InterruptLatency {
public:
34
  static tapasco_func_id_t const COUNTER_ID = 14;
35

36
37
  InterruptLatency(Tapasco& tapasco) : tapasco(tapasco) {
    if (tapasco.func_instance_count(COUNTER_ID) == 0)
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
      throw "need at least one instance of 'Counter' (14) in bitstream";
  }
  virtual ~InterruptLatency() {}

  static constexpr long OP_ALLOCFREE = 0;
  static constexpr long OP_COPYFROM  = 1;
  static constexpr long OP_COPYTO    = 2;

  double operator()(size_t const runtime_usecs) {
    CumulativeAverage<double> cavg { 0 };
    uint32_t clock_cycles = runtime_usecs * 100; // assuming 100Mhz clock
    bool stop = false;
    initscr(); noecho(); curs_set(0); timeout(0);
    int x, y;
    getyx(stdscr, y, x);
    future<void> f = async(launch::async, [&]() { trigger(stop, clock_cycles, cavg); });
Jens Korinth's avatar
Jens Korinth committed
54
55
    const size_t m_runs = 100.0 * pow(M_E, -log(runtime_usecs / 10000.0));
    const size_t min_runs = m_runs > 100 ? m_runs : 100;
56
57
    do {
      mvprintw(y, x, "Runtime: %8zu us, Latency: %8.2f", runtime_usecs, cavg());
Jens Korinth's avatar
Jens Korinth committed
58
59
60
61
      move(y, 0);
      clrtoeol();
      mvprintw(y, x, "Runtime: %8zu us, Latency: % 12.1f, Min: % 12.1f, Max: % 12.1f, Count: %zu/%zu",
        runtime_usecs, cavg(), cavg.min(), cavg.max(), cavg.size(), min_runs);
62
63
      refresh();
      usleep(1000);
Jens Korinth's avatar
Jens Korinth committed
64
    } while (getch() == ERR && (fabs(cavg.delta()) > 0.01 || cavg.size() < min_runs));
65
66
67
68
69
70
71
    stop = true;
    f.get();
    move(y+1, 0);
    endwin();
    return cavg();
  }

Jens Korinth's avatar
Jens Korinth committed
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
  double atcycles(uint32_t const clock_cycles, size_t const min_runs = 100) {
    CumulativeAverage<double> cavg { 0 };
    bool stop = false;
    initscr(); noecho(); curs_set(0); timeout(0);
    int x, y, maxx, maxy;
    getyx(stdscr, y, x);
    getmaxyx(stdscr, maxy, maxx);
    future<void> f = async(launch::async, [&]() { trigger(stop, clock_cycles, cavg); });
    do {
      move(y, 0);
      clrtoeol();
      mvprintw(y, x, "Runtime: %12zu cc, Latency: % 12.1f, Min: % 12.1f, Max: % 12.1f, Count: %zu/%zu",
        clock_cycles, cavg(), cavg.min(), cavg.max(), cavg.size(), min_runs);
      refresh();
      usleep(1000);
    } while (getch() == ERR && (fabs(cavg.delta()) > 0.001 || cavg.size() < min_runs));
    stop = true;
    f.get();

    move((y+1) % maxy, 0);
    endwin();
    return cavg();
  }

96
97
private:
  void trigger(volatile bool& stop, uint32_t const clock_cycles, CumulativeAverage<double>& cavg) {
98
    tapasco_res_t res;
99
100
101
102
    while (! stop) {
      auto tstart = high_resolution_clock::now();
      // if 0, use 1us - 100ms interval (clock period is 10ns)
      uint32_t cc = clock_cycles > 0 ? clock_cycles : (rand() % (10000000 - 100) + 100);
103
104
      if ((res = tapasco.launch_no_return(COUNTER_ID, cc)) != TAPASCO_SUCCESS)
        throw Tapasco::tapasco_error(res);
105
106
107
108
109
110
111
112
113
114
115
116
      microseconds const d = duration_cast<microseconds>(high_resolution_clock::now() - tstart);
      cavg.update(d.count() - cc / 100);
    }
  }

  static const std::string maskToString(long const opmask) {
    stringstream tmp;
    tmp << (opmask & OP_COPYFROM ? "r" : " ") 
        << (opmask & OP_COPYTO   ? "w" : " ");
    return tmp.str();
  }

117
  Tapasco& tapasco;
118
119
};

Jens Korinth's avatar
Jens Korinth committed
120
#endif /* INTERRUPT_LATENCY_HPP__ */
121
/* vim: set foldmarker=@{,@} foldlevel=0 foldmethod=marker : */