-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathts_task.hpp
158 lines (112 loc) · 4.45 KB
/
ts_task.hpp
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
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
#pragma once
namespace ts {
// std::mt19937_64
// __gnu_cxx::sfmt19937_64 (from #include <ext/random>)
using random_generator_t = __gnu_cxx::sfmt19937_64;
template <typename T = int32_t>
using int_distribution_t = std::uniform_int_distribution <T>;
// TODO: add shm for stderr?
class task {
std::string m_name;
int m_score_divisor;
protected:
ts::shm m_stdin;
ts::shm m_stdout;
ts::shm m_expected;
public:
task( const std::string & name, int score_divisor, size_t stdin_max_size, size_t stdout_max_size )
: m_name( name )
, m_score_divisor( score_divisor )
, m_stdin ( "/ts_stdin" , stdin_max_size )
, m_stdout ( "/ts_stdout" , stdout_max_size )
, m_expected( "/ts_expected", stdout_max_size ) {}
virtual ~task() = default;
constexpr explicit operator bool () const {
return m_stdin && m_stdout && m_expected;
}
virtual bool generate_input( random_generator_t & ) = 0;
virtual bool check_result() {
// chech only N first chars (m_expected.size())
return m_stdout.mem_view<char>() == m_expected.mem_view<char>();
}
bool run( const std::string & executable, int iterations = 3 ) {
const int output_indent = 34;
printf( " # Testing '%s', %d iteration%s...\n", m_name.c_str(), iterations, iterations > 1 ? "s" : "" );
std::random_device rd;
std::seed_seq seed{ rd(), rd(), rd(), rd(), rd(), rd(), rd(), rd() };
random_generator_t random_generator( seed );
ts::timer timer_child;
double time_sum = 0;
uint64_t score_sum = 0;
double time_best = 1e5;
uint64_t score_best = 0;
float read_throughput_max = 0;
int iter = 0;
for ( ; iter < iterations; iter++ ) {
// Truncate to reserved size...
m_stdin.reset();
m_stdin.rewind();
m_stdout.rewind();
fmt::print( "\n Iteration #{:2}:\n", iter + 1 );
fmt::print( " Generating input data... " );
fflush( stdout );
// Child process timer...
ts::timer <RUSAGE_SELF> timer_self;
if ( !generate_input( random_generator ) ) {
//fprintf( stderr, "\ngenerate_input(): failed\n" );
fmt::print( stderr, "\ngenerate_input(): failed\n" );
return false;
}
fmt::print( " {:.2f} secs., size: {} bytes\n", timer_self.us() / 1e6, m_stdin.size() );
{
ts::scoped_fd_subst dup_stdin ( STDIN_FILENO , m_stdin .fd() );
ts::scoped_fd_subst dup_stdout( STDOUT_FILENO, m_stdout.fd() );
timer_child.reset();
if ( system( ("./" + executable).c_str() ) == -1 ) {
perror( "system()" );
return false;
}
fflush( stdout );
}
uint64_t time_ns = timer_child.ns();
double time_sec = time_ns / 1e9;
uint64_t score = time_ns / m_score_divisor;
time_sum += time_sec;
score_sum += score;
if ( time_sec < time_best ) {
time_best = time_sec;
score_best = score;
}
bool is_correct = check_result();
fmt::print( "\n" );
if ( m_expected.mem_view<char>().size() < 80 ) {
fmt::print( "{: >{}}: [{:.{}}]\n", "Expected", output_indent, m_expected.mem_view<char>().data(), m_expected.mem_view<char>().size() );
fmt::print( "{: >{}}: [{:.{}}]\n", "Got", output_indent, m_stdout.mem_view<char>().data(), m_stdout.mem_view<char>().size() );
}
fmt::print( "{: >{}}: ", "Result", output_indent );
if ( is_correct ) {
fmt::print( fg(fmt::color::light_green), "passed\n" );
} else {
fmt::print( fg(fmt::color::red), "not passed\n" );
}
fmt::print( "{: >{}}: {}\n", "Score", output_indent, score );
fmt::print( "{: >{}}: {:.3f} secs.\n", "Time", output_indent, time_sec );
float read_throughput = m_stdin.size() / time_sec / (1024 * 1024 * 1024);
if ( read_throughput > read_throughput_max ) read_throughput_max = read_throughput;
fmt::print( "{: >{}}: ", "Possible read throughput", output_indent );
fmt::print( fg(fmt::color::aqua), "{:.3f}", read_throughput );
fmt::print( " GB/s\n" );
// if ( !is_correct ) return false;
}
fmt::print( " {:->{}}\n", "", 50 );
fmt::print( "\n{: >{}}: {:.3f} secs.\n", "Avarage time ", output_indent, time_sum / iter );
fmt::print( "{: >{}}: {}\n" , "Avarage score", output_indent, score_sum / iter );
fmt::print( "\n{: >{}}: {:.3f} secs.\n", "Best time " , output_indent, time_best );
fmt::print( "{: >{}}: {}\n" , "Best score" , output_indent, score_best );
fmt::print( "\n{: >{}}: ", "Possible max. read throughput", output_indent );
fmt::print( fg(fmt::color::aqua), "{:.3f}", read_throughput_max );
fmt::print( " GB/s\n" );
return true;
}
}; // class task
} // namespace ts