1 #include "cado.h" // IWYU pragma: keep
2 #include <cstdint> // for SIZE_MAX
3 #include <cstring> // for memset, strlen
4 #include <cstdio> // fprintf // IWYU pragma: keep
5 #include <cstdarg> // va_list // IWYU pragma: keep
6 #include <cstdlib>
7 #include <string> // for string, basic_string
8 #include <vector>
9 #include "logline.h"
10 #include "memusage.h" // Memusage2
11 #include "params.h" // param_list_parse_*
12 #include "select_mpi.h"
13 #include "timing.h" // seconds
14 #include "portability.h" // asprintf // IWYU pragma: keep
15 #include "misc.h" // size_disp_fine
16 #include "macros.h"
17
18 /* This is intended to provide progress info, and optionally also more
19 * detailed progress info when needed. Detailed progress info is assumed
20 * to possibly take several lines, while terse progress info is expected
21 * to take only one line.
22 */
23
24 /* Log messages are provided in the form [[x, "text"]], with x an integer
25 * indicating a level of detail. 0 is the lowest level of detail, and
26 * higher means more detailed (and printed less often).
27 *
28 * Whenever we output an info which is more detailed than what we had
29 * before, and with no finishing newline, then the unfinished previous
30 * line is terminated with ..., and the terminating messaged will be
31 * issued alone later on.
32 *
33 * An exception is for level 0 (introduced by logline_begin()), for which
34 * the "title" is then echoed when finishing the printing.
35 */
36 struct logline {
37 /* Only log messages prefixed with <x> with x <= max will be printed
38 */
39 int max = 0;
40 /* Title string introducing this log set */
41 std::string header;
42 /* Did last print contain a trailing newline ? */
43 bool eol = false;
44 /* Last printed detail level */
45 int lastlevel = 0;
46
47 FILE * f = NULL;
48
49 /* Number of newlines seen (used to tell whether the title has to be
50 * echoed again) */
51 int nnl = 0;
52
53 double start = 0;
54
55 std::vector<std::string> prefixes;
56 };
57
58 double logline_serialize();
59 void logline_unserialize(double);
60
61 static struct logline * current;
62
63 size_t logline_thresholds[10] = {
64 /* This list should be increasing */
65 SIZE_MAX,
66 SIZE_MAX,
67 SIZE_MAX,
68 SIZE_MAX,
69 SIZE_MAX,
70 SIZE_MAX,
71 SIZE_MAX,
72 SIZE_MAX,
73 SIZE_MAX,
74 SIZE_MAX,
75 };
76
77 int logline_timings = 1;
78
79 int logline_print_all_mpi_nodes = 0;
80
81 static double start_time = -1;
82
logline_init_timer()83 void logline_init_timer()
84 {
85 start_time = wct_seconds();
86 }
87
88 int logline_report_wct = 0;
89
logline_timer()90 static double logline_timer()
91 {
92 return logline_report_wct ? wct_seconds() : seconds();
93 }
94
logline_serialize()95 double logline_serialize()
96 {
97 double tt = wct_seconds() - start_time;
98 return tt;
99 }
100
logline_unserialize(double tt)101 void logline_unserialize(double tt)
102 {
103 start_time = wct_seconds() - tt;
104 }
105
106
logline_decl_usage(param_list_ptr pl)107 void logline_decl_usage(param_list_ptr pl)
108 {
109 param_list_decl_usage(pl, "logline_threshold",
110 "print log lines of verbosity level i only for sizes greater than i-th item in this comma-separated list");
111 param_list_decl_usage(pl, "logline_timings",
112 "print timings with log lines");
113 param_list_decl_usage(pl, "logline_report_wct",
114 "print wct taken by each step marked by log lines");
115 param_list_decl_usage(pl, "logline_print_all_mpi_nodes",
116 "enable logline printing on all MPI nodes");
117
118 }
119
logline_interpret_parameters(param_list_ptr pl)120 int logline_interpret_parameters(param_list_ptr pl)
121 {
122 int thr[10];
123 int n = param_list_parse_int_list(pl, "logline_threshold", thr, 10, ",");
124 for(int i = 0 ; i < n ; i++) {
125 logline_thresholds[i] = thr[i];
126 }
127 param_list_parse_int(pl, "logline_timings", &logline_timings);
128 param_list_parse_int(pl, "logline_report_wct", &logline_report_wct);
129 param_list_parse_int(pl, "logline_print_all_mpi_nodes", &logline_print_all_mpi_nodes);
130 return 0;
131 }
132
logline_puts_raw(int level,const char * s)133 static void logline_puts_raw(int level, const char * s)
134 {
135 if (!current) return;
136 if (level > current->max) return;
137 if (level != current->lastlevel && !current->eol) {
138
139 fputs(" ...\n", current->f);
140 current->nnl += (current->eol = 1);
141 }
142 for( ; current->prefixes.size() > (unsigned int) level ; current->prefixes.pop_back()) ;
143 if (current->eol) {
144 if (logline_timings) {
145 char buf1[16];
146 char buf2[16];
147 size_disp_fine(1024UL * Memusage2(), buf1, 10000.0);
148 size_disp_fine(1024UL * PeakMemusage(), buf2, 10000.0);
149 fprintf(current->f, "[%.3f %.3f %s %s] ", wct_seconds() - start_time, seconds(), buf1, buf2);
150 }
151 for(auto const & c : current->prefixes) {
152 fputs(c.c_str(), current->f);
153 fputc(' ', current->f);
154 }
155 } else if (level == current->lastlevel) {
156 fputc(' ', current->f);
157 }
158 fputs(s, current->f);
159 current->prefixes.push_back(s);
160 size_t n = strlen(s);
161 current->nnl += (current->eol = s[n-1] == '\n');
162 current->lastlevel = level;
163 }
164
165
logline_begin(FILE * f,size_t size,const char * fmt,...)166 int logline_begin(FILE * f, size_t size, const char * fmt, ...)
167 {
168 va_list ap;
169 int rank;
170 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
171 if (rank && !logline_print_all_mpi_nodes) return 0;
172 ASSERT_ALWAYS(!current);
173 if (size < logline_thresholds[0]) return 0;
174 int level;
175 for(level = 0 ; level < 10 && size >= logline_thresholds[level] ; level++);
176 if (level == 0) return 0;
177 level--;
178 current = new logline;
179 current->max = level;
180 current->lastlevel = 0;
181 current->f = f;
182 current->start = logline_timer();
183 char * tmp;
184 va_start(ap, fmt);
185 int rc = vasprintf(&(tmp), fmt, ap);
186 ASSERT_ALWAYS(rc >= 0);
187 current->header = tmp;
188 free(tmp);
189 current->eol = true;
190 logline_puts_raw(0, current->header.c_str());
191 va_end(ap);
192 return 1;
193 }
194
logline_end(double * rr,const char * fmt,...)195 int logline_end(double * rr, const char * fmt, ...)
196 {
197 if (!current) return 0;
198 va_list ap;
199 va_start(ap, fmt);
200 char * text2;
201 double tt = logline_timer() - current->start;
202 if (fmt) {
203 char * text;
204 int rc;
205 rc = vasprintf(&text, fmt, ap);
206 ASSERT_ALWAYS(rc >= 0);
207 rc = asprintf(&text2, "%s [%.2f]\n", text, tt);
208 ASSERT_ALWAYS(rc >= 0);
209 free(text);
210 } else {
211 int rc;
212 rc = asprintf(&text2, "[%.2f]\n", tt);
213 ASSERT_ALWAYS(rc >= 0);
214 }
215 if (current->nnl)
216 logline_puts_raw(0, current->header.c_str());
217 logline_puts_raw(0, text2);
218 free(text2);
219 delete current;
220 current = NULL;
221 va_end(ap);
222 if (rr) *rr += tt;
223 return 1;
224 }
225
226
logline_vprintf(int level,const char * fmt,va_list ap)227 int logline_vprintf(int level, const char * fmt, va_list ap)
228 {
229 if (!current) return 0;
230 char * text;
231 int rc = vasprintf(&text, fmt, ap);
232 ASSERT_ALWAYS(rc >= 0);
233 logline_puts_raw(level, text);
234 free(text);
235 return 1;
236 }
237
logline_printf(int level,const char * fmt,...)238 int logline_printf(int level, const char * fmt, ...)
239 {
240 va_list ap;
241 va_start(ap, fmt);
242 logline_vprintf(level, fmt, ap);
243 va_end(ap);
244 return 1;
245 }
246
247
248