xref: /aosp_15_r20/external/igt-gpu-tools/runner/resultgen.c (revision d83cc019efdc2edc6c4b16e9034a3ceb8d35d77c)
1*d83cc019SAndroid Build Coastguard Worker #include <assert.h>
2*d83cc019SAndroid Build Coastguard Worker #include <ctype.h>
3*d83cc019SAndroid Build Coastguard Worker #include <fcntl.h>
4*d83cc019SAndroid Build Coastguard Worker #include <stdio.h>
5*d83cc019SAndroid Build Coastguard Worker #include <string.h>
6*d83cc019SAndroid Build Coastguard Worker #include <sys/mman.h>
7*d83cc019SAndroid Build Coastguard Worker #include <sys/stat.h>
8*d83cc019SAndroid Build Coastguard Worker #include <sys/types.h>
9*d83cc019SAndroid Build Coastguard Worker #include <unistd.h>
10*d83cc019SAndroid Build Coastguard Worker 
11*d83cc019SAndroid Build Coastguard Worker #include <json.h>
12*d83cc019SAndroid Build Coastguard Worker 
13*d83cc019SAndroid Build Coastguard Worker #include "igt_core.h"
14*d83cc019SAndroid Build Coastguard Worker #include "resultgen.h"
15*d83cc019SAndroid Build Coastguard Worker #include "settings.h"
16*d83cc019SAndroid Build Coastguard Worker #include "executor.h"
17*d83cc019SAndroid Build Coastguard Worker #include "output_strings.h"
18*d83cc019SAndroid Build Coastguard Worker 
19*d83cc019SAndroid Build Coastguard Worker #define INCOMPLETE_EXITCODE -1
20*d83cc019SAndroid Build Coastguard Worker 
21*d83cc019SAndroid Build Coastguard Worker _Static_assert(INCOMPLETE_EXITCODE != IGT_EXIT_SKIP, "exit code clash");
22*d83cc019SAndroid Build Coastguard Worker _Static_assert(INCOMPLETE_EXITCODE != IGT_EXIT_SUCCESS, "exit code clash");
23*d83cc019SAndroid Build Coastguard Worker _Static_assert(INCOMPLETE_EXITCODE != IGT_EXIT_INVALID, "exit code clash");
24*d83cc019SAndroid Build Coastguard Worker 
25*d83cc019SAndroid Build Coastguard Worker struct subtests
26*d83cc019SAndroid Build Coastguard Worker {
27*d83cc019SAndroid Build Coastguard Worker 	char **names;
28*d83cc019SAndroid Build Coastguard Worker 	size_t size;
29*d83cc019SAndroid Build Coastguard Worker };
30*d83cc019SAndroid Build Coastguard Worker 
31*d83cc019SAndroid Build Coastguard Worker struct results
32*d83cc019SAndroid Build Coastguard Worker {
33*d83cc019SAndroid Build Coastguard Worker 	struct json_object *tests;
34*d83cc019SAndroid Build Coastguard Worker 	struct json_object *totals;
35*d83cc019SAndroid Build Coastguard Worker 	struct json_object *runtimes;
36*d83cc019SAndroid Build Coastguard Worker };
37*d83cc019SAndroid Build Coastguard Worker 
38*d83cc019SAndroid Build Coastguard Worker /*
39*d83cc019SAndroid Build Coastguard Worker  * A lot of string handling here operates on an mmapped buffer, and
40*d83cc019SAndroid Build Coastguard Worker  * thus we can't assume null-terminated strings. Buffers will be
41*d83cc019SAndroid Build Coastguard Worker  * passed around as pointer+size, or pointer+pointer-past-the-end, the
42*d83cc019SAndroid Build Coastguard Worker  * mem*() family of functions is used instead of str*().
43*d83cc019SAndroid Build Coastguard Worker  */
44*d83cc019SAndroid Build Coastguard Worker 
find_line_starting_with(char * haystack,const char * needle,char * end)45*d83cc019SAndroid Build Coastguard Worker static char *find_line_starting_with(char *haystack, const char *needle, char *end)
46*d83cc019SAndroid Build Coastguard Worker {
47*d83cc019SAndroid Build Coastguard Worker 	while (haystack < end) {
48*d83cc019SAndroid Build Coastguard Worker 		char *line_end = memchr(haystack, '\n', end - haystack);
49*d83cc019SAndroid Build Coastguard Worker 
50*d83cc019SAndroid Build Coastguard Worker 		if (end - haystack < strlen(needle))
51*d83cc019SAndroid Build Coastguard Worker 			return NULL;
52*d83cc019SAndroid Build Coastguard Worker 		if (!memcmp(haystack, needle, strlen(needle)))
53*d83cc019SAndroid Build Coastguard Worker 			return haystack;
54*d83cc019SAndroid Build Coastguard Worker 		if (line_end == NULL)
55*d83cc019SAndroid Build Coastguard Worker 			return NULL;
56*d83cc019SAndroid Build Coastguard Worker 		haystack = line_end + 1;
57*d83cc019SAndroid Build Coastguard Worker 	}
58*d83cc019SAndroid Build Coastguard Worker 
59*d83cc019SAndroid Build Coastguard Worker 	return NULL;
60*d83cc019SAndroid Build Coastguard Worker }
61*d83cc019SAndroid Build Coastguard Worker 
find_line_starting_with_either(char * haystack,const char * needle1,const char * needle2,char * end)62*d83cc019SAndroid Build Coastguard Worker static char *find_line_starting_with_either(char *haystack,
63*d83cc019SAndroid Build Coastguard Worker 					    const char *needle1,
64*d83cc019SAndroid Build Coastguard Worker 					    const char *needle2,
65*d83cc019SAndroid Build Coastguard Worker 					    char *end)
66*d83cc019SAndroid Build Coastguard Worker {
67*d83cc019SAndroid Build Coastguard Worker 	while (haystack < end) {
68*d83cc019SAndroid Build Coastguard Worker 		char *line_end = memchr(haystack, '\n', end - haystack);
69*d83cc019SAndroid Build Coastguard Worker 		size_t linelen = line_end != NULL ? line_end - haystack : end - haystack;
70*d83cc019SAndroid Build Coastguard Worker 		if ((linelen >= strlen(needle1) && !memcmp(haystack, needle1, strlen(needle1))) ||
71*d83cc019SAndroid Build Coastguard Worker 		    (linelen >= strlen(needle2) && !memcmp(haystack, needle2, strlen(needle2))))
72*d83cc019SAndroid Build Coastguard Worker 			return haystack;
73*d83cc019SAndroid Build Coastguard Worker 
74*d83cc019SAndroid Build Coastguard Worker 		if (line_end == NULL)
75*d83cc019SAndroid Build Coastguard Worker 			return NULL;
76*d83cc019SAndroid Build Coastguard Worker 
77*d83cc019SAndroid Build Coastguard Worker 		haystack = line_end + 1;
78*d83cc019SAndroid Build Coastguard Worker 	}
79*d83cc019SAndroid Build Coastguard Worker 
80*d83cc019SAndroid Build Coastguard Worker 	return NULL;
81*d83cc019SAndroid Build Coastguard Worker }
82*d83cc019SAndroid Build Coastguard Worker 
next_line(char * line,char * bufend)83*d83cc019SAndroid Build Coastguard Worker static char *next_line(char *line, char *bufend)
84*d83cc019SAndroid Build Coastguard Worker {
85*d83cc019SAndroid Build Coastguard Worker 	char *ret;
86*d83cc019SAndroid Build Coastguard Worker 
87*d83cc019SAndroid Build Coastguard Worker 	if (!line)
88*d83cc019SAndroid Build Coastguard Worker 		return NULL;
89*d83cc019SAndroid Build Coastguard Worker 
90*d83cc019SAndroid Build Coastguard Worker 	ret = memchr(line, '\n', bufend - line);
91*d83cc019SAndroid Build Coastguard Worker 	if (ret)
92*d83cc019SAndroid Build Coastguard Worker 		ret++;
93*d83cc019SAndroid Build Coastguard Worker 
94*d83cc019SAndroid Build Coastguard Worker 	if (ret < bufend)
95*d83cc019SAndroid Build Coastguard Worker 		return ret;
96*d83cc019SAndroid Build Coastguard Worker 	else
97*d83cc019SAndroid Build Coastguard Worker 		return NULL;
98*d83cc019SAndroid Build Coastguard Worker }
99*d83cc019SAndroid Build Coastguard Worker 
find_line_after_last(char * begin,const char * needle1,const char * needle2,char * end)100*d83cc019SAndroid Build Coastguard Worker static char *find_line_after_last(char *begin,
101*d83cc019SAndroid Build Coastguard Worker 				  const char *needle1,
102*d83cc019SAndroid Build Coastguard Worker 				  const char *needle2,
103*d83cc019SAndroid Build Coastguard Worker 				  char *end)
104*d83cc019SAndroid Build Coastguard Worker {
105*d83cc019SAndroid Build Coastguard Worker 	char *one, *two;
106*d83cc019SAndroid Build Coastguard Worker 	char *current_pos = begin;
107*d83cc019SAndroid Build Coastguard Worker 	char *needle1_newline = malloc(strlen(needle1) + 2);
108*d83cc019SAndroid Build Coastguard Worker 	char *needle2_newline = malloc(strlen(needle2) + 2);
109*d83cc019SAndroid Build Coastguard Worker 
110*d83cc019SAndroid Build Coastguard Worker 	needle1_newline[0] = needle2_newline[0] = '\n';
111*d83cc019SAndroid Build Coastguard Worker 	strcpy(needle1_newline + 1, needle1);
112*d83cc019SAndroid Build Coastguard Worker 	strcpy(needle2_newline + 1, needle2);
113*d83cc019SAndroid Build Coastguard Worker 
114*d83cc019SAndroid Build Coastguard Worker 	while (true) {
115*d83cc019SAndroid Build Coastguard Worker 		one = memmem(current_pos, end - current_pos, needle1_newline, strlen(needle1_newline));
116*d83cc019SAndroid Build Coastguard Worker 		two = memmem(current_pos, end - current_pos, needle2_newline, strlen(needle2_newline));
117*d83cc019SAndroid Build Coastguard Worker 		if (one == NULL && two == NULL)
118*d83cc019SAndroid Build Coastguard Worker 			break;
119*d83cc019SAndroid Build Coastguard Worker 
120*d83cc019SAndroid Build Coastguard Worker 		if (one != NULL && current_pos < one)
121*d83cc019SAndroid Build Coastguard Worker 			current_pos = one;
122*d83cc019SAndroid Build Coastguard Worker 		if (two != NULL && current_pos < two)
123*d83cc019SAndroid Build Coastguard Worker 			current_pos = two;
124*d83cc019SAndroid Build Coastguard Worker 
125*d83cc019SAndroid Build Coastguard Worker 		one = next_line(current_pos, end);
126*d83cc019SAndroid Build Coastguard Worker 		if (one != NULL)
127*d83cc019SAndroid Build Coastguard Worker 			current_pos = one;
128*d83cc019SAndroid Build Coastguard Worker 	}
129*d83cc019SAndroid Build Coastguard Worker 	free(needle1_newline);
130*d83cc019SAndroid Build Coastguard Worker 	free(needle2_newline);
131*d83cc019SAndroid Build Coastguard Worker 
132*d83cc019SAndroid Build Coastguard Worker 	one = memchr(current_pos, '\n', end - current_pos);
133*d83cc019SAndroid Build Coastguard Worker 	if (one != NULL)
134*d83cc019SAndroid Build Coastguard Worker 		return ++one;
135*d83cc019SAndroid Build Coastguard Worker 
136*d83cc019SAndroid Build Coastguard Worker 	return current_pos;
137*d83cc019SAndroid Build Coastguard Worker }
138*d83cc019SAndroid Build Coastguard Worker 
count_lines(const char * buf,const char * bufend)139*d83cc019SAndroid Build Coastguard Worker static size_t count_lines(const char *buf, const char *bufend)
140*d83cc019SAndroid Build Coastguard Worker {
141*d83cc019SAndroid Build Coastguard Worker 	size_t ret = 0;
142*d83cc019SAndroid Build Coastguard Worker 	while (buf < bufend && (buf = memchr(buf, '\n', bufend - buf)) != NULL) {
143*d83cc019SAndroid Build Coastguard Worker 		ret++;
144*d83cc019SAndroid Build Coastguard Worker 		buf++;
145*d83cc019SAndroid Build Coastguard Worker 	}
146*d83cc019SAndroid Build Coastguard Worker 
147*d83cc019SAndroid Build Coastguard Worker 	return ret;
148*d83cc019SAndroid Build Coastguard Worker }
149*d83cc019SAndroid Build Coastguard Worker 
append_line(char ** buf,size_t * buflen,char * line)150*d83cc019SAndroid Build Coastguard Worker static void append_line(char **buf, size_t *buflen, char *line)
151*d83cc019SAndroid Build Coastguard Worker {
152*d83cc019SAndroid Build Coastguard Worker 	size_t linelen = strlen(line);
153*d83cc019SAndroid Build Coastguard Worker 
154*d83cc019SAndroid Build Coastguard Worker 	*buf = realloc(*buf, *buflen + linelen + 1);
155*d83cc019SAndroid Build Coastguard Worker 	strcpy(*buf + *buflen, line);
156*d83cc019SAndroid Build Coastguard Worker 	*buflen += linelen;
157*d83cc019SAndroid Build Coastguard Worker }
158*d83cc019SAndroid Build Coastguard Worker 
159*d83cc019SAndroid Build Coastguard Worker static const struct {
160*d83cc019SAndroid Build Coastguard Worker 	const char *output_str;
161*d83cc019SAndroid Build Coastguard Worker 	const char *result_str;
162*d83cc019SAndroid Build Coastguard Worker } resultmap[] = {
163*d83cc019SAndroid Build Coastguard Worker 	{ "SUCCESS", "pass" },
164*d83cc019SAndroid Build Coastguard Worker 	{ "SKIP", "skip" },
165*d83cc019SAndroid Build Coastguard Worker 	{ "FAIL", "fail" },
166*d83cc019SAndroid Build Coastguard Worker 	{ "CRASH", "crash" },
167*d83cc019SAndroid Build Coastguard Worker 	{ "TIMEOUT", "timeout" },
168*d83cc019SAndroid Build Coastguard Worker };
parse_result_string(char * resultstring,size_t len,const char ** result,double * time)169*d83cc019SAndroid Build Coastguard Worker static void parse_result_string(char *resultstring, size_t len, const char **result, double *time)
170*d83cc019SAndroid Build Coastguard Worker {
171*d83cc019SAndroid Build Coastguard Worker 	size_t i;
172*d83cc019SAndroid Build Coastguard Worker 	size_t wordlen = 0;
173*d83cc019SAndroid Build Coastguard Worker 
174*d83cc019SAndroid Build Coastguard Worker 	while (wordlen < len && !isspace(resultstring[wordlen])) {
175*d83cc019SAndroid Build Coastguard Worker 		wordlen++;
176*d83cc019SAndroid Build Coastguard Worker 	}
177*d83cc019SAndroid Build Coastguard Worker 
178*d83cc019SAndroid Build Coastguard Worker 	*result = NULL;
179*d83cc019SAndroid Build Coastguard Worker 	for (i = 0; i < (sizeof(resultmap) / sizeof(resultmap[0])); i++) {
180*d83cc019SAndroid Build Coastguard Worker 		if (!strncmp(resultstring, resultmap[i].output_str, wordlen)) {
181*d83cc019SAndroid Build Coastguard Worker 			*result = resultmap[i].result_str;
182*d83cc019SAndroid Build Coastguard Worker 			break;
183*d83cc019SAndroid Build Coastguard Worker 		}
184*d83cc019SAndroid Build Coastguard Worker 	}
185*d83cc019SAndroid Build Coastguard Worker 
186*d83cc019SAndroid Build Coastguard Worker 	/* If the result string is unknown, use incomplete */
187*d83cc019SAndroid Build Coastguard Worker 	if (!*result)
188*d83cc019SAndroid Build Coastguard Worker 		*result = "incomplete";
189*d83cc019SAndroid Build Coastguard Worker 
190*d83cc019SAndroid Build Coastguard Worker 	/*
191*d83cc019SAndroid Build Coastguard Worker 	 * Check for subtest runtime after the result. The string is
192*d83cc019SAndroid Build Coastguard Worker 	 * '(' followed by the runtime in seconds as floating point,
193*d83cc019SAndroid Build Coastguard Worker 	 * followed by 's)'.
194*d83cc019SAndroid Build Coastguard Worker 	 */
195*d83cc019SAndroid Build Coastguard Worker 	wordlen++;
196*d83cc019SAndroid Build Coastguard Worker 	if (wordlen < len && resultstring[wordlen] == '(') {
197*d83cc019SAndroid Build Coastguard Worker 		char *dup;
198*d83cc019SAndroid Build Coastguard Worker 
199*d83cc019SAndroid Build Coastguard Worker 		wordlen++;
200*d83cc019SAndroid Build Coastguard Worker 		dup = malloc(len - wordlen + 1);
201*d83cc019SAndroid Build Coastguard Worker 		memcpy(dup, resultstring + wordlen, len - wordlen);
202*d83cc019SAndroid Build Coastguard Worker 		dup[len - wordlen] = '\0';
203*d83cc019SAndroid Build Coastguard Worker 		*time = strtod(dup, NULL);
204*d83cc019SAndroid Build Coastguard Worker 
205*d83cc019SAndroid Build Coastguard Worker 		free(dup);
206*d83cc019SAndroid Build Coastguard Worker 	}
207*d83cc019SAndroid Build Coastguard Worker }
208*d83cc019SAndroid Build Coastguard Worker 
parse_subtest_result(char * subtest,const char ** result,double * time,char * buf,char * bufend)209*d83cc019SAndroid Build Coastguard Worker static void parse_subtest_result(char *subtest, const char **result, double *time, char *buf, char *bufend)
210*d83cc019SAndroid Build Coastguard Worker {
211*d83cc019SAndroid Build Coastguard Worker 	char *line;
212*d83cc019SAndroid Build Coastguard Worker 	char *line_end;
213*d83cc019SAndroid Build Coastguard Worker 	char *resultstring;
214*d83cc019SAndroid Build Coastguard Worker 	size_t linelen;
215*d83cc019SAndroid Build Coastguard Worker 	size_t subtestlen = strlen(subtest);
216*d83cc019SAndroid Build Coastguard Worker 
217*d83cc019SAndroid Build Coastguard Worker 	*result = NULL;
218*d83cc019SAndroid Build Coastguard Worker 	*time = 0.0;
219*d83cc019SAndroid Build Coastguard Worker 
220*d83cc019SAndroid Build Coastguard Worker 	if (!buf) return;
221*d83cc019SAndroid Build Coastguard Worker 
222*d83cc019SAndroid Build Coastguard Worker 	/*
223*d83cc019SAndroid Build Coastguard Worker 	 * The result line structure is:
224*d83cc019SAndroid Build Coastguard Worker 	 *
225*d83cc019SAndroid Build Coastguard Worker 	 * - The string "Subtest " (`SUBTEST_RESULT` from output_strings.h)
226*d83cc019SAndroid Build Coastguard Worker 	 * - The subtest name
227*d83cc019SAndroid Build Coastguard Worker 	 * - The characters ':' and ' '
228*d83cc019SAndroid Build Coastguard Worker 	 * - Subtest result string
229*d83cc019SAndroid Build Coastguard Worker 	 * - Optional:
230*d83cc019SAndroid Build Coastguard Worker 	 * -- The characters ' ' and '('
231*d83cc019SAndroid Build Coastguard Worker 	 * -- Subtest runtime in seconds as floating point
232*d83cc019SAndroid Build Coastguard Worker 	 * -- The characters 's' and ')'
233*d83cc019SAndroid Build Coastguard Worker 	 *
234*d83cc019SAndroid Build Coastguard Worker 	 * Example:
235*d83cc019SAndroid Build Coastguard Worker 	 * Subtest subtestname: PASS (0.003s)
236*d83cc019SAndroid Build Coastguard Worker 	 */
237*d83cc019SAndroid Build Coastguard Worker 
238*d83cc019SAndroid Build Coastguard Worker 	line = find_line_starting_with(buf, SUBTEST_RESULT, bufend);
239*d83cc019SAndroid Build Coastguard Worker 	if (!line) {
240*d83cc019SAndroid Build Coastguard Worker 		*result = "incomplete";
241*d83cc019SAndroid Build Coastguard Worker 		return;
242*d83cc019SAndroid Build Coastguard Worker 	}
243*d83cc019SAndroid Build Coastguard Worker 
244*d83cc019SAndroid Build Coastguard Worker 	line_end = memchr(line, '\n', bufend - line);
245*d83cc019SAndroid Build Coastguard Worker 	linelen = line_end != NULL ? line_end - line : bufend - line;
246*d83cc019SAndroid Build Coastguard Worker 
247*d83cc019SAndroid Build Coastguard Worker 	if (strlen(SUBTEST_RESULT) + subtestlen + strlen(": ") > linelen ||
248*d83cc019SAndroid Build Coastguard Worker 	    strncmp(line + strlen(SUBTEST_RESULT), subtest, subtestlen))
249*d83cc019SAndroid Build Coastguard Worker 		return parse_subtest_result(subtest, result, time, line + linelen, bufend);
250*d83cc019SAndroid Build Coastguard Worker 
251*d83cc019SAndroid Build Coastguard Worker 	resultstring = line + strlen(SUBTEST_RESULT) + subtestlen + strlen(": ");
252*d83cc019SAndroid Build Coastguard Worker 	parse_result_string(resultstring, linelen - (resultstring - line), result, time);
253*d83cc019SAndroid Build Coastguard Worker }
254*d83cc019SAndroid Build Coastguard Worker 
get_or_create_json_object(struct json_object * base,const char * key)255*d83cc019SAndroid Build Coastguard Worker static struct json_object *get_or_create_json_object(struct json_object *base,
256*d83cc019SAndroid Build Coastguard Worker 						     const char *key)
257*d83cc019SAndroid Build Coastguard Worker {
258*d83cc019SAndroid Build Coastguard Worker 	struct json_object *ret;
259*d83cc019SAndroid Build Coastguard Worker 
260*d83cc019SAndroid Build Coastguard Worker 	if (json_object_object_get_ex(base, key, &ret))
261*d83cc019SAndroid Build Coastguard Worker 		return ret;
262*d83cc019SAndroid Build Coastguard Worker 
263*d83cc019SAndroid Build Coastguard Worker 	ret = json_object_new_object();
264*d83cc019SAndroid Build Coastguard Worker 	json_object_object_add(base, key, ret);
265*d83cc019SAndroid Build Coastguard Worker 
266*d83cc019SAndroid Build Coastguard Worker 	return ret;
267*d83cc019SAndroid Build Coastguard Worker }
268*d83cc019SAndroid Build Coastguard Worker 
set_result(struct json_object * obj,const char * result)269*d83cc019SAndroid Build Coastguard Worker static void set_result(struct json_object *obj, const char *result)
270*d83cc019SAndroid Build Coastguard Worker {
271*d83cc019SAndroid Build Coastguard Worker 	json_object_object_add(obj, "result",
272*d83cc019SAndroid Build Coastguard Worker 			       json_object_new_string(result));
273*d83cc019SAndroid Build Coastguard Worker }
274*d83cc019SAndroid Build Coastguard Worker 
add_runtime(struct json_object * obj,double time)275*d83cc019SAndroid Build Coastguard Worker static void add_runtime(struct json_object *obj, double time)
276*d83cc019SAndroid Build Coastguard Worker {
277*d83cc019SAndroid Build Coastguard Worker 	double oldtime;
278*d83cc019SAndroid Build Coastguard Worker 	struct json_object *timeobj = get_or_create_json_object(obj, "time");
279*d83cc019SAndroid Build Coastguard Worker 	struct json_object *oldend;
280*d83cc019SAndroid Build Coastguard Worker 
281*d83cc019SAndroid Build Coastguard Worker 	json_object_object_add(timeobj, "__type__",
282*d83cc019SAndroid Build Coastguard Worker 			       json_object_new_string("TimeAttribute"));
283*d83cc019SAndroid Build Coastguard Worker 	json_object_object_add(timeobj, "start",
284*d83cc019SAndroid Build Coastguard Worker 			       json_object_new_double(0.0));
285*d83cc019SAndroid Build Coastguard Worker 
286*d83cc019SAndroid Build Coastguard Worker 	if (!json_object_object_get_ex(timeobj, "end", &oldend)) {
287*d83cc019SAndroid Build Coastguard Worker 		json_object_object_add(timeobj, "end",
288*d83cc019SAndroid Build Coastguard Worker 				       json_object_new_double(time));
289*d83cc019SAndroid Build Coastguard Worker 		return;
290*d83cc019SAndroid Build Coastguard Worker 	}
291*d83cc019SAndroid Build Coastguard Worker 
292*d83cc019SAndroid Build Coastguard Worker 	/* Add the runtime to the existing runtime. */
293*d83cc019SAndroid Build Coastguard Worker 	oldtime = json_object_get_double(oldend);
294*d83cc019SAndroid Build Coastguard Worker 	time += oldtime;
295*d83cc019SAndroid Build Coastguard Worker 	json_object_object_add(timeobj, "end",
296*d83cc019SAndroid Build Coastguard Worker 			       json_object_new_double(time));
297*d83cc019SAndroid Build Coastguard Worker }
298*d83cc019SAndroid Build Coastguard Worker 
set_runtime(struct json_object * obj,double time)299*d83cc019SAndroid Build Coastguard Worker static void set_runtime(struct json_object *obj, double time)
300*d83cc019SAndroid Build Coastguard Worker {
301*d83cc019SAndroid Build Coastguard Worker 	struct json_object *timeobj = get_or_create_json_object(obj, "time");
302*d83cc019SAndroid Build Coastguard Worker 
303*d83cc019SAndroid Build Coastguard Worker 	json_object_object_add(timeobj, "__type__",
304*d83cc019SAndroid Build Coastguard Worker 			       json_object_new_string("TimeAttribute"));
305*d83cc019SAndroid Build Coastguard Worker 	json_object_object_add(timeobj, "start",
306*d83cc019SAndroid Build Coastguard Worker 			       json_object_new_double(0.0));
307*d83cc019SAndroid Build Coastguard Worker 	json_object_object_add(timeobj, "end",
308*d83cc019SAndroid Build Coastguard Worker 			       json_object_new_double(time));
309*d83cc019SAndroid Build Coastguard Worker }
310*d83cc019SAndroid Build Coastguard Worker 
fill_from_output(int fd,const char * binary,const char * key,struct subtests * subtests,struct json_object * tests)311*d83cc019SAndroid Build Coastguard Worker static bool fill_from_output(int fd, const char *binary, const char *key,
312*d83cc019SAndroid Build Coastguard Worker 			     struct subtests *subtests,
313*d83cc019SAndroid Build Coastguard Worker 			     struct json_object *tests)
314*d83cc019SAndroid Build Coastguard Worker {
315*d83cc019SAndroid Build Coastguard Worker 	char *buf, *bufend, *nullchr;
316*d83cc019SAndroid Build Coastguard Worker 	struct stat statbuf;
317*d83cc019SAndroid Build Coastguard Worker 	char piglit_name[256];
318*d83cc019SAndroid Build Coastguard Worker 	char *igt_version = NULL;
319*d83cc019SAndroid Build Coastguard Worker 	size_t igt_version_len = 0;
320*d83cc019SAndroid Build Coastguard Worker 	struct json_object *current_test = NULL;
321*d83cc019SAndroid Build Coastguard Worker 	size_t i;
322*d83cc019SAndroid Build Coastguard Worker 
323*d83cc019SAndroid Build Coastguard Worker 	if (fstat(fd, &statbuf))
324*d83cc019SAndroid Build Coastguard Worker 		return false;
325*d83cc019SAndroid Build Coastguard Worker 
326*d83cc019SAndroid Build Coastguard Worker 	if (statbuf.st_size != 0) {
327*d83cc019SAndroid Build Coastguard Worker 		buf = mmap(NULL, statbuf.st_size, PROT_READ, MAP_SHARED, fd, 0);
328*d83cc019SAndroid Build Coastguard Worker 		if (buf == MAP_FAILED)
329*d83cc019SAndroid Build Coastguard Worker 			return false;
330*d83cc019SAndroid Build Coastguard Worker 	} else {
331*d83cc019SAndroid Build Coastguard Worker 		buf = NULL;
332*d83cc019SAndroid Build Coastguard Worker 	}
333*d83cc019SAndroid Build Coastguard Worker 
334*d83cc019SAndroid Build Coastguard Worker 	/*
335*d83cc019SAndroid Build Coastguard Worker 	 * Avoid null characters: Just pretend the output stops at the
336*d83cc019SAndroid Build Coastguard Worker 	 * first such character, if any.
337*d83cc019SAndroid Build Coastguard Worker 	 */
338*d83cc019SAndroid Build Coastguard Worker 	if ((nullchr = memchr(buf, '\0', statbuf.st_size)) != NULL) {
339*d83cc019SAndroid Build Coastguard Worker 		statbuf.st_size = nullchr - buf;
340*d83cc019SAndroid Build Coastguard Worker 	}
341*d83cc019SAndroid Build Coastguard Worker 
342*d83cc019SAndroid Build Coastguard Worker 	bufend = buf + statbuf.st_size;
343*d83cc019SAndroid Build Coastguard Worker 
344*d83cc019SAndroid Build Coastguard Worker 	igt_version = find_line_starting_with(buf, IGT_VERSIONSTRING, bufend);
345*d83cc019SAndroid Build Coastguard Worker 	if (igt_version) {
346*d83cc019SAndroid Build Coastguard Worker 		char *newline = memchr(igt_version, '\n', bufend - igt_version);
347*d83cc019SAndroid Build Coastguard Worker 		igt_version_len = newline - igt_version;
348*d83cc019SAndroid Build Coastguard Worker 	}
349*d83cc019SAndroid Build Coastguard Worker 
350*d83cc019SAndroid Build Coastguard Worker 	/* TODO: Refactor to helper functions */
351*d83cc019SAndroid Build Coastguard Worker 	if (subtests->size == 0) {
352*d83cc019SAndroid Build Coastguard Worker 		/* No subtests */
353*d83cc019SAndroid Build Coastguard Worker 		generate_piglit_name(binary, NULL, piglit_name, sizeof(piglit_name));
354*d83cc019SAndroid Build Coastguard Worker 		current_test = get_or_create_json_object(tests, piglit_name);
355*d83cc019SAndroid Build Coastguard Worker 
356*d83cc019SAndroid Build Coastguard Worker 		json_object_object_add(current_test, key,
357*d83cc019SAndroid Build Coastguard Worker 				       json_object_new_string_len(buf, statbuf.st_size));
358*d83cc019SAndroid Build Coastguard Worker 		if (igt_version)
359*d83cc019SAndroid Build Coastguard Worker 			json_object_object_add(current_test, "igt-version",
360*d83cc019SAndroid Build Coastguard Worker 					       json_object_new_string_len(igt_version,
361*d83cc019SAndroid Build Coastguard Worker 									  igt_version_len));
362*d83cc019SAndroid Build Coastguard Worker 
363*d83cc019SAndroid Build Coastguard Worker 		return true;
364*d83cc019SAndroid Build Coastguard Worker 	}
365*d83cc019SAndroid Build Coastguard Worker 
366*d83cc019SAndroid Build Coastguard Worker 	for (i = 0; i < subtests->size; i++) {
367*d83cc019SAndroid Build Coastguard Worker 		char *this_sub_begin, *this_sub_result;
368*d83cc019SAndroid Build Coastguard Worker 		const char *resulttext;
369*d83cc019SAndroid Build Coastguard Worker 		char *beg, *end, *startline;
370*d83cc019SAndroid Build Coastguard Worker 		double time;
371*d83cc019SAndroid Build Coastguard Worker 		int begin_len;
372*d83cc019SAndroid Build Coastguard Worker 		int result_len;
373*d83cc019SAndroid Build Coastguard Worker 
374*d83cc019SAndroid Build Coastguard Worker 		generate_piglit_name(binary, subtests->names[i], piglit_name, sizeof(piglit_name));
375*d83cc019SAndroid Build Coastguard Worker 		current_test = get_or_create_json_object(tests, piglit_name);
376*d83cc019SAndroid Build Coastguard Worker 
377*d83cc019SAndroid Build Coastguard Worker 		begin_len = asprintf(&this_sub_begin, "%s%s\n", STARTING_SUBTEST, subtests->names[i]);
378*d83cc019SAndroid Build Coastguard Worker 		result_len = asprintf(&this_sub_result, "%s%s: ", SUBTEST_RESULT, subtests->names[i]);
379*d83cc019SAndroid Build Coastguard Worker 
380*d83cc019SAndroid Build Coastguard Worker 		if (begin_len < 0 || result_len < 0) {
381*d83cc019SAndroid Build Coastguard Worker 			fprintf(stderr, "Failure generating strings\n");
382*d83cc019SAndroid Build Coastguard Worker 			return false;
383*d83cc019SAndroid Build Coastguard Worker 		}
384*d83cc019SAndroid Build Coastguard Worker 
385*d83cc019SAndroid Build Coastguard Worker 		beg = find_line_starting_with(buf, this_sub_begin, bufend);
386*d83cc019SAndroid Build Coastguard Worker 		end = find_line_starting_with(buf, this_sub_result, bufend);
387*d83cc019SAndroid Build Coastguard Worker 		startline = beg;
388*d83cc019SAndroid Build Coastguard Worker 
389*d83cc019SAndroid Build Coastguard Worker 		free(this_sub_begin);
390*d83cc019SAndroid Build Coastguard Worker 		free(this_sub_result);
391*d83cc019SAndroid Build Coastguard Worker 
392*d83cc019SAndroid Build Coastguard Worker 		if (beg == NULL && end == NULL) {
393*d83cc019SAndroid Build Coastguard Worker 			/* No output at all */
394*d83cc019SAndroid Build Coastguard Worker 			beg = bufend;
395*d83cc019SAndroid Build Coastguard Worker 			end = bufend;
396*d83cc019SAndroid Build Coastguard Worker 		}
397*d83cc019SAndroid Build Coastguard Worker 
398*d83cc019SAndroid Build Coastguard Worker 		if (beg == NULL) {
399*d83cc019SAndroid Build Coastguard Worker 			/*
400*d83cc019SAndroid Build Coastguard Worker 			 * Subtest didn't start, probably skipped from
401*d83cc019SAndroid Build Coastguard Worker 			 * fixture already. Start from the result
402*d83cc019SAndroid Build Coastguard Worker 			 * line, it gets adjusted below.
403*d83cc019SAndroid Build Coastguard Worker 			 */
404*d83cc019SAndroid Build Coastguard Worker 			beg = end;
405*d83cc019SAndroid Build Coastguard Worker 		}
406*d83cc019SAndroid Build Coastguard Worker 
407*d83cc019SAndroid Build Coastguard Worker 		/* Include the output after the previous subtest output */
408*d83cc019SAndroid Build Coastguard Worker 		beg = find_line_after_last(buf,
409*d83cc019SAndroid Build Coastguard Worker 					   STARTING_SUBTEST,
410*d83cc019SAndroid Build Coastguard Worker 					   SUBTEST_RESULT,
411*d83cc019SAndroid Build Coastguard Worker 					   beg);
412*d83cc019SAndroid Build Coastguard Worker 
413*d83cc019SAndroid Build Coastguard Worker 		if (end == NULL) {
414*d83cc019SAndroid Build Coastguard Worker 			/* Incomplete result. Find the next starting subtest or result. */
415*d83cc019SAndroid Build Coastguard Worker 			end = next_line(startline, bufend);
416*d83cc019SAndroid Build Coastguard Worker 			if (end != NULL) {
417*d83cc019SAndroid Build Coastguard Worker 				end = find_line_starting_with_either(end,
418*d83cc019SAndroid Build Coastguard Worker 								     STARTING_SUBTEST,
419*d83cc019SAndroid Build Coastguard Worker 								     SUBTEST_RESULT,
420*d83cc019SAndroid Build Coastguard Worker 								     bufend);
421*d83cc019SAndroid Build Coastguard Worker 			}
422*d83cc019SAndroid Build Coastguard Worker 			if (end == NULL) {
423*d83cc019SAndroid Build Coastguard Worker 				end = bufend;
424*d83cc019SAndroid Build Coastguard Worker 			}
425*d83cc019SAndroid Build Coastguard Worker 		} else {
426*d83cc019SAndroid Build Coastguard Worker 			/*
427*d83cc019SAndroid Build Coastguard Worker 			 * Now pointing to the line where this sub's
428*d83cc019SAndroid Build Coastguard Worker 			 * result is. We need to include that of
429*d83cc019SAndroid Build Coastguard Worker 			 * course.
430*d83cc019SAndroid Build Coastguard Worker 			 */
431*d83cc019SAndroid Build Coastguard Worker 			char *nexttest = next_line(end, bufend);
432*d83cc019SAndroid Build Coastguard Worker 
433*d83cc019SAndroid Build Coastguard Worker 			/* Stretch onwards until the next subtest begins or ends */
434*d83cc019SAndroid Build Coastguard Worker 			if (nexttest != NULL) {
435*d83cc019SAndroid Build Coastguard Worker 				nexttest = find_line_starting_with_either(nexttest,
436*d83cc019SAndroid Build Coastguard Worker 									  STARTING_SUBTEST,
437*d83cc019SAndroid Build Coastguard Worker 									  SUBTEST_RESULT,
438*d83cc019SAndroid Build Coastguard Worker 									  bufend);
439*d83cc019SAndroid Build Coastguard Worker 			}
440*d83cc019SAndroid Build Coastguard Worker 			if (nexttest != NULL) {
441*d83cc019SAndroid Build Coastguard Worker 				end = nexttest;
442*d83cc019SAndroid Build Coastguard Worker 			} else {
443*d83cc019SAndroid Build Coastguard Worker 				end = bufend;
444*d83cc019SAndroid Build Coastguard Worker 			}
445*d83cc019SAndroid Build Coastguard Worker 		}
446*d83cc019SAndroid Build Coastguard Worker 
447*d83cc019SAndroid Build Coastguard Worker 		json_object_object_add(current_test, key,
448*d83cc019SAndroid Build Coastguard Worker 				       json_object_new_string_len(beg, end - beg));
449*d83cc019SAndroid Build Coastguard Worker 
450*d83cc019SAndroid Build Coastguard Worker 		if (igt_version) {
451*d83cc019SAndroid Build Coastguard Worker 			json_object_object_add(current_test, "igt-version",
452*d83cc019SAndroid Build Coastguard Worker 					       json_object_new_string_len(igt_version,
453*d83cc019SAndroid Build Coastguard Worker 									  igt_version_len));
454*d83cc019SAndroid Build Coastguard Worker 		}
455*d83cc019SAndroid Build Coastguard Worker 
456*d83cc019SAndroid Build Coastguard Worker 		if (!json_object_object_get_ex(current_test, "result", NULL)) {
457*d83cc019SAndroid Build Coastguard Worker 			parse_subtest_result(subtests->names[i], &resulttext, &time, beg, end);
458*d83cc019SAndroid Build Coastguard Worker 			set_result(current_test, resulttext);
459*d83cc019SAndroid Build Coastguard Worker 			set_runtime(current_test, time);
460*d83cc019SAndroid Build Coastguard Worker 		}
461*d83cc019SAndroid Build Coastguard Worker 	}
462*d83cc019SAndroid Build Coastguard Worker 
463*d83cc019SAndroid Build Coastguard Worker 	return true;
464*d83cc019SAndroid Build Coastguard Worker }
465*d83cc019SAndroid Build Coastguard Worker 
466*d83cc019SAndroid Build Coastguard Worker /*
467*d83cc019SAndroid Build Coastguard Worker  * This regexp controls the kmsg handling. All kernel log records that
468*d83cc019SAndroid Build Coastguard Worker  * have log level of warning or higher convert the result to
469*d83cc019SAndroid Build Coastguard Worker  * dmesg-warn/dmesg-fail unless they match this regexp.
470*d83cc019SAndroid Build Coastguard Worker  *
471*d83cc019SAndroid Build Coastguard Worker  * TODO: Move this to external files, i915-suppressions.txt,
472*d83cc019SAndroid Build Coastguard Worker  * general-suppressions.txt et al.
473*d83cc019SAndroid Build Coastguard Worker  */
474*d83cc019SAndroid Build Coastguard Worker 
475*d83cc019SAndroid Build Coastguard Worker #define _ "|"
476*d83cc019SAndroid Build Coastguard Worker static const char igt_dmesg_whitelist[] =
477*d83cc019SAndroid Build Coastguard Worker 	"ACPI: button: The lid device is not compliant to SW_LID" _
478*d83cc019SAndroid Build Coastguard Worker 	"ACPI: .*: Unable to dock!" _
479*d83cc019SAndroid Build Coastguard Worker 	"IRQ [0-9]+: no longer affine to CPU[0-9]+" _
480*d83cc019SAndroid Build Coastguard Worker 	"IRQ fixup: irq [0-9]+ move in progress, old vector [0-9]+" _
481*d83cc019SAndroid Build Coastguard Worker 	/* i915 tests set module options, expected message */
482*d83cc019SAndroid Build Coastguard Worker 	"Setting dangerous option [a-z_]+ - tainting kernel" _
483*d83cc019SAndroid Build Coastguard Worker 	/* Raw printk() call, uses default log level (warn) */
484*d83cc019SAndroid Build Coastguard Worker 	"Suspending console\\(s\\) \\(use no_console_suspend to debug\\)" _
485*d83cc019SAndroid Build Coastguard Worker 	"atkbd serio[0-9]+: Failed to (deactivate|enable) keyboard on isa[0-9]+/serio[0-9]+" _
486*d83cc019SAndroid Build Coastguard Worker 	"cache: parent cpu[0-9]+ should not be sleeping" _
487*d83cc019SAndroid Build Coastguard Worker 	"hpet[0-9]+: lost [0-9]+ rtc interrupts" _
488*d83cc019SAndroid Build Coastguard Worker 	/* i915 selftests terminate normally with ENODEV from the
489*d83cc019SAndroid Build Coastguard Worker 	 * module load after the testing finishes, which produces this
490*d83cc019SAndroid Build Coastguard Worker 	 * message.
491*d83cc019SAndroid Build Coastguard Worker 	 */
492*d83cc019SAndroid Build Coastguard Worker 	"i915: probe of [0-9:.]+ failed with error -25" _
493*d83cc019SAndroid Build Coastguard Worker 	/* swiotbl warns even when asked not to */
494*d83cc019SAndroid Build Coastguard Worker 	"mock: DMA: Out of SW-IOMMU space for [0-9]+ bytes" _
495*d83cc019SAndroid Build Coastguard Worker 	"usb usb[0-9]+: root hub lost power or was reset"
496*d83cc019SAndroid Build Coastguard Worker 	;
497*d83cc019SAndroid Build Coastguard Worker #undef _
498*d83cc019SAndroid Build Coastguard Worker 
499*d83cc019SAndroid Build Coastguard Worker static const char igt_piglit_style_dmesg_blacklist[] =
500*d83cc019SAndroid Build Coastguard Worker 	"(\\[drm:|drm_|intel_|i915_)";
501*d83cc019SAndroid Build Coastguard Worker 
init_regex_whitelist(struct settings * settings,GRegex ** re)502*d83cc019SAndroid Build Coastguard Worker static bool init_regex_whitelist(struct settings* settings, GRegex **re)
503*d83cc019SAndroid Build Coastguard Worker {
504*d83cc019SAndroid Build Coastguard Worker 	GError *err = NULL;
505*d83cc019SAndroid Build Coastguard Worker 	const char *regex = settings->piglit_style_dmesg ?
506*d83cc019SAndroid Build Coastguard Worker 		igt_piglit_style_dmesg_blacklist :
507*d83cc019SAndroid Build Coastguard Worker 		igt_dmesg_whitelist;
508*d83cc019SAndroid Build Coastguard Worker 
509*d83cc019SAndroid Build Coastguard Worker 	*re = g_regex_new(regex, G_REGEX_OPTIMIZE, 0, &err);
510*d83cc019SAndroid Build Coastguard Worker 	if (err) {
511*d83cc019SAndroid Build Coastguard Worker 		fprintf(stderr, "Cannot compile dmesg regexp\n");
512*d83cc019SAndroid Build Coastguard Worker 		g_error_free(err);
513*d83cc019SAndroid Build Coastguard Worker 		return false;
514*d83cc019SAndroid Build Coastguard Worker 	}
515*d83cc019SAndroid Build Coastguard Worker 
516*d83cc019SAndroid Build Coastguard Worker 	return true;
517*d83cc019SAndroid Build Coastguard Worker }
518*d83cc019SAndroid Build Coastguard Worker 
parse_dmesg_line(char * line,unsigned * flags,unsigned long long * ts_usec,char * continuation,char ** message)519*d83cc019SAndroid Build Coastguard Worker static bool parse_dmesg_line(char* line,
520*d83cc019SAndroid Build Coastguard Worker 			     unsigned *flags, unsigned long long *ts_usec,
521*d83cc019SAndroid Build Coastguard Worker 			     char *continuation, char **message)
522*d83cc019SAndroid Build Coastguard Worker {
523*d83cc019SAndroid Build Coastguard Worker 	unsigned long long seq;
524*d83cc019SAndroid Build Coastguard Worker 	int s;
525*d83cc019SAndroid Build Coastguard Worker 
526*d83cc019SAndroid Build Coastguard Worker 	s = sscanf(line, "%u,%llu,%llu,%c;", flags, &seq, ts_usec, continuation);
527*d83cc019SAndroid Build Coastguard Worker 	if (s != 4) {
528*d83cc019SAndroid Build Coastguard Worker 		/*
529*d83cc019SAndroid Build Coastguard Worker 		 * Machine readable key/value pairs begin with
530*d83cc019SAndroid Build Coastguard Worker 		 * a space. We ignore them.
531*d83cc019SAndroid Build Coastguard Worker 		 */
532*d83cc019SAndroid Build Coastguard Worker 		if (line[0] != ' ') {
533*d83cc019SAndroid Build Coastguard Worker 			fprintf(stderr, "Cannot parse kmsg record: %s\n", line);
534*d83cc019SAndroid Build Coastguard Worker 		}
535*d83cc019SAndroid Build Coastguard Worker 		return false;
536*d83cc019SAndroid Build Coastguard Worker 	}
537*d83cc019SAndroid Build Coastguard Worker 
538*d83cc019SAndroid Build Coastguard Worker 	*message = strchr(line, ';');
539*d83cc019SAndroid Build Coastguard Worker 	if (!message) {
540*d83cc019SAndroid Build Coastguard Worker 		fprintf(stderr, "No ; found in kmsg record, this shouldn't happen\n");
541*d83cc019SAndroid Build Coastguard Worker 		return false;
542*d83cc019SAndroid Build Coastguard Worker 	}
543*d83cc019SAndroid Build Coastguard Worker 	(*message)++;
544*d83cc019SAndroid Build Coastguard Worker 
545*d83cc019SAndroid Build Coastguard Worker 	return true;
546*d83cc019SAndroid Build Coastguard Worker }
547*d83cc019SAndroid Build Coastguard Worker 
generate_formatted_dmesg_line(char * message,unsigned flags,unsigned long long ts_usec,char ** formatted)548*d83cc019SAndroid Build Coastguard Worker static void generate_formatted_dmesg_line(char *message,
549*d83cc019SAndroid Build Coastguard Worker 					  unsigned flags,
550*d83cc019SAndroid Build Coastguard Worker 					  unsigned long long ts_usec,
551*d83cc019SAndroid Build Coastguard Worker 					  char **formatted)
552*d83cc019SAndroid Build Coastguard Worker {
553*d83cc019SAndroid Build Coastguard Worker 	char prefix[512];
554*d83cc019SAndroid Build Coastguard Worker 	size_t messagelen;
555*d83cc019SAndroid Build Coastguard Worker 	size_t prefixlen;
556*d83cc019SAndroid Build Coastguard Worker 	char *p, *f;
557*d83cc019SAndroid Build Coastguard Worker 
558*d83cc019SAndroid Build Coastguard Worker 	snprintf(prefix, sizeof(prefix),
559*d83cc019SAndroid Build Coastguard Worker 		 "<%u> [%llu.%06llu] ",
560*d83cc019SAndroid Build Coastguard Worker 		 flags & 0x07,
561*d83cc019SAndroid Build Coastguard Worker 		 ts_usec / 1000000,
562*d83cc019SAndroid Build Coastguard Worker 		 ts_usec % 1000000);
563*d83cc019SAndroid Build Coastguard Worker 
564*d83cc019SAndroid Build Coastguard Worker 	messagelen = strlen(message);
565*d83cc019SAndroid Build Coastguard Worker 	prefixlen = strlen(prefix);
566*d83cc019SAndroid Build Coastguard Worker 
567*d83cc019SAndroid Build Coastguard Worker 	/*
568*d83cc019SAndroid Build Coastguard Worker 	 * Decoding the hex escapes only makes the string shorter, so
569*d83cc019SAndroid Build Coastguard Worker 	 * we can use the original length
570*d83cc019SAndroid Build Coastguard Worker 	 */
571*d83cc019SAndroid Build Coastguard Worker 	*formatted = malloc(strlen(prefix) + messagelen + 1);
572*d83cc019SAndroid Build Coastguard Worker 	strcpy(*formatted, prefix);
573*d83cc019SAndroid Build Coastguard Worker 
574*d83cc019SAndroid Build Coastguard Worker 	f = *formatted + prefixlen;
575*d83cc019SAndroid Build Coastguard Worker 	for (p = message; *p; p++, f++) {
576*d83cc019SAndroid Build Coastguard Worker 		if (p - message + 4 < messagelen &&
577*d83cc019SAndroid Build Coastguard Worker 		    p[0] == '\\' && p[1] == 'x') {
578*d83cc019SAndroid Build Coastguard Worker 			int c = 0;
579*d83cc019SAndroid Build Coastguard Worker 			/* newline and tab are not isprint(), but they are isspace() */
580*d83cc019SAndroid Build Coastguard Worker 			if (sscanf(p, "\\x%2x", &c) == 1 &&
581*d83cc019SAndroid Build Coastguard Worker 			    (isprint(c) || isspace(c))) {
582*d83cc019SAndroid Build Coastguard Worker 				*f = c;
583*d83cc019SAndroid Build Coastguard Worker 				p += 3;
584*d83cc019SAndroid Build Coastguard Worker 				continue;
585*d83cc019SAndroid Build Coastguard Worker 			}
586*d83cc019SAndroid Build Coastguard Worker 		}
587*d83cc019SAndroid Build Coastguard Worker 		*f = *p;
588*d83cc019SAndroid Build Coastguard Worker 	}
589*d83cc019SAndroid Build Coastguard Worker 	*f = '\0';
590*d83cc019SAndroid Build Coastguard Worker }
591*d83cc019SAndroid Build Coastguard Worker 
add_dmesg(struct json_object * obj,const char * dmesg,size_t dmesglen,const char * warnings,size_t warningslen)592*d83cc019SAndroid Build Coastguard Worker static void add_dmesg(struct json_object *obj,
593*d83cc019SAndroid Build Coastguard Worker 		      const char *dmesg, size_t dmesglen,
594*d83cc019SAndroid Build Coastguard Worker 		      const char *warnings, size_t warningslen)
595*d83cc019SAndroid Build Coastguard Worker {
596*d83cc019SAndroid Build Coastguard Worker 	json_object_object_add(obj, "dmesg",
597*d83cc019SAndroid Build Coastguard Worker 			       json_object_new_string_len(dmesg, dmesglen));
598*d83cc019SAndroid Build Coastguard Worker 
599*d83cc019SAndroid Build Coastguard Worker 	if (warnings) {
600*d83cc019SAndroid Build Coastguard Worker 		json_object_object_add(obj, "dmesg-warnings",
601*d83cc019SAndroid Build Coastguard Worker 				       json_object_new_string_len(warnings, warningslen));
602*d83cc019SAndroid Build Coastguard Worker 	}
603*d83cc019SAndroid Build Coastguard Worker }
604*d83cc019SAndroid Build Coastguard Worker 
add_empty_dmesgs_where_missing(struct json_object * tests,char * binary,struct subtests * subtests)605*d83cc019SAndroid Build Coastguard Worker static void add_empty_dmesgs_where_missing(struct json_object *tests,
606*d83cc019SAndroid Build Coastguard Worker 					   char *binary,
607*d83cc019SAndroid Build Coastguard Worker 					   struct subtests *subtests)
608*d83cc019SAndroid Build Coastguard Worker {
609*d83cc019SAndroid Build Coastguard Worker 	struct json_object *current_test;
610*d83cc019SAndroid Build Coastguard Worker 	char piglit_name[256];
611*d83cc019SAndroid Build Coastguard Worker 	size_t i;
612*d83cc019SAndroid Build Coastguard Worker 
613*d83cc019SAndroid Build Coastguard Worker 	for (i = 0; i < subtests->size; i++) {
614*d83cc019SAndroid Build Coastguard Worker 		generate_piglit_name(binary, subtests->names[i], piglit_name, sizeof(piglit_name));
615*d83cc019SAndroid Build Coastguard Worker 		current_test = get_or_create_json_object(tests, piglit_name);
616*d83cc019SAndroid Build Coastguard Worker 		if (!json_object_object_get_ex(current_test, "dmesg", NULL)) {
617*d83cc019SAndroid Build Coastguard Worker 			add_dmesg(current_test, "", 0, NULL, 0);
618*d83cc019SAndroid Build Coastguard Worker 		}
619*d83cc019SAndroid Build Coastguard Worker 	}
620*d83cc019SAndroid Build Coastguard Worker 
621*d83cc019SAndroid Build Coastguard Worker }
622*d83cc019SAndroid Build Coastguard Worker 
fill_from_dmesg(int fd,struct settings * settings,char * binary,struct subtests * subtests,struct json_object * tests)623*d83cc019SAndroid Build Coastguard Worker static bool fill_from_dmesg(int fd,
624*d83cc019SAndroid Build Coastguard Worker 			    struct settings *settings,
625*d83cc019SAndroid Build Coastguard Worker 			    char *binary,
626*d83cc019SAndroid Build Coastguard Worker 			    struct subtests *subtests,
627*d83cc019SAndroid Build Coastguard Worker 			    struct json_object *tests)
628*d83cc019SAndroid Build Coastguard Worker {
629*d83cc019SAndroid Build Coastguard Worker 	char *line = NULL, *warnings = NULL, *dmesg = NULL;
630*d83cc019SAndroid Build Coastguard Worker 	size_t linelen = 0, warningslen = 0, dmesglen = 0;
631*d83cc019SAndroid Build Coastguard Worker 	struct json_object *current_test = NULL;
632*d83cc019SAndroid Build Coastguard Worker 	FILE *f = fdopen(fd, "r");
633*d83cc019SAndroid Build Coastguard Worker 	char piglit_name[256];
634*d83cc019SAndroid Build Coastguard Worker 	ssize_t read;
635*d83cc019SAndroid Build Coastguard Worker 	size_t i;
636*d83cc019SAndroid Build Coastguard Worker 	GRegex *re;
637*d83cc019SAndroid Build Coastguard Worker 
638*d83cc019SAndroid Build Coastguard Worker 	if (!f) {
639*d83cc019SAndroid Build Coastguard Worker 		return false;
640*d83cc019SAndroid Build Coastguard Worker 	}
641*d83cc019SAndroid Build Coastguard Worker 
642*d83cc019SAndroid Build Coastguard Worker 	if (!init_regex_whitelist(settings, &re)) {
643*d83cc019SAndroid Build Coastguard Worker 		fclose(f);
644*d83cc019SAndroid Build Coastguard Worker 		return false;
645*d83cc019SAndroid Build Coastguard Worker 	}
646*d83cc019SAndroid Build Coastguard Worker 
647*d83cc019SAndroid Build Coastguard Worker 	while ((read = getline(&line, &linelen, f)) > 0) {
648*d83cc019SAndroid Build Coastguard Worker 		char *formatted;
649*d83cc019SAndroid Build Coastguard Worker 		unsigned flags;
650*d83cc019SAndroid Build Coastguard Worker 		unsigned long long ts_usec;
651*d83cc019SAndroid Build Coastguard Worker 		char continuation;
652*d83cc019SAndroid Build Coastguard Worker 		char *message, *subtest;
653*d83cc019SAndroid Build Coastguard Worker 
654*d83cc019SAndroid Build Coastguard Worker 		if (!parse_dmesg_line(line, &flags, &ts_usec, &continuation, &message))
655*d83cc019SAndroid Build Coastguard Worker 			continue;
656*d83cc019SAndroid Build Coastguard Worker 
657*d83cc019SAndroid Build Coastguard Worker 		generate_formatted_dmesg_line(message, flags, ts_usec, &formatted);
658*d83cc019SAndroid Build Coastguard Worker 
659*d83cc019SAndroid Build Coastguard Worker 		if ((subtest = strstr(message, STARTING_SUBTEST_DMESG)) != NULL) {
660*d83cc019SAndroid Build Coastguard Worker 			if (current_test != NULL) {
661*d83cc019SAndroid Build Coastguard Worker 				/* Done with the previous subtest, file up */
662*d83cc019SAndroid Build Coastguard Worker 				add_dmesg(current_test, dmesg, dmesglen, warnings, warningslen);
663*d83cc019SAndroid Build Coastguard Worker 
664*d83cc019SAndroid Build Coastguard Worker 				free(dmesg);
665*d83cc019SAndroid Build Coastguard Worker 				free(warnings);
666*d83cc019SAndroid Build Coastguard Worker 				dmesg = warnings = NULL;
667*d83cc019SAndroid Build Coastguard Worker 				dmesglen = warningslen = 0;
668*d83cc019SAndroid Build Coastguard Worker 			}
669*d83cc019SAndroid Build Coastguard Worker 
670*d83cc019SAndroid Build Coastguard Worker 			subtest += strlen(STARTING_SUBTEST_DMESG);
671*d83cc019SAndroid Build Coastguard Worker 			generate_piglit_name(binary, subtest, piglit_name, sizeof(piglit_name));
672*d83cc019SAndroid Build Coastguard Worker 			current_test = get_or_create_json_object(tests, piglit_name);
673*d83cc019SAndroid Build Coastguard Worker 		}
674*d83cc019SAndroid Build Coastguard Worker 
675*d83cc019SAndroid Build Coastguard Worker 		if (settings->piglit_style_dmesg) {
676*d83cc019SAndroid Build Coastguard Worker 			if ((flags & 0x07) <= settings->dmesg_warn_level && continuation != 'c' &&
677*d83cc019SAndroid Build Coastguard Worker 			    g_regex_match(re, message, 0, NULL)) {
678*d83cc019SAndroid Build Coastguard Worker 				append_line(&warnings, &warningslen, formatted);
679*d83cc019SAndroid Build Coastguard Worker 			}
680*d83cc019SAndroid Build Coastguard Worker 		} else {
681*d83cc019SAndroid Build Coastguard Worker 			if ((flags & 0x07) <= settings->dmesg_warn_level && continuation != 'c' &&
682*d83cc019SAndroid Build Coastguard Worker 			    !g_regex_match(re, message, 0, NULL)) {
683*d83cc019SAndroid Build Coastguard Worker 				append_line(&warnings, &warningslen, formatted);
684*d83cc019SAndroid Build Coastguard Worker 			}
685*d83cc019SAndroid Build Coastguard Worker 		}
686*d83cc019SAndroid Build Coastguard Worker 		append_line(&dmesg, &dmesglen, formatted);
687*d83cc019SAndroid Build Coastguard Worker 		free(formatted);
688*d83cc019SAndroid Build Coastguard Worker 	}
689*d83cc019SAndroid Build Coastguard Worker 	free(line);
690*d83cc019SAndroid Build Coastguard Worker 
691*d83cc019SAndroid Build Coastguard Worker 	if (current_test != NULL) {
692*d83cc019SAndroid Build Coastguard Worker 		add_dmesg(current_test, dmesg, dmesglen, warnings, warningslen);
693*d83cc019SAndroid Build Coastguard Worker 	} else {
694*d83cc019SAndroid Build Coastguard Worker 		/*
695*d83cc019SAndroid Build Coastguard Worker 		 * Didn't get any subtest messages at all. If there
696*d83cc019SAndroid Build Coastguard Worker 		 * are subtests, add all of the dmesg gotten to all of
697*d83cc019SAndroid Build Coastguard Worker 		 * them.
698*d83cc019SAndroid Build Coastguard Worker 		 */
699*d83cc019SAndroid Build Coastguard Worker 		for (i = 0; i < subtests->size; i++) {
700*d83cc019SAndroid Build Coastguard Worker 			generate_piglit_name(binary, subtests->names[i], piglit_name, sizeof(piglit_name));
701*d83cc019SAndroid Build Coastguard Worker 			current_test = get_or_create_json_object(tests, piglit_name);
702*d83cc019SAndroid Build Coastguard Worker 			/*
703*d83cc019SAndroid Build Coastguard Worker 			 * Don't bother with warnings, any subtests
704*d83cc019SAndroid Build Coastguard Worker 			 * there are would have skip as their result
705*d83cc019SAndroid Build Coastguard Worker 			 * anyway.
706*d83cc019SAndroid Build Coastguard Worker 			 */
707*d83cc019SAndroid Build Coastguard Worker 			add_dmesg(current_test, dmesg, dmesglen, NULL, 0);
708*d83cc019SAndroid Build Coastguard Worker 		}
709*d83cc019SAndroid Build Coastguard Worker 
710*d83cc019SAndroid Build Coastguard Worker 		if (subtests->size == 0) {
711*d83cc019SAndroid Build Coastguard Worker 			generate_piglit_name(binary, NULL, piglit_name, sizeof(piglit_name));
712*d83cc019SAndroid Build Coastguard Worker 			current_test = get_or_create_json_object(tests, piglit_name);
713*d83cc019SAndroid Build Coastguard Worker 			add_dmesg(current_test, dmesg, dmesglen, warnings, warningslen);
714*d83cc019SAndroid Build Coastguard Worker 		}
715*d83cc019SAndroid Build Coastguard Worker 	}
716*d83cc019SAndroid Build Coastguard Worker 
717*d83cc019SAndroid Build Coastguard Worker 	add_empty_dmesgs_where_missing(tests, binary, subtests);
718*d83cc019SAndroid Build Coastguard Worker 
719*d83cc019SAndroid Build Coastguard Worker 	free(dmesg);
720*d83cc019SAndroid Build Coastguard Worker 	free(warnings);
721*d83cc019SAndroid Build Coastguard Worker 	g_regex_unref(re);
722*d83cc019SAndroid Build Coastguard Worker 	fclose(f);
723*d83cc019SAndroid Build Coastguard Worker 	return true;
724*d83cc019SAndroid Build Coastguard Worker }
725*d83cc019SAndroid Build Coastguard Worker 
result_from_exitcode(int exitcode)726*d83cc019SAndroid Build Coastguard Worker static const char *result_from_exitcode(int exitcode)
727*d83cc019SAndroid Build Coastguard Worker {
728*d83cc019SAndroid Build Coastguard Worker 	switch (exitcode) {
729*d83cc019SAndroid Build Coastguard Worker 	case IGT_EXIT_SKIP:
730*d83cc019SAndroid Build Coastguard Worker 		return "skip";
731*d83cc019SAndroid Build Coastguard Worker 	case IGT_EXIT_SUCCESS:
732*d83cc019SAndroid Build Coastguard Worker 		return "pass";
733*d83cc019SAndroid Build Coastguard Worker 	case IGT_EXIT_INVALID:
734*d83cc019SAndroid Build Coastguard Worker 		return "notrun";
735*d83cc019SAndroid Build Coastguard Worker 	case INCOMPLETE_EXITCODE:
736*d83cc019SAndroid Build Coastguard Worker 		return "incomplete";
737*d83cc019SAndroid Build Coastguard Worker 	default:
738*d83cc019SAndroid Build Coastguard Worker 		return "fail";
739*d83cc019SAndroid Build Coastguard Worker 	}
740*d83cc019SAndroid Build Coastguard Worker }
741*d83cc019SAndroid Build Coastguard Worker 
add_subtest(struct subtests * subtests,char * subtest)742*d83cc019SAndroid Build Coastguard Worker static void add_subtest(struct subtests *subtests, char *subtest)
743*d83cc019SAndroid Build Coastguard Worker {
744*d83cc019SAndroid Build Coastguard Worker 	size_t len = strlen(subtest);
745*d83cc019SAndroid Build Coastguard Worker 	size_t i;
746*d83cc019SAndroid Build Coastguard Worker 
747*d83cc019SAndroid Build Coastguard Worker 	if (len == 0)
748*d83cc019SAndroid Build Coastguard Worker 		return;
749*d83cc019SAndroid Build Coastguard Worker 
750*d83cc019SAndroid Build Coastguard Worker 	if (subtest[len - 1] == '\n')
751*d83cc019SAndroid Build Coastguard Worker 		subtest[len - 1] = '\0';
752*d83cc019SAndroid Build Coastguard Worker 
753*d83cc019SAndroid Build Coastguard Worker 	/* Don't add if we already have this subtest */
754*d83cc019SAndroid Build Coastguard Worker 	for (i = 0; i < subtests->size; i++)
755*d83cc019SAndroid Build Coastguard Worker 		if (!strcmp(subtest, subtests->names[i]))
756*d83cc019SAndroid Build Coastguard Worker 			return;
757*d83cc019SAndroid Build Coastguard Worker 
758*d83cc019SAndroid Build Coastguard Worker 	subtests->size++;
759*d83cc019SAndroid Build Coastguard Worker 	subtests->names = realloc(subtests->names, sizeof(*subtests->names) * subtests->size);
760*d83cc019SAndroid Build Coastguard Worker 	subtests->names[subtests->size - 1] = subtest;
761*d83cc019SAndroid Build Coastguard Worker }
762*d83cc019SAndroid Build Coastguard Worker 
free_subtests(struct subtests * subtests)763*d83cc019SAndroid Build Coastguard Worker static void free_subtests(struct subtests *subtests)
764*d83cc019SAndroid Build Coastguard Worker {
765*d83cc019SAndroid Build Coastguard Worker 	size_t i;
766*d83cc019SAndroid Build Coastguard Worker 
767*d83cc019SAndroid Build Coastguard Worker 	for (i = 0; i < subtests->size; i++)
768*d83cc019SAndroid Build Coastguard Worker 		free(subtests->names[i]);
769*d83cc019SAndroid Build Coastguard Worker 	free(subtests->names);
770*d83cc019SAndroid Build Coastguard Worker }
771*d83cc019SAndroid Build Coastguard Worker 
fill_from_journal(int fd,struct job_list_entry * entry,struct subtests * subtests,struct results * results)772*d83cc019SAndroid Build Coastguard Worker static void fill_from_journal(int fd,
773*d83cc019SAndroid Build Coastguard Worker 			      struct job_list_entry *entry,
774*d83cc019SAndroid Build Coastguard Worker 			      struct subtests *subtests,
775*d83cc019SAndroid Build Coastguard Worker 			      struct results *results)
776*d83cc019SAndroid Build Coastguard Worker {
777*d83cc019SAndroid Build Coastguard Worker 	FILE *f = fdopen(fd, "r");
778*d83cc019SAndroid Build Coastguard Worker 	char *line = NULL;
779*d83cc019SAndroid Build Coastguard Worker 	size_t linelen = 0;
780*d83cc019SAndroid Build Coastguard Worker 	ssize_t read;
781*d83cc019SAndroid Build Coastguard Worker 	char exitline[] = "exit:";
782*d83cc019SAndroid Build Coastguard Worker 	char timeoutline[] = "timeout:";
783*d83cc019SAndroid Build Coastguard Worker 	int exitcode = INCOMPLETE_EXITCODE;
784*d83cc019SAndroid Build Coastguard Worker 	bool has_timeout = false;
785*d83cc019SAndroid Build Coastguard Worker 	struct json_object *tests = results->tests;
786*d83cc019SAndroid Build Coastguard Worker 	struct json_object *runtimes = results->runtimes;
787*d83cc019SAndroid Build Coastguard Worker 
788*d83cc019SAndroid Build Coastguard Worker 	while ((read = getline(&line, &linelen, f)) > 0) {
789*d83cc019SAndroid Build Coastguard Worker 		if (read >= strlen(exitline) && !memcmp(line, exitline, strlen(exitline))) {
790*d83cc019SAndroid Build Coastguard Worker 			char *p = strchr(line, '(');
791*d83cc019SAndroid Build Coastguard Worker 			char piglit_name[256];
792*d83cc019SAndroid Build Coastguard Worker 			double time = 0.0;
793*d83cc019SAndroid Build Coastguard Worker 			struct json_object *obj;
794*d83cc019SAndroid Build Coastguard Worker 
795*d83cc019SAndroid Build Coastguard Worker 			exitcode = atoi(line + strlen(exitline));
796*d83cc019SAndroid Build Coastguard Worker 
797*d83cc019SAndroid Build Coastguard Worker 			if (p)
798*d83cc019SAndroid Build Coastguard Worker 				time = strtod(p + 1, NULL);
799*d83cc019SAndroid Build Coastguard Worker 
800*d83cc019SAndroid Build Coastguard Worker 			generate_piglit_name(entry->binary, NULL, piglit_name, sizeof(piglit_name));
801*d83cc019SAndroid Build Coastguard Worker 			obj = get_or_create_json_object(runtimes, piglit_name);
802*d83cc019SAndroid Build Coastguard Worker 			add_runtime(obj, time);
803*d83cc019SAndroid Build Coastguard Worker 
804*d83cc019SAndroid Build Coastguard Worker 			/* If no subtests, the test result node also gets the runtime */
805*d83cc019SAndroid Build Coastguard Worker 			if (subtests->size == 0 && entry->subtest_count == 0) {
806*d83cc019SAndroid Build Coastguard Worker 				obj = get_or_create_json_object(tests, piglit_name);
807*d83cc019SAndroid Build Coastguard Worker 				add_runtime(obj, time);
808*d83cc019SAndroid Build Coastguard Worker 			}
809*d83cc019SAndroid Build Coastguard Worker 		} else if (read >= strlen(timeoutline) && !memcmp(line, timeoutline, strlen(timeoutline))) {
810*d83cc019SAndroid Build Coastguard Worker 			has_timeout = true;
811*d83cc019SAndroid Build Coastguard Worker 
812*d83cc019SAndroid Build Coastguard Worker 			if (subtests->size) {
813*d83cc019SAndroid Build Coastguard Worker 				/* Assign the timeout to the previously appeared subtest */
814*d83cc019SAndroid Build Coastguard Worker 				char *last_subtest = subtests->names[subtests->size - 1];
815*d83cc019SAndroid Build Coastguard Worker 				char piglit_name[256];
816*d83cc019SAndroid Build Coastguard Worker 				char *p = strchr(line, '(');
817*d83cc019SAndroid Build Coastguard Worker 				double time = 0.0;
818*d83cc019SAndroid Build Coastguard Worker 				struct json_object *obj;
819*d83cc019SAndroid Build Coastguard Worker 
820*d83cc019SAndroid Build Coastguard Worker 				generate_piglit_name(entry->binary, last_subtest, piglit_name, sizeof(piglit_name));
821*d83cc019SAndroid Build Coastguard Worker 				obj = get_or_create_json_object(tests, piglit_name);
822*d83cc019SAndroid Build Coastguard Worker 
823*d83cc019SAndroid Build Coastguard Worker 				set_result(obj, "timeout");
824*d83cc019SAndroid Build Coastguard Worker 
825*d83cc019SAndroid Build Coastguard Worker 				if (p)
826*d83cc019SAndroid Build Coastguard Worker 					time = strtod(p + 1, NULL);
827*d83cc019SAndroid Build Coastguard Worker 
828*d83cc019SAndroid Build Coastguard Worker 				/* Add runtime for the subtest... */
829*d83cc019SAndroid Build Coastguard Worker 				add_runtime(obj, time);
830*d83cc019SAndroid Build Coastguard Worker 
831*d83cc019SAndroid Build Coastguard Worker 				/* ... and also for the binary */
832*d83cc019SAndroid Build Coastguard Worker 				generate_piglit_name(entry->binary, NULL, piglit_name, sizeof(piglit_name));
833*d83cc019SAndroid Build Coastguard Worker 				obj = get_or_create_json_object(runtimes, piglit_name);
834*d83cc019SAndroid Build Coastguard Worker 				add_runtime(obj, time);
835*d83cc019SAndroid Build Coastguard Worker 			}
836*d83cc019SAndroid Build Coastguard Worker 		} else {
837*d83cc019SAndroid Build Coastguard Worker 			add_subtest(subtests, strdup(line));
838*d83cc019SAndroid Build Coastguard Worker 		}
839*d83cc019SAndroid Build Coastguard Worker 	}
840*d83cc019SAndroid Build Coastguard Worker 
841*d83cc019SAndroid Build Coastguard Worker 	if (subtests->size == 0) {
842*d83cc019SAndroid Build Coastguard Worker 		char *subtestname = NULL;
843*d83cc019SAndroid Build Coastguard Worker 		char piglit_name[256];
844*d83cc019SAndroid Build Coastguard Worker 		struct json_object *obj;
845*d83cc019SAndroid Build Coastguard Worker 		const char *result = has_timeout ? "timeout" : result_from_exitcode(exitcode);
846*d83cc019SAndroid Build Coastguard Worker 
847*d83cc019SAndroid Build Coastguard Worker 		/*
848*d83cc019SAndroid Build Coastguard Worker 		 * If the test was killed before it printed that it's
849*d83cc019SAndroid Build Coastguard Worker 		 * entering a subtest, we would incorrectly generate
850*d83cc019SAndroid Build Coastguard Worker 		 * results as the binary had no subtests. If we know
851*d83cc019SAndroid Build Coastguard Worker 		 * otherwise, do otherwise.
852*d83cc019SAndroid Build Coastguard Worker 		 */
853*d83cc019SAndroid Build Coastguard Worker 		if (entry->subtest_count > 0) {
854*d83cc019SAndroid Build Coastguard Worker 			subtestname = entry->subtests[0];
855*d83cc019SAndroid Build Coastguard Worker 			add_subtest(subtests, strdup(subtestname));
856*d83cc019SAndroid Build Coastguard Worker 		}
857*d83cc019SAndroid Build Coastguard Worker 
858*d83cc019SAndroid Build Coastguard Worker 		generate_piglit_name(entry->binary, subtestname, piglit_name, sizeof(piglit_name));
859*d83cc019SAndroid Build Coastguard Worker 		obj = get_or_create_json_object(tests, piglit_name);
860*d83cc019SAndroid Build Coastguard Worker 		set_result(obj, result);
861*d83cc019SAndroid Build Coastguard Worker 	}
862*d83cc019SAndroid Build Coastguard Worker 
863*d83cc019SAndroid Build Coastguard Worker 	free(line);
864*d83cc019SAndroid Build Coastguard Worker 	fclose(f);
865*d83cc019SAndroid Build Coastguard Worker }
866*d83cc019SAndroid Build Coastguard Worker 
override_result_single(struct json_object * obj)867*d83cc019SAndroid Build Coastguard Worker static void override_result_single(struct json_object *obj)
868*d83cc019SAndroid Build Coastguard Worker {
869*d83cc019SAndroid Build Coastguard Worker 	const char *errtext = "", *result = "";
870*d83cc019SAndroid Build Coastguard Worker 	struct json_object *textobj;
871*d83cc019SAndroid Build Coastguard Worker 	bool dmesgwarns = false;
872*d83cc019SAndroid Build Coastguard Worker 
873*d83cc019SAndroid Build Coastguard Worker 	if (json_object_object_get_ex(obj, "err", &textobj))
874*d83cc019SAndroid Build Coastguard Worker 		errtext = json_object_get_string(textobj);
875*d83cc019SAndroid Build Coastguard Worker 	if (json_object_object_get_ex(obj, "result", &textobj))
876*d83cc019SAndroid Build Coastguard Worker 		result = json_object_get_string(textobj);
877*d83cc019SAndroid Build Coastguard Worker 	if (json_object_object_get_ex(obj, "dmesg-warnings", &textobj))
878*d83cc019SAndroid Build Coastguard Worker 		dmesgwarns = true;
879*d83cc019SAndroid Build Coastguard Worker 
880*d83cc019SAndroid Build Coastguard Worker 	if (!strcmp(result, "pass") &&
881*d83cc019SAndroid Build Coastguard Worker 	    count_lines(errtext, errtext + strlen(errtext)) > 2) {
882*d83cc019SAndroid Build Coastguard Worker 		set_result(obj, "warn");
883*d83cc019SAndroid Build Coastguard Worker 		result = "warn";
884*d83cc019SAndroid Build Coastguard Worker 	}
885*d83cc019SAndroid Build Coastguard Worker 
886*d83cc019SAndroid Build Coastguard Worker 	if (dmesgwarns) {
887*d83cc019SAndroid Build Coastguard Worker 		if (!strcmp(result, "pass") || !strcmp(result, "warn")) {
888*d83cc019SAndroid Build Coastguard Worker 			set_result(obj, "dmesg-warn");
889*d83cc019SAndroid Build Coastguard Worker 		} else if (!strcmp(result, "fail")) {
890*d83cc019SAndroid Build Coastguard Worker 			set_result(obj, "dmesg-fail");
891*d83cc019SAndroid Build Coastguard Worker 		}
892*d83cc019SAndroid Build Coastguard Worker 	}
893*d83cc019SAndroid Build Coastguard Worker }
894*d83cc019SAndroid Build Coastguard Worker 
override_results(char * binary,struct subtests * subtests,struct json_object * tests)895*d83cc019SAndroid Build Coastguard Worker static void override_results(char *binary,
896*d83cc019SAndroid Build Coastguard Worker 			     struct subtests *subtests,
897*d83cc019SAndroid Build Coastguard Worker 			     struct json_object *tests)
898*d83cc019SAndroid Build Coastguard Worker {
899*d83cc019SAndroid Build Coastguard Worker 	struct json_object *obj;
900*d83cc019SAndroid Build Coastguard Worker 	char piglit_name[256];
901*d83cc019SAndroid Build Coastguard Worker 	size_t i;
902*d83cc019SAndroid Build Coastguard Worker 
903*d83cc019SAndroid Build Coastguard Worker 	if (subtests->size == 0) {
904*d83cc019SAndroid Build Coastguard Worker 		generate_piglit_name(binary, NULL, piglit_name, sizeof(piglit_name));
905*d83cc019SAndroid Build Coastguard Worker 		obj = get_or_create_json_object(tests, piglit_name);
906*d83cc019SAndroid Build Coastguard Worker 		override_result_single(obj);
907*d83cc019SAndroid Build Coastguard Worker 		return;
908*d83cc019SAndroid Build Coastguard Worker 	}
909*d83cc019SAndroid Build Coastguard Worker 
910*d83cc019SAndroid Build Coastguard Worker 	for (i = 0; i < subtests->size; i++) {
911*d83cc019SAndroid Build Coastguard Worker 		generate_piglit_name(binary, subtests->names[i], piglit_name, sizeof(piglit_name));
912*d83cc019SAndroid Build Coastguard Worker 		obj = get_or_create_json_object(tests, piglit_name);
913*d83cc019SAndroid Build Coastguard Worker 		override_result_single(obj);
914*d83cc019SAndroid Build Coastguard Worker 	}
915*d83cc019SAndroid Build Coastguard Worker }
916*d83cc019SAndroid Build Coastguard Worker 
get_totals_object(struct json_object * totals,const char * key)917*d83cc019SAndroid Build Coastguard Worker static struct json_object *get_totals_object(struct json_object *totals,
918*d83cc019SAndroid Build Coastguard Worker 					     const char *key)
919*d83cc019SAndroid Build Coastguard Worker {
920*d83cc019SAndroid Build Coastguard Worker 	struct json_object *obj = NULL;
921*d83cc019SAndroid Build Coastguard Worker 
922*d83cc019SAndroid Build Coastguard Worker 	if (json_object_object_get_ex(totals, key, &obj))
923*d83cc019SAndroid Build Coastguard Worker 		return obj;
924*d83cc019SAndroid Build Coastguard Worker 
925*d83cc019SAndroid Build Coastguard Worker 	obj = json_object_new_object();
926*d83cc019SAndroid Build Coastguard Worker 	json_object_object_add(totals, key, obj);
927*d83cc019SAndroid Build Coastguard Worker 
928*d83cc019SAndroid Build Coastguard Worker 	json_object_object_add(obj, "crash", json_object_new_int(0));
929*d83cc019SAndroid Build Coastguard Worker 	json_object_object_add(obj, "pass", json_object_new_int(0));
930*d83cc019SAndroid Build Coastguard Worker 	json_object_object_add(obj, "dmesg-fail", json_object_new_int(0));
931*d83cc019SAndroid Build Coastguard Worker 	json_object_object_add(obj, "dmesg-warn", json_object_new_int(0));
932*d83cc019SAndroid Build Coastguard Worker 	json_object_object_add(obj, "skip", json_object_new_int(0));
933*d83cc019SAndroid Build Coastguard Worker 	json_object_object_add(obj, "incomplete", json_object_new_int(0));
934*d83cc019SAndroid Build Coastguard Worker 	json_object_object_add(obj, "timeout", json_object_new_int(0));
935*d83cc019SAndroid Build Coastguard Worker 	json_object_object_add(obj, "notrun", json_object_new_int(0));
936*d83cc019SAndroid Build Coastguard Worker 	json_object_object_add(obj, "fail", json_object_new_int(0));
937*d83cc019SAndroid Build Coastguard Worker 	json_object_object_add(obj, "warn", json_object_new_int(0));
938*d83cc019SAndroid Build Coastguard Worker 
939*d83cc019SAndroid Build Coastguard Worker 	return obj;
940*d83cc019SAndroid Build Coastguard Worker }
941*d83cc019SAndroid Build Coastguard Worker 
add_result_to_totals(struct json_object * totals,const char * result)942*d83cc019SAndroid Build Coastguard Worker static void add_result_to_totals(struct json_object *totals,
943*d83cc019SAndroid Build Coastguard Worker 				 const char *result)
944*d83cc019SAndroid Build Coastguard Worker {
945*d83cc019SAndroid Build Coastguard Worker 	json_object *numobj = NULL;
946*d83cc019SAndroid Build Coastguard Worker 	int old;
947*d83cc019SAndroid Build Coastguard Worker 
948*d83cc019SAndroid Build Coastguard Worker 	if (!json_object_object_get_ex(totals, result, &numobj)) {
949*d83cc019SAndroid Build Coastguard Worker 		fprintf(stderr, "Warning: Totals object without count for %s\n", result);
950*d83cc019SAndroid Build Coastguard Worker 		return;
951*d83cc019SAndroid Build Coastguard Worker 	}
952*d83cc019SAndroid Build Coastguard Worker 
953*d83cc019SAndroid Build Coastguard Worker 	old = json_object_get_int(numobj);
954*d83cc019SAndroid Build Coastguard Worker 	json_object_object_add(totals, result, json_object_new_int(old + 1));
955*d83cc019SAndroid Build Coastguard Worker }
956*d83cc019SAndroid Build Coastguard Worker 
add_to_totals(const char * binary,struct subtests * subtests,struct results * results)957*d83cc019SAndroid Build Coastguard Worker static void add_to_totals(const char *binary,
958*d83cc019SAndroid Build Coastguard Worker 			  struct subtests *subtests,
959*d83cc019SAndroid Build Coastguard Worker 			  struct results *results)
960*d83cc019SAndroid Build Coastguard Worker {
961*d83cc019SAndroid Build Coastguard Worker 	struct json_object *test, *resultobj, *emptystrtotal, *roottotal, *binarytotal;
962*d83cc019SAndroid Build Coastguard Worker 	char piglit_name[256];
963*d83cc019SAndroid Build Coastguard Worker 	const char *result;
964*d83cc019SAndroid Build Coastguard Worker 	size_t i;
965*d83cc019SAndroid Build Coastguard Worker 
966*d83cc019SAndroid Build Coastguard Worker 	generate_piglit_name(binary, NULL, piglit_name, sizeof(piglit_name));
967*d83cc019SAndroid Build Coastguard Worker 	emptystrtotal = get_totals_object(results->totals, "");
968*d83cc019SAndroid Build Coastguard Worker 	roottotal = get_totals_object(results->totals, "root");
969*d83cc019SAndroid Build Coastguard Worker 	binarytotal = get_totals_object(results->totals, piglit_name);
970*d83cc019SAndroid Build Coastguard Worker 
971*d83cc019SAndroid Build Coastguard Worker 	if (subtests->size == 0) {
972*d83cc019SAndroid Build Coastguard Worker 		test = get_or_create_json_object(results->tests, piglit_name);
973*d83cc019SAndroid Build Coastguard Worker 		if (!json_object_object_get_ex(test, "result", &resultobj)) {
974*d83cc019SAndroid Build Coastguard Worker 			fprintf(stderr, "Warning: No results set for %s\n", piglit_name);
975*d83cc019SAndroid Build Coastguard Worker 			return;
976*d83cc019SAndroid Build Coastguard Worker 		}
977*d83cc019SAndroid Build Coastguard Worker 		result = json_object_get_string(resultobj);
978*d83cc019SAndroid Build Coastguard Worker 		add_result_to_totals(emptystrtotal, result);
979*d83cc019SAndroid Build Coastguard Worker 		add_result_to_totals(roottotal, result);
980*d83cc019SAndroid Build Coastguard Worker 		add_result_to_totals(binarytotal, result);
981*d83cc019SAndroid Build Coastguard Worker 		return;
982*d83cc019SAndroid Build Coastguard Worker 	}
983*d83cc019SAndroid Build Coastguard Worker 
984*d83cc019SAndroid Build Coastguard Worker 	for (i = 0; i < subtests->size; i++) {
985*d83cc019SAndroid Build Coastguard Worker 		generate_piglit_name(binary, subtests->names[i], piglit_name, sizeof(piglit_name));
986*d83cc019SAndroid Build Coastguard Worker 		test = get_or_create_json_object(results->tests, piglit_name);
987*d83cc019SAndroid Build Coastguard Worker 		if (!json_object_object_get_ex(test, "result", &resultobj)) {
988*d83cc019SAndroid Build Coastguard Worker 			fprintf(stderr, "Warning: No results set for %s\n", piglit_name);
989*d83cc019SAndroid Build Coastguard Worker 			return;
990*d83cc019SAndroid Build Coastguard Worker 		}
991*d83cc019SAndroid Build Coastguard Worker 		result = json_object_get_string(resultobj);
992*d83cc019SAndroid Build Coastguard Worker 		add_result_to_totals(emptystrtotal, result);
993*d83cc019SAndroid Build Coastguard Worker 		add_result_to_totals(roottotal, result);
994*d83cc019SAndroid Build Coastguard Worker 		add_result_to_totals(binarytotal, result);
995*d83cc019SAndroid Build Coastguard Worker 	}
996*d83cc019SAndroid Build Coastguard Worker }
997*d83cc019SAndroid Build Coastguard Worker 
parse_test_directory(int dirfd,struct job_list_entry * entry,struct settings * settings,struct results * results)998*d83cc019SAndroid Build Coastguard Worker static bool parse_test_directory(int dirfd,
999*d83cc019SAndroid Build Coastguard Worker 				 struct job_list_entry *entry,
1000*d83cc019SAndroid Build Coastguard Worker 				 struct settings *settings,
1001*d83cc019SAndroid Build Coastguard Worker 				 struct results *results)
1002*d83cc019SAndroid Build Coastguard Worker {
1003*d83cc019SAndroid Build Coastguard Worker 	int fds[_F_LAST];
1004*d83cc019SAndroid Build Coastguard Worker 	struct subtests subtests = {};
1005*d83cc019SAndroid Build Coastguard Worker 	bool status = true;
1006*d83cc019SAndroid Build Coastguard Worker 
1007*d83cc019SAndroid Build Coastguard Worker 	if (!open_output_files(dirfd, fds, false)) {
1008*d83cc019SAndroid Build Coastguard Worker 		fprintf(stderr, "Error opening output files\n");
1009*d83cc019SAndroid Build Coastguard Worker 		return false;
1010*d83cc019SAndroid Build Coastguard Worker 	}
1011*d83cc019SAndroid Build Coastguard Worker 
1012*d83cc019SAndroid Build Coastguard Worker 	/*
1013*d83cc019SAndroid Build Coastguard Worker 	 * fill_from_journal fills the subtests struct and adds
1014*d83cc019SAndroid Build Coastguard Worker 	 * timeout results where applicable.
1015*d83cc019SAndroid Build Coastguard Worker 	 */
1016*d83cc019SAndroid Build Coastguard Worker 	fill_from_journal(fds[_F_JOURNAL], entry, &subtests, results);
1017*d83cc019SAndroid Build Coastguard Worker 
1018*d83cc019SAndroid Build Coastguard Worker 	if (!fill_from_output(fds[_F_OUT], entry->binary, "out", &subtests, results->tests) ||
1019*d83cc019SAndroid Build Coastguard Worker 	    !fill_from_output(fds[_F_ERR], entry->binary, "err", &subtests, results->tests) ||
1020*d83cc019SAndroid Build Coastguard Worker 	    !fill_from_dmesg(fds[_F_DMESG], settings, entry->binary, &subtests, results->tests)) {
1021*d83cc019SAndroid Build Coastguard Worker 		fprintf(stderr, "Error parsing output files\n");
1022*d83cc019SAndroid Build Coastguard Worker 		status = false;
1023*d83cc019SAndroid Build Coastguard Worker 		goto parse_output_end;
1024*d83cc019SAndroid Build Coastguard Worker 	}
1025*d83cc019SAndroid Build Coastguard Worker 
1026*d83cc019SAndroid Build Coastguard Worker 	override_results(entry->binary, &subtests, results->tests);
1027*d83cc019SAndroid Build Coastguard Worker 	add_to_totals(entry->binary, &subtests, results);
1028*d83cc019SAndroid Build Coastguard Worker 
1029*d83cc019SAndroid Build Coastguard Worker  parse_output_end:
1030*d83cc019SAndroid Build Coastguard Worker 	close_outputs(fds);
1031*d83cc019SAndroid Build Coastguard Worker 	free_subtests(&subtests);
1032*d83cc019SAndroid Build Coastguard Worker 
1033*d83cc019SAndroid Build Coastguard Worker 	return status;
1034*d83cc019SAndroid Build Coastguard Worker }
1035*d83cc019SAndroid Build Coastguard Worker 
try_add_notrun_results(const struct job_list_entry * entry,const struct settings * settings,struct results * results)1036*d83cc019SAndroid Build Coastguard Worker static void try_add_notrun_results(const struct job_list_entry *entry,
1037*d83cc019SAndroid Build Coastguard Worker 				   const struct settings *settings,
1038*d83cc019SAndroid Build Coastguard Worker 				   struct results *results)
1039*d83cc019SAndroid Build Coastguard Worker {
1040*d83cc019SAndroid Build Coastguard Worker 	struct subtests subtests = {};
1041*d83cc019SAndroid Build Coastguard Worker 	struct json_object *current_test;
1042*d83cc019SAndroid Build Coastguard Worker 	size_t i;
1043*d83cc019SAndroid Build Coastguard Worker 
1044*d83cc019SAndroid Build Coastguard Worker 	if (entry->subtest_count == 0) {
1045*d83cc019SAndroid Build Coastguard Worker 		char piglit_name[256];
1046*d83cc019SAndroid Build Coastguard Worker 
1047*d83cc019SAndroid Build Coastguard Worker 		/* We cannot distinguish no-subtests from run-all-subtests in multiple-mode */
1048*d83cc019SAndroid Build Coastguard Worker 		if (settings->multiple_mode)
1049*d83cc019SAndroid Build Coastguard Worker 			return;
1050*d83cc019SAndroid Build Coastguard Worker 		generate_piglit_name(entry->binary, NULL, piglit_name, sizeof(piglit_name));
1051*d83cc019SAndroid Build Coastguard Worker 		current_test = get_or_create_json_object(results->tests, piglit_name);
1052*d83cc019SAndroid Build Coastguard Worker 		json_object_object_add(current_test, "out", json_object_new_string(""));
1053*d83cc019SAndroid Build Coastguard Worker 		json_object_object_add(current_test, "err", json_object_new_string(""));
1054*d83cc019SAndroid Build Coastguard Worker 		json_object_object_add(current_test, "dmesg", json_object_new_string(""));
1055*d83cc019SAndroid Build Coastguard Worker 		json_object_object_add(current_test, "result", json_object_new_string("notrun"));
1056*d83cc019SAndroid Build Coastguard Worker 	}
1057*d83cc019SAndroid Build Coastguard Worker 
1058*d83cc019SAndroid Build Coastguard Worker 	for (i = 0; i < entry->subtest_count; i++) {
1059*d83cc019SAndroid Build Coastguard Worker 		char piglit_name[256];
1060*d83cc019SAndroid Build Coastguard Worker 
1061*d83cc019SAndroid Build Coastguard Worker 		generate_piglit_name(entry->binary, entry->subtests[i], piglit_name, sizeof(piglit_name));
1062*d83cc019SAndroid Build Coastguard Worker 		current_test = get_or_create_json_object(results->tests, piglit_name);
1063*d83cc019SAndroid Build Coastguard Worker 		json_object_object_add(current_test, "out", json_object_new_string(""));
1064*d83cc019SAndroid Build Coastguard Worker 		json_object_object_add(current_test, "err", json_object_new_string(""));
1065*d83cc019SAndroid Build Coastguard Worker 		json_object_object_add(current_test, "dmesg", json_object_new_string(""));
1066*d83cc019SAndroid Build Coastguard Worker 		json_object_object_add(current_test, "result", json_object_new_string("notrun"));
1067*d83cc019SAndroid Build Coastguard Worker 		add_subtest(&subtests, strdup(entry->subtests[i]));
1068*d83cc019SAndroid Build Coastguard Worker 	}
1069*d83cc019SAndroid Build Coastguard Worker 
1070*d83cc019SAndroid Build Coastguard Worker 	add_to_totals(entry->binary, &subtests, results);
1071*d83cc019SAndroid Build Coastguard Worker 	free_subtests(&subtests);
1072*d83cc019SAndroid Build Coastguard Worker }
1073*d83cc019SAndroid Build Coastguard Worker 
create_result_root_nodes(struct json_object * root,struct results * results)1074*d83cc019SAndroid Build Coastguard Worker static void create_result_root_nodes(struct json_object *root,
1075*d83cc019SAndroid Build Coastguard Worker 				     struct results *results)
1076*d83cc019SAndroid Build Coastguard Worker {
1077*d83cc019SAndroid Build Coastguard Worker 	results->tests = json_object_new_object();
1078*d83cc019SAndroid Build Coastguard Worker 	json_object_object_add(root, "tests", results->tests);
1079*d83cc019SAndroid Build Coastguard Worker 	results->totals = json_object_new_object();
1080*d83cc019SAndroid Build Coastguard Worker 	json_object_object_add(root, "totals", results->totals);
1081*d83cc019SAndroid Build Coastguard Worker 	results->runtimes = json_object_new_object();
1082*d83cc019SAndroid Build Coastguard Worker 	json_object_object_add(root, "runtimes", results->runtimes);
1083*d83cc019SAndroid Build Coastguard Worker }
1084*d83cc019SAndroid Build Coastguard Worker 
generate_results_json(int dirfd)1085*d83cc019SAndroid Build Coastguard Worker struct json_object *generate_results_json(int dirfd)
1086*d83cc019SAndroid Build Coastguard Worker {
1087*d83cc019SAndroid Build Coastguard Worker 	struct settings settings;
1088*d83cc019SAndroid Build Coastguard Worker 	struct job_list job_list;
1089*d83cc019SAndroid Build Coastguard Worker 	struct json_object *obj, *elapsed;
1090*d83cc019SAndroid Build Coastguard Worker 	struct results results;
1091*d83cc019SAndroid Build Coastguard Worker 	int testdirfd, fd;
1092*d83cc019SAndroid Build Coastguard Worker 	size_t i;
1093*d83cc019SAndroid Build Coastguard Worker 
1094*d83cc019SAndroid Build Coastguard Worker 	init_settings(&settings);
1095*d83cc019SAndroid Build Coastguard Worker 	init_job_list(&job_list);
1096*d83cc019SAndroid Build Coastguard Worker 
1097*d83cc019SAndroid Build Coastguard Worker 	if (!read_settings_from_dir(&settings, dirfd)) {
1098*d83cc019SAndroid Build Coastguard Worker 		fprintf(stderr, "resultgen: Cannot parse settings\n");
1099*d83cc019SAndroid Build Coastguard Worker 		return NULL;
1100*d83cc019SAndroid Build Coastguard Worker 	}
1101*d83cc019SAndroid Build Coastguard Worker 
1102*d83cc019SAndroid Build Coastguard Worker 	if (!read_job_list(&job_list, dirfd)) {
1103*d83cc019SAndroid Build Coastguard Worker 		fprintf(stderr, "resultgen: Cannot parse job list\n");
1104*d83cc019SAndroid Build Coastguard Worker 		return NULL;
1105*d83cc019SAndroid Build Coastguard Worker 	}
1106*d83cc019SAndroid Build Coastguard Worker 
1107*d83cc019SAndroid Build Coastguard Worker 	obj = json_object_new_object();
1108*d83cc019SAndroid Build Coastguard Worker 	json_object_object_add(obj, "__type__", json_object_new_string("TestrunResult"));
1109*d83cc019SAndroid Build Coastguard Worker 	json_object_object_add(obj, "results_version", json_object_new_int(10));
1110*d83cc019SAndroid Build Coastguard Worker 	json_object_object_add(obj, "name",
1111*d83cc019SAndroid Build Coastguard Worker 			       settings.name ?
1112*d83cc019SAndroid Build Coastguard Worker 			       json_object_new_string(settings.name) :
1113*d83cc019SAndroid Build Coastguard Worker 			       json_object_new_string(""));
1114*d83cc019SAndroid Build Coastguard Worker 
1115*d83cc019SAndroid Build Coastguard Worker 	if ((fd = openat(dirfd, "uname.txt", O_RDONLY)) >= 0) {
1116*d83cc019SAndroid Build Coastguard Worker 		char buf[128];
1117*d83cc019SAndroid Build Coastguard Worker 		ssize_t r = read(fd, buf, sizeof(buf));
1118*d83cc019SAndroid Build Coastguard Worker 
1119*d83cc019SAndroid Build Coastguard Worker 		if (r > 0 && buf[r - 1] == '\n')
1120*d83cc019SAndroid Build Coastguard Worker 			r--;
1121*d83cc019SAndroid Build Coastguard Worker 
1122*d83cc019SAndroid Build Coastguard Worker 		json_object_object_add(obj, "uname",
1123*d83cc019SAndroid Build Coastguard Worker 				       json_object_new_string_len(buf, r));
1124*d83cc019SAndroid Build Coastguard Worker 		close(fd);
1125*d83cc019SAndroid Build Coastguard Worker 	}
1126*d83cc019SAndroid Build Coastguard Worker 
1127*d83cc019SAndroid Build Coastguard Worker 	elapsed = json_object_new_object();
1128*d83cc019SAndroid Build Coastguard Worker 	json_object_object_add(elapsed, "__type__", json_object_new_string("TimeAttribute"));
1129*d83cc019SAndroid Build Coastguard Worker 	if ((fd = openat(dirfd, "starttime.txt", O_RDONLY)) >= 0) {
1130*d83cc019SAndroid Build Coastguard Worker 		char buf[128] = {};
1131*d83cc019SAndroid Build Coastguard Worker 		read(fd, buf, sizeof(buf));
1132*d83cc019SAndroid Build Coastguard Worker 		json_object_object_add(elapsed, "start", json_object_new_double(atof(buf)));
1133*d83cc019SAndroid Build Coastguard Worker 		close(fd);
1134*d83cc019SAndroid Build Coastguard Worker 	}
1135*d83cc019SAndroid Build Coastguard Worker 	if ((fd = openat(dirfd, "endtime.txt", O_RDONLY)) >= 0) {
1136*d83cc019SAndroid Build Coastguard Worker 		char buf[128] = {};
1137*d83cc019SAndroid Build Coastguard Worker 		read(fd, buf, sizeof(buf));
1138*d83cc019SAndroid Build Coastguard Worker 		json_object_object_add(elapsed, "end", json_object_new_double(atof(buf)));
1139*d83cc019SAndroid Build Coastguard Worker 		close(fd);
1140*d83cc019SAndroid Build Coastguard Worker 	}
1141*d83cc019SAndroid Build Coastguard Worker 	json_object_object_add(obj, "time_elapsed", elapsed);
1142*d83cc019SAndroid Build Coastguard Worker 
1143*d83cc019SAndroid Build Coastguard Worker 	create_result_root_nodes(obj, &results);
1144*d83cc019SAndroid Build Coastguard Worker 
1145*d83cc019SAndroid Build Coastguard Worker 	/*
1146*d83cc019SAndroid Build Coastguard Worker 	 * Result fields that won't be added:
1147*d83cc019SAndroid Build Coastguard Worker 	 *
1148*d83cc019SAndroid Build Coastguard Worker 	 * - glxinfo
1149*d83cc019SAndroid Build Coastguard Worker 	 * - wglinfo
1150*d83cc019SAndroid Build Coastguard Worker 	 * - clinfo
1151*d83cc019SAndroid Build Coastguard Worker 	 *
1152*d83cc019SAndroid Build Coastguard Worker 	 * Result fields that are TODO:
1153*d83cc019SAndroid Build Coastguard Worker 	 *
1154*d83cc019SAndroid Build Coastguard Worker 	 * - lspci
1155*d83cc019SAndroid Build Coastguard Worker 	 * - options
1156*d83cc019SAndroid Build Coastguard Worker 	 */
1157*d83cc019SAndroid Build Coastguard Worker 
1158*d83cc019SAndroid Build Coastguard Worker 	for (i = 0; i < job_list.size; i++) {
1159*d83cc019SAndroid Build Coastguard Worker 		char name[16];
1160*d83cc019SAndroid Build Coastguard Worker 
1161*d83cc019SAndroid Build Coastguard Worker 		snprintf(name, 16, "%zd", i);
1162*d83cc019SAndroid Build Coastguard Worker 		if ((testdirfd = openat(dirfd, name, O_DIRECTORY | O_RDONLY)) < 0) {
1163*d83cc019SAndroid Build Coastguard Worker 			try_add_notrun_results(&job_list.entries[i], &settings, &results);
1164*d83cc019SAndroid Build Coastguard Worker 			continue;
1165*d83cc019SAndroid Build Coastguard Worker 		}
1166*d83cc019SAndroid Build Coastguard Worker 
1167*d83cc019SAndroid Build Coastguard Worker 		if (!parse_test_directory(testdirfd, &job_list.entries[i], &settings, &results)) {
1168*d83cc019SAndroid Build Coastguard Worker 			close(testdirfd);
1169*d83cc019SAndroid Build Coastguard Worker 			return NULL;
1170*d83cc019SAndroid Build Coastguard Worker 		}
1171*d83cc019SAndroid Build Coastguard Worker 		close(testdirfd);
1172*d83cc019SAndroid Build Coastguard Worker 	}
1173*d83cc019SAndroid Build Coastguard Worker 
1174*d83cc019SAndroid Build Coastguard Worker 	if ((fd = openat(dirfd, "aborted.txt", O_RDONLY)) >= 0) {
1175*d83cc019SAndroid Build Coastguard Worker 		char buf[4096];
1176*d83cc019SAndroid Build Coastguard Worker 		char piglit_name[] = "igt@runner@aborted";
1177*d83cc019SAndroid Build Coastguard Worker 		struct subtests abortsub = {};
1178*d83cc019SAndroid Build Coastguard Worker 		struct json_object *aborttest = get_or_create_json_object(results.tests, piglit_name);
1179*d83cc019SAndroid Build Coastguard Worker 		ssize_t s;
1180*d83cc019SAndroid Build Coastguard Worker 
1181*d83cc019SAndroid Build Coastguard Worker 		add_subtest(&abortsub, strdup("aborted"));
1182*d83cc019SAndroid Build Coastguard Worker 
1183*d83cc019SAndroid Build Coastguard Worker 		s = read(fd, buf, sizeof(buf));
1184*d83cc019SAndroid Build Coastguard Worker 
1185*d83cc019SAndroid Build Coastguard Worker 		json_object_object_add(aborttest, "out",
1186*d83cc019SAndroid Build Coastguard Worker 				       json_object_new_string_len(buf, s));
1187*d83cc019SAndroid Build Coastguard Worker 		json_object_object_add(aborttest, "err",
1188*d83cc019SAndroid Build Coastguard Worker 				       json_object_new_string(""));
1189*d83cc019SAndroid Build Coastguard Worker 		json_object_object_add(aborttest, "dmesg",
1190*d83cc019SAndroid Build Coastguard Worker 				       json_object_new_string(""));
1191*d83cc019SAndroid Build Coastguard Worker 		json_object_object_add(aborttest, "result",
1192*d83cc019SAndroid Build Coastguard Worker 				       json_object_new_string("fail"));
1193*d83cc019SAndroid Build Coastguard Worker 
1194*d83cc019SAndroid Build Coastguard Worker 		add_to_totals("runner", &abortsub, &results);
1195*d83cc019SAndroid Build Coastguard Worker 
1196*d83cc019SAndroid Build Coastguard Worker 		free_subtests(&abortsub);
1197*d83cc019SAndroid Build Coastguard Worker 	}
1198*d83cc019SAndroid Build Coastguard Worker 
1199*d83cc019SAndroid Build Coastguard Worker 	free_settings(&settings);
1200*d83cc019SAndroid Build Coastguard Worker 	free_job_list(&job_list);
1201*d83cc019SAndroid Build Coastguard Worker 
1202*d83cc019SAndroid Build Coastguard Worker 	return obj;
1203*d83cc019SAndroid Build Coastguard Worker }
1204*d83cc019SAndroid Build Coastguard Worker 
generate_results(int dirfd)1205*d83cc019SAndroid Build Coastguard Worker bool generate_results(int dirfd)
1206*d83cc019SAndroid Build Coastguard Worker {
1207*d83cc019SAndroid Build Coastguard Worker 	struct json_object *obj = generate_results_json(dirfd);
1208*d83cc019SAndroid Build Coastguard Worker 	const char *json_string;
1209*d83cc019SAndroid Build Coastguard Worker 	int resultsfd;
1210*d83cc019SAndroid Build Coastguard Worker 
1211*d83cc019SAndroid Build Coastguard Worker 	if (obj == NULL)
1212*d83cc019SAndroid Build Coastguard Worker 		return false;
1213*d83cc019SAndroid Build Coastguard Worker 
1214*d83cc019SAndroid Build Coastguard Worker 	/* TODO: settings.overwrite */
1215*d83cc019SAndroid Build Coastguard Worker 	if ((resultsfd = openat(dirfd, "results.json", O_WRONLY | O_CREAT | O_TRUNC, 0666)) < 0) {
1216*d83cc019SAndroid Build Coastguard Worker 		fprintf(stderr, "resultgen: Cannot create results file\n");
1217*d83cc019SAndroid Build Coastguard Worker 		return false;
1218*d83cc019SAndroid Build Coastguard Worker 	}
1219*d83cc019SAndroid Build Coastguard Worker 
1220*d83cc019SAndroid Build Coastguard Worker 	json_string = json_object_to_json_string_ext(obj, JSON_C_TO_STRING_PRETTY);
1221*d83cc019SAndroid Build Coastguard Worker 	write(resultsfd, json_string, strlen(json_string));
1222*d83cc019SAndroid Build Coastguard Worker 	close(resultsfd);
1223*d83cc019SAndroid Build Coastguard Worker 	return true;
1224*d83cc019SAndroid Build Coastguard Worker }
1225*d83cc019SAndroid Build Coastguard Worker 
generate_results_path(char * resultspath)1226*d83cc019SAndroid Build Coastguard Worker bool generate_results_path(char *resultspath)
1227*d83cc019SAndroid Build Coastguard Worker {
1228*d83cc019SAndroid Build Coastguard Worker 	int dirfd = open(resultspath, O_DIRECTORY | O_RDONLY);
1229*d83cc019SAndroid Build Coastguard Worker 
1230*d83cc019SAndroid Build Coastguard Worker 	if (dirfd < 0)
1231*d83cc019SAndroid Build Coastguard Worker 		return false;
1232*d83cc019SAndroid Build Coastguard Worker 
1233*d83cc019SAndroid Build Coastguard Worker 	return generate_results(dirfd);
1234*d83cc019SAndroid Build Coastguard Worker }
1235