JobThroughput.hpp 2.47 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
/**
 *  @file       JobThroughput.hpp
 *  @brief      Measures the maximal number of jobs per second.
 *              Requires counter cores (e.g., precision_counter); will trigger
 *              interrupts after 1cc runtime and count finished jobs. Useful
 *              upper bound for job throughput in the system.
 *              The design must run at 100 MHz (assumption of timing calc).
 *  @author  J. Korinth, TU Darmstadt (jk@esa.cs.tu-darmstadt.de)
 **/
#ifndef JOB_THROUGHPUT_HPP__
#define JOB_THROUGHPUT_HPP__

#include <atomic>
#include <future>
#include <vector>
#include <ncurses.h>
#include <tapasco_api.hpp>

using namespace std;
using namespace std::chrono;
using namespace tapasco;

class JobThroughput {
public:
  static tapasco_func_id_t const COUNTER_ID = 14;
  JobThroughput(Tapasco& tapasco): tapasco(tapasco), jobs(0) {
    if (tapasco.func_instance_count(COUNTER_ID) < 16)
      throw "need at least 16 instances of 'Counter' (14) in bitstream";
  }
  virtual ~JobThroughput() {}

  double operator()(size_t const num_threads) {
    CumulativeAverage<double> cavg { 0 };
    jobs.store(0U);
    bool stop = false;
    int x, y;
    getyx(stdscr, y, x);
    vector<future<void> > threads;
    auto const t_start = steady_clock::now();
    for (size_t t = 0; t < num_threads; ++t)
      threads.push_back(async(launch::async, [&]() { run(stop, jobs); }));
42
    auto c = getch();
43
44
45
46
47
48
49
50
51
52
53
54
    do {
      move(y, 0);
      clrtoeol();
      mvprintw(y, x, "Num threads: % 2zu, jobs/second: % 12.1f, max: % 12.f, min: % 12.1f",
          num_threads, cavg(), cavg.max(), cavg.min());
      refresh();
      usleep(5000000);
      auto const j = jobs.load();
      auto const t = steady_clock::now();
      auto const s = duration_cast<seconds>(t - t_start);
      auto const v = s.count() > 0 ? static_cast<double>(j) / static_cast<double>(s.count()) : 0.0;
      if (v > 10.0) cavg.update(v);
55
56
57
      c = getch();
      // exit gracefully on ctrl+c
      if (c == 3) { endwin(); exit(3); }
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
    } while(getch() == ERR && (fabs(cavg.delta()) > 10.0 || cavg.size() < 5));
    stop = true;
    for (auto &f : threads)
      f.get();
    move(y+1, 0);
    return cavg();
  }

private:
  void run(volatile bool& stop, atomic<uint64_t>& count) {
    tapasco_res_t res;
    while (! stop) {
      if ((res = tapasco.launch_no_return(COUNTER_ID, 1U)) != TAPASCO_SUCCESS)
        throw Tapasco::tapasco_error(res);
      jobs++;
    }
  }
  Tapasco& tapasco;
  atomic<uint64_t> jobs { 0 };
};
#endif /* JOB_THROUGHPUT_HPP__ */