InterruptLatency.hpp 3.45 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.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
      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;

46
  double atcycles(uint32_t const clock_cycles, size_t const min_runs = 100, double *min = NULL, double *max = NULL) {
Jens Korinth's avatar
Jens Korinth committed
47
48
49
50
51
52
    CumulativeAverage<double> cavg { 0 };
    bool stop = false;
    int x, y, maxx, maxy;
    getyx(stdscr, y, x);
    getmaxyx(stdscr, maxy, maxx);
    future<void> f = async(launch::async, [&]() { trigger(stop, clock_cycles, cavg); });
53
    auto c = getch();
Jens Korinth's avatar
Jens Korinth committed
54
55
56
57
58
59
    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();
60
      usleep(1000000);
61
62
63
64
      // exit gracefully on ctrl+c
      c = getch();
      if (c == 3) { endwin(); exit(3); }
    } while (c == ERR && (fabs(cavg.delta()) > 0.01 || cavg.size() < min_runs));
Jens Korinth's avatar
Jens Korinth committed
65
66
    stop = true;
    f.get();
67
68
69
    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();
Jens Korinth's avatar
Jens Korinth committed
70
71

    move((y+1) % maxy, 0);
72
73
    if (min) *min = cavg.min();
    if (max) *max = cavg.max();
Jens Korinth's avatar
Jens Korinth committed
74
75
76
    return cavg();
  }

77
78
private:
  void trigger(volatile bool& stop, uint32_t const clock_cycles, CumulativeAverage<double>& cavg) {
79
    tapasco_res_t res;
80
    while (! stop) {
81
      auto tstart = high_resolution_clock::now();
82
83
      // if 0, use 1us - 100ms interval (clock period is 10ns)
      uint32_t cc = clock_cycles > 0 ? clock_cycles : (rand() % (10000000 - 100) + 100);
84
85
      if ((res = tapasco.launch_no_return(COUNTER_ID, cc)) != TAPASCO_SUCCESS)
        throw Tapasco::tapasco_error(res);
86
      microseconds const d = duration_cast<microseconds>(high_resolution_clock::now() - tstart);
87
88
89
90
91
92
93
94
95
96
97
      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();
  }

98
  Tapasco& tapasco;
99
100
};

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