1<?php
2
3/*
4	Phoronix Test Suite
5	URLs: http://www.phoronix.com, http://www.phoronix-test-suite.com/
6	Copyright (C) 2009 - 2019, Phoronix Media
7	Copyright (C) 2009 - 2019, Michael Larabel
8	pts_ResultFileTable.php: The result file table object
9
10	This program is free software; you can redistribute it and/or modify
11	it under the terms of the GNU General Public License as published by
12	the Free Software Foundation; either version 3 of the License, or
13	(at your option) any later version.
14
15	This program is distributed in the hope that it will be useful,
16	but WITHOUT ANY WARRANTY; without even the implied warranty of
17	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18	GNU General Public License for more details.
19
20	You should have received a copy of the GNU General Public License
21	along with this program. If not, see <http://www.gnu.org/licenses/>.
22*/
23
24class pts_ResultFileTable extends pts_Table
25{
26	public $flagged_results = array();
27
28	public function __construct(&$result_file, $system_id_keys = null, $result_object_index = -1, $extra_attributes = null)
29	{
30		list($rows, $columns, $table_data) = pts_ResultFileTable::result_file_to_result_table($result_file, $system_id_keys, $result_object_index, $this->flagged_results, $extra_attributes);
31		parent::__construct($rows, $columns, $table_data, $result_file);
32		$this->result_object_index = $result_object_index;
33
34		if($result_object_index == -1)
35		{
36			$this->i['graph_title'] = $result_file->get_title();
37		}
38		else
39		{
40			$result_object = $result_file->get_result_objects($result_object_index);
41			if(isset($result_object[0]))
42			{
43				$this->i['graph_title'] = $result_object[0]->test_profile->get_title();
44				$this->graph_sub_titles[] = $result_object[0]->get_arguments_description();
45			}
46		}
47
48		// where to start the table values
49		$this->longest_row_identifier = null;
50		$longest_row_title_length = 0;
51		foreach($this->rows as $result_test)
52		{
53			if(($len = strlen($result_test)) > $longest_row_title_length)
54			{
55				$this->longest_row_identifier = $result_test;
56				$longest_row_title_length = $len;
57			}
58		}
59		$this->column_heading_vertical = false;
60		//$this->longest_column_identifier = max(pts_strings::find_longest_string($this->columns), pts_strings::find_longest_string($result_file->get_system_identifiers()));
61	}
62	public static function result_file_to_result_table(&$result_file, &$system_id_keys = null, &$result_object_index = -1, &$flag_delta_results = false, $extra_attributes = null)
63	{
64		$result_table = array();
65		$result_tests = array();
66		$result_counter = 0;
67
68		foreach($result_file->get_system_identifiers() as $sys_identifier)
69		{
70			$result_table[$sys_identifier] = null;
71		}
72
73		foreach($result_file->get_result_objects($result_object_index) as $ri => $result_object)
74		{
75			if($result_object->test_profile->get_identifier() == null)
76			{
77				continue;
78			}
79
80			if($extra_attributes != null)
81			{
82				if(isset($extra_attributes['reverse_result_buffer']))
83				{
84					$result_object->test_result_buffer->buffer_values_reverse();
85				}
86				if(isset($extra_attributes['normalize_result_buffer']))
87				{
88					if(isset($extra_attributes['highlight_graph_values']) && is_array($extra_attributes['highlight_graph_values']) && count($extra_attributes['highlight_graph_values']) == 1)
89					{
90						$normalize_against = $extra_attributes['highlight_graph_values'][0];
91					}
92					else
93					{
94						$normalize_against = false;
95					}
96
97					$result_object->normalize_buffer_values($normalize_against);
98				}
99			}
100
101			if($result_object_index != -1)
102			{
103				if(is_array($result_object_index))
104				{
105					$result_tests[$result_counter] = new pts_graph_ir_value($result_object->get_arguments_description());
106				}
107				else
108				{
109					$result_tests[$result_counter] = new pts_graph_ir_value('Results');
110				}
111			}
112			else
113			{
114				if($result_object->test_profile->get_identifier() != null)
115				{
116					$result_tests[$result_counter] = new pts_graph_ir_value($result_object->test_profile->get_identifier_base_name() . ': ' . $result_object->get_arguments_description_shortened(false));
117					$result_tests[$result_counter]->set_attribute('title', $result_object->get_arguments_description());
118					$result_tests[$result_counter]->set_attribute('href', 'https://openbenchmarking.org/test/' . $result_object->test_profile->get_identifier());
119				}
120				else if($result_object->test_profile->get_title() != null)
121				{
122					$result_tests[$result_counter] = new pts_graph_ir_value($result_object->test_profile->get_title() . ': ' . $result_object->get_arguments_description());
123				}
124			}
125
126			if(false && $result_object->test_profile->get_identifier() == null)
127			{
128				if($result_object->test_profile->get_display_format() == 'BAR_GRAPH')
129				{
130					//$result_tests[$result_counter]->set_attribute('alert', true);
131					foreach($result_object->test_result_buffer->get_buffer_items() as $index => $buffer_item)
132					{
133						$identifier = $buffer_item->get_result_identifier();
134						$value = $buffer_item->get_result_value();
135						$result_table[$identifier][$result_counter] = new pts_graph_ir_value($value, array('alert' => true));
136					}
137					$result_counter++;
138				}
139				continue;
140			}
141
142			$values_in_buffer = $result_object->test_result_buffer->get_values();
143			$has_numeric = false;
144			foreach($values_in_buffer as $i => $vb)
145			{
146				if(is_numeric($vb))
147				{
148					$has_numeric = true;
149					break;
150				}
151				else
152				{
153					unset($values_in_buffer[$i]);
154				}
155			}
156			if(!$has_numeric)
157			{
158				continue;
159			}
160
161			switch($result_object->test_profile->get_display_format())
162			{
163				case 'BAR_GRAPH':
164					$best_value = 0;
165					$worst_value = 0;
166
167					if(!defined('PHOROMATIC_TRACKER') && count($result_object->test_result_buffer->get_values()) > 1)
168					{
169						switch($result_object->test_profile->get_result_proportion())
170						{
171							case 'HIB':
172								$best_value = max($result_object->test_result_buffer->get_values());
173								$worst_value = min($result_object->test_result_buffer->get_values());
174								break;
175							case 'LIB':
176								$best_value = min($result_object->test_result_buffer->get_values());
177								$worst_value = max($result_object->test_result_buffer->get_values());
178								break;
179						}
180					}
181
182					$prev_value = 0;
183					$prev_identifier = null;
184					$prev_identifier_0 = null;
185
186					sort($values_in_buffer);
187					$min_value_in_buffer = $values_in_buffer[0];
188
189					if(empty($min_value_in_buffer))
190					{
191						// Go through the values until something not 0, otherwise down in the code will be a divide by zero
192						for($i = 1; $i < count($values_in_buffer) && empty($min_value_in_buffer); $i++)
193						{
194							$min_value_in_buffer = $values_in_buffer[$i];
195						}
196					}
197
198					$max_value_in_buffer = $values_in_buffer[(count($values_in_buffer) - 1)];
199
200					foreach($result_object->test_result_buffer->get_buffer_items() as $index => $buffer_item)
201					{
202						$identifier = $buffer_item->get_result_identifier();
203						$value = $buffer_item->get_result_value();
204
205						if(!is_numeric($value))
206						{
207							continue;
208						}
209
210						$raw_values = pts_strings::colon_explode($buffer_item->get_result_raw());
211						$percent_std = pts_math::set_precision(pts_math::percent_standard_deviation($raw_values), 2);
212						$std_error = pts_math::set_precision(pts_math::standard_error($raw_values), 2);
213						$delta = 0;
214
215						if(defined('PHOROMATIC_TRACKER'))
216						{
217							$identifier_r = pts_strings::colon_explode($identifier);
218
219							if($identifier_r[0] == $prev_identifier_0 && $prev_value != 0)
220							{
221								$delta = pts_math::set_precision(abs(1 - ($value / $prev_value)), 4);
222
223								if($delta > 0.02 && $delta > pts_math::standard_deviation($raw_values))
224								{
225									switch($result_object->test_profile->get_result_proportion())
226									{
227										case 'HIB':
228											if($value < $prev_value)
229											{
230												$delta = 0 - $delta;
231											}
232											break;
233										case 'LIB':
234											if($value > $prev_value)
235											{
236												$delta = 0 - $delta;
237											}
238											break;
239									}
240								}
241								else
242								{
243									$delta = 0;
244								}
245							}
246
247							$prev_identifier_0 = $identifier_r[0];
248							$highlight = false;
249							$alert = false;
250						}
251						else
252						{
253							if($result_file->is_multi_way_comparison())
254							{
255								// TODO: make it work better for highlighting multiple winners in multi-way comparisons
256								$highlight = false;
257								$alert = false;
258
259								// TODO: get this working right
260								if(false && $index % 2 == 1 && $prev_value != 0)
261								{
262									switch($result_object->test_profile->get_result_proportion())
263									{
264										case 'HIB':
265											if($value > $prev_value)
266											{
267												$highlight = true;
268											}
269											else
270											{
271												$result_table[$prev_identifier][$result_counter]->set_attribute('highlight', true);
272												$result_table[$prev_identifier][$result_counter]->set_attribute('delta', -1);
273											}
274											break;
275										case 'LIB':
276											if($value < $prev_value)
277											{
278												$highlight = true;
279											}
280											else
281											{
282												$result_table[$prev_identifier][$result_counter]->set_attribute('highlight', true);
283												$result_table[$prev_identifier][$result_counter]->set_attribute('delta', -1);
284											}
285											break;
286									}
287								}
288							}
289							else
290							{
291								$alert = $worst_value == $value;
292								$highlight = $best_value == $value;
293							}
294
295							if($min_value_in_buffer != $max_value_in_buffer)
296							{
297								switch($result_object->test_profile->get_result_proportion())
298								{
299									case 'HIB':
300										$delta = pts_math::set_precision($value / $min_value_in_buffer, 2);
301										break;
302									case 'LIB':
303										$delta = pts_math::set_precision(1 - ($value / $max_value_in_buffer) + 1, 2);
304										break;
305								}
306							}
307						}
308
309						$attributes = array(
310							'std_percent' => $percent_std,
311							'std_error' => $std_error,
312							'delta' => $delta,
313							'highlight' => $highlight,
314							'alert' => $alert
315							);
316
317						if($delta > $percent_std && $flag_delta_results !== false)
318						{
319							$flag_delta_results[$ri] = $delta;
320						}
321
322						$result_table[$identifier][$result_counter] = new pts_graph_ir_value($value, $attributes);
323						$prev_identifier = $identifier;
324						$prev_value = $value;
325					}
326					break;
327				case 'LINE_GRAPH':
328				case 'FILLED_LINE_GRAPH':
329					$result_tests[$result_counter] = new pts_graph_ir_value($result_object->test_profile->get_title() . ' (Avg)');
330
331					foreach($result_object->test_result_buffer->get_buffer_items() as $index => $buffer_item)
332					{
333						$identifier = $buffer_item->get_result_identifier();
334						$values = pts_strings::comma_explode($buffer_item->get_result_value());
335						$avg_value = pts_math::set_precision(pts_math::arithmetic_mean($values), 2);
336						$result_table[$identifier][$result_counter] = new pts_graph_ir_value($avg_value);
337					}
338					break;
339			}
340
341			$result_counter++;
342		}
343
344		if($result_counter == 1)
345		{
346			// This should provide some additional information under normal modes
347			$has_written_std = false;
348			$has_written_diff = false;
349			$has_written_error = false;
350
351			foreach($result_table as $identifier => $info)
352			{
353				if(!isset($info[($result_counter - 1)]))
354				{
355					continue;
356				}
357
358				$std_percent = $info[($result_counter - 1)]->get_attribute('std_percent');
359				$std_error = $info[($result_counter - 1)]->get_attribute('std_error');
360				$delta = $info[($result_counter - 1)]->get_attribute('delta');
361
362				if($delta != 0)
363				{
364					$result_table[$identifier][] = new pts_graph_ir_value($delta . 'x');
365					$has_written_diff = true;
366				}
367				if($std_error != 0)
368				{
369					$result_table[$identifier][] = new pts_graph_ir_value($std_error);
370					$has_written_error = true;
371				}
372				if($std_percent != 0)
373				{
374					$result_table[$identifier][] = new pts_graph_ir_value($std_percent . '%');
375					$has_written_std = true;
376				}
377			}
378
379			if($has_written_diff)
380			{
381				$result_tests[] = new pts_graph_ir_value('Difference');
382			}
383			if($has_written_error)
384			{
385				$result_tests[] = new pts_graph_ir_value('Standard Error');
386			}
387			if($has_written_std)
388			{
389				$result_tests[] = new pts_graph_ir_value('Standard Deviation');
390			}
391		}
392
393		if(defined('PHOROMATIC_TRACKER'))
394		{
395			// Resort the results by SYSTEM, then date
396			$systems_table = array();
397			$sorted_table = array();
398
399			foreach($result_table as $system_identifier => &$identifier_table)
400			{
401				$identifier = pts_strings::colon_explode($system_identifier);
402
403				if(!isset($systems_table[$identifier[0]]))
404				{
405					$systems_table[$identifier[0]] = array();
406				}
407
408				$systems_table[$identifier[0]][$system_identifier] = $identifier_table;
409			}
410
411			$result_table = array();
412			$result_systems = array();
413
414			foreach($systems_table as &$group)
415			{
416				foreach($group as $identifier => $table)
417				{
418					$result_table[$identifier] = $table;
419
420					$identifier = pts_strings::colon_explode($identifier);
421					$show_id = isset($identifier[1]) ? $identifier[1] : $identifier[0];/*
422
423					if($system_id_keys != null && ($s = array_search($identifier[0], $system_id_keys)) !== false)
424					{
425						$system_id = $s;
426					}
427					else
428					{
429						$system_id = null;
430					}*/
431
432					$result_systems[] = $show_id;
433				}
434			}
435		}
436		else
437		{
438			$result_systems = array();
439
440			foreach(array_keys($result_table) as $id)
441			{
442				$result_systems[] = $id;
443			}
444		}
445
446		return array($result_tests, $result_systems, $result_table);
447	}
448}
449
450?>
451